【问题标题】:Comparing rotated images比较旋转的图像
【发布时间】:2017-12-07 22:38:25
【问题描述】:

我正在寻找一种方法来比较几乎相同(95% 以上相似度)但可以围绕中心轴旋转的图像。

我是整个计算机图形/视觉领域的新手,我不确定是否有现成的工具或系统,或者即使这是正确的堆栈交换要求。

目前,我正在研究使用 C# 生成位图直方图,然后通过 Panda 运行它进行分析,并根据直方图的相似性对图像进行理想分组,尽管我听说 OpenCv + tesseract 可能是一个可行的替代方案。

【问题讨论】:

    标签: image-processing ocr


    【解决方案1】:

    您需要计算两个图像之间的仿射变换矩阵,以便获取有关缩放、平移和旋转的信息。

    这个矩阵看起来如何以及如何获得旋转差异?

    From this answer:

    我使用了以下 Java 代码(使用 OpenCV 3.2)计算 scalingtranslationrotation 两个 Mat 图像之间的差异。我希望你会发现它有用。

    static void calculateDifferences(Mat img1, Mat img2){
    
            // Initialization
            FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
            DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
            DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
    
            // First image objects
            Mat img1_descriptors = new Mat();
            MatOfKeyPoint img1_keypoints_mat = new MatOfKeyPoint();
    
            // Detect KeyPoints for first image
            detector.detect(img1, img1_keypoints_mat);
            descriptor.compute(img1, img1_keypoints_mat, img1_descriptors);
    
            // Second image objects
            Mat img2_descriptors = new Mat();
            MatOfKeyPoint img2_keypoints_mat = new MatOfKeyPoint();
    
            // Detect KeyPoints for second image
            detector.detect(img2, img2_keypoints_mat);
            descriptor.compute(img2, img2_keypoints_mat, img2_descriptors);
    
            // Match KeyPoints
            MatOfDMatch matOfDMatch = new MatOfDMatch();
            matcher.match(img1_descriptors, img2_descriptors, matOfDMatch);
    
            // Filtering the matches
            List<DMatch> dMatchList = matOfDMatch.toList();
            Double max_dist = 0.0;
            Double min_dist = 100.0;
    
            for(int i = 0; i < img1_descriptors.rows(); i++){
                Double dist = (double) dMatchList.get(i).distance;
                if(dist < min_dist) min_dist = dist;
                if(dist > max_dist) max_dist = dist;
            }
            LinkedList<DMatch> good_matches = new LinkedList<>();
            for(int i = 0; i < img1_descriptors.rows(); i++){
                if(dMatchList.get(i).distance < 3*min_dist){
                    good_matches.addLast(dMatchList.get(i));
                }
            }
    
            // Converting to MatOfPoint2f format
            LinkedList<Point> img1_points_list = new LinkedList<>();
            LinkedList<Point> img2_points_list = new LinkedList<>();
    
            List<KeyPoint> img1_keyPoints_list = img1_keypoints_mat.toList();
            List<KeyPoint> img2_keyPoints_list = img2_keypoints_mat.toList();
    
            int limit = good_matches.size();
            for(int i = 0; i < limit; i++){
                img1_points_list.addLast(img1_keyPoints_list.get(good_matches.get(i).queryIdx).pt);
                img2_points_list.addLast(img2_keyPoints_list.get(good_matches.get(i).trainIdx).pt);
            }
    
            MatOfPoint2f img1_point2f_mat = new MatOfPoint2f();
            img1_point2f_mat.fromList(img1_points_list);
    
            MatOfPoint2f img2_point2f_mat = new MatOfPoint2f();
            img2_point2f_mat.fromList(img2_points_list);
    
            // Computing the affine transform matrix
            Mat result = Video.estimateRigidTransform(img1_point2f_mat, img2_point2f_mat, true);
            printMat(result); // Printing the optimal affine transformation 2x3 array
    
            // The following variables correspond to the estimateRigidTransform result as shown here: https://stackoverflow.com/a/29511091/5165833
            double a = result.get(0,0)[0];
            double b = result.get(0,1)[0];
            double d = result.get(1,1)[0];
            double c = result.get(1,0)[0];
            double tx = result.get(0,2)[0];
            double ty = result.get(1,2)[0];
    
            // Solving for scale,translation and rotation as shown in the link above
            double scale_x = Math.signum(a) * Math.sqrt( (a*a) + (b*b) ); // Axis x scale difference
            double scale_y = Math.signum(d) * Math.sqrt( (c*c) + (d*d) ); // Axis y scale difference
            double translation = ty; // The translation difference
            double rotation_angle = Math.atan2(c,d); // Rotation difference
    
            // Printing results
            println("Scale_x diff: " + scale_x);
            println("Scale_y diff: " + scale_y);
            println("Translation diff: " + translation);
            println("Rotation diff: " + rotation_angle);
        }
    
        static void printMat(Mat m)
        {
            for (int x=0; x < m.height(); x++) {
                for (int y=0; y < m.width(); y++) {
                    System.out.printf("%f",m.get(x,y)[0]);
                    System.out.printf("%s"," ");
                }
                System.out.println();
            }
        }
    

    【讨论】:

      【解决方案2】:

      您可以使用特征点提取来比较图像相似度,并使用旋转和尺度不变算法进行匹配。

      OpenCV 中已经提供了旋转不变特征匹配算法 - SIFT ,SURF 但这些都是专利的,所以如果你想在商业上使用它们,你必须付费。

      幸运的是,可以使用 SIFT 或 SURF 的有效替代方案,即 ORB(面向 FAST 和 Rotated Brief)

      这些算法在大多数图像中都能正常工作,除了少数类似文档图像。

      PS:正如问题中提到的(OpenCV + tesseract)或者可以通过使用Tesseract库(开源OCR引擎)提取图像中的文本内容来用于文档图像

      【讨论】:

      • 谢谢。我开始混合使用 ORB 和 SURF,这似乎可以解决问题。
      猜你喜欢
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 2022-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多