Python实战之基于OpenCV的美颜挂件制作

 更新时间:2021年11月18日 15:26:11   作者:盼小辉丶  
在本文中,我们将学习如何创建有趣的基于Snapchat的增强现实,主要包括两个实战项目:在检测到的人脸上的鼻子和嘴巴之间添加胡子挂件,在检测到的人脸上添加眼镜挂件。感兴趣的童鞋可以看看哦

基于 Snapchat 的增强现实

胡子挂件融合

第一个项目中,我们将在检测到的脸上覆盖了一个小胡子。我们可以使用从摄像头捕获的连续视频帧,也可以使用单张测试图像。在进行实际讲解程序的关键步骤前,首先查看应用程序预期输出的结果图像:


项目的第一步是检测图像中的人脸。如上图所示,使用青色矩形绘制图像中检测到的人脸的位置和大小;接下来迭代图像中所有检测到的人脸,在其区域内搜索鼻子,粉红色矩形表示图像中检测到的鼻子;检测到鼻子之后,就要根据之前计算出的鼻子的位置和大小来调整我们想要覆盖“胡子”挂件的区域,蓝色矩形表示计算获得的胡须将被覆盖的区域位置。如果处理的目标是连续视频帧,在处理完成所有检测到的人脸后,将继续分析下一帧。

根据上述描述,程序应当首先检测图像中的人脸和鼻子。为了检测这些对象,创建了两个分类器,一个用于检测人脸,另一个用于检测鼻子:

# 用于人脸和鼻子检测的级联分类器
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
nose_cascade = cv2.CascadeClassifier("haarcascade_mcs_nose.xml")

一旦创建了分类器,下一步就是使用 cv2.detectMultiScale() 函数检测图像中的这些对象。cv2.detectMultiScale() 函数检测输入灰度图像中不同大小的对象,并将检测到的对象作为矩形列表返回。例如,检测人脸时使用以下代码:

faces = face_cascade.detectMultiScale(gray, 1.3, 5)

接下来,遍历检测到的人脸,尝试检测鼻子:

# 遍历检测到的人脸
for (x, y, w, h) in faces:
    # 根据检测到的面大小创建感兴趣区域(ROI)
    roi_gray = gray[y:y + h, x:x + w]
    roi_color = frame[y:y + h, x:x + w]

    # 在检测到的人脸内检测鼻子
    noses = nose_cascade.detectMultiScale(roi_gray)

检测到鼻子后,遍历所有检测到的鼻子,并计算将被“胡子”挂件覆盖的区域。过滤掉错误的鼻子位置后,将“胡子”挂件根据先前计算的区域覆盖在图像上:

for (nx, ny, nw, nh) in noses:
    # 计算将被“胡子”挂件覆盖的区域坐标
    x1 = int(nx - nw / 2)
    x2 = int(nx + nw / 2 + nw)
    y1 = int(ny + nh / 2 + nh / 8)
    y2 = int(ny + nh + nh / 4 + nh / 6)

    if x1 < 0 or x2 < 0 or x2 > w or y2 > h:
        continue

    # 计算将被“胡子”挂件覆盖的区域尺寸
    img_moustache_res_width = int(x2 - x1)
    img_moustache_res_height = int(y2 - y1)

    # 调整掩膜大小,使其与放置“胡子”挂件的区域相等
    mask = cv2.resize(img_moustache_mask, (img_moustache_res_width, img_moustache_res_height))

    # 翻转掩膜
    mask_inv = cv2.bitwise_not(mask)

    # 将“胡子”挂件调整为所需区域
    img = cv2.resize(img_moustache, (img_moustache_res_width, img_moustache_res_height))
    # 获取原始图像的ROI
    roi = roi_color[y1:y2, x1:x2]
    # 创建ROI背景和ROI前景
    roi_bakground = cv2.bitwise_and(roi, roi, mask=mask_inv)
    roi_foreground = cv2.bitwise_and(img, img, mask=mask)
    # 获取结果
    res = cv2.add(roi_bakground, roi_foreground)
    # 将res置于原始图像中
    roi_color[y1:y2, x1:x2] = res
    break

