文章目录
项目介绍实现步骤代码说明1、导入需要的库2、定义绘图函数3、导入前景图片和背景图片4、对两张图片进行水平(镜像)翻转5、将前景图片从 BGR 转换到 HSV 空间6、检测红色区域7、处理红色区域8、融合前景和背景
完整代码参考资料
项目介绍
在这个项目中,我们会使用 Opencv 来将红色物体变成透明状,以此来达到隐身效果,如下面这张动图所示:
实现步骤
找到一个只含有背景的帧;检测红色物体的位置;将红色区域用背景中的相同区域代替。
代码说明
我们先用下面这两张图片(前者为背景,后者为前景)来举例说明。 在实现隐身效果之后,得到的图片应该为:
1、导入需要的库
import cv2
import numpy
as np
2、定义绘图函数
def cv_show(name
,img
):
cv2
.imshow
(name
, img
)
cv2
.waitKey
(0)
cv2
.destroyAllWindows
()
3、导入前景图片和背景图片
background
= cv2
.imread
('background.jpg')
img
= cv2
.imread
('foreground.jpg')
4、对两张图片进行水平(镜像)翻转
因为调用摄像头之后显示的画面和真实的画面是镜像的,所以这里要先调整一下。
background
= np
.flip
(background
, axis
=1)
img
= np
.flip
(img
, axis
=1)
这里使用的 np.flip 函数中的 axis 指的是将这张图片基于哪个维度翻转,如果 axis=0,那么就是上下翻转;如果 axis=1,那么就是左右翻转;如果 axis=2,那么就是基于 RGB 三通道之间的转变。
5、将前景图片从 BGR 转换到 HSV 空间
如果基于 RGB 空间检测红色很困难,因为红色是 RGB 三通道综合起来获得的。所以我们要先将图片转到 HSV 空间。HSV 对颜色的定义更接近人的视觉系统。
HSV空间各个参数如下:
色调(Hue):用角度度量,取值范围为 0°-360°。可以认为 0° 对应于红色,120° 对应于绿色,240° 对应于蓝色。饱和度(Saturation):饱和度表示颜色的强度和纯度。明度(Value):表示颜色的明暗程度,取值范围为 0.0 (黑色)~1.0 (白色)。
颜色仅由色调(Hue)决定。在 OpenCV 中色调不是 0° 到 360°,而是被量化为 0° 到 180°。
hsv
= cv2
.cvtColor
(img
, cv2
.COLOR_BGR2HSV
)
6、检测红色区域
基于 OpenCV 中的 inRange 函数筛选颜色。其中红色 H 值的范围为 0°-10° 和 170°-180°,以避免发现皮肤为红色。因为红布应该是高度饱和的红色。所以 S 值设定为 120 到 255。V 值设置为 105 到 255。根据以上能够获得红色 H 值的范围为 0°-10° 和 170°-180° 的两个红色区域,然后合并这两个区域。
lower_red
= np
.array
([0,120,105])
upper_red
= np
.array
([10,255,255])
mask1
= cv2
.inRange
(hsv
, lower_red
, upper_red
)
lower_red
= np
.array
([170,120,105])
upper_red
= np
.array
([180,255,255])
mask2
= cv2
.inRange
(hsv
,lower_red
,upper_red
)
mask
= mask1
+ mask2
合并后的区域如下图所示:
7、处理红色区域
因为上一步中提取到的红色区域中掺入了少量面部的红色区域,所以这里用形态学操作去掉这些区域。
mask
= cv2
.morphologyEx
(mask
, cv2
.MORPH_OPEN
, np
.ones
((3,3),np
.uint8
),iterations
=2)
mask
= cv2
.dilate
(mask
,np
.ones
((3,3),np
.uint8
),iterations
= 1)
mask_inverse
= cv2
.bitwise_not
(mask
)
最终得到的红色区域为: 可以看到,经过形态学操作后,面部被识别出的区域已经被去除掉了。
8、融合前景和背景
res1
= cv2
.bitwise_and
(background
, background
, mask
=mask
)
res2
= cv2
.bitwise_and
(img
, img
, mask
=mask_no
)
final_output
= cv2
.addWeighted
(res1
, 1, res2
, 1, 0)
res1、res2 和 final_output 的图片分别为:
完整代码
import cv2
import numpy
as np
cap
= cv2
.VideoCapture
(0)
for i
in range(30):
ret
, background
= cap
.read
()
background
= np
.flip
(background
, axis
=1)
while True:
ret
, img
= cap
.read
()
if not ret
:
break
count
+=1
img
= np
.flip
(img
, axis
=1)
hsv
= cv2
.cvtColor
(img
, cv2
.COLOR_BGR2HSV
)
lower_red
= np
.array
([0,120,105])
upper_red
= np
.array
([10,255,255])
mask1
= cv2
.inRange
(hsv
, lower_red
, upper_red
)
lower_red
= np
.array
([170,120,105])
upper_red
= np
.array
([180,255,255])
mask2
= cv2
.inRange
(hsv
, lower_red
, upper_red
)
mask
= mask1
+ mask2
mask
= cv2
.morphologyEx
(mask
, cv2
.MORPH_OPEN
, np
.ones
((3,3),np
.uint8
), iterations
=2)
mask
= cv2
.dilate
(mask
, np
.ones
((3,3),np
.uint8
), iterations
= 1)
mask_inverse
= cv2
.bitwise_not
(mask
)
res1
= cv2
.bitwise_and
(background
, background
, mask
=mask
)
res2
= cv2
.bitwise_and
(img
, img
, mask
=mask_inverse
)
final_output
= cv2
.addWeighted
(res1
, 1, res2
, 1, 0)
cv2
.imshow
('Magic !!!',final_output
)
if cv2
.waitKey
(1) & 0xff == ord('q'):
break
cap
.release
()
cv2
.destroyAllWindows
()
参考资料
luohenyueji