2022-7-8 16:37:01 [显示全部楼层]
24359浏览
查看: 24359|回复: 0

【行空板Python入门教程】第十二课:人脸检测之魔法贴图

[复制链接]
本帖最后由 NciJlUN1qMan 于 2022-7-8 16:55 编辑

人脸检测之魔法贴图


自拍是许多小伙伴的爱好之一,而为了使得拍出的照片显得更加生动有趣,大家常常会在自己的头像上添加一些滤镜贴图。

你知道这是如何实现的吗?

这节课上,让我们结合行空板和摄像头,模拟体验一下这个功能吧!


1.png



任务目标

使用USB摄像头来实时显示画面,当画面中检测到人脸时,为其添加特效图像。


屏幕快照 2022-07-08 4.06.30 PM.png



知识点

1、了解人脸检测

2、学习使用opencv库调用摄像头显示实时视频流的方法

3、学习使用opencv库进行人脸检测的方法

4、学习使用PIL库Image模块转换图像格式的方法

5、学习使用PIL库Image模块在图像上粘贴图片的方法


材料清单

硬件清单:


屏幕快照 2022-07-08 4.06.50 PM.png


软件使用:Mind+编程软件x1

知识储备

1、什么是人脸检测

人脸检测,是指对于任意一幅给定的图像,采用一定的策略对其进行搜索以确定其中是否含有人脸,如果是则返回脸的位置、大小和姿态。简单来说,人脸检测就是在图像中找到人脸区域的过程,它解决的是“是不是人脸”的问题。

2、什么是级联分类器

在进行人脸检测时,常常需要借助分类器,分类器是判别某个事物是否属于某种分类的器件工具,级联分类器可以理解为将N个单类的分类器串联起来,如果一个事物能属于这一系列串联起来的所有分类器,则最终结果就成立。比如人脸,它有很多属性,我们可以将每个属性做成一个分类器,如果一个模型符合了我们定义的人脸的所有属性(两条眉毛、两只眼睛、一个鼻子、一张嘴、一个大概U形状的下巴或者是轮廓等等),则我们认为这个模型就是一个人脸。

在Opencv库中,已经有一些训练好的级联分类器供用户使用。这些分类器可以用来检测人脸、脸部特征(眼睛、鼻子)、人类和其他物体。

3、Opencv库“VideoCapture()”函数打开摄像头

Opencv库中的“VideoCapture()”函数可以用来打开摄像头并初始化以便显示实时视频流,使用前需要先导入opencv库。同时,需要输入指定参数编号来表示要打开的摄像头,输入“-1”表示随机选取一个摄像头,如果有多个摄像头,输入数字“0”、“1”分别表示第一个摄像头和第二个摄像头,依次类推。如果只有一个摄像头,既可以用“0”,也可以使用“-1”来作为摄像头ID号。

  1. import cv2 # 导入opencv库
  2. cap = cv2.VideoCapture(0) # 打开0号摄像头
复制代码

其中,cap是创建的一个摄像头对象

4、Opencv库“set()”函数设置摄像头属性

在打开摄像头后,我们可以通过“set()”方法设置一些属性,比如显示视频流时所需要的缓冲时间,这里我们可以将缓冲时间理解为屏幕延时,数值越大,屏幕延时显示则越久。

  1. cap.set(cv2.CAP_PROP_BUFFERSIZE,1) # 设置1帧的缓冲,减少延迟
复制代码

其中,“cv2.CAP_PROP_BUFFERSIZE”指的就是就是缓冲属性,“1”表示1帧。

5、Opencv库“isOpened()”函数判断摄像头是否打开成功

在设置打开摄像头后,我们可以通过“isOpened()”方法来检测判断摄像头是否成功打开,打开则返回True,未打开则返回False。

  1. while(cap.isOpened()): # 当摄像头打开时
复制代码

6、Opencv库“read()”函数读取图像

