1、项目介绍:
2、环境安装
- usb摄像头
- 平台:windows 10
- 编译器:pycharm
- cuda 11.3
- cudnn 8.2.0.53
conda create -n invisible python=3.8
conda activate invisible
pip install opencv-python
pip install numpy
3、执行代码
步骤1:捕捉并存储背景帧
关键思想是将当前与布料相对应的帧像素替换为背景像素,从而产生一件隐身衣的效果。为此,我们需要存储一个背景帧。
步骤2:检测红色
# 创建视频捕获对象
# 这将用于稍后代码中的图像采集。
cap = cv2.VideoCapture(5)
# 我们给相机一些时间来初始化
time.sleep(3)
count = 0
background=0
# 捕获和存储静态背景帧
for i in range(60):
ret,background = cap.read()
在上面的代码中,cap.read()方法使我们能够通过相机捕获最新的帧(存储在变量‘background’中),它还返回一个布尔值(True/False存储在‘ret’中)。如果一个帧被正确读取,它将为真。所以你可以通过检查这个返回值来检查视频的结束。
为什么捕获背景图像使用’循环’?
因为背景是静态的,我们不能简单地使用一个帧吗?当然,但是与多帧图像相比,捕获的图像有点暗。这是因为相机刚刚开始捕捉帧,因此它的参数还不稳定。因此,使用for循环捕获静态背景的多个图像就可以完成这个任务。多帧平均也可以降低噪声。
因为我们使用了一块红色的布来将它转换成一件隐形斗篷,所以我们将着重于在框架中检测红色。
听起来简单吗?我们有一个RGB(红-绿-蓝)图像,使用简单阈值的R通道来得到我们的mask。结果证明,这将并不会特别有效,因为RGB值是高度敏感的照明。因此,即使斗篷是红色的,也可能有一些区域,由于阴影,相应像素的红色通道值相当低。
正确的方法是将图像的颜色空间从 RGB转换为HSV(色相-饱和度-亮度)。
HSV颜色空间是什么?
HSV颜色空间表示使用三个值的颜色
1.色相(Hue):这个通道对颜色信息进行编码。色相可以被认为是一个角度,0度对应红色,120度对应绿色,240度对应蓝色。
2.饱和度(Saturation):这个通道编码颜色的强度/纯度。例如,粉色比红色的饱和度低。
3.值(Value):该通道对颜色的亮度进行编码。图像的阴影和光泽成分出现在这个通道中。
不像RGB是根据三原色来定义的,HSV的定义方式类似于人类感知颜色的方式。
对于我们的应用而言,使用 HSV 颜色空间的主要优点是颜色/色调/波长仅由色相组件表示。
所以当我说,我需要一个特定的颜色,选择色相组件,然后根据饱和度组件,我得到了那个颜色的不同的阴影,进一步根据值组件,我得到了一个颜色的特定阴影的不同的强度。
ret, img = cap.read()
if not ret:
break
count+=1
# 将颜色空间从BGR转换为HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 生成掩码以检测红色
lower_red = np.array([0,120,70])
upper_red = np.array([10,255,255])
mask1 = cv2.inRange(hsv,lower_red,upper_red)
lower_red = np.array([170,120,70])
upper_red = np.array([180,255,255])
mask2 = cv2.inRange(hsv,lower_red,upper_red)
mask1 = mask1+mask2
inRange 函数简单地返回一个二值化掩码,其中白色像素(255)表示属于上限和下限范围的像素,黑色像素(0)不属于上限和下限范围的像素。
色相值 实际上分布在一个圆上(范围在0-360度之间),但在OpenCV中为了适应8bit 值,其范围是0-180度。红色由0-30和150-180值表示。
我们使用范围0-10和170-180,以避免检测皮肤为红色。饱和度使用较高范围120-255的值,因为我们的布料应该是高度饱和的红色。亮度值在的较低范围是70,这样我们也可以在布料的褶皱中检测到红色。
mask1 = mask1 + mask2
使用上面的代码,我们合并两个红色范围生成的mask。它基本上是在像素上进行OR操作。这是一个操作符重载+的简单例子。
现在,您已经了解了如何进行颜色检测,您可以更改H-S-V范围,并使用一些其他的单色布来代替红色。事实上,绿色的布比红色的效果更好,因为绿色离人的肤色差异最大。
步骤3:将检测到的红色布料分割开来
在上一步中,我们生成了一个mask来确定帧中与检测到的颜色相对应的区域。我们精炼这个mask,然后用它从frame上分割布料。下面的代码说明了它是如何实现的。
# 修改与检测到的红色对应的掩码
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3,3),np.uint8),iterations=2)
mask1 = cv2.dilate(mask1,np.ones((3,3),np.uint8),iterations = 1)
mask2 = cv2.bitwise_not(mask1)
步骤4:生成最终的增强输出,以创建一个神奇的效果。
最后,我们将检测到的红色区域的像素值替换为静态背景对应的像素值,最后生成一个增强输出,产生神奇的效果,将我们的布料变成了一件隐身斗篷。为此,我们首先使用bitwise_and操作创建一个像素值对应于检测区域的图像,像素值等于静态背景的像素值,然后将输出添加到我们从中分割出红布的图像(res1)中。
# 生成最终输出
res1 = cv2.bitwise_and(background,background,mask=mask1)
res2 = cv2.bitwise_and(img,img,mask=mask2)
final_output = cv2.addWeighted(res1,1,res2,1,0)
io.imshow('Magic !!!',final_output)
完整代码:
import cv2
import numpy as np
import time
cap = cv2.VideoCapture(0)
# We give some time for the camera to setup
time.sleep(3)
count = 0
background = 0
# Capturing and storing the static background frame
for i in range(60):
ret, background = cap.read()
# background = np.flip(background,axis=1)
while (cap.isOpened()):
ret, img = cap.read()
if not ret:
break
count += 1
# img = np.flip(img,axis=1)
# Converting the color space from BGR to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Generating mask to detect red color
lower_red = np.array([0, 120, 70])
upper_red = np.array([10, 255, 255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
lower_red = np.array([170, 170, 70])
upper_red = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red, upper_red)
mask1 = mask1 + mask2
# Refining the mask corresponding to the detected red color
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8), iterations=2)
mask1 = cv2.dilate(mask1, np.ones((3, 3), np.uint8), iterations=1)
mask2 = cv2.bitwise_not(mask1)
# Generating the final output
res1 = cv2.bitwise_and(background, background, mask=mask1)
res2 = cv2.bitwise_and(img, img, mask=mask2)
final_output = cv2.addWeighted(res1, 1, res2, 1, 0)
cv2.imshow('Magic !!!', final_output)
k = cv2.waitKey(10)
if k == 27:
break