黑魔法之隐身衣
1.简述
通过编写Python代码实现基于OpenCV的颜色检测和分割的隐形斗篷。
如果你是个哈利波特迷,你就会知道什么是隐形衣。是的!这是哈利波特用来隐身的隐形衣。当然,我们都知道隐形衣不是真的——它都是图形上的诡计。
在实验中,我们将学习如何使用OpenCV中的简单计算机视觉技术创建我们自己的“隐形衣”。
事实上,你可以用一种叫做颜色检测和分割的图像处理技术来创造这种神奇的体验。
2.硬件
- USB摄像头
- 电脑
- 或带摄像头笔记本电脑
3.需要的模块和函数
- cv2模块
- time模块
- numpy模块
4.程序功能框图
5.步骤
步骤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 颜色空间的主要优点是颜色/色调/波长仅由色相组件表示。
所以当我说,我需要一个特定的颜色,选择色相组件,然后根据饱和度组件,我得到了那个颜色的不同的阴影,进一步根据值组件,我得到了一个颜色的特定阴影的不同的强度。
在下面的代码中,我们首先捕获一个活动帧,将图像从RGB转换为HSV颜色空间,然后定义一个特定范围的H-S-V值来检测红色。
ret, img = cap.read()if not ret:breakcount+=1# 将颜色空间从BGR转换为HSVhsv = 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
import argparseparser = argparse.ArgumentParser()
# Input argument
parser.add_argument("--video", help = "Path to input video file. Skip this argument to capture frames from a camera.")args = parser.parse_args()print("""Harry : Hey !! Would you like to try my invisibility cloak ??Its awesome !!Prepare to get invisible .....................""")# Creating an VideoCapture object
# This will be used for image acquisition later in the code.
cap = cv2.VideoCapture(args.video if args.video else 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:breakcount+=1#img = np.flip(img,axis=1)# Converting the color space from BGR to HSVhsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)# Generating mask to detect red colorlower_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# Refining the mask corresponding to the detected red colormask1 = 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 outputres1 = 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
效果
本文链接:https://my.lmcjl.com/post/8326.html
4 评论