python JPG图片手动圈画掩膜Mask轮廓ROI
创始人
2024-04-06 17:11:30
0

首先尝试实现一张JPG图片的勾画
注:opencv2键鼠操作可参考本博主的文章:python-opencv控制鼠标操作

import numpy as np
import cv2 as cv
from matplotlib import pylab as pltdef drawing(event, x, y, flags, param):global img #声明img为全局变量以在drawing函数内部使用imgif event == 0 and flags == 1: #发现鼠标移动且左键按下print(x,y,"\n") #x y为此时鼠标坐标cv.circle(img, (x, y), 1, (71,0, 255), -1) #img图像为底 在(x,y)处画一个大小为1的点,其颜色为(71,0,255)(RGB)cv.imshow('img1', img) #显示新的img图像与窗口img = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00001.jpg')#读取jpg文件
cv.namedWindow("img1")#命名窗口为img1
cv.moveWindow('img1',100,100)#将名为img1的窗口移动到屏幕100,100的位置
cv.setMouseCallback('img1', drawing)#将名为img1的窗口与IO操作函数drawing关联
cv.imshow('img1', img)#显示名为img1的窗口,窗口内图片为刚读取的JPG图像:img
cv.waitKey(0)#等待操作
cv.destroyAllWindows()#关闭窗口

运行可以得到如下图窗口 按下鼠标左键并移动即可画图
注意:若移动过快则会画出许多点,所以请勿勾画过快
在这里插入图片描述
目前我们只实现了一张图像的勾画,怎样才能实现多张图像的快速勾画呢?
比如使用鼠标滚轮快速切换图像
听起来很简单,但也是需要做不少修改的,需要我们理解opencv2窗口、图像、IO函数的机制,以五张图像为例,代码如下(为方便大家理解,未采用循环操作,请大家在自己代码中自行更改):

import numpy as np
import cv2 as cv
from matplotlib import pylab as pltnow=0 #从第一张图片开始 意为当前为第几张图片
im=[] #用来存储所有图片
imgs='image'+str(now) #当前窗口名 根据now进行修改以实现窗口切换def drawing(event, x, y, flags, param):global imgsglobal nowglobal imif event == 0 and flags == 1: #检测到鼠标移动且左键按下print(x,y,"\n")cv.circle(im[now], (x, y), 1, (71,0, 255), -1)cv.imshow(imgs, im[now])elif event==10: #检测到滚轮滑动cv.destroyAllWindows() #先关闭当前窗口if(flags<0): #如果是下滑now+=1 #图片切换到下一张if(now>(num-1)):now=0 #若超过最大图片数则置为第一张循环开始imgs='image'+str(now) #窗口名也随之进行修改cv.namedWindow(imgs) #建立新的窗口cv.moveWindow(imgs,100,100) #移动新的窗口cv.setMouseCallback(imgs, drawing) #为新的窗口关联IO函数cv.imshow(imgs, im[now]) #显示新的窗口 else: #如果是上滑now-=1 #切换到上一张if(now<0):now=num-1 #若当前为第一张 则切换为最后一张进行循环imgs='image'+str(now) #以下同上cv.namedWindow(imgs)cv.moveWindow(imgs,100,100)cv.setMouseCallback(imgs, drawing)  cv.imshow(imgs, im[now])num = 5 #共五张图片
#依次读取五张图片
img = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00001.jpg')
img2 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00002.jpg')
img3 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00003.jpg')
img4 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00004.jpg')
img5 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00005.jpg')
#将图片数据保存在im列表中
im.append(img)
im.append(img2)
im.append(img3)
im.append(img4)
im.append(img5)#↓↓↓↓↓↓↓↓↓先建立第一张图片的窗口↓↓↓↓↓↓↓↓↓
cv.namedWindow(imgs) 
cv.moveWindow(imgs,100,100)
cv.setMouseCallback(imgs, drawing)
cv.imshow(imgs, im[now])cv.waitKey(0)
cv.destroyAllWindows()

由此一来,便实现了滚轮快速切换勾画图像的需求。

现在只实现了画图而已,MASK掩膜其实是勾画内部全部为1,外部全部为0的图像,与原JPG文件并无关系,所以我们需要记录勾画的坐标然后找到内部的点并将其置为1,其余置为0

先尝试记录下每张图像勾画的坐标

import numpy as np
import cv2 as cv
from matplotlib import pylab as pltnum = 5
now=0
im=[]
XY=[] #XY用来存储五张图片各自勾画的坐标
imgs='image'+str(now)
for i in range(num):XY.append([])def drawing(event, x, y, flags, param):global imgs #窗口名global now #当前图片global im #所有图片if event == 0 and flags == 1: #鼠标移动 and 左键按下#注:为了加快运算速度,勾画时不会存储本图片已勾画过的点if([x,y] not in XY[now]): #若当前点未记录则添加XY[now].append([x,y])if([x+1,y+1] not in XY[now]):#将当前点与附近的点都添加进勾画坐标以防止出现间隙XY[now].append([x+1,y+1])if([x-1,y-1] not in XY[now]):XY[now].append([x-1,y-1])if([x+1,y-1] not in XY[now]):XY[now].append([x+1,y-1])if([x-1,y+1] not in XY[now]):XY[now].append([x-1,y+1])if([x+1,y] not in XY[now]):XY[now].append([x+1,y])if([x-1,y] not in XY[now]):XY[now].append([x-1,y])if([x,y+1] not in XY[now]):XY[now].append([x,y+1])if([x,y-1] not in XY[now]):XY[now].append([x,y-1])cv.circle(im[now], (x, y), 1, (71,0, 255), -1)cv.imshow(imgs, im[now])elif event==10: #滚轮cv.destroyAllWindows()if(flags<0): #向下滚now+=1if(now>num-1):now=0imgs='image'+str(now)cv.namedWindow(imgs)cv.moveWindow(imgs,100,100)cv.setMouseCallback(imgs, drawing)  cv.imshow(imgs, im[now])else: #向下滚now-=1if(now<0):now=num-1imgs='image'+str(now)cv.namedWindow(imgs)cv.moveWindow(imgs,100,100)cv.setMouseCallback(imgs, drawing)  cv.imshow(imgs, im[now])img = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00001.jpg')
img2 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00002.jpg')
img3 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00003.jpg')
img4 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00004.jpg')
img5 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00005.jpg')
im.append(img)
im.append(img2)
im.append(img3)
im.append(img4)
im.append(img5)
cv.namedWindow(imgs)
cv.moveWindow(imgs,100,100)
cv.setMouseCallback(imgs, drawing)
cv.imshow(imgs, im[now])cv.waitKey(0)
cv.destroyAllWindows()

