目 录
一、准备工作:
opencv库和PyQt5库
一张背景图和同一背景人举着红布的图
二、大致思路
要实现的效果如下:
图片隐身思路:
背景图
手持红布图
(1)先将手持红布图片格式转化为方便操作的hsv格式
(2)用背景图扣出纯色板。
(3)再根据掩膜取反,用红布背景扣出除了红布外的背景。
(4)将两张图片像素做与运算,即两张照片拼在一起
摄像头实时隐身思路:
(1)打开摄像头,然后最先读取到的图片充当背景。
(2)后面人进入摄像头范围手举着红布(红色物体),代入刚刚的图片隐身思路。
使用Qt组件:
(1)将视频放入窗口。
(2)通过按钮控制实时隐身视频。
人脸识别那篇文章详细讲解了所需的组件,此处不再赘述。
三、代码实现
1、小试牛刀
先读取一张有红色背景的图片
import cv2 as cv
image = cv.imread("image.jpg") # 读取图片
cv.imshow("image", image) # 展示图片
cv.waitKey(0) # 参数0为等待用户操作
运行结果如下:
将图片改为hsv格式
imgHSV = cv.cvtColor(image, cv.COLOR_BGR2HSV) # 改为hsv格式
运行结果如下:
利用这个hsv颜色空间扣出红色背景图,发现红色有两栏,那我们分别扣出两栏,再直接相加:
mask1 = cv.inRange(imgHSV, (0, 43, 46), (10, 255, 255))
mask2 = cv.inRange(imgHSV, (156, 43, 46), (180, 255, 255))
mask = mask1 + mask2
运行结果如下:
此时我们成功扣出红色背景,接下来我们将掩膜做取反操作:
dst = cv.bitwise_not(mask)
运行结果如下:
此时我们成功扣出人像。
2、图片隐身
(1)我们先读取背景图和手持红布图。
Red_cloth = cv.imread("redbackground.jpg")
cv.imshow("red_cloth", Red_cloth)
background = cv.imread("background.jpg")
cv.imshow("back", background)
运行结果如下:
(2)我们读取图片后将图片转化为hsv格式,然后根据hsv颜色空间扣出红色区域。
imgHSV = cv.cvtColor(Red_cloth, cv.COLOR_BGR2HSV) # 改为hsv格式
cv.imshow("imghsv", imgHSV)
# 取红色区域
mask1 = cv.inRange(imgHSV, (0, 43, 46), (10, 255, 255))
mask2 = cv.inRange(imgHSV, (156, 43, 46), (180, 255, 255))
mask3 = mask1 + mask2
cv.imshow("mask", mask3)
运行结果如下:
我们再将掩膜取反试试。
# 取反操作
mask_not = cv.bitwise_not(mask3)
cv.imshow("mask_not", mask_not)
运行结果如下:
我们发现,我们只想要的是扣红布区域,但却扣出了其他一些无关的东西。
并不是代码和颜色空间有问题,只是因为旁边的物体呈暗红色,也属于红色的范围,所以也被抠出来了。此时我们只需要缩小hsv所给的红色范围,让它只包含红布的颜色范围,即可扣出红布,参数可自行慢慢调节。
mask1 = cv.inRange(imgHSV, (0, 158, 46), (10, 230, 230))
mask2 = cv.inRange(imgHSV, (156, 158, 46), (180, 230, 230))
mask3 = mask1 + mask2
运行结果如下:
(3)我们将掩膜取反,扣出除了红布外的区域。
mask_not = cv.bitwise_not(mask3)
cv.imshow("mask_not", mask_not)
运行结果如下:
(4)将背景图和红布掩膜做像素与运算。
image1 = cv.bitwise_and(background, background, mask=mask3)
cv.imshow("red_cloth_background", image1)
运行结果如下:
(5)将手持红布图与取反的掩膜做像素与运算。
image2 = cv.bitwise_and(Red_cloth, Red_cloth, mask=mask_not)
cv.imshow("background", image2)
运行结果如下:
(6)将两张图片相加。
image = cv.add(image1, image2)
cv.imshow("Stealth", image)
运行结果如下:
我们已经成功实现图片隐身。
3、摄像头实时隐身
此部分不再展示运行结果。
(1)打开摄像头先捕获的图片作为背景
cap = cv.VideoCapture(0)
for i in range(1, 10):
flag, frame = cap.read()
background = frame
(2)人进入摄像头范围后,手持红布作为隐身布
cap = cv.VideoCapture(0)
flag, image = cap.read()
imgHSV = cv.cvtColor(image, cv.COLOR_BGR2HSV)
mask1 = cv.inRange(imgHSV, (0, 158, 46), (10, 255, 255))
mask2 = cv.inRange(imgHSV, (156, 158, 46), (180, 255, 255))
mask3 = mask1 + mask2
mask_not = cv.bitwise_not(mask3)
image1 = cv.bitwise_and(self.background, self.background, mask=mask3)
image2 = cv.bitwise_and(image, image, mask=mask_not)
image3 = cv.add(image1, image2)
小结:摄像头隐身部分已经完成,可用esc键关闭程序,小结代码如下(可运行):
import cv2 as cv
cap = cv.VideoCapture(0)
# 刚打开摄像头读取的图片作为背景
for i in range(1, 10):
flag, frame = cap.read()
background = frame
while True:
flag, image = cap.read()
# 图片转hsv格式
imgHSV = cv.cvtColor(image, cv.COLOR_BGR2HSV)
# 取红色掩膜
mask1 = cv.inRange(imgHSV, (0, 100, 46), (10, 255, 255))
mask2 = cv.inRange(imgHSV, (156, 100, 46), (180, 255, 255))
mask3 = mask1 + mask2
# 掩膜取反
mask_not = cv.bitwise_not(mask3)
# 像素与运算
image1 = cv.bitwise_and(background, background, mask=mask3)
image2 = cv.bitwise_and(image, image, mask=mask_not)
image3 = cv.add(image1, image2)
cv.imshow("Stealth", image3)
if cv.waitKey(40) == 27:
break
cap.release() # 释放内存空间
4、使用Qt组件
人脸识别那篇文章详细讲解了所需的组件,此处不再赘述。
这是部分Qt组件和定时器的代码:
from PyQt5.Qt import *
import sys
def intiUI(self):
self.resize(600, 600) # 窗口大小,可自行调整参数
self.setWindowTitle("隐身术") # 窗口标题
# 定时器链接槽函数
self.timer.timeout.connect(self.Stealth)
startbtn = QPushButton("播放", self) # "播放"为按钮的名称
startbtn.resize(560, 30) # 播放按钮的大小设置函数
startbtn.move(20, 480) # 播放按钮的坐标位置函数
startbtn.clicked.connect(self.on_setting_click) # 播放按钮链接鼠标事件
# 同理,暂停按钮如下:
endbtn = QPushButton("暂停", self)
endbtn.resize(560, 30)
endbtn.move(20, 520)
endbtn.clicked.connect(self.up_setting_click) # 暂停按钮链接鼠标事件
self.lab = QLabel("这里是显示视频的区域", self) # 文本标签
self.lab.move(220, 250) # 标签位置
def on_setting_click(self):
# 刚打开摄像头读取的图片作为背景
for i in range(1, 10):
flag, frame = cap.read()
self.background = frame
self.timer.start(20)
def up_setting_click(self):
self.timer.stop()
def Stealth(self):
image3 = cv.cvtColor(image3, cv.COLOR_BGR2RGB) # frame opencv mat
# mat => Qt 图片容器格式
image4 = QImage(image3.data,image3.shape[1],image3.shape[0],QImage.Format_RGB888)
pixmap = QPixmap.fromImage(image4)
pixmap = pixmap.scaled(self.lab.size())
self.lab.setPixmap(pixmap)
self.lab.move(40, 40) # 位置设置函数
self.lab.resize(520, 390) # 大小设置函数
if __name__ == '__main__':
app = QApplication(sys.argv)
setting = SettingUI()
setting.show()
sys.exit(app.exec())
四、总结
总代码如下:
import cv2 as cv
from PyQt5.Qt import *
import sys
cap = cv.VideoCapture(0)
class SettingUI(QWidget):
def __init__(self):
super(SettingUI, self).__init__()
self.timer = QTimer()
self.intiUI()
def intiUI(self):
self.resize(600, 600) # 窗口大小,可自行调整参数
self.setWindowTitle("隐身术") # 窗口标题
# 定时器链接槽函数
self.timer.timeout.connect(self.Stealth)
startbtn = QPushButton("播放", self) # "播放"为按钮的名称
startbtn.resize(560, 30) # 播放按钮的大小设置函数
startbtn.move(20, 480) # 播放按钮的坐标位置函数
startbtn.clicked.connect(self.on_setting_click) # 播放按钮链接鼠标事件
# 同理,暂停按钮如下:
endbtn = QPushButton("暂停", self)
endbtn.resize(560, 30)
endbtn.move(20, 520)
endbtn.clicked.connect(self.up_setting_click) # 暂停按钮链接鼠标事件
self.lab = QLabel("这里是显示视频的区域", self) # 文本标签
self.lab.move(220, 250) # 标签位置
def on_setting_click(self):
# 刚打开摄像头读取的图片作为背景
for i in range(1, 10):
flag, frame = cap.read()
self.background = frame
self.timer.start(20)
def up_setting_click(self):
self.timer.stop()
def Stealth(self):
flag, image = cap.read()
imgHSV = cv.cvtColor(image, cv.COLOR_BGR2HSV)
# 取红色掩膜
mask1 = cv.inRange(imgHSV, (0, 158, 46), (10, 255, 255))
mask2 = cv.inRange(imgHSV, (156, 158, 46), (180, 255, 255))
mask3 = mask1 + mask2
# 掩膜取反
mask_not = cv.bitwise_not(mask3)
# 像素与运算
image1 = cv.bitwise_and(self.background, self.background, mask=mask3)
image2 = cv.bitwise_and(image, image, mask=mask_not)
image3 = cv.add(image1, image2)
image3 = cv.cvtColor(image3, cv.COLOR_BGR2RGB) # frame opencv mat
image4 = QImage(image3.data, image3.shape[1], image3.shape[0], QImage.Format_RGB888)
pixmap = QPixmap.fromImage(image4)
pixmap = pixmap.scaled(self.lab.size())
self.lab.setPixmap(pixmap)
self.lab.move(40, 40) # 位置设置函数
self.lab.resize(520, 390) # 大小设置函数
if __name__ == '__main__':
app = QApplication(sys.argv)
setting = SettingUI()
setting.show()
sys.exit(app.exec())
运行结果如下: