首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenCV:使用Java语言中的单应性和透视变换将对象适配到场景中

OpenCV:使用Java语言中的单应性和透视变换将对象适配到场景中
EN

Stack Overflow用户
提问于 2014-10-29 02:19:53
回答 2查看 4.4K关注 0票数 2

我正在使用Java语言实现使用单应性http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html#feature-homography在场景中查找对象的OpenCV教程

下面是我的实现,其中img1是场景,img2是对象

代码语言:javascript
复制
    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);

    //set up img1 (scene)
    Mat descriptors1 = new Mat();
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
    //calculate descriptor for img1
    detector.detect(img1, keypoints1);
    descriptor.compute(img1, keypoints1, descriptors1);

    //set up img2 (template)
    Mat descriptors2 = new Mat();
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
    //calculate descriptor for img2
    detector.detect(img2, keypoints2);
    descriptor.compute(img2, keypoints2, descriptors2);

    //match 2 images' descriptors
    MatOfDMatch matches = new MatOfDMatch();
    matcher.match(descriptors1, descriptors2,matches);

    //calculate max and min distances between keypoints
    double max_dist=0;double min_dist=99;

    List<DMatch> matchesList = matches.toList();
    for(int i=0;i<descriptors1.rows();i++)
    {
        double dist = matchesList.get(i).distance;
        if (dist<min_dist) min_dist = dist;
        if (dist>max_dist) max_dist = dist;
    }

    //set up good matches, add matches if close enough
    LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
    MatOfDMatch gm = new MatOfDMatch();
    for (int i=0;i<descriptors2.rows();i++)
    {
        if(matchesList.get(i).distance<3*min_dist)
        {
            good_matches.addLast(matchesList.get(i));
        }
    }
    gm.fromList(good_matches);

    //put keypoints mats into lists
    List<KeyPoint> keypoints1_List = keypoints1.toList();
    List<KeyPoint> keypoints2_List = keypoints2.toList();

    //put keypoints into point2f mats so calib3d can use them to find homography
    LinkedList<Point> objList = new LinkedList<Point>();
    LinkedList<Point> sceneList = new LinkedList<Point>();
    for(int i=0;i<good_matches.size();i++)
    {
        objList.addLast(keypoints2_List.get(good_matches.get(i).queryIdx).pt);
        sceneList.addLast(keypoints1_List.get(good_matches.get(i).trainIdx).pt);
    }
    MatOfPoint2f obj = new MatOfPoint2f();
    MatOfPoint2f scene = new MatOfPoint2f();
    obj.fromList(objList);
    scene.fromList(sceneList);

    //output image
    Mat outputImg = new Mat();
    MatOfByte drawnMatches = new MatOfByte();
    Features2d.drawMatches(img1, keypoints1, img2, keypoints2, gm, outputImg, Scalar.all(-1), Scalar.all(-1), drawnMatches,Features2d.NOT_DRAW_SINGLE_POINTS);

    //run homography on object and scene points
    Mat H = Calib3d.findHomography(obj, scene,Calib3d.RANSAC, 5);
    Mat tmp_corners = new Mat(4,1,CvType.CV_32FC2);
    Mat scene_corners = new Mat(4,1,CvType.CV_32FC2);

    //get corners from object
    tmp_corners.put(0, 0, new double[] {0,0});
    tmp_corners.put(1, 0, new double[] {img2.cols(),0});
    tmp_corners.put(2, 0, new double[] {img2.cols(),img2.rows()});
    tmp_corners.put(3, 0, new double[] {0,img2.rows()});

    Core.perspectiveTransform(tmp_corners,scene_corners, H);


    Core.line(outputImg, new Point(scene_corners.get(0,0)), new Point(scene_corners.get(1,0)), new Scalar(0, 255, 0),4);
    Core.line(outputImg, new Point(scene_corners.get(1,0)), new Point(scene_corners.get(2,0)), new Scalar(0, 255, 0),4);
    Core.line(outputImg, new Point(scene_corners.get(2,0)), new Point(scene_corners.get(3,0)), new Scalar(0, 255, 0),4);
    Core.line(outputImg, new Point(scene_corners.get(3,0)), new Point(scene_corners.get(0,0)), new Scalar(0, 255, 0),4);

该程序能够计算和显示来自两个图像的特征点。然而,返回的scene_corners是闭合簇(小绿色斑点)中的4个点,它们应该表示对象到场景上的透视投影的4个角。我仔细检查了一下,以确保我的程序尽可能接近c++实现。这可能是什么原因造成的?

我检查了单应矩阵,似乎角坐标被矩阵中的两个非常大的结果扭曲了。单应矩阵是否计算错误?

我很感谢你的意见,谢谢。

更新:

我尝试了一下好匹配的过滤阈值,发现2.75*min_dist似乎可以很好地处理这组图像。我现在可以得到零离群值的良好匹配。但是,边界框仍然是错误的。http://i.imgur.com/fuXeOqL.png

我如何知道用于最佳匹配的阈值是多少,以及单应性如何与它们相关?为什么在示例中使用3*min_dist?

EN

回答 2

Stack Overflow用户

发布于 2014-11-20 10:54:31

我设法解决了这个问题,并在调查索引越界错误时正确地使用了单应性。事实证明,当我将好的匹配项添加到对象和场景列表中时,我交换了查询和训练索引

代码语言:javascript
复制
objList.addLast(keypoints2_List.get(good_matches.get(i).queryIdx).pt);
sceneList.addLast(keypoints1_List.get(good_matches.get(i).trainIdx).pt);

根据这个问题OpenCV drawMatches -- queryIdx and trainIdx,自从我打电话给

代码语言:javascript
复制
matcher.match(descriptors1, descriptors2,matches);

对于先使用descriptor1再使用descriptor2的情况,正确的索引应该是:

代码语言:javascript
复制
objList.addLast(keypoints2_List.get(good_matches.get(i).trainIdx).pt);
sceneList.addLast(keypoints1_List.get(good_matches.get(i).queryIdx).pt);

其中queryIdx是指keypoints1_List,trainIdx是指keypoints2_List。

下面是一个示例结果:

http://i.imgur.com/LZNBjY2.png

票数 2
EN

Stack Overflow用户

发布于 2016-07-29 09:16:01

目前,我也在java中实现2D单应性,我也找到了OpenCV tutorial,然后你的问题。

我不认为这会提高你的结果,但在OpenCV教程中,当他们计算最小和最大距离时,他们使用descriptors_object.rows循环,在你的代码中,你使用的是描述符1.rows(),它是场景描述符,而不是对象描述符。

编辑:我也注意到matcher也是如此。对你来说:

  • img1/descriptor1 Scene
  • img2/descriptor2 -> -> object to find

在本教程中:

代码语言:javascript
复制
matcher.match( descriptors_object, descriptors_scene, matches );

但是在你的代码中:

代码语言:javascript
复制
matcher.match(descriptors1, descriptors2,matches);

和Javadoc:

代码语言:javascript
复制
void org.opencv.features2d.DescriptorMatcher.match(Mat queryDescriptors, Mat trainDescriptors, MatOfDMatch matches)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26615649

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档