OpenCV-iOS計算圖片相似度

簡書更新停留在17年?????

demo下載

  • 需求分析:

1、尋寶活動,商家藏寶并將場景拍照上傳至服務(wù)器,用戶根據(jù)線索到達(dá)指定地點,打開app進(jìn)行實時掃描,如掃描到的圖片與服務(wù)器的圖片匹配成功,則視為中獎;

2、OpenCV中用于圖片對比及識別的算法較多,具體原理及優(yōu)缺點本文不做介紹,demo中用到的是特征點對比中的ORB算法;

3、本次需求中用到兩個算法:特征點-ORB和直方圖;
經(jīng)反復(fù)測試發(fā)現(xiàn)特征點對比較為適合棱角分明的場景,比如桌子/電腦等;而直方圖對比較為適合復(fù)雜且棱角較少的場景,比如辦公室的盆栽類;(ps:測試分為室內(nèi)測試及室外測試,且測試次數(shù)及測試量都不太大,結(jié)論僅限于參考)

  • OpenCV集成

1、OpenCV下載:官網(wǎng)地址

2、demo中OpenCV版本為3.4.3;

3、添加依賴庫:


OpenCV依賴庫
  • 功能開發(fā):

1、拍照上傳:

1)將.m文件后綴改為.mm;

2)導(dǎo)入頭文件(務(wù)必放在所有頭文件之上)

#import <opencv2/opencv.hpp>
#import <opencv2/imgproc/types_c.h>
#import <opencv2/videoio/cap_ios.h>
#import <opencv2/imgcodecs/ios.h>

3)打開相機(jī)具體實現(xiàn):

@interface CaptureView()<CvVideoCameraDelegate>

@property (strong, nonatomic)  UIImageView *CvImageV;

@property (nonatomic,retain) CvVideoCamera *videoCamera;

@end

@implementation CaptureView

- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
    if (self) {
    
        [self setupCvVideoCamera];
    
    }
     return self;
}

// MARK: - init
-(void)setupCvVideoCamera{

    self.CvImageV = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];

    self.videoCamera = [[CvVideoCamera  alloc]initWithParentView:self.CvImageV];

    self.videoCamera.delegate = self;
    self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;

    self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetiFrame960x540;
    self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;

    self.videoCamera.grayscaleMode = NO;
    self.videoCamera.defaultFPS = 30;
    [self addSubview:self.CvImageV];
}

// MARK: - CvVideoCameraDelegate
- (void)processImage:(cv::Mat &)image{

    // 將Mat轉(zhuǎn)換為Xcode的UIImageView顯示
    UIImage *currentImage = MatToUIImage(image);
}

// MARK: - event and response
// 開啟
- (void)start{
    [self.videoCamera start];
}

// 暫停
- (void)stop{
    [self.videoCamera stop];
}

4)問題:opencv返回的圖片矩陣為BGR,需要轉(zhuǎn)成RGB來上傳,具體代碼見demo

2、圖片對比:

1)將.m文件后綴改為.mm;

2)導(dǎo)入頭文件(務(wù)必放在所有頭文件之上)

#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
#include "opencv2/core/core.hpp"
#include <iostream>
#include <vector>

3)實現(xiàn)代碼:

 /**
 @param boxImage 模板圖片
 @param senceImage 實時圖片
 @return 對比結(jié)果(見圖)
 */
 -(UIImage *)similarlyMatchWithBox:(UIImage *)boxImage andSence:(UIImage *)senceImage{

    if (boxImage && senceImage) {
    
        cv::Mat sence,box;
        box = [self cvMatFromUIImage:boxImage];
        sence = [self cvMatFromUIImage:senceImage];
    
        cvtColor(box, box, CV_RGBA2RGB);
        cvtColor(sence, sence, CV_RGBA2RGB);
    
        vector<KeyPoint> keyPoints_obj, keyPoints_sence;
        Ptr<ORB> detector = ORB::create();
    
        detector->detect(box, keyPoints_obj);
        detector->detect(sence, keyPoints_sence);
    
        Mat description_box,description_sence;
    
        detector->compute(box, keyPoints_obj, description_box);
        detector->compute(sence, keyPoints_sence, description_sence);
        vector<DMatch> matches;
    
        Ptr<DescriptorMatcher> matcher = DescriptorMatcher ::create(cv::BFMatcher::BRUTEFORCE);
    
        // 處理拍的區(qū)域為黑色,比如手機(jī)平放在桌面上,會閃退
        if (description_sence.cols <= 0) {
            return nil;
        }
    
        if (description_sence.rows <= 0) {
            return nil;
        }
    
        matcher->match(description_box, description_sence, matches);
    
        // 發(fā)現(xiàn)匹配
        vector<DMatch> good_matches;
    
        for (unsigned int i = 0; i < matches.size(); i++) {
            //distance 值根據(jù)實際開發(fā)來調(diào)試
            if (matches[i].distance <= 320) {
                good_matches.push_back(matches[i]);
            }
        }
    
        Mat imgMatches;
        drawMatches(box,keyPoints_obj,sence,keyPoints_sence,good_matches,imgMatches,Scalar::all(-1),Scalar::all(-1),vector<char>(),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    
        UIImage *m = [self UIImageFromCVMat:imgMatches];
        return m;
    }

    return nil;
}

4)具體代碼見demo中ImageCompared文件;

5)問題:

① 相機(jī)拍到黑色時會崩潰:可通過description_sence.cols <= 0 && description_sence.rows <= 0來判斷;這個坑我和安卓都爬了好久才爬出來;(悄悄告訴你我先爬出來的,美滋滋)

② 存儲在服務(wù)器的模板圖可多上傳幾張,一張圖片匹配成功率會很低:可設(shè)置至少上傳X張,且在上傳的時候也進(jìn)行匹配,匹配率達(dá)到某個值則可上傳,否則要求商家重拍,防止上傳的圖片不是同一個場景;

③ 內(nèi)存問題:實時掃描且進(jìn)行相似度對比消耗內(nèi)存非常大,很快就會內(nèi)存溢出導(dǎo)致閃退,我的解決方法是設(shè)置為每隔X秒進(jìn)行一次匹配,時間可自己調(diào)試然后給定;

6)匹配結(jié)果圖:


匹配結(jié)果
  • 最后:OpenCV里的學(xué)問太多了,這次需求甲方爸爸趕得急是一方面,之前沒了解過也是真的,熬了幾個通宵才搞定,大概算是一只腳邁進(jìn)去了,如果二期需求有時間排的話可能另一只腳也就能邁進(jìn)去了,如果沒有的話就此打住。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容