上述程序的关键在于 img_mustache_mask 图像。此图像是使用要融合的“胡子”图像的 Alpha 通道创建的,使用此图像,将可以只绘制叠加图像的前景,基于融合图像的 alpha 通道创建的“胡子”蒙版如下:

img_moustache = cv2.imread('moustache.png', -1)
img_moustache_mask = img_moustache[:, :, 3]
cv2.imshow("img moustache mask", img_moustache_mask)

获得的胡子蒙版,如下所示:

增强现实融合“胡子”挂件后的结果如下所示:

这里不再针对视频帧的处理进行讲解,因为其方法与单个图像相同,在接下来的完整代码中,给出对连续视频帧进行增强现实的代码。

完整代码

import cv2

# 用于人脸和鼻子检测的级联分类器
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
nose_cascade = cv2.CascadeClassifier("haarcascade_mcs_nose.xml")

# 加载胡子图像
img_moustache = cv2.imread('moustache.png', -1)
# 创建胡子蒙版
img_moustache_mask = img_moustache[:, :, 3]
# 将胡子图像转换为 BGR 图像
img_moustache = img_moustache[:, :, 0:3]

# 创建 VideoCapture 对象
video_capture = cv2.VideoCapture(0)

while True:
    # 从 VideoCapture 对象捕获帧
    ret, frame = video_capture.read()
    # 将 frame 转换为灰度图像
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # 检测人脸
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)

    # 迭代检测到的人脸
    for (x, y, w, h) in faces:
        # 根据检测到的人脸大小创建ROI
        roi_gray = gray[y:y + h, x:x + w]
        roi_color = frame[y:y + h, x:x + w]
        # 在检测到的人脸中检测鼻子
        noses = nose_cascade.detectMultiScale(roi_gray)

        for (nx, ny, nw, nh) in noses:
            # 计算将放置 “胡子” 挂件的坐标
            x1 = int(nx - nw / 2)
            x2 = int(nx + nw / 2 + nw)
            y1 = int(ny + nh / 2 + nh / 8)
            y2 = int(ny + nh + nh / 4 + nh / 6)

            if x1 < 0 or x2 < 0 or x2 > w or y2 > h:
                continue

            # 计算“胡子”挂件区域的尺寸
            img_moustache_res_width = int(x2 - x1)
            img_moustache_res_height = int(y2 - y1)

            # 根据挂件区域缩放“胡子”蒙版
            mask = cv2.resize(img_moustache_mask, (img_moustache_res_width, img_moustache_res_height))
            # 翻转蒙版
            mask_inv = cv2.bitwise_not(mask)
            # 缩放“胡子”挂件
            img = cv2.resize(img_moustache, (img_moustache_res_width, img_moustache_res_height))

            # 从原始图像中获取ROI
            roi = roi_color[y1:y2, x1:x2]
            # 创建ROI前景和背景
            roi_bakground = cv2.bitwise_and(roi, roi, mask=mask_inv)
            roi_foreground = cv2.bitwise_and(img, img, mask=mask)

            # roi_bakground 与 roi_foreground 加和获取结果
            res = cv2.add(roi_bakground, roi_foreground)
            roi_color[y1:y2, x1:x2] = res

            break
    # 显示结果
    cv2.imshow('Snapchat-based OpenCV moustache overlay', frame)

    # 按下 “q” 键退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
video_capture.release()
cv2.destroyAllWindows()

眼镜挂件融合

在这一实战程序中,我们将学习在检测到的面部眼睛区域上融合眼镜挂件。我们通过下图首次查看程序预期结果:


同样为了实现眼镜挂件融合,需要首先使用眼睛检测器检测图像中的眼睛:

eyepair_cascade= cv2.CascadeClassifier("haarcascade_mcs_eyepair_big.xml")

上图中青色矩形表示检测到的人脸在图像中的位置和大小;粉红色矩形表示图像中检测到的眼睛;黄色矩形表示眼镜将被覆盖的位置,其根据眼睛所在区域的位置和大小进行计算。

同时,为融合的眼镜眼镜挂件图像增加一些透明度,以使它们更逼真,眼镜图像蒙版如下所示:

融合后的结果图像如下图所示:

完整代码

基本代码与上例相同,因此不再进行赘述,需要注意的是“眼镜”挂件的融合区域计算。

import cv2

face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
eyepair_cascade = cv2.CascadeClassifier("haarcascade_mcs_eyepair_big.xml")

