logo
发布于

OpenCV人脸检测

5843-–
作者
  • avatar
    姓名
    zhli

人脸检测是很多图像处理和计算机视觉处理的第一步,OpenCV 4.5.4 版本收录了一个基于深度学习神经网络的人脑模块,其中人脸检测使用 YuNet 模型,也是广受好评的人脸检测库 libfacedetection 使用的模型。

开发环境准备

我的开发环境是 MacBook Pro M1,先用 miniforge 安装 python3.9,搭建一套支持 arm64 的虚拟环境,具体步骤如下:

miniforge

  1. 下载 miniforge,GitHub 地址
  2. 根据自己的开发环境选择合适的版本,我选择的是 arm64(Apple Silicon)
  3. 在 terminal 终端执行命令:
sh Miniforge3-MacOSX-arm64.sh
  1. 安装完成后,重启终端,输入如下命令检查安装是否成功
conda --version
  1. 创建虚拟环境
conda create -n py39 python==3.9
  1. 激活虚拟环境
conda activate py39

OpenCV

conda 中没有这个包 opencv-python,所以需要在 conda 环境中,用 python 自带的 pip 进行安装:

conda activate py39
pip install opencv-python

VS Code

按下 Command+Shift+P 出现命令栏,输入

Python: Select Interpreter

选择刚刚创建的 py39

coding

环境准备好了,开始愉快的 coding 吧

face_detection.py
import os
import numpy as np
import cv2 as cv

def resize_image_keep_ratio(image, target_size):
    old_size = image.shape[0:2]
    radio = min(float(target_size[i])/(old_size[i])
                for i in range(len(old_size)))

    new_size = tuple([int(i*radio) for i in old_size])

    new_image = cv.resize(image, (new_size[1], new_size[0]))

    pad_w = target_size[1] - new_size[1]
    pad_h = target_size[0] - new_size[0]

    top, bottom = pad_h//2, pad_h-(pad_h//2)
    left, right = pad_w // 2, pad_w - (pad_w // 2)

    return cv.copyMakeBorder(new_image, top, bottom, left, right, cv.BORDER_CONSTANT, None, (0, 0, 0))


def main():
    directory = os.path.dirname(__file__)
    capture = cv.VideoCapture(1)

    if not capture.isOpened():
        exit()

    weights = os.path.join(
        directory, "yunet_yunet_final_640_640_simplify.onnx")

    face_detector = cv.FaceDetectorYN_create(weights, "", (0, 0))

    while True:
        result, image = capture.read()
        if result is False:
            cv.waitKey(0)
            break

        channels = 1 if len(image.shape) == 2 else image.shape[2]

        if channels == 1:
            image = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
        if channels == 4:
            image = cv.cvtColor(image, cv.COLOR_BGRA2BGR)

        image = resize_image_keep_ratio(image, (640, 640))

        height, width, _ = image.shape
        face_detector.setInputSize((width, height))

        _, faces = face_detector.detect(image)
        faces = faces if faces is not None else []

        for face in faces:
            box = list(map(int, face[:4]))
            color = (0, 0, 255)
            thickness = 1
            cv.rectangle(image, box, color, thickness, cv.LINE_AA)

            landmarks = list(map(int, face[4:len(face)-1]))
            landmarks = np.array_split(landmarks, len(landmarks) / 2)
            for landmark in landmarks:
                radius = 5
                thickness = -1
                cv.circle(image, landmark, radius,
                          color, thickness, cv.LINE_AA)

            confidence = face[-1]
            confidence = "{:.2f}".format(confidence)
            position = (box[0], box[1] - 10)
            font = cv.FONT_HERSHEY_SIMPLEX
            scale = 0.5
            thickness = 1
            cv.putText(image, confidence, position, font,
                       scale, color, thickness, cv.LINE_AA)

        cv.imshow("face detection", image)
        key = cv.waitKey(10)
        if key == ord('q'):
            break

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

yunet_yunet_final_640_640_simplify.onnx

测试效果

2022-07-28-16-46-33-1658997919634