在摄像头成功开启后,我们可以通过其中的“read()”方法来按帧读取图像,在连续快速读取图像后,呈现的效果即为实时的视频流。

  1. while(cap.isOpened()): # 当摄像头打开时
  2.     ret, img = cap.read() # 按帧读取图像
复制代码

其中,ret,img是两个变量,前者用于存储是否读取到图像,读取到返回True,否则返回False,后者用于存储实际读取到的图像。

7、Opencv库“resize()”函数调整图像的尺寸

当一张图像尺寸不合适时,我们可以通过Opencv库中的“resize()”函数对它进行缩放来调整图像的尺寸。

   
  1. ret, img = cap.read() # 按帧读取图像
  2.     if ret:
  3.         '''crop the center of the frame and resize to (240, 320) while keeping image ratio. '''
  4.         '''# 裁剪框架的中心并调整尺寸(尺寸同行空板),同时保持图像比例 # 将摄像头捕获的图像,以适应行空板屏幕的比例显示在屏幕上'''
  5.         h, w, c = img.shape  # 记录图像的形状尺寸,分别为高、宽、通道
  6.         w1 = h*240//320
  7.         x1 = (w-w1)//2
  8.         img = img[:, x1:x1+w1] # 裁剪图像
  9.         img2 = cv2.resize(img, (240, 320)) # 调整图像尺寸
复制代码

其中,第一行的img指的是通过摄像头读取到的原图像,最后一行的img2指的是调整尺寸后的图像,“(240,320)”指的是宽和高的像素值,这里我们将其调整至和行空板同尺寸,以便能在屏幕上显示。

同时,由于摄像头读取到的图像分辨率为640*480,而调整尺寸时只能同比例缩放,因此,这里,我们需要先对原图像进行裁剪。如下图,原图为640*480,裁剪后得到橘色矩形,大小为360*480,与240*320同比例。其中,在裁剪时,默认是以左上角为基点,而缩放时则是默认以矩形中心点为基点。





8、Opencv库“release()”函数关闭摄像头

打开摄像头后,我们还需要在结束后释放掉它,这里,可以通过“release()”方法来实现。

  1. cap.release() # 释放摄像头
复制代码

9、Opencv库“CascadeClassifier()”函数加载人脸检测分类器

Opencv库中已经自带了训练好的人脸检测分类器,这些级联分类器以XML文件的形式存放在Opencv根文件夹的data文件夹下,该文件夹包含三个子文件夹:haarcascades、hogcascades、lbpcascades,里面分别存储的是Harr级联分类器、HOG级联分类器、LBP级联分类器。加载不同级联分类器的XML文件就可以实现对不同对象的检测。

在Harr级联分类器中,就提供了用于正面人脸检测的类型“haarcascade_frontalface_default.xml”要想调用它,我们可以通过“CascadeClassifier()”函数来实现,加载的一种方式是在括号中传入路径+具体的分类器名称。

  1. faceCascade=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')#
  2. Load face recognition model. # 加载人脸检测分类器
复制代码

其中,“haarcascade_frontalface_default.xml”是指具体的用于正面人脸检测的级联分类器,前面的“cv2.data.haarcascades”是它所在的路径,对应的是opencv库data文件夹下的haarcascades子文件夹。

10、Opencv库“detectMultiScale()”函数检测人脸

在加载人脸检测分类器后,可通过其中的“detectMultiScale()”方法来检测出图片中所有的人脸,并返回各个人脸的坐标、大小(x、y、w、h四个参数)


  1. faces = faceCascade.detectMultiScale(
  2.         gray,  # 要检测的图像
  3.         scaleFactor=1.1, # 每次图像尺寸减小的比例,默认1.1
  4.         minNeighbors=5,  # 表示每一个目标至少要被检测到5次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)
  5.         minSize=(30, 30) # 目标的最小尺寸
  6.     )
复制代码

其中,gray是要检测的灰度图像,scaleFactor是缩放因子,minNeighbors表示每隔目标至少要被检测的次数,一般选3-5,minSize表示图像中人脸目标的最小尺寸,这里我们设置最小宽度和高度皆为30像素。

