OpenCV: размещение объекта в сцене с использованием гомографии и преобразования перспективы в Java

Я реализую с помощью Java учебник OpenCV для поиска объекта в сцене с использованием гомографии http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html#feature-homography

Ниже моя реализация, где img1 — это сцена, а img2 — это объект.

    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?


person Jas X    schedule 28.10.2014    source источник
comment
Пожалуйста, ознакомьтесь с разделом 7.1 этого документа: cs.ubc.ca/ ~lowe/papers/ijcv04.pdf Речь идет об эффективном способе сопоставления ключевых точек без использования меры расстояния, которая не работает хорошо, поскольку некоторые дескрипторы гораздо более различимы, чем другие. Я думаю, что это даст вам лучшие результаты. Если у вас есть вопросы по реализации Ratio Test, я могу помочь. Если результаты не улучшатся, возможно, вам придется использовать другой дескриптор, например, SIFT.   -  person zedv    schedule 30.10.2014
comment
Я сузил проблему до функции findhomography, я не думаю, что проблема в совпадениях, но полученная матрица преобразования была неправильной. Это приводит к тому, что преобразование перспективы также дает неверный результат. См. этот вопрос для получения дополнительной информации stackoverflow.com/ вопросы/26771285/   -  person Jas X    schedule 06.11.2014


Ответы (2)


Мне удалось решить проблему и правильно использовать гомографию при исследовании ошибок индекса за пределами границ. Оказывается, когда я добавил свои хорошие совпадения в свои списки объектов и сцен, я поменял местами индексы запросов и поездов.

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 и trainIdx, поскольку я позвонил

matcher.match(descriptors1, descriptors2,matches);

сначала с дескриптором1, затем с дескриптором2, правильные индексы должны быть:

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.

Вот пример результата:

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

person Jas X    schedule 20.11.2014
comment
он все еще падает, любая помощь? - person Nilabja; 26.04.2017

В настоящее время я также реализую 2D-гомографию в Java, и я также нашел Учебник по OpenCV, тогда ваш вопрос.

Я не думаю, что это улучшит ваши результаты, но в учебнике OpenCV, когда они вычисляют минимальное и максимальное расстояние, они зацикливаются с descriptors_object.rows, а в вашем коде вы делаете это с descriptors1. rows(), который является дескриптором сцены, а не дескриптором объекта.

Изменить: только что заметил то же самое с матчером. Для тебя:

  • img1/descriptor1 -> Сцена
  • img2/descriptor2 -> объект для поиска

В учебнике:

matcher.match( descriptors_object, descriptors_scene, matches );

Но в вашем коде:

matcher.match(descriptors1, descriptors2,matches);

И Джавадок:

void org.opencv.features2d.DescriptorMatcher.match(Mat queryDescriptors, Mat trainDescriptors, MatOfDMatch matches)
person Zou    schedule 29.07.2016