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

Python手写签名相似度匹配:如何提升示例2的结果准确性?

提升手写签名相似度匹配精度的优化方案

针对视觉相似签名(示例2)SSIM匹配得分偏低的问题,核心原因是当前方案仅依赖全局结构相似性,未处理签名的几何形变(平移、缩放、旋转)、笔画粗细差异等问题。以下是具体优化方向及代码实现:

1. 加入几何对齐:用特征匹配实现仿射变换对齐

示例2中两个签名存在明显的缩放和位置偏移,直接resize会导致笔画错位。通过特征点匹配计算变换矩阵,将两张签名对齐到同一坐标系:

import cv2
import numpy as np

def align_signatures(img1, img2):
    # 初始化ORB特征检测器
    orb = cv2.ORB_create(500)
    kp1, des1 = orb.detectAndCompute(img1, None)
    kp2, des2 = orb.detectAndCompute(img2, None)
    
    # 暴力匹配特征点
    matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = matcher.match(des1, des2)
    matches = sorted(matches, key=lambda x: x.distance)
    
    # 提取匹配的关键点对
    src_pts = np.float32([kp1[m.queryIdx].pt for m in matches[:100]]).reshape(-1, 1, 2)
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches[:100]]).reshape(-1, 1, 2)
    
    # 计算单应性矩阵并做透视变换
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
    h, w = img1.shape
    aligned_img1 = cv2.warpPerspective(img1, M, (w, h))
    
    return aligned_img1, img2

在match函数中,替换resize步骤为对齐操作:

# 原resize代码替换为:
img1, img2 = align_signatures(img1, img2)
# 再统一resize到相同尺寸
img1 = cv2.resize(img1, (300, 300))
img2 = cv2.resize(img2, (300, 300))

2. 优化预处理:加入形态学操作与笔画归一化

签名的笔画粗细、噪声会影响SSIM计算,加入二值化、形态学处理和骨架提取,统一笔画特征:

def preprocess_signature(img):
    # 去白边
    img = removeWhiteSpace(img)
    # 灰度化
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 自适应二值化(应对光照不均)
    binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    # 形态学开运算消除噪声,闭运算填补笔画缺口
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
    binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
    # 骨架提取(归一化笔画宽度)
    skeleton = cv2.ximgproc.thinning(binary)
    return skeleton

修改match函数中的预处理步骤,用preprocess_signature替代原有的灰度化和resize前的操作。

3. 替换SSIM为更适合签名的匹配算法

SSIM对全局结构变化敏感,可改用基于轮廓特征的匹配方法,比如Hu不变矩:

def calculate_similarity_hu(img1, img2):
    # 提取轮廓
    contours1, _ = cv2.findContours(img1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours2, _ = cv2.findContours(img2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # 计算Hu矩
    if contours1 and contours2:
        cnt1 = max(contours1, key=cv2.contourArea)
        cnt2 = max(contours2, key=cv2.contourArea)
        hu1 = cv2.HuMoments(cv2.moments(cnt1)).flatten()
        hu2 = cv2.HuMoments(cv2.moments(cnt2)).flatten()
        
        # 计算Hu矩的相似度(取对数后计算欧氏距离)
        hu1 = -np.sign(hu1) * np.log10(np.abs(hu1))
        hu2 = -np.sign(hu2) * np.log10(np.abs(hu2))
        distance = np.linalg.norm(hu1 - hu2)
        # 转换为相似度百分比(距离越小相似度越高)
        similarity = 100 - (distance / np.max([hu1.max(), hu2.max()]) * 100)
        return round(similarity, 2)
    return 0.0

4. 混合匹配策略:结合SSIM与局部特征

如果不想完全替换SSIM,可以结合局部特征匹配的结果,加权计算最终相似度:

def hybrid_similarity(img1, img2):
    ssim_score = ssim(img1, img2, gaussian_weights=True, sigma=1.2, use_sample_covariance=False)*100
    hu_score = calculate_similarity_hu(img1, img2)
    # 加权平均,可根据实际效果调整权重
    return round((ssim_score * 0.4 + hu_score * 0.6), 2)

通过以上优化,示例2中的签名匹配得分会显著提升,同时也能增强整体匹配算法的鲁棒性。

内容的提问来源于stack exchange,提问作者Ahmed Ansari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:27:32