Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之二 简单人脸检测添加戴眼镜效果

发布于:2024-04-24 ⋅ 阅读:(36) ⋅ 点赞:(0)

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之二 简单人脸检测添加戴眼镜效果

目录

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之二 简单人脸检测添加戴眼镜效果

一、简单介绍

二、简单人脸检测添加戴眼镜效果实现原理

三、简单人脸检测添加戴眼镜效果案例实现简单步骤

四、注意事项


一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

这里使用 Python  基于 OpenCV 进行视觉图像处理,......

人脸检测的两个重要概念:哈尔特征分类器(Haar Feature Classifier)和级联分类器(Cascade Classifier)是用于。

哈尔特征分类器:

    定义:哈尔特征分类器是一种基于哈尔特征的机器学习算法,用于检测图像中的对象或特定区域。

    原理:哈尔特征是一种基于图像局部特征的数学描述方法,通过对图像中不同区域像素值的差异进行计算,提取出具有区分度的特征。这些特征可以是边缘、线段、角点等。哈尔特征分类器通过训练过程学习到一组有效的特征模式,用于区分目标和非目标区域。

    应用:哈尔特征分类器常用于对象检测任务,如人脸检测、眼睛检测等。在训练过程中,通常需要提供正样本(包含目标的图像)和负样本(不包含目标的图像),让分类器学习区分目标和非目标的特征模式。

级联分类器:

    定义:级联分类器是一种多级联组成的分类器结构,由多个弱分类器组成,通过级联方式实现目标检测。

    原理:级联分类器将多个简单的分类器组合成一个复杂的分类器,每个简单分类器都是一个弱分类器,对目标区域进行初步筛选或过滤。级联分类器通过级联多个弱分类器,每个分类器都负责判断一组特征是否满足条件,通过级联的方式实现高效的目标检测。

    应用:级联分类器常用于实时目标检测任务,如人脸检测、车辆检测等。OpenCV 中的 Haar 级联分类器是基于哈尔特征的级联分类器,通过级联多个分类阶段来实现高效的人脸检测。级联分类器的优势在于其高速、高效的检测性能,适用于实时应用场景。

OpenCV 提供了一些已经训练好的级联分类器,这些级联分类器以XML文件的方式保存在以下路径中:

 ...\Python\Lib\site-packages\cv2\data\

OpenCV提供了一些经过预训练的人脸检测器模型文件,这些文件通常包含在OpenCV的安装包中。你可以在OpenCV的官方GitHub页面或者OpenCV官方网站的下载页面找到这些模型文件的下载链接。

一般来说,你可以从以下位置获取OpenCV的预训练模型文件:

  • OpenCV GitHub Release 页面:在 Releases · opencv/opencv · GitHub 找到你需要的版本,然后在下载的压缩包中找到位于 opencv\data 目录下的人脸检测器模型文件。
  • OpenCV 官方网站下载页面:访问 OpenCV 官方网站 Releases - OpenCV ,下载你需要的版本,并在相应的压缩包中查找人脸检测器模型文件。

请确保下载与你使用的OpenCV版本兼容的模型文件。

二、简单人脸检测添加戴眼镜效果实现原理

人脸检测添加带眼镜效果是指利用计算机视觉技术中的人脸检测算法,识别图像或视频中的人脸,并在识别到的人脸位置上叠加眼镜图像,以实现给人脸添加眼镜的效果。

实现原理:

  1. 使用 OpenCV 的人脸识别功能检测图像中的人脸位置。
  2. 在检测到的每张人脸位置上,根据人脸的宽度调整眼镜的大小。
  3. 将调整后的眼镜图像覆盖到人脸图像上,完成眼镜效果的添加。

具体方法:

  1. 使用 OpenCV 加载人脸识别分类器。
  2. 读取人脸图像和眼镜图像。
  3. 对人脸图像进行人脸检测,获取人脸的位置信息。
  4. 遍历检测到的每张人脸,根据人脸宽度调整眼镜大小。
  5. 将调整后的眼镜图像覆盖到对应人脸位置上。
  6. 返回带有眼镜效果的图像数据。

案例中涉及的两个关键函数说明

  1. over_img(img, img_over, over_x, over_y)

    • 功能:将一个图像覆盖在另一个图像的指定位置上。
    • 参数:
      • img:原始图像,numpy 数组格式。
      • img_over:要覆盖的图像,numpy 数组格式。
      • over_x:要覆盖图像的左上角 x 坐标。
      • over_y:要覆盖图像的左上角 y 坐标。
    • 返回值:覆盖后的图像,numpy 数组格式。
  2. apply_glasses(input_image_path, glasses_image_path, vertical_offset=0.35)

    • 功能:在输入的人脸图像上添加眼镜效果。
    • 参数:
      • input_image_path:输入的人脸图像路径。
      • glasses_image_path:眼镜图像的路径。
      • vertical_offset:眼镜垂直位置的调整参数,默认值为0.35。
    • 返回值:带眼镜效果的图像数据,numpy 数组格式。
  3. cv2.CascadeClassifier()

    • 函数说明:用于加载 Haar 级联分类器,用于人脸检测。
    • 参数:
      • xml_file_path:Haar 级联分类器的 XML 文件路径。
    • 返回值:返回一个级联分类器对象,用于后续的人脸检测

