基于离散傅里叶变换(DFT)的人脸图像匹配效果不佳求优化
问题分析与解决方案
你的DFT人脸匹配效果差,核心原因有这几点:
- 未对检测到的人脸做对齐与归一化:DFT对图像的位置、尺度变化极度敏感,哪怕同一人脸在图像中位置偏移、大小不同,DFT幅值的差异都会盖过人脸本身的特征差异。
- 直接处理彩色图像:彩色图的三通道会干扰DFT特征提取,应该转灰度单通道处理。
- 幅值计算的偏移量过大:
+1700会严重压缩不同图像间的幅值差异,导致特征区分度极低。 - 未利用人脸关键点对齐:正面人脸的关键点(眼睛、鼻子等)是对齐的核心依据,能消除姿态、位置带来的干扰。
具体修正步骤
- 人脸对齐与归一化:用
face_recognition提取人脸关键点,将人脸对齐到标准姿态,并统一尺寸(比如256x256)。 - 转灰度图处理:DFT对单通道灰度图的特征提取更稳定,避免彩色通道的冗余信息。
- 优化DFT幅值计算:使用常规的
log(1 + 幅值)保留细节差异,去掉过大的偏移量。 - 改进相似度计算:结合余弦相似度(对幅值特征的分布更敏感)和SSIM,提升区分度。
修改后的代码
import cv2 import face_recognition import numpy as np from skimage.metrics import structural_similarity as ssim from sklearn.metrics.pairwise import cosine_similarity def align_face(image): # 提取人脸关键点 face_landmarks_list = face_recognition.face_landmarks(image) if not face_landmarks_list: return None landmarks = face_landmarks_list[0] # 取左右眼中心作为对齐基准 left_eye = np.mean(landmarks['left_eye'], axis=0) right_eye = np.mean(landmarks['right_eye'], axis=0) # 计算旋转角度 dy = right_eye[1] - left_eye[1] dx = right_eye[0] - left_eye[0] angle = np.degrees(np.arctan2(dy, dx)) - 180 # 计算两眼中点 eye_center = ((left_eye[0] + right_eye[0]) // 2, (left_eye[1] + right_eye[1]) // 2) # 旋转图像对齐人脸 rotation_matrix = cv2.getRotationMatrix2D(eye_center, angle, scale=1.0) aligned_face = cv2.warpAffine(image, rotation_matrix, (image.shape[1], image.shape[0]), flags=cv2.INTER_CUBIC) # 重新检测对齐后的人脸并裁剪,统一尺寸为256x256 face_locations = face_recognition.face_locations(aligned_face) if not face_locations: return None top, right, bottom, left = face_locations[0] cropped_face = aligned_face[top:bottom, left:right] normalized_face = cv2.resize(cropped_face, (256, 256)) return normalized_face def dft_magnitude(image): # 转灰度图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 做DFT fourier = cv2.dft(np.float32(gray), flags=cv2.DFT_COMPLEX_OUTPUT) fourier_shift = np.fft.fftshift(fourier) # 计算幅值,用log(1+幅值)保留细节 magnitude = 20 * np.log(1 + cv2.magnitude(fourier_shift[:, :, 0], fourier_shift[:, :, 1])) return magnitude def compare_images(img1, img2): # 对齐归一化人脸 face1 = align_face(img1) face2 = align_face(img2) if face1 is None or face2 is None: return 0.0 # 计算DFT幅值 dft_img1 = dft_magnitude(face1) dft_img2 = dft_magnitude(face2) # 归一化到[0,1] dft_img1 = cv2.normalize(dft_img1, None, 0, 1, cv2.NORM_MINMAX) dft_img2 = cv2.normalize(dft_img2, None, 0, 1, cv2.NORM_MINMAX) # 计算SSIM ssim_score = ssim(dft_img1, dft_img2, data_range=dft_img1.max() - dft_img1.min()) # 计算余弦相似度(将二维幅值转为一维向量) cos_score = cosine_similarity(dft_img1.flatten().reshape(1,-1), dft_img2.flatten().reshape(1,-1))[0][0] # 综合两个分数(可根据实际情况调整权重) combined_score = (ssim_score + cos_score) / 2 return combined_score # 示例使用 sample_image = cv2.imread('1.jpg') target_image = cv2.imread('3.jpg') similarity_score = compare_images(sample_image, target_image) print(f'综合相似度得分: {similarity_score:.4f}')
额外说明
- 人脸对齐是提升DFT匹配效果的关键,它消除了空间变换对傅里叶特征的干扰。
- 如果仍觉得区分度不够,可以尝试加入DFT的相位信息(相位对图像结构的描述比幅值更精准),但相位匹配需要更复杂的处理(比如相位相关法)。
- 对于批量处理文件夹中的图像,可以遍历文件夹路径,逐个调用
compare_images函数即可。
内容的提问来源于stack exchange,提问作者30-Phạm Thánh Trí-11T1
相关产品推荐
相关产品推荐