img_glasses = cv2.imread('glasses.png', -1)
img_glasses_mask = img_glasses[:, :, 3]
img_glasses = img_glasses[:, :, 0:3]

video_capture = cv2.VideoCapture(0)

while True:
    ret, frame = video_capture.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # 检测人脸
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)

    for (x, y, w, h) in faces:
        roi_gray = gray[y:y + h, x:x + w]
        roi_color = frame[y:y + h, x:x + w]

        # 在检测到的人脸中检测眼睛
        eyepairs = eyepair_cascade.detectMultiScale(roi_gray)

        for (ex, ey, ew, eh) in eyepairs:
            # 计算“眼睛”挂件放置的坐标
            x1 = int(ex - ew / 10)
            x2 = int((ex + ew) + ew / 10)
            y1 = int(ey)
            y2 = int(ey + eh + eh / 2)

            if x1 < 0 or x2 < 0 or x2 > w or y2 > h:
                continue

            # 计算“眼睛”挂件放置区域大小
            img_glasses_res_width = int(x2 - x1)
            img_glasses_res_height = int(y2 - y1)


            mask = cv2.resize(img_glasses_mask, (img_glasses_res_width, img_glasses_res_height))
            mask_inv = cv2.bitwise_not(mask)
            img = cv2.resize(img_glasses, (img_glasses_res_width, img_glasses_res_height))

            roi = roi_color[y1:y2, x1:x2]
            roi_bakground = cv2.bitwise_and(roi, roi, mask=mask_inv)
            roi_foreground = cv2.bitwise_and(img, img, mask=mask)

            res = cv2.add(roi_bakground, roi_foreground):
            roi_color[y1:y2, x1:x2] = res

            break

    # 显示结果画面
    cv2.imshow('Snapchat-based OpenCV glasses filter', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video_capture.release()
cv2.destroyAllWindows()

以上就是Python实战之基于OpenCV的美颜挂件制作的详细内容,更多关于Python OpenCV的内容请关注脚本之家其它相关文章!

相关文章

  • Python 用NumPy创建二维数组的案例

    Python 用NumPy创建二维数组的案例

    这篇文章主要介绍了Python 用NumPy创建二维数组的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Python用requests-html爬取网页的实现

    Python用requests-html爬取网页的实现

    本文主要介绍了Python用requests-html爬取网页的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • python 实现简单的计算器(gui界面)

    python 实现简单的计算器(gui界面)

    这篇文章主要介绍了python 如何实现简单的计算器,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下
    2020-11-11
  • pytorch中的卷积和池化计算方式详解

    pytorch中的卷积和池化计算方式详解

    今天小编就为大家分享一篇pytorch中的卷积和池化计算方式详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • python从入门到精通(DAY 3)

    python从入门到精通(DAY 3)

    本文是python从入门到精通系列文章的第三篇,主要是给大家讲诉做的一个编写登陆接口练习程序的全过程,非常的细致,有需要的小伙伴可以参考下。
    2015-12-12
  • 一文搞懂Python中subprocess模块的使用

    一文搞懂Python中subprocess模块的使用

    subprocess是子流程,即进程的意思,该模块可以启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。本文将和大家聊聊subprocess模块的使用,需要的可以参考一下
    2022-11-11
  • Python正则表达式基本原理

    Python正则表达式基本原理

    正则表达式是一个特殊的符号系列,它可以帮助我们检查某个字符串和某种模式匹配。在python中,re库拥有全部的正则表达式的功能。想了解更多的小伙伴可以参考阅读本文
    2023-04-04
  • python读取测试数据的多种方式

    python读取测试数据的多种方式

    本文主要介绍了python读取测试数据的多种方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • python通过pil将图片转换成黑白效果的方法

    python通过pil将图片转换成黑白效果的方法

    这篇文章主要介绍了python通过pil将图片转换成黑白效果的方法,实例分析了Python中pil库的使用技巧,需要的朋友可以参考下
    2015-03-03
  • python 中 关于reverse() 和 reversed()的用法详解

    python 中 关于reverse() 和 reversed()的用法详解

    这篇文章主要介绍了python 中 关于reverse() 和 reversed()的用法介绍,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-01-01

最新评论