美文网首页
OpenCV 相似图搜索学习笔记(一)

OpenCV 相似图搜索学习笔记(一)

作者: 翼徳 | 来源:发表于2018-02-06 11:42 被阅读156次

    学习目标

    找出目标图集中相似度最高的图片;

    开发环境

    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) {
            // 声明系统库
            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;
        }
    
        /**
         * 计算数组的方差
         */
        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;
        }
    
    }
    
    

    运行结果

    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
    

    相关文章

      网友评论

          本文标题:OpenCV 相似图搜索学习笔记(一)

          本文链接:https://www.haomeiwen.com/subject/xhfgzxtx.html