11、PIL库Image模块图像处理

PIL库Image模块是一个可进行图像处理的Python模块,其中的功能函数有很多,这里我们只作简单介绍。使用前需要先导入该模块。

(1)“fromarray()”函数将array数组格式图像转换为Image格式图像由于opencv处理的图像皆为array数组格式,而粘贴时的特效图像需为Image格式,因此我们需要先通过“fromarray()”函数对该图像做处理,进行格式转换,将其从array数组格式图像转换为Image格式图像。

  1. from PIL import Image  # 导入PIL库Image模块
  2. ret, img = cap.read()
  3. img = Image.fromarray(img) # 将opencv读取到的数组格式图像转换为图片(image)格式
复制代码

(2)“paste()”函数粘贴图像

PIL库Image模块中的“paste()”函数可以将一张图像覆盖粘贴到其他图像上。

  1. img.paste(mark, (x, y-h1),mark) # 将特效图像粘贴显示在摄像头的图像上
复制代码

其中,img指的是被粘贴的原图像,第一个mark指的是用于粘贴的特效图像,“(x,   y-h1)”指的是图像左上角对应要粘贴的位置,第三个mark指的是粘贴时做掩膜处理的图像(这里为同一张),通过这种方式我们可以将图像以透明的形式贴于原图上,这里我们也可以写为

“img.paste(mark, (x, y-h1), mask = mark)”。

动手实践

任务描述1:显示实时视频流

将摄像头拍摄到的视频流画面,实时显示在屏幕上

1、硬件搭建

STEP1:通过USB连接线将行空板连接到计算机

STEP2:将USB摄像头连接在行空板上

2、程序编写

STEP1:创建与保存项目文件

启动Mind+,另存项目并命名为“012、镜子魔法”。

STEP2:创建与保存Python文件

创建一个Python程序文件“main1.py”,双击打开。

STEP3:程序编写

(1)导入所需功能库在这个任务中,我们需要使用opencv库来调用摄像头显示视频流,因此,我们需要先导入它。

  1. import cv2  # 导入opencv库
复制代码