XY数据如下图所示 其中图片0 1 2被勾画 3 4未勾画
在这里插入图片描述
现在我们便成功得到了勾画坐标,进行一些处理便可以生成MASK掩膜文件
①找到勾画内部的坐标点
②将圈画及内部置为1,外部置为0
③优化速度

找到内部坐标点最稳定的方法就是检测当前点的上下左右是否含有勾画点,缺点是速度比较慢,但可以通过一些优化大大加快其速度
请注意: 代码中图像存储行列大小与此处分辨率应做调换 详见代码及注释在这里插入图片描述

完整代码如下:

import numpy as np
import cv2 as cv
from matplotlib import pylab as pltnum = 5
now=0
im=[]
XY=[]
imgs='image'+str(now)
for i in range(num):XY.append([])#检测左侧是否有勾画点
def left(ii,jj,l):for i in l:if(i[0]==ii and i[1]jj):return Truereturn False
#检测上侧是否有勾画点
def up(ii,jj,l):for i in l:if(i[1]==jj and i[0]ii):return Truereturn False def drawing(event, x, y, flags, param):global imgsglobal nowglobal imif event == 0 and flags == 1: #鼠标移动 and 左键按下if([x,y] not in XY[now]):XY[now].append([x,y])if([x+1,y+1] not in XY[now]):XY[now].append([x+1,y+1])if([x-1,y-1] not in XY[now]):XY[now].append([x-1,y-1])if([x+1,y-1] not in XY[now]):XY[now].append([x+1,y-1])if([x-1,y+1] not in XY[now]):XY[now].append([x-1,y+1])if([x+1,y] not in XY[now]):XY[now].append([x+1,y])if([x-1,y] not in XY[now]):XY[now].append([x-1,y])if([x,y+1] not in XY[now]):XY[now].append([x,y+1])if([x,y-1] not in XY[now]):XY[now].append([x,y-1])cv.circle(im[now], (x, y), 1, (71,0, 255), -1)cv.imshow(imgs, im[now])elif event==10: #滚轮cv.destroyAllWindows()if(flags<0): #向下滚now+=1if(now>num-1):now=0imgs='image'+str(now)cv.namedWindow(imgs)cv.moveWindow(imgs,100,100)cv.setMouseCallback(imgs, drawing)  cv.imshow(imgs, im[now])else: #向下滚now-=1if(now<0):now=num-1imgs='image'+str(now)cv.namedWindow(imgs)cv.moveWindow(imgs,100,100)cv.setMouseCallback(imgs, drawing)  cv.imshow(imgs, im[now])img = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00001.jpg')
img2 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00002.jpg')
img3 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00003.jpg')
img4 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00004.jpg')
img5 = cv.imread(r'C:\Users\Miao\Desktop\T1jpg\IMG-0003-00005.jpg')
im.append(img)
im.append(img2)
im.append(img3)
im.append(img4)
im.append(img5)
cv.namedWindow(imgs)
cv.moveWindow(imgs,100,100)
cv.setMouseCallback(imgs, drawing)
cv.imshow(imgs, im[now])cv.waitKey(0)
cv.destroyAllWindows()img_size = [260, 320, 3] #根据自己的JPG图像修改前两个数据大小 与分辨率调换行列for l in XY: #依次处理每张图片的勾画if(l):#若本图有勾画信息img2 = np.zeros(img_size, np.uint16)#先生成同型的全0数据for m in l:           img2[m[1]][m[0]]=[1,1,1]#若想可视化,请修改为[255,255,255],但掩膜文件应全为1,方便后续处理iii=0jjj=0start=0 #当前行是否有勾画 for i in img2:jjj=0if(right(iii,jjj,l) or left(iii,jjj,l) or up(iii,jjj,l) or down(iii,jjj,l)):start=1 #若当前行有勾画则处理本行if(start):for j in i:if(right(iii,jjj,l) and left(iii,jjj,l) and up(iii,jjj,l) and down(iii,jjj,l)):img2[jjj][iii]=[1,1,1] #注:若想可视化请修改为[255,255,255],但制作掩膜需要使用[1,1,1]jjj+=1start=0iii+=1#若需要可视化 请先将代码中[1,1,1]修改为[255,255,255]    #plt.figure(figsize=(26, 32))#ax = plt.subplot(3,1,1)#ax.imshow(img2)#ax.axis("off")

若将代码中[1,1,1]修改为[255,255,255]并取消最后四行的注释则可进行可视化
在这里插入图片描述

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...