这些函数负责在人脸图像上添加眼镜效果,其中over_img函数用于将眼镜图像覆盖到人脸图像的指定位置上,而apply_glasses函数则是整个眼镜效果添加的入口函数,调用了人脸识别、图像处理等功能。

三、简单人脸检测添加戴眼镜效果案例实现简单步骤

1、编写代码

2、运行效果

3、具体代码

"""
简单人脸检测添加戴眼镜效果
    1、使用 OpenCV 加载人脸识别分类器。
    2、读取人脸图像和眼镜图像。
    3、对人脸图像进行人脸检测,获取人脸的位置信息。
    4、遍历检测到的每张人脸,根据人脸宽度调整眼镜大小。
    5、将调整后的眼镜图像覆盖到对应人脸位置上。
    6、返回带有眼镜效果的图像数据。
"""

import cv2


def over_img(img, img_over, over_x, over_y):
    """
    将一张图像覆盖到另一张图像上
    :param img: (numpy.ndarray) 目标图像数据
    :param img_over: (numpy.ndarray) 待覆盖图像数据,包含 alpha 通道
    :param over_x: (int) 待覆盖图像左上角的 x 坐标
    :param over_y: (int) 待覆盖图像左上角的 y 坐标
    :return: numpy.ndarray 覆盖后的图像数据
    """
    img_h, img_w, c = img.shape
    img_over_h, img_over_w, over_c = img_over.shape
    # 将待覆盖图像转换为带 alpha 通道的 BGRA 格式
    if over_c == 3:
        img_over = cv2.cvtColor(img_over, cv2.COLOR_BGR2BGRA)
    # 遍历待覆盖图像的每个像素
    for w in range(0, img_over_w):
        for h in range(0, img_over_h):
            # 透明像素不能覆盖目标图像
            if img_over[h, w, 3] != 0:
                # 遍历 RGB 通道
                for c in range(0, 3):
                    x = over_x + w
                    y = over_y + h
                    # 如果超出目标图像范围,则跳出循环
                    if x >= img_w or y >= img_h:
                        break
                    # 将待覆盖图像像素覆盖到目标图像上
                    img[y, x, c] = img_over[h, w, c]
    return img


def apply_glasses(input_image_path, glasses_image_path, vertical_offset=0.35):
    """
    在人脸图像上添加眼镜效果
    :param input_image_path: (str) 输入的人脸图像路径
    :param glasses_image_path: (str) 眼镜图像的路径
    :param vertical_offset: (float) 眼镜垂直位置的调整参数,范围为0到1,默认值为0.35
    :return: numpy.ndarray 带眼镜效果的图像数据
    """
    # 参数安全性校验
    if not isinstance(input_image_path, str) or not input_image_path.strip():
        raise ValueError("Invalid input image path.")

    if not isinstance(glasses_image_path, str) or not glasses_image_path.strip():
        raise ValueError("Invalid glasses image path.")

    if not (0 <= vertical_offset <= 1):
        raise ValueError("Vertical offset parameter must be between 0 and 1.")

    # 读取人脸和眼镜图像
    img = cv2.imread(input_image_path)
    glass = cv2.imread(glasses_image_path, cv2.IMREAD_UNCHANGED)  # 保留图像类型
    height, weight, channel = glass.shape
    # 加载人脸识别联结器
    faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
    # 进行人脸检测
    faces = faceCascade.detectMultiScale(img, 1.15, 4)
    # 对每个检测到的人脸应用眼镜效果
    for (x, y, w, h) in faces:
        gw = w
        gh = int(height * gw / weight)
        # 调整眼镜图像大小以适应人脸宽度
        img_over_new = cv2.resize(glass, (gw, gh))
        # 将眼镜图像覆盖到人脸图像上
        img = over_img(img, img_over_new, x, y + int(h * vertical_offset))
        # 绘制脸部范围图框
        # cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 5)
    return img


# 测试接口调用
if __name__ == "__main__":
    input_image_path = "Images/TwoManFace.png"
    glasses_image_path = "Images/glasses.png"

    try:
        output_img = apply_glasses(input_image_path, glasses_image_path, vertical_offset=0.0)
        cv2.imshow("output_img", output_img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        print("Glasses applied successfully.")
    except ValueError as ve:
        print(f"Error: {ve}")

四、注意事项

  1. 人脸识别结果可能有误,因此需要根据实际情况调整眼镜的位置和大小。
  2. 眼镜图像的背景应该是透明的,以便与人脸图像进行叠加。
  3. 调整眼镜大小时,应保持眼镜的比例,以确保效果自然。
  4. 确保输入图像路径和眼镜图像路径有效,以避免出现读取失败的情况。
  5. 在覆盖眼镜图像到人脸图像时,注意边界情况,防止超出图像范围。
  6. 眼镜的垂直位置调整参数应在0到1之间,表示眼镜在人脸垂直方向上的偏移量。