iOS:如何使用OpenVC库计算照片相似度

  1. 图像格式转换

    使用 UIImagecv::Mat 的转换时,注意通道顺序(iOS使用BGRA格式)。

  2. 性能优化

    • 对于移动端,可降低HOG参数复杂度(如减少方向数)。
    • 使用 @autoreleasepool 管理内存。
  3. 动态阈值

    建议根据实际数据集通过ROC曲线确定最佳阈值。

  4. 错误处理

    增加对空图像、无轮廓等异常情况的检查。

** 关键步骤:**
1.引入OpenCV库
2.涉及C++,需要将.m文件更新为.mm文件
#pragma mark - 图像预处理
// 将UIImage转换为cv::Mat
+ (cv::Mat)preprocessSignatureImage:(UIImage *)image {

    CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);

    CGFloat cols = image.size.width;

    CGFloat rows = image.size.height;

    cv::Mat cvMat(rows, cols, CV_8UC4); // 8-bit 4通道

    CGContextRef contextRef = CGBitmapContextCreate(

        cvMat.data, cols, rows, 8, cvMat.step[0], colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault

    );

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);

    CGContextRelease(contextRef);

    // 转为灰度图
    Mat gray;
    cvtColor(cvMat, gray, COLOR_BGRA2GRAY);

    // 二值化(Otsu)

    Mat binary;

    threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

    // 形态学去噪(开运算)

    Mat kernel = getStructuringElement(MORPH_RECT, cv::Size(3, 3));

    morphologyEx(binary, binary, MORPH_OPEN, kernel);
    // 尺寸归一化

    resize(binary, binary, cv::Size(128, 64));
    return binary;
}

mark - 特征提取

+ (NSArray<NSNumber *> *)extractFeaturesFromImage:(cv::Mat)binaryImage {

    vector<float> features;
    // --------------------- HOG特征 ---------------------

    HOGDescriptor hog(

                      cv::Size(128, 64), // 窗口尺寸

                      cv::Size(16, 16),  // 块尺寸

                      cv::Size(8, 8),    // 块步长

                      cv::Size(8, 8),    // 胞元尺寸

        9              // 方向数

    );

    vector<float> hogFeatures;

    hog.compute(binaryImage, hogFeatures);

    features.insert(features.end(), hogFeatures.begin(), hogFeatures.end());

    

    // --------------------- 轮廓特征 ---------------------

    vector<vector<cv::Point>> contours;

    findContours(binaryImage.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // 添加轮廓数量

    features.push_back(contours.size());

    // 添加面积占比

    if (!contours.empty()) {

        double area = contourArea(contours[0]);

        features.push_back(area / (binaryImage.cols * binaryImage.rows));

    } else {

        features.push_back(0.0);

    }
    // 转为NSArray

    NSMutableArray *result = [NSMutableArray array];

    for (float val : features) {

        [result addObject:@(val)];
    }
    return result;
}`

#pragma mark - 相似度计算

+ (double)cosineSimilarityBetweenFeature1:(NSArray<NSNumber *> *)feat1

                              feature2:(NSArray<NSNumber *> *)feat2 {

    if (feat1.count != feat2.count) {

        NSLog(@"特征维度不匹配");

        return -1;

    }

    double dotProduct = 0.0, norm1 = 0.0, norm2 = 0.0;

    for (NSUInteger i = 0; i < feat1.count; i++) {

        double val1 = feat1[i].doubleValue;

        double val2 = feat2[i].doubleValue;

        dotProduct += val1 * val2;

        norm1 += val1 * val1;

        norm2 += val2 * val2;
    }
    return dotProduct / (sqrt(norm1) * sqrt(norm2));
}

//比对方法

+ (BOOL)compareSignaturesWithImage1:(UIImage *)image1 image2:(UIImage *)image2 similarityThreshold:(double)threshold{

    // 获取签名图像

    UIImage *signature1 = image1;

    UIImage *signature2 = image2;

    // 预处理

    cv::Mat binary1 = [ImageProcessor preprocessSignatureImage:signature1];

    cv::Mat binary2 = [ImageProcessor preprocessSignatureImage:signature2];
  
    // 特征提取

    NSArray *feat1 = [ImageProcessor extractFeaturesFromImage:binary1];
    NSArray *feat2 = [ImageProcessor extractFeaturesFromImage:binary2];
    // 计算相似度
    double similarity = [ImageProcessor cosineSimilarityBetweenFeature1:feat1

                                                              feature2:feat2];

    NSLog(@"签名相似度:%lf",similarity);

    // 判断结果(阈值根据实际数据调整)
    if (similarity > threshold) {
        return YES;
    } else {
        return NO;
    }

}

使用方法:

很简单,isSamePic是阈值,这个根据实际情况你可以设置动态的,这样就可以计算出来两张照片的相似度

double threshold = 0.7;

 BOOL isSamePic =   [ImageProcessor compareSignaturesWithImage1:self.s1.image image2:self.s2.image similarityThreshold:threshold];

    if (isSamePic) {

        NSLog(@"两张签名照片可能是同一个人的签名。");

    } else {

        NSLog(@"两张签名照片可能不是同一个人的签名。");

    }
相关推荐
挪不动29 分钟前
OpenCore Legacy Patcher 问题解决
macos
獨枭15 小时前
macOS 安装 CMake GUI 后找不到 cmake 命令的解决方案
macos
软购商城15 小时前
立即释放 Mac 空间!Duplicate File Finder 8 重复文件高速清理工具
macos·正版软件·mac 重复文件清理工具软件
水木姚姚17 小时前
图形界面控件编程(iOS)
人工智能·python·macos·ios·xcode
skywalk816317 小时前
MacOS Big Sur 11 新机安装brew wget python3.12 exo
人工智能·macos·exo
书弋江山20 小时前
Flutter 调用原生IOS接口
flutter·ios·cocoa
甜于酸21 小时前
Bartender 5 for Mac 多功能菜单栏管理
macos
大波V521 小时前
vscode mac版本 配置git
git·vscode·macos
kxiaozhuk1 天前
DeepSeek-R1本地化部署(Mac)
macos·ai·deepseek
程序猿微刊1 天前
Mac软件卸载后启动台图标还在
macos