OpenCV 相似圖搜索學習筆記(一)

學習目標

找出目標圖集中相似度最高的圖片瞎颗;

開發(fā)環(huán)境

JDK 8监署, OpenCV 2.3.14内列, Windows 7 64位;

測試圖

測試圖片

源碼

package com.dotions.opencv;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.features2d.DMatch;
import org.opencv.features2d.DescriptorExtractor;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.FeatureDetector;
import org.opencv.highgui.Highgui;

/**
 * @author Scott 2018-02-05
 */
public class TestImageSearch {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // 聲明系統(tǒng)庫
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        String f1 = "C:\\Users\\demo\\Pictures\\test\\CA4517-1-1.jpg";
        String f2 = "C:\\Users\\demo\\Pictures\\test\\CB4943-5.jpg";
        String f3 = "C:\\Users\\demo\\Pictures\\test\\CA4517-1-2.jpg";
        String f4 = "C:\\Users\\demo\\Pictures\\test\\CB4943-4.jpg";
        String f5 = "C:\\Users\\demo\\Pictures\\test\\CA4517-1-3.jpg";

        String url = find(f1, Arrays.asList(f2, f3, f4, f5));
        
        System.out.println("原圖為:" + f1);
        System.out.println("最相似的圖片為:" + url);
    }

    /**
     * 找出最相似的圖片
     * @param base 原圖
     * @param imgs 目標圖集
     * @return 最相似的圖片
     */
    public static String find(String base, List<String> imgs) {
        FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
        DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);

        Mat baseDesc = getDescriptors(detector, extractor, base);

        Mat tempDesc;
        String resultImage = null;
        double minScore = Double.MAX_VALUE;
        double score;
        for (String f : imgs) {
            tempDesc = getDescriptors(detector, extractor, f);
            score = computeScore(baseDesc, tempDesc, matcher);

            if (score < minScore) {
                minScore = score;
                resultImage = f;
            }
        }
        return resultImage;
    }

    public static Mat getDescriptors(FeatureDetector fd, DescriptorExtractor de, String fname) {
        Mat src = Highgui.imread(fname);
        MatOfKeyPoint kp = new MatOfKeyPoint();
        fd.detect(src, kp);
        Mat desc = new Mat();
        de.compute(src, kp, desc);
        return desc;
    }
    /**
     * 計算相似度(此處用方差來作為衡量標準恩够,可以用其他算法替換)
     * */
    public static double computeScore(Mat desc1, Mat desc2, DescriptorMatcher dm) {
        MatOfDMatch mdm = new MatOfDMatch();
        dm.match(desc1, desc2, mdm);

        double maxDist = Double.MIN_VALUE;
        double minDist = Double.MAX_VALUE;

        DMatch[] mats = mdm.toArray();
        double dist = 0.0d;
        for (int i = 0; i < mats.length; i++) {
            dist = mats[i].distance;
            if (dist < minDist)
                minDist = dist;
            if (dist > maxDist)
                maxDist = dist;
        }

        List<DMatch> goodMatches = new LinkedList<>();
        for (int i = 0; i < mats.length; i++) {
            dist = mats[i].distance;
            if (dist < 5 * minDist) {
                goodMatches.add(mats[i]);
            }
        }

        List<Float> list = goodMatches.stream().map(m -> m.distance).collect(Collectors.toList());
        Float[] dists = list.toArray(new Float[] {});

        double score = computeScore(dists);
        System.out.println("maxDist=" + maxDist);
        System.out.println("minDist=" + minDist);
        System.out.println("score=" + score);
        System.out.println("--------------------------------");
        return score;
    }

    /**
     * 計算數(shù)組的方差
     */
    public static double computeScore(Float[] dists) {
        double sum = 0.0d;
        for (int i = 0; i < dists.length; i++) {
            sum += dists[i];
        }
        double avg = sum / dists.length;
        double dvar = 0.0d;
        for (int i = 0; i < dists.length; i++) {
            dvar += (dists[i] - avg) * (dists[i] - avg);
        }
        return dvar;
    }

}

運行結(jié)果

maxDist=0.6122338175773621
minDist=0.039984580129384995
score=14.781858758643258
--------------------------------
maxDist=0.7934221625328064
minDist=0.0831444263458252
score=94.25050941872964
--------------------------------
maxDist=0.8908746838569641
minDist=0.08397696167230606
score=74.58133620484614
--------------------------------
maxDist=0.8740571141242981
minDist=0.08881661295890808
score=92.69089855851176
--------------------------------
原圖為:C:\Users\demo\Pictures\test\1.jpg
最相似的圖片為:C:\Users\demo\Pictures\test\2.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卒落,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜂桶,更是在濱河造成了極大的恐慌儡毕,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扑媚,死亡現(xiàn)場離奇詭異腰湾,居然都是意外死亡,警方通過查閱死者的電腦和手機疆股,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門费坊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旬痹,你說我怎么就攤上這事葵萎。” “怎么了唱凯?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谎痢。 經(jīng)常有香客問我磕昼,道長,這世上最難降的妖魔是什么节猿? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任票从,我火速辦了婚禮,結(jié)果婚禮上滨嘱,老公的妹妹穿的比我還像新娘峰鄙。我一直安慰自己,他們只是感情好太雨,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布吟榴。 她就那樣靜靜地躺著,像睡著了一般囊扳。 火紅的嫁衣襯著肌膚如雪吩翻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天锥咸,我揣著相機與錄音狭瞎,去河邊找鬼。 笑死搏予,一個胖子當著我的面吹牛熊锭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碗殷,長吁一口氣:“原來是場噩夢啊……” “哼精绎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起亿扁,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤捺典,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后从祝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體襟己,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年牍陌,在試婚紗的時候發(fā)現(xiàn)自己被綠了擎浴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毒涧,死狀恐怖贮预,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情契讲,我是刑警寧澤仿吞,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站捡偏,受9級特大地震影響唤冈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜银伟,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一你虹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彤避,春花似錦傅物、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至模孩,卻和暖如春尖阔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背榨咐。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工介却, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人块茁。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓齿坷,卻偏偏與公主長得像桂肌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子永淌,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • 從今天開始讀《深入理解 Java 虛擬機》一書崎场,并開設(shè)了同名專題 深入理解 Java 虛擬機。計劃在 2 周內(nèi)將全...
    SawyerZh閱讀 10,247評論 17 215
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評論 6 342
  • 當你在時間中緩慢地站起身來遂蛀,以財富奠基谭跨,以才華吶喊,以顏值笑傲江湖李滴,以意志獨步天下螃宙,你會發(fā)現(xiàn),身后情話如雨所坯,桃花如...
    最美_露珠閱讀 209評論 0 0
  • 1谆扎、為什么要用SurfaceView 項目中經(jīng)常會出現(xiàn)多個自定義View,并且可能會多次且頻繁的調(diào)用canvas進...
    搬磚人閱讀 4,550評論 0 2