You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于离散傅里叶变换(DFT)的人脸图像匹配效果不佳求优化

问题分析与解决方案

你的DFT人脸匹配效果差,核心原因有这几点:

  • 未对检测到的人脸做对齐与归一化:DFT对图像的位置、尺度变化极度敏感,哪怕同一人脸在图像中位置偏移、大小不同,DFT幅值的差异都会盖过人脸本身的特征差异。
  • 直接处理彩色图像:彩色图的三通道会干扰DFT特征提取,应该转灰度单通道处理。
  • 幅值计算的偏移量过大:+1700会严重压缩不同图像间的幅值差异,导致特征区分度极低。
  • 未利用人脸关键点对齐:正面人脸的关键点(眼睛、鼻子等)是对齐的核心依据,能消除姿态、位置带来的干扰。

具体修正步骤

  1. 人脸对齐与归一化:用face_recognition提取人脸关键点,将人脸对齐到标准姿态,并统一尺寸(比如256x256)。
  2. 转灰度图处理:DFT对单通道灰度图的特征提取更稳定,避免彩色通道的冗余信息。
  3. 优化DFT幅值计算:使用常规的log(1 + 幅值)保留细节差异,去掉过大的偏移量。
  4. 改进相似度计算:结合余弦相似度(对幅值特征的分布更敏感)和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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:55:21