使用opencv haar cascades级联检测器识别人脸,使用opencv facemark LBF识别人脸关键点。
- 在本地电脑新建一个目录(如face_recognition_demo),用来存放新的python项目。创建完成后进入该目录。
mkdir face_recognition_demo
cd face_recognition_demo - 为新的python项目建立一个python虚拟环境(在.venv子目录下),并激活。
python3 -m venv .venv
source .venv/bin/activate
激活虚拟环境后,.venv/bin这个目录会加入PATH环境变量的头部,这个目录下包含python, pip等命令。所以后面执行python或pip命令时,就会执行虚拟环境下bin目录里对应的命令。
如果想关闭虚拟环境,在项目根目录执行:deactivate。 - 安装依赖包,准备facemark LBF模型文件,准备人脸照片。
pip install opencv-contrib-python
注意:opencv-contrib-python已经包含了opencv核心,所以不需要再安装opencv-python包。2个都安装会造成重复。
新建model子目录,将lbfmodel.yaml放入其中。
将人脸照片(这里命名为face9.jpeg),放到项目根目录。 - 启动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()
- 运行程序。
在虚拟环境已经激活的情况下(如未激活,则需要执行上面提及的source命令),在终端或命令行中,在项目的根目录下,执行:python demo.py
目录下会生成一张标记人脸及人脸关键点的图片。人脸用绿色方框标出,人脸关键点用红色圆点标出,每个关键点会标出序号,从0~67。因为我们使用的是人脸68点标记。



