25.OpenCV的交互式前景提取——示例
前言
人工干预(体现交互)的方法将前景从图像中分割或提取出来。
一、使用模板匹配查找图像
# 使用模板匹配查找图像
img1 = cv2.imread('handball.jpg') # 打开输入图像
temp = cv2.imread('ball.jpg') # 打开模板图像
cv2.imshow('original',img1)
cv2.imshow('template',temp)
img1gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY, dstCn=1) # 转换为单通道灰度图像
tempgray = cv2.cvtColor(temp, cv2.COLOR_BGR2GRAY, dstCn=1) # 转换为单通道灰度图像
h,w = tempgray.shape # 获得模板图像的高度和宽度
res = cv2.matchTemplate(img1gray, tempgray, cv2.TM_SQDIFF) # 执行匹配
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 返回匹配位置
top_left = min_loc # 最小值为最佳匹配,获得其位置
bottom_right = (top_left[0] + w, top_left[1] + h) # 获得匹配范围的右下角位置
cv2.rectangle(img1, top_left, bottom_right, (0,0,255), 2) # 绘制匹配范围,红色边框
cv2.imshow('Detected Range',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、使用交互式前景提取方法分割图像
# 使用交互式前景提取方法分割图像
img = cv2.imread('cup.jpg')
cv2.imshow('original',img)
mask = np.zeros(img.shape[:2], np.uint8) # 定义原始掩模
bg = np.zeros((1,65),np.float64)
fg = np.zeros((1,65),np.float64)
rect = (50,50,200,300) # 根据原图设置包含前景的矩形大小
cv2.grabCut(img, mask, rect, bg, fg, 5, cv2.GC_INIT_WITH_RECT) # 第1次提取前景,矩形模式
imgmask = cv2.imread('cup2.jpg') # 读取已标注的掩模图像
cv2.imshow('mask image',imgmask)
mask2 = cv2.cvtColor(imgmask,cv2.COLOR_BGR2GRAY,dstCn=1) # 转换未单通道灰度图像
mask[mask2 == 0] = 0 # 根据掩模图像,将掩模图像中白黑色像素对应的原始掩模像素设置为0
mask[mask2 == 255] = 1 # 根据掩模图像,将掩模图像中白色像素对应的原始掩模像素设置为1
cv2.grabCut(img, mask ,None, bg, fg, 5, cv2.GC_INIT_WITH_MASK) # 第2次提取前景,掩模模式
#将返回的掩模中像数值为0或2像素设置为0(确认为背景),
#所有1或3的像素设置为1(确认为前景)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis] # 将掩模与原图像相乘获得分割出来的前景图像
cv2.imshow('grabCut', img) # 显示获得的前景
cv2.waitKey(0)
cv2.destroyAllWindows()
三、使用鼠标选取范围的前景提取
# 鼠标事件的回调函数
def on_mouse(event, x, y, flag, param):
global rect
global leftButtonDowm
global leftButtonUp
# 鼠标左键按下
if event == cv2.EVENT_LBUTTONDOWN:
rect[0] = x
rect[2] = x
rect[1] = y
rect[3] = y
leftButtonDowm = True
leftButtonUp = False
# 移动鼠标事件
if event == cv2.EVENT_MOUSEMOVE:
if leftButtonDowm and not leftButtonUp:
rect[2] = x
rect[3] = y
# 鼠标左键松开
if event == cv2.EVENT_LBUTTONUP:
if leftButtonDowm and not leftButtonUp:
x_min = min(rect[0], rect[2])
y_min = min(rect[1], rect[3])
x_max = max(rect[0], rect[2])
y_max = max(rect[1], rect[3])
rect[0] = x_min
rect[1] = y_min
rect[2] = x_max
rect[3] = y_max
leftButtonDowm = False
leftButtonUp = True
# 读入图片
img = cv2.imread('hehua.jpg')
# 掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;
# 在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果
mask = np.zeros(img.shape[:2],np.uint8)
# 背景模型,如果为None,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型图像,且行数只能为1,列数只能为13x5;
bgdModel = np.zeros((1,65),np.float64)
# 前景模型,如果为None,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型图像,且行数只能为1,列数只能为13x5;
fgdModel = np.zeros((1,65),np.float64)
#用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
rect = [0,0,0,0]
#鼠标左键按下
leftButtonDowm = False
#鼠标左键松开
leftButtonUp = True
#指定窗口名来创建窗口
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
#设置鼠标事件回调函数 来获取鼠标输入
cv2.setMouseCallback('img',on_mouse)
#显示图片
cv2.imshow('img',img)
while cv2.waitKey(2) == -1:
# 左键按下,画矩阵
if leftButtonDowm and not leftButtonUp:
img_copy = img.copy()
# 在img图像上,绘制矩形 线条颜色为green 线宽为2
cv2.rectangle(img_copy,(rect[0],rect[1]),(rect[2],rect[3]),(0,255,0),5)
# 显示图片
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.imshow('img',img_copy)
# 左键松开,矩形画好
elif not leftButtonDowm and leftButtonUp and rect[2] - rect[0] != 0 and rect[3] - rect[1] != 0:
# 转换为宽度高度
rect[2] = rect[2] - rect[0]
rect[3] = rect[3] - rect[1]
rect_copy = tuple(rect.copy())
rect = [0,0,0,0]
#物体分割
cv2.grabCut(img,mask,rect_copy,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img_show = img * mask2[:,:,np.newaxis]
#显示图片分割后结果
cv2.namedWindow('grabcut', cv2.WINDOW_NORMAL)
cv2.imshow('grabcut',img_show)
#显示原图
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
四、OpenCV-Python资源下载
OpenCV-Python测试用图片、中文官方文档、opencv-4.5.4源码
总结
以上内容介绍了OpenCV-Python的交互式前景提取的相关示例,有关Python、数据科学、人工智能等文章后续会不定期发布,请大家多多关注,一键三连哟(●’◡’●)。