利用Opencv-python做 “ 隐形衣 “

参考文献:
Learn-opencv网站blog

所谓电影中的 “隐身衣” ,即是对于固定背景中,筛去选定颜色值的像素并用背景像素替换。

这听起来十分奇怪,然而你可曾想到,我们生活中99%的电影特效渲染都利用了蓝幕/绿幕技术,通过后期处理,扣掉视频帧图里面frame中为特定值蓝/绿的像素,并辅以制作好的电影特效帧去替换。
电影拍摄中常用的绿幕技术
话不多说,来看具体技术。

工作原理

  1. 多次捕捉并存储固定的背景框
  2. 使用颜色检测算法检测红色布料
  3. 通过生成Mask遮罩将红色布料分段
  4. 最终以增强输出

工作步骤

1.捕捉并存储多帧背景框

为了将“隐形衣”所对应的对应像素替换为背景像素,我们需要首先捕捉并存储背景(background)来看代码:

# Creating a VideoCapture object
# This will be used for image acquisition later in the code.
cap = cv2.VideoCapture(0)

# We give some time for the camera to warm-up!
time.sleep(3)

background=0

for i in range(30):
  ret,background = cap.read()

# Laterally invert the image / flip the image.
background = np.flip(background,axis=1)

前面的摄像头图片捕捉比较好理解,有两点需要注意:

  1. time.sleep(3) 是为了让摄像头去进行一些预热以跳过最开始几个不稳定的frame。
  2. 为何用for循环去获取background?因为我们最开始获得的几帧可能会相对较暗,这很可能是由于摄像头刚开启时相机的内参参数并不稳定(参考相机校准)。可以看到代码中进行了30次循环以尽量确保背景像素的准确性(减少噪声)。
  3. 由于摄像头获取的图片是左右镜像的,我们用np.flip并设定axis为1去水平翻转图像以获得正常的图像输入。

2.对于红色布料的检测

在本例中我们用红色布料去制作“隐形衣”,因此我们可能想到去检测RGB中的第一个值R并控制GB去检测红色,然而这种方法不够明智,因为RGB颜色模式更容易受环境明暗程度的影响,这可能使“隐形衣”在某些较暗的环境中失效。因此我们决定去采用HSV颜色模式
如果你不了解HSV颜色模式或者想知道HSV在较暗环境下颜色辨析表现依然良好原因,可以参考LearnopenCV上的颜色模式教程
或者参考之前写的的:
关于RGB和HSV区别的Blog

来看这一段对布料进行掩码Mask建立的代码:

# converting from BGR to HSV color space
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

# Range for lower range of red
lower_red = np.array([0,120,70])
upper_red = np.array([10,255,255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)

# Range for upper range of red 
lower_red = np.array([170,120,70])
upper_red = np.array([180,255,255])
mask2 = cv2.inRange(hsv,lower_red,upper_red)

# Generating the final mask to detect red color
mask1 = mask1+mask2


可以看到,我们先将读取的img转化为HSV颜色模式,然后定义了所谓红色在HSV中的下界和上界。其中:
H在OpenCV中取[0,180],我们取[-10,10]作为红色(理解为360°状态下)。
饱和度S取120-255以判定宽泛的“红色”
强度V取[70,255]以确保“隐身衣”的褶皱处(因为那里往往光照强度较低,相对较暗)也被判定为红色。

: 红色在H中实际上对应[-30,30],但为了避免人的皮肤等被检测为红色,我们取了上述值。

我们用inRange函数去构造布料的Mask,这个函数返回黑/白,若被检测像素落入Range则返回白色,否则为黑色。

3.对Mask进行进一步处理(形态学处理)

关于形态学处理我学习的还比较少,以后有时间专门学习一下。
我们只需要知道进行形态学处理有助于让我们更加精确地取让Mask真正与布料的像素贴合。此处我们用到了开操作膨胀操作,利用了MorphologyEx函数,参数采用MORPH_OPEN,MORPH_DILATE两个参数。
然后我们利用bitwise_not 否运算构造了Mask2,Mask是二进制图像则Mask2恰好与Mask1黑白相反
我们将最后一部分代码合并一起看一下:

mask1 = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((3,3),np.uint8))
mask1 = cv2.morphologyEx(mask, cv2.MORPH_DILATE, np.ones((3,3),np.uint8))

#creating an inverted mask to segment out the cloth from the frame
mask2 = cv2.bitwise_not(mask1)

#Segmenting the cloth out of the frame using bitwise and with the inverted mask
res1 = cv2.bitwise_and(img,img,mask=mask2)

# creating image showing static background frame pixels only for the masked region
res2 = cv2.bitwise_and(background, background, mask = mask1)

#Generating the final output
final_output = cv2.addWeighted(res1,1,res2,1,0)
imshow("magic",final_output)
cv2.waitKey(1)


Mask1经历开/膨胀操作后称为“隐形衣”的遮罩,Mask2经历对1的二进制否操作后称为当前帧率除去隐形衣部分的遮罩。
接下来,我们用二进制与操作让img成为隐形衣部分全黑,其余部分为当前帧图像,记为res1;
用二进制与操作让background将隐形衣替换为background,其余部分全黑,记为res2。
最后用cv2.addWeighted去将res1,res2合并,即为最终的输出。

个人因为手边没有红布,用黑色去制作隐形衣,改了一下HSV参数,
对于一般颜色,开始设立mask的时候一个即可,因为红色比较特殊,H值占据了[0,30][150,180]…

来看最终输出截图,我的衣服是黑色的,然后用黑色的pad遮住了一半的脸:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值