如何从带倾斜角度的旋转图像中提取人脸区域?
问题根因
你当前使用的haarcascade_frontalface_default.xml是针对正向无偏转人脸训练的传统检测器,本身不支持旋转、大角度倾斜的人脸检测,因此无法处理倾斜人脸的提取需求。
可用解决方案
方案1:适配原有haar检测器,增加旋转遍历逻辑
如果不想更换检测器,可以对输入图像按固定步长旋转不同角度,每次旋转后执行人脸检测,检测到人脸后再将区域映射回原始图像裁剪即可,参考实现代码如下:
import cv2 import numpy as np import matplotlib.pyplot as plt %matplotlib inline def rotate_image(image, angle): h, w = image.shape[:2] center = (w // 2, h // 2) M = cv2.getRotationMatrix2D(center, angle, 1.0) rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) return rotated, M # 待检测的角度列表,可根据实际场景调整步长和范围 angles = [0, 10, -10, 20, -20, 30, -30, 45, -45, 60, -60, 90, -90, 180] faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml") image = cv2.imread('_img_1.png') found_faces = [] for angle in angles: rotated_img, M = rotate_image(image, angle) gray = cv2.cvtColor(rotated_img, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale( gray, scaleFactor=1.3, minNeighbors=3, minSize=(30, 30) ) if len(faces) > 0: # 把检测到的框映射回原始图像 for (x, y, w, h) in faces: # 旋转框的四个点 points = np.array([[x, y], [x+w, y], [x, y+h], [x+w, y+h]], dtype='float32') # 求逆变换矩阵,映射回原图 M_inv = cv2.invertAffineTransform(M) original_points = cv2.transform(points.reshape(-1, 1, 2), M_inv).reshape(-1, 2) # 取最小外接矩形 x_min, y_min = np.min(original_points, axis=0).astype(int) x_max, y_max = np.max(original_points, axis=0).astype(int) # 裁剪人脸 roi = image[y_min:y_max, x_min:x_max] found_faces.append(roi) cv2.rectangle(image, (x_min, y_min), (x_max, y_max), (0,255,0), 2) break print(f"[INFO] 共检测到{len(found_faces)}张人脸") for idx, face in enumerate(found_faces): cv2.imwrite(f'face_{idx}.jpg', face) plt.imshow(cv2.cvtColor(face, cv2.COLOR_BGR2RGB)) plt.show() cv2.imwrite('detected_result.jpg', image)
方案2:更换深度学习人脸检测器(更推荐,准确率和效率更高)
传统haar检测器精度低、适配场景少,直接换用支持多角度的深度学习人脸检测器效果更好,比如MTCNN,实现代码如下:
首先安装依赖:pip install mtcnn opencv-python matplotlib
import cv2 from mtcnn import MTCNN import matplotlib.pyplot as plt %matplotlib inline detector = MTCNN() image = cv2.imread('_img_1.png') rgb_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = detector.detect_faces(rgb_img) print(f"[INFO] 共检测到{len(results)}张人脸") found_faces = [] for res in results: x1, y1, width, height = res['box'] x2, y2 = x1 + width, y1 + height roi = image[y1:y2, x1:x2] found_faces.append(roi) cv2.rectangle(image, (x1, y1), (x2, y2), (0,255,0), 2) for idx, face in enumerate(found_faces): cv2.imwrite(f'face_{idx}.jpg', face) plt.imshow(cv2.cvtColor(face, cv2.COLOR_BGR2RGB)) plt.show() cv2.imwrite('detected_result.jpg', image)
该方案天生支持最大±90度的旋转、俯仰、侧偏人脸检测,不需要额外做旋转遍历,针对你提供的示例图也能正常检测:
内容的提问来源于stack exchange,提问作者Md. Rezwanul Haque
相关产品推荐
相关产品推荐

