使用OpenCV进行人脸检测和人脸关键点检测

使用opencv haar cascades级联检测器识别人脸,使用opencv facemark LBF识别人脸关键点。

  1. 在本地电脑新建一个目录(如face_recognition_demo),用来存放新的python项目。创建完成后进入该目录。
    mkdir face_recognition_demo
    cd face_recognition_demo
  2. 为新的python项目建立一个python虚拟环境(在.venv子目录下),并激活。
    python3 -m venv .venv
    source .venv/bin/activate
    激活虚拟环境后,.venv/bin这个目录会加入PATH环境变量的头部,这个目录下包含python, pip等命令。所以后面执行python或pip命令时,就会执行虚拟环境下bin目录里对应的命令。
    如果想关闭虚拟环境,在项目根目录执行:deactivate。
  3. 安装依赖包,准备facemark LBF模型文件,准备人脸照片。
    pip install opencv-contrib-python
    注意:opencv-contrib-python已经包含了opencv核心,所以不需要再安装opencv-python包。2个都安装会造成重复。
    新建model子目录,将lbfmodel.yaml放入其中。
    将人脸照片(这里命名为face9.jpeg),放到项目根目录。
  4. 启动VScode,打开上面的python项目的根目录。新建1个python文件(这里文件名为demo.py)。
    以下列出代码。顺便说一下obsidian里关于代码块的注意事项:
    (1)obsidian里,代码块用3个反引号开始,后面紧跟编程语言的名字(如python),用3个反引号结束。
    (2)粘贴代码到代码块时,如果想保留原先代码里的缩进,粘贴时按住 Command + Shift + V (MacOS系统) 或 Control + Shift + V (windows系统)。
from pathlib import Path

import cv2


def resolve_haarcascade(base_dir: Path) -> str:
    candidates = []

    if hasattr(cv2, "data") and hasattr(cv2.data, "haarcascades"):
        candidates.append(Path(cv2.data.haarcascades) / "haarcascade_frontalface_alt2.xml")

    cv2_root = Path(cv2.__file__).resolve().parent
    print(f"cv2_root:{cv2_root}")
    
    candidates.extend(
        [
            base_dir / "haarcascade_frontalface_alt2.xml",
            Path("/opt/homebrew/Cellar/opencv/4.13.0_10/share/opencv4/haarcascades/haarcascade_frontalface_alt2.xml"),
            cv2_root / "data" / "haarcascade_frontalface_alt2.xml",
            cv2_root.parent.parent.parent / "share" / "opencv4" / "haarcascades" / "haarcascade_frontalface_alt2.xml",
        ]
    )

    for candidate in candidates:
        if candidate.exists():
            return str(candidate)

    raise FileNotFoundError(
        "Cannot find haarcascade_frontalface_alt2.xml. "
        "Download it from https://raw.githubusercontent.com/opencv/opencv/4.x/data/haarcascades/haarcascade_frontalface_alt2.xml "
        "and place it next to demo.py."
    )


def main() -> None:
    base_dir = Path(__file__).resolve().parent
    image_path = base_dir / "face9.jpeg"
    model_path = base_dir / "model" / "lbfmodel.yaml"
    output_path = base_dir / "face9_landmarks.jpg"

    image = cv2.imread(str(image_path))
    if image is None:
        raise FileNotFoundError(f"Cannot read image: {image_path}")

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    cascade_path = resolve_haarcascade(base_dir)
    detector = cv2.CascadeClassifier(cascade_path)
    if detector.empty():
        raise RuntimeError(f"Failed to load Haar cascade: {cascade_path}")

    faces = detector.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5,
        minSize=(80, 80),
    )
    if len(faces) == 0:
        raise RuntimeError("No face detected in face4.jpeg")

    facemark = cv2.face.createFacemarkLBF()
    facemark.loadModel(str(model_path))

    ok, landmarks = facemark.fit(gray, faces)
    if not ok:
        raise RuntimeError("Facemark fitting failed")

    for (x, y, w, h), face_landmarks in zip(faces, landmarks):
        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
        # for px, py in face_landmarks[0]:
        #     cv2.circle(image, (int(px), int(py)), 2, (0, 0, 255), -1)
        for i, (px, py) in enumerate(face_landmarks[0]):
            x, y = int(px), int(py)
            cv2.circle(image, (x, y), 2, (0, 0, 255), -1)
            cv2.putText(image, str(i), (x + 2, y - 2),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)

    cv2.imwrite(str(output_path), image)

    print(f"Detected {len(faces)} face(s)")
    print(f"Saved result to: {output_path}")


if __name__ == "__main__":
    main()

  1. 运行程序。
    在虚拟环境已经激活的情况下(如未激活,则需要执行上面提及的source命令),在终端或命令行中,在项目的根目录下,执行:python demo.py
    目录下会生成一张标记人脸及人脸关键点的图片。人脸用绿色方框标出,人脸关键点用红色圆点标出,每个关键点会标出序号,从0~67。因为我们使用的是人脸68点标记。

Mac系统 (m系列芯片) 安装d2l (Dive into Deep Learning|动手学深度学习)

  1. 安装miniforge
    不要用文档上说的miniconda。
    下载最新版mac系统arm版本的miniforge,比如:Miniforge3-26.3.2-2-MacOSX-arm64.sh。
    执行bash ./Miniforge3-26.3.2-2-MacOSX-arm64.sh, 默认会安装到/Users/xxx/miniforge3,安装过程中可以自定义安装路径。
  2. 新建1个虚拟环境并激活
    安装miniforge完成后,关闭终端,重新打开一个终端。
    conda create -n d2l python=3.10
    conda activate d2l
    这里,python版本选择3.10,其它版本会报错。
  3. 安装依赖
    conda install pytorch torchvision torchaudio -c pytorch
    pip install d2l
  4. 下载代码并运行
    按照文档,执行以下命令。
    mkdir d2l-zh && cd d2l-zh
    curl https://zh-v2.d2l.ai/d2l-zh-2.0.0.zip -o d2l-zh.zip
    unzip d2l-zh.zip && rm d2l-zh.zip
    cd pytorch
    jupyter notebook
    Web浏览器中打开http://localhost:8888(通常会自动打开)。