比较旋转的图像

时间:2017-12-07 22:38:26

标签: image-processing ocr

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

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

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

3 个答案:

答案 0 :(得分:1)

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

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

幸运的是,有一种有效的SIFT或SURF替代品,即ORB(定向快速和轮流简介)

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

PS:如问题(OpenCV + tesseract)中所述,通过使用Tesseract库(Opensource OCR引擎)提取图像中的文本内容,可以将其用于文档图像

答案 1 :(得分:1)

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

此矩阵的外观如何以及如何获得旋转差异?

From this answer:

enter image description here

我使用了以下 Java 代码(使用OpenCV 3.2)来计算缩放翻译轮换两个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 :(得分:0)

也许您需要像https://huddle.github.io/Resemble.js/这样的算法?

在左侧的框上放下两张图像。下面的框将显示生成的“差异”图像,粉红色区域显示不匹配。此示例最适用于两个非常相似但略有不同的图像。