opencv-python 小白笔记(16)

第十六节:cv2.selectROI函数,图像的背景替换

(一)cv2.selectROI与cv2.selectROIs函数

这个函数可以帮助我们首先上一节的鼠标提取目标区域的功能,非常方便。
上一节传送门

selectROI(windowName, img, showCrosshair, fromCenter):

参数解释
windowName选择的区域被显示在的窗口的名字
img要在什么图片上选择ROI
showCrosshair是否在矩形框里画十字线(True为画十字线)
fromCenter是否是从矩形框的中心开始画(True为从矩形框的中心开始画)

这个函数的返回值为 (x_min, y_min, w, h),即矩形框的左上角的坐标和矩形框的宽高。

下面我们将实现用该函数对目标区域进行框选,然后对框选区域进行截取

PS:在你使用该函数对目标区域进行框选时,终端还会打印出该函的使用方法

import cv2
import numpy as np

img = cv2.imread("shapes.png")

r = cv2.selectROI('input', img, True,False)  # 返回 (x_min, y_min, w, h)

# roi区域
roi = img[int(r[1]):int(r[1]+r[3]), int(r[0]):int(r[0]+r[2])]

cv2.imshow('roi', roi)
cv2.waitKey(0)

在这里插入图片描述
这时候可能就会有小伙伴问了,假如我想同选择多个目标怎么办,那么这时候你就需要用到cv2.selectROIs函数,注意后面有个s

下面将用cv2.selectROIs函数,同时框选3个目标,并将它们裁剪下来(框选方法:当你使用鼠标框选一个一个目标后,你需要点击space或enter键,然后才能框选下一个吗目标。当你框选所有的目标后,你需要esc键)

下面程序会依次显示截取的目标图片

import cv2
import numpy as np

img = cv2.imread("shapes.png")

ROIs = cv2.selectROIs('input', img, True,False)  # 返回 (x_min, y_min, w, h)

if len(ROIs) >0:
    for ROI in ROIs:
        x,y,w,h=ROI
        roi = img[int(y):int(y + h), int(x):int(x + w)]
        cv2.imshow('roi', roi)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

这里就不展示结果了,感兴趣的小伙伴自己跑一下吧

(二)图像的背景替换

下面是我写的背景替换,可能比较笨,但是勉强可用

import cv2
import numpy as np

kernel=np.ones((3,3),np.uint8)
src = cv2.imread("lambo.PNG")


r = cv2.selectROI('input', src, True)  # 返回 (x_min, y_min, w, h)

# roi区域
roi = src[int(r[1]):int(r[1]+r[3]), int(r[0]):int(r[0]+r[2])]

# 原图mask
mask = np.zeros(src.shape[:2], dtype=np.uint8)

# 矩形roi
rect = (int(r[0]), int(r[1]), int(r[2]), int(r[3])) # 包括前景的矩形,格式为(x,y,w,h)

bgdmodel = np.zeros((1,65),np.float64) # bg模型的临时数组
fgdmodel = np.zeros((1,65),np.float64) # fg模型的临时数组

cv2.grabCut(src,mask,rect,bgdmodel,fgdmodel, 5, mode=cv2.GC_INIT_WITH_RECT)

# 提取前景和可能的前景区域
mask1 = np.where((mask==1) + (mask==3), 255, 0).astype('uint8')


result = cv2.bitwise_and(src,src,mask=mask1)#这里先抠出目标图片
cv2.imshow("result", result)
cv2.waitKey(0)

img1=cv2.imread('background.jpg')#加载背景图片
cv2.imshow('background',img1)
cv2.waitKey(0)

img1=cv2.GaussianBlur(img1,(3,3),15)#虚化背景图片
mask_inv=cv2.bitwise_not(mask1)#这里先生成mask1的反码
cv2.imshow('mask_inv',mask_inv)
cv2.waitKey(0)

out_put = cv2.bitwise_and(img1,img1,mask=mask_inv)#用上面生成的反码,在背景图片上扣一个与目标图片大小的位置
cv2.morphologyEx(out_put,cv2.MORPH_OPEN,kernel)#对上面生成的位置进行光滑处理与降噪
cv2.imshow("out_put",out_put)
cv2.waitKey(0)

cv2.morphologyEx(result.copy(),cv2.MORPH_OPEN,kernel)#对目标图片进行光滑处理与降噪
res=result.copy()+out_put#将目标图片与处理后的背景图片进行相加
cv2.imshow('res',res)
cv2.waitKey(0)

cv2.destroyAllWindows()

在这里插入图片描述
这里就不一一展示每幅图片了,小伙伴们自己跑一下(要注意的是,背景图片要与目标图片设置为相同的大小)

下面另一种背景融合的方法,与上面最大的区别就是,最后的图像融合部分

import cv2
import numpy as np

kernel=np.ones((3,3),np.uint8)
src = cv2.imread("lambo.PNG")


r = cv2.selectROI('input', src, True)  # 返回 (x_min, y_min, w, h)

# roi区域
roi = src[int(r[1]):int(r[1]+r[3]), int(r[0]):int(r[0]+r[2])]

# 原图mask
mask = np.zeros(src.shape[:2], dtype=np.uint8)

# 矩形roi
rect = (int(r[0]), int(r[1]), int(r[2]), int(r[3])) # 包括前景的矩形,格式为(x,y,w,h)

#bgdmodel = np.zeros((1,65),np.float64) # bg模型的临时数组
#fgdmodel = np.zeros((1,65),np.float64) # fg模型的临时数组

cv2.grabCut(src,mask,rect,None,None, 5, mode=cv2.GC_INIT_WITH_RECT)

# 提取前景和可能的前景区域
mask1 = np.where((mask==1) + (mask==3), 255, 0).astype('uint8')

cv2.erode(mask1,kernel,iterations=3)#腐蚀一下
cv2.dilate(mask1,kernel,iterations=3)#在膨胀回去
cv2.imshow('mask1',mask1)
cv2.waitKey(0)


img1=cv2.imread('background.jpg')#加载背景图片
h,w=img1.shape[:2]
print(h,w)
img1=cv2.GaussianBlur(img1,(3,3),15)#虚化背景图片
cv2.imshow('background',img1)
cv2.waitKey(0)


#遍历替换
pianyi=[0,0]#目标图片相对与在原图中的偏移量,这里设置为0
for i in range(h):
    for j in range(w):
        if mask1[i,j]==255:#0代表白色的点
            img1[pianyi[0]+i,pianyi[1]+j]=src[i,j]#此处替换颜色,为BGR通道

cv2.imshow('out_put',img1)
cv2.waitKey(0)

cv2.destroyAllWindows()

在这里插入图片描述
我感觉,这种图像融合的方法,更好。

(三)结语

学习opencv有很多的方法,我的建议是你可以加一些群,可以充分利用B站,CSDN,和百度。

在我的博客中,我不会讲解opencv的算法实现(当然我也不太会),我只会讲解一些函数的调用,不理解就多改一些参数,多尝试尝试,慢慢你就理解来。相信你总有一天可以说opencv不过“Ctrl+C,Crtl+V”

如果有什么错误的地方,还请大家批评指正,最后,希望小伙伴们都能有所收获。

在这里插入图片描述

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值