(2)设置摄像头为了能将摄像头拍摄到的画面实时显示在行空板的屏幕上,这里,我们需要进行四步设置。首先是打开摄像头;接着给视频流设置1帧的缓冲,避免卡顿或延迟太高;之后构建一个窗口并在最后设置窗口全屏化以便在窗口上显示视频流画面。

  1. # Open usb camera 0. # 打开0号摄像头
  2. cap = cv2.VideoCapture(0)
  3. # Set the camera buffer to 1, to decrease the latency. # 设置1帧的缓冲,减少延迟
  4. cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
  5. # Set the windows to be full screen. # 构建一个窗口,名称为winname,默认属性为可以全屏
  6. cv2.namedWindow('winname',cv2.WND_PROP_FULLSCREEN)
  7. # Set the windows to be full screen. # 设置winname窗口全屏
  8. cv2.setWindowProperty('winname',cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
复制代码

(3)显示视频流

在设置好窗口之后,我们再编程实现视频流画面的显示。这里,当摄像头打开时,我们首先按帧读取图像,如果成功读取到,我们先记录所得到图像的尺寸大小,接着对它进行裁剪,之后再对裁剪后的图像调整尺寸大小使之与行空板的屏幕一致,最后我们设置将处理过的图像显示在窗口上并且每1ms刷新一帧,形成视频流,同时,也设置好按下a键退出程序。

  1. while (cap.isOpened()): # 当摄像头打开时
  2.     # Read one frame from usbcam. # 按帧读取图像,ret返回的是True和False,表示是否读取到图片,frame指读取到一帧的图像
  3.     ret, img = cap.read()
  4.     # If frame available. # 如果读取到图像
  5.     if ret:
  6.         '''crop the center of the frame and resize to (240, 320) while keeping image ratio.'''
  7.         '''裁剪框架的中心并调整尺寸(尺寸同行空板),同时保持图像比例'''
  8.         h, w, c = img.shape # 记录图像的形状尺寸,分别为高、宽、通道
  9.         w1 = h*240//320 # change the height to fit the render image
  10.         x1 = (w-w1)//2 # midpoint of width without resizing
  11.         img = img[:, x1:x1+w1] # crop into the center # 裁剪图像
  12.         img = cv2.resize(img, (240, 320)) # resize according to the screen keeping the aspect ratio # 调整图像尺寸

  13.         '''显示实时视频流'''
  14.         cv2.imshow('winname',img) # 在winname窗口上显示图像img
  15.         key = cv2.waitKey(1)  # 每1ms刷新图像,这里延时不能为 0,否则读取的结果会是静态帧
  16.         '''按a键退出程序'''
  17.         if key & 0xFF == ord('a'):
  18.             break
复制代码

(4)关闭摄像头和窗口

在按下a键退出后,我们释放掉摄像头,并关闭所有图像窗口。

  1. cap.release() # 释放摄像头
  2. cv2.destroyAllWindows() # 关闭所有窗口
复制代码

Tips:完整示例程序如下

  1. import cv2  # 导入opencv库


  2. # Open usb camera 0. # 打开0号摄像头
  3. cap = cv2.VideoCapture(0)
  4. # Set the camera buffer to 1, to decrease the latency. # 设置1帧的缓冲,减少延迟
  5. cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
  6. # Set the windows to be full screen. # 构建一个窗口,名称为winname,默认属性为可以全屏
  7. cv2.namedWindow('winname',cv2.WND_PROP_FULLSCREEN)
  8. # Set the windows to be full screen. # 设置winname窗口全屏
  9. cv2.setWindowProperty('winname',cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)


  10. while (cap.isOpened()): # 当摄像头打开时
  11.     # Read one frame from usbcam. # 按帧读取图像,ret返回的是True和False,表示是否读取到图片,frame指读取到一帧的图像
  12.     ret, img = cap.read()
  13.     # If frame available. # 如果读取到图像
  14.     if ret:
  15.         '''crop the center of the frame and resize to (240, 320) while keeping image ratio.'''
  16.         '''裁剪框架的中心并调整尺寸(尺寸同行空板),同时保持图像比例'''
  17.         h, w, c = img.shape # 记录图像的形状尺寸,分别为高、宽、通道
  18.         w1 = h*240//320 # change the height to fit the render image
  19.         x1 = (w-w1)//2 # midpoint of width without resizing
  20.         img = img[:, x1:x1+w1] # crop into the center # 裁剪图像
  21.         img = cv2.resize(img, (240, 320)) # resize according to the screen keeping the aspect ratio # 调整图像尺寸

  22.         '''显示实时视频流'''
  23.         cv2.imshow('winname',img) # 在winname窗口上显示图像img
  24.         key = cv2.waitKey(1)  # 每1ms刷新图像,这里延时不能为 0,否则读取的结果会是静态帧
  25.         '''按a键退出程序'''
  26.         if key & 0xFF == ord('a'):
  27.             break

  28. cap.release() # 释放摄像头
  29. cv2.destroyAllWindows() # 关闭所有窗口
复制代码

3、程序运行

STEP1:远程连接行空板,运行程序并观察效果

观察行空板,可以发现摄像头实时拍摄到的画面全屏显示在了板子上。如下图,将摄像头对着一张人脸,即可看到相应的画面。





任务描述2:检测人脸并添加特效图像

在上个任务中,我们实现了将摄像头拍摄到的视频流画面实时显示在了行空板上,接下来,我们将添加功能,检测人脸并在其上添加滤镜贴图(特效图像)。

1、程序编写

STEP1:创建与保存项目文件

新建一个Python程序文件“main2.py”,双击打开。

STEP2:导入图片素材

在项目文件夹中将两张特效图像导入。(下载链接见附录1)

Step3:程序编写

(1)补充导入numpy库和PIL库Image模块

在这个任务中,我们将使用numpy库和PIL库Image模块来对图像进行处理,因此我们需要补充导入它们。

  1. import numpy as np # 导入numpy库
  2. from PIL import Image  # 导入PIL库Image模块
复制代码

(2)加载人脸检测分类器

由于我们将对摄像头画面中的人脸添加特效图像,因此,我们首先需要进行人脸检测,而由于opencv库中已有相应的人脸识别分类器,因此,我们只需要加载即可使用。

  1. # Load face recognition model. # 加载人脸检测分类器
  2. faceCascade=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')
复制代码

(3)读取特效图像

为了能在检测到人脸后添加特效,我们首先需要读取给定的特效图像。

  1. ImageID = 1
  2. # Read the mark image file from disk.
  3. # 读取加载第一张特效图像1.png,并将其数组格式转换为图片(image)格式,(cv2.IMREAD_UNCHANGED指读取完整图片)
  4. markOrigin = Image.fromarray(cv2.imread(str(ImageID) + ".png" , cv2.IMREAD_UNCHANGED))
复制代码

(4)定义函数--获取人脸并添加特效图像

这里,由于在视频流中检测人脸并添加特效图像的过程比较复杂,因此我们将其写在函数中。

首先,由于摄像头读取到的图像是三通道的,为了降低处理图片时的复杂度,我们将其转换为灰度图(一个通道);之后对该图像进行检测,获取人脸识别数据;最后当检测到人脸时,再添加特效图像。而在检测人脸识别时,我们设定四个需要的参数,分别是要检测的灰度图像,图像尺寸默认减小的比例,每个目标最少被检测次数,目标的最小尺寸。

  1. # 定义函数--获取人脸并在其上添加图像 get and render face with mark.
  2. def getAndRenderFace(img):
  3.     # 人脸识别数据.
  4.     # 将图像img的BGR颜色空间转换为GRAY颜色空间,并命名新图像为gray (二值化,变为灰度图, 可以减少维度降低图片复杂度)
  5.     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  6.     # 检测,获取人脸识别数据.
  7.     faces = faceCascade.detectMultiScale(
  8.         gray,  # 要检测的图像
  9.         scaleFactor=1.1, # 每次图像尺寸减小的比例,默认1.1
  10.         minNeighbors=5,  # 表示每一个目标至少要被检测到5次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)
  11.         minSize=(30, 30) # 目标的最小尺寸
  12.     )
  13.     for (x, y, w, h) in faces:
  14.         # img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)  # 绘画人脸识别数据.
  15.         img = drawMark(img, x, y, w, h) # 根据人脸识别数据添加特效图像.
  16.     return img
复制代码

(5)定义函数--在视频流画面上添加特效图像

由于添加特效图像的过程比较复杂,我们同样放在函数中。这里,我们需要先对待显示的特效图像进行处理,可分三步进行,首先是获取特效图像的尺寸;之后是按比例调整该图像的尺寸大小,使之适应屏幕;接着将它的数组格式转换为Image图片格式。

在处理好特效图像后,我们再将其粘贴在摄像头拍摄到的图像上,并将最后的完整图像转换为array数组格式,以便以视频流的形式显示在板子的窗口上。

  1. # 定义函数--添加特效图像功能
  2. def drawMark(img, x, y, w, h):
  3.     # Get the size of the mark image. # 获取特效图像的尺寸
  4.     wm, hm = markOrigin.size  
  5.     # Keep the ratio and resize the image to fit the width of face. # 保持这个比例并调整图像的大小以适应脸部的宽度
  6.     h1 = w*hm//wm  
  7.     # Resize. # 调整特效图像的尺寸
  8.     mark = markOrigin.resize((w, h1))
  9.     # Convert from opencv Mat to Pillow Image. # 将opencv读取到的数组格式图像转换为图片(image)格式
  10.     img = Image.fromarray(img)
  11.     # 将特效图像粘贴显示在摄像头的图像上
  12.     img.paste(mark, (x, y-h1), mark)  
  13.     # Convert from Pillow Image to opencv Mat. # 再将image格式的图像转换为array数组格式以便与opencv摄像头显示相匹配
  14.     img = np.array(img)
  15.     return img
复制代码

(6)调用函数实现效果

最后,我们在循环中补充调用检测人脸并添加特效图像的函数,同时补充功能,按下按键b切换特效图像。

  1. while(cap.isOpened()):  # 当摄像头打开时
  2.     # Read one frame from usbcam. # 按帧读取图像
  3.     ret, img = cap.read()
  4.     # If frame available. # 如果读取到图像
  5.     if ret:
  6.         '''实时识别并添加图像.'''
  7.         img = getAndRenderFace(img)

  8.         '''显示实时视频流'''
  9.         cv2.imshow('winname',img) # 在winname窗口上显示图像img
  10.         key = cv2.waitKey(1) # 每1ms刷新图像 ,这里延时不能为 0,否则读取的结果会是静态帧

  11.         '''按a键退出程序,b键切换特效图像'''
  12.         if key & 0xFF == ord('a'): # Press the "a" key on Unihiker will stop the program.
  13.             print("退出视频")
  14.             break
  15.         elif key & 0xFF == ord('b'): # Press the "b" key on Unihiker will change the mark.
  16.             ImageID += 1  # Change the ImageID on every A click.
  17.             if ImageID > 2: # Two marks are available in this program.
  18.                 ImageID = 1
  19.             # Reload the mark from disk. # 重新加载特效图像
  20.             markOrigin = Image.fromarray(cv2.imread(str(ImageID) + ".png" , cv2.IMREAD_UNCHANGED))  
  21.     else:
  22.         break
复制代码

Tips:完整示例程序如下:

  1. import numpy as np # 导入numpy库
  2. import cv2  # 导入opencv库
  3. from PIL import Image  # 导入PIL库Image模块


  4. # Open usb camera 0. # 打开0号摄像头
  5. cap = cv2.VideoCapture(0)
  6. # Set the camera buffer to 1, to decrease the latency. # 设置1帧的缓冲,减少延迟
  7. cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
  8. # Set the windows to be full screen. # 构建一个窗口,名称为winname,默认属性为可以全屏
  9. cv2.namedWindow('winname',cv2.WND_PROP_FULLSCREEN)
  10. # Set the windows to be full screen. # 设置winname窗口全屏
  11. cv2.setWindowProperty('winname', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)



  12. # Load face recognition model. # 加载人脸检测分类器
  13. faceCascade=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')
  14. # Name of the png file like 1.png 2.png ... # 定义一个ID编号记录特效图像,初始时为1(第一张)
  15. ImageID = 1
  16. # Read the mark image file from disk.
  17. # 读取加载第一张特效图像1.png,并将其数组格式转换为图片(image)格式,(cv2.IMREAD_UNCHANGED指读取完整图片,包括用于记录透明度的alpha通道)
  18. markOrigin = Image.fromarray(cv2.imread(str(ImageID) + ".png" , cv2.IMREAD_UNCHANGED))  


  19. # 定义函数--获取人脸并在其上添加图像 get and render face with mark.
  20. def getAndRenderFace(img):
  21.     # 人脸识别数据.
  22.     # 将图像img的BGR颜色空间转换为GRAY颜色空间,并命名新图像为gray (二值化,变为灰度图, 可以减少维度降低图片复杂度)
  23.     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  24.     # 检测,获取人脸识别数据.
  25.     faces = faceCascade.detectMultiScale(
  26.         gray,  # 要检测的图像
  27.         scaleFactor=1.1, # 每次图像尺寸减小的比例,默认1.1
  28.         minNeighbors=5,  # 表示每一个目标至少要被检测到5次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)
  29.         minSize=(30, 30) # 目标的最小尺寸
  30.     )
  31.     for (x, y, w, h) in faces:
  32.         # img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)  # 绘画人脸识别数据.
  33.         img = drawMark(img, x, y, w, h) # 根据人脸识别数据添加特效图像.
  34.     return img


  35. # 定义函数--添加特效图像功能
  36. def drawMark(img, x, y, w, h):
  37.     # Get the size of the mark image. # 获取特效图像的尺寸
  38.     wm, hm = markOrigin.size  
  39.     # Keep the ratio and resize the image to fit the width of face. # 保持这个比例并调整图像的大小以适应脸部的宽度
  40.     h1 = w*hm//wm  
  41.     # Resize. # 调整特效图像的尺寸
  42.     mark = markOrigin.resize((w, h1))
  43.     # Convert from opencv Mat to Pillow Image. # 将opencv读取到的数组格式图像转换为图片(image)格式
  44.     img = Image.fromarray(img)
  45.     # 将特效图像粘贴显示在摄像头的图像上
  46.     img.paste(mark, (x, y-h1), mark)  
  47.     # Convert from Pillow Image to opencv Mat. # 再将image格式的图像转换为array数组格式以便与opencv摄像头显示相匹配
  48.     img = np.array(img)
  49.     return img


  50. while(cap.isOpened()):  # 当摄像头打开时
  51.     # Read one frame from usbcam. # 按帧读取图像
  52.     ret, img = cap.read()
  53.     # If frame available. # 如果读取到图像   
  54.     if ret:
  55.         '''crop the center of the frame and resize to (240, 320) while keeping image ratio. '''
  56.         '''# 裁剪框架的中心并调整尺寸(尺寸同行空板),同时保持图像比例 # 将摄像头捕获的图像,以适应行空板屏幕的比例显示在屏幕上'''
  57.         h, w, c = img.shape  # 记录图像的形状尺寸,分别为高、宽、通道
  58.         w1 = h*240//320
  59.         x1 = (w-w1)//2
  60.         img = img[:, x1:x1+w1] # 裁剪图像
  61.         img = cv2.resize(img, (240, 320)) # 调整图像尺寸

  62.         '''实时识别并添加特效图像.'''
  63.         img = getAndRenderFace(img)

  64.         '''显示实时视频流'''
  65.         cv2.imshow('winname',img) # 在winname窗口上显示图像img
  66.         key = cv2.waitKey(1) # 每1ms刷新图像 ,这里延时不能为 0,否则读取的结果会是静态帧

  67.         '''按a键退出程序,b键切换特效图像'''
  68.         if key & 0xFF == ord('a'): # Press the "a" key on Unihiker will stop the program.
  69.             print("退出视频")
  70.             break
  71.         elif key & 0xFF == ord('b'): # Press the "b" key on Unihiker will change the mark.
  72.             ImageID += 1  # Change the ImageID on every A click.
  73.             if ImageID > 2: # Two marks are available in this program.
  74.                 ImageID = 1
  75.             # Reload the mark from disk. # 重新加载特效图像
  76.             markOrigin = Image.fromarray(cv2.imread(str(ImageID) + ".png" , cv2.IMREAD_UNCHANGED))  
  77.     else:
  78.         break

  79. cap.release() # Release usb camera. # 释放摄像头
  80. cv2.destroyAllWindows() # Destory all windows created by opencv. # 关闭所有窗口
复制代码

2、程序运行

STEP1:远程连接行空板,运行程序并观察效果

观察行空板,可以发现当摄像头检测到人脸后,一顶魔法帽会立即显示在人的头上,在按下板载按钮b进行切换后,再检测到人脸,魔法帽变成了兔耳朵。


屏幕快照 2022-07-08 4.06.30 PM.png

挑战自我

自己再来试一试,更换更多有趣好玩的魔法图像体验一下吧!

附录

附录1:特效图像链接
链接:https://pan.baidu.com/s/1w17kSxlmdmmWAzgz0BknpA?pwd=9sxa
提取码:9sxa



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail