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

4、效果展示

5、总结