如何使用OpenCV特征匹配技术检测复制-粘贴篡改?

8
在我的opencv项目中,我想要检测图像中的复制移动伪造。我知道如何使用opencv FLANN进行2个不同图像的特征匹配,但是我对如何在图像中使用FLANN进行复制移动伪造检测感到困惑。
附注1:我获取了图像的SIFT关键点和描述符,并卡在使用特征匹配类上。
附注2:特征匹配的类型对我来说不重要。
提前致谢。
更新:
这些图片是我需要的示例。

Input Image

Result

以下是一段匹配两张图像特征并在两张图像上执行类似操作的代码(不是单张图像),这段代码是以Android原生OpenCV格式编写的:

    vector<KeyPoint> keypoints;
        Mat descriptors;

        // Create a SIFT keypoint detector.
        SiftFeatureDetector detector;
        detector.detect(image_gray, keypoints);
        LOGI("Detected %d Keypoints ...", (int) keypoints.size());

        // Compute feature description.
        detector.compute(image, keypoints, descriptors);
        LOGI("Compute Feature ...");


        FlannBasedMatcher matcher;
        std::vector< DMatch > matches;
        matcher.match( descriptors, descriptors, matches );

        double max_dist = 0; double min_dist = 100;

        //-- Quick calculation of max and min distances between keypoints
          for( int i = 0; i < descriptors.rows; i++ )
          { double dist = matches[i].distance;
            if( dist < min_dist ) min_dist = dist;
            if( dist > max_dist ) max_dist = dist;
          }

          printf("-- Max dist : %f \n", max_dist );
          printf("-- Min dist : %f \n", min_dist );

          //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
          //-- or a small arbitary value ( 0.02 ) in the event that min_dist is very
          //-- small)
          //-- PS.- radiusMatch can also be used here.
          std::vector< DMatch > good_matches;

          for( int i = 0; i < descriptors.rows; i++ )
          { if( matches[i].distance <= max(2*min_dist, 0.02) )
            { good_matches.push_back( matches[i]); }
          }

          //-- Draw only "good" matches
          Mat img_matches;
          drawMatches( image, keypoints, image, keypoints,
                       good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
                       vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

          //-- Show detected matches
//          imshow( "Good Matches", img_matches );
          imwrite(imgOutFile, img_matches);

1
展示您当前的代码和正在使用的图像样本肯定会很有帮助。 - alexisrozhkov
@user3896254,感谢您的建议,我已经编辑了我的帖子并添加了示例和代码。 - Mohamad MohamadPoor
1
各位,你们知道如何使用Python在图像中实现字体(字符/数字)的复制和移动伪造吗? - Azam Rafique
@MohamadMohamadPoor,你有没有找到满意的答案解决这个问题? - jtlz2
1个回答

2
“我不确定使用关键点是否是解决这个问题的好方法。我更愿意尝试模板匹配(使用滑动窗口在图像上作为补丁)。与关键点相比,这种方法的缺点是对旋转和比例敏感。
如果您想使用关键点,可以:”
  • find a set of keypoints (SURF, SIFT, or whatever you want),
  • compute the matching score with every other keypoints, with the knnMatch function of the Brute Force Matcher (cv::BFMatcher),
  • keep matches between distincts points, i.e. points whose distance is greater than zero (or a threshold).

    int nknn = 10; // max number of matches for each keypoint
    double minDist = 0.5; // distance threshold
    
    // Match each keypoint with every other keypoints
    cv::BFMatcher matcher(cv::NORM_L2, false);
    std::vector< std::vector< cv::DMatch > > matches;
    matcher.knnMatch(descriptors, descriptors, matches, nknn);
    
    double max_dist = 0; double min_dist = 100;
    
    //-- Quick calculation of max and min distances between keypoints
    for( int i = 0; i < descriptors.rows; i++ )
    { 
        double dist = matches[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
    }
    
    // Compute distance and store distant matches
    std::vector< cv::DMatch > good_matches;
    for (int i = 0; i < matches.size(); i++)
    {
        for (int j = 0; j < matches[i].size(); j++)
        {
            // The METRIC distance
            if( matches[i][j].distance> max(2*min_dist, 0.02) )
                continue;
    
            // The PIXELIC distance
            Point2f pt1 = keypoints[queryIdx].pt;
            Point2f pt2 = keypoints[trainIdx].pt;
    
            double dist = cv::norm(pt1 - pt2);
            if (dist > minDist)
                good_matches.push_back(matches[i][j]);
        }
    }
    
    Mat img_matches;
    drawMatches(image_gray, keypoints, image_gray, keypoints, good_matches, img_matches);
    

1
@Evil 这是我会遵循的建议。如果你有需要检测的图像,那么可以使用模板匹配。否则,就跟随Gwen给出的示例。 - John
@Gwen,这周我太忙了,我会尝试你的解决方案并告诉你结果,顺便说一下,谢谢你的答案和替代方案,但我需要使用关键点。 - Mohamad MohamadPoor
@Gwen 我已经尝试了你的示例代码,但最终它并没有给我我需要的结果,它给了我很多匹配项,并且没有在单个图像中显示!!!(显示在两个相同的图像旁边...),还有什么进一步的帮助吗?提前致谢。 - Mohamad MohamadPoor
@Evil 我已经更正了距离计算(我使用了度量距离而不是像素距离...)。代码未经测试,但思路在这里。但是,正如我所说,我不能保证这种方法会起作用。 - Gwen
@Gwen,谢谢你的回复,虽然不符合我的需求,但感谢你的想法。 - Mohamad MohamadPoor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接