Сшивание 2 изображений (OpenCV)

Я пытаюсь сшить два изображения вместе, используя OpenCV Java API. Однако я получаю неверный результат и не могу решить проблему. Я использую следующие шаги: 1. обнаруживаю признаки 2. извлекаю признаки 3. сопоставляю признаки. 4. найти гомографию 5. найти преобразование перспективы 6. ​​искривить перспективу 7. «сшить» 2 изображения в объединенное изображение.

но где-то я ошибаюсь. Думаю, так я прочесываю 2 изображения, но не уверен. Я получаю 214 хороших совпадений функций между двумя изображениями, но не могу их сшить?

public class ImageStitching {

static Mat image1;
static Mat image2;

static FeatureDetector fd;
static DescriptorExtractor fe;
static DescriptorMatcher fm;

public static void initialise(){
    fd = FeatureDetector.create(FeatureDetector.BRISK); 
    fe = DescriptorExtractor.create(DescriptorExtractor.SURF); 
    fm = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);

    //images
    image1 = Highgui.imread("room2.jpg");
    image2 = Highgui.imread("room3.jpg");

    //structures for the keypoints from the 2 images
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint();

    //structures for the computed descriptors
    Mat descriptors1 = new Mat();
    Mat descriptors2 = new Mat();

    //structure for the matches
    MatOfDMatch matches = new MatOfDMatch();

    //getting the keypoints
    fd.detect(image1, keypoints1);
    fd.detect(image1, keypoints2);

    //getting the descriptors from the keypoints
    fe.compute(image1, keypoints1, descriptors1);
    fe.compute(image2,keypoints2,descriptors2);

    //getting the matches the 2 sets of descriptors 
    fm.match(descriptors2,descriptors1, matches);

    //turn the matches to a list
    List<DMatch> matchesList = matches.toList();

    Double maxDist = 0.0; //keep track of max distance from the matches
    Double minDist = 100.0; //keep track of min distance from the matches

    //calculate max & min distances between keypoints
    for(int i=0; i<keypoints1.rows();i++){
        Double dist = (double) matchesList.get(i).distance;
        if (dist<minDist) minDist = dist;
        if(dist>maxDist) maxDist=dist;
    }

    System.out.println("max dist: " + maxDist );
    System.out.println("min dist: " + minDist);

    //structure for the good matches
    LinkedList<DMatch> goodMatches = new LinkedList<DMatch>();

    //use only the good matches (i.e. whose distance is less than 3*min_dist)
    for(int i=0;i<descriptors1.rows();i++){
        if(matchesList.get(i).distance<3*minDist){
            goodMatches.addLast(matchesList.get(i));
        }
    }

    //structures to hold points of the good matches (coordinates)
    LinkedList<Point> objList = new LinkedList<Point>(); // image1
    LinkedList<Point> sceneList = new LinkedList<Point>(); //image 2

    List<KeyPoint> keypoints_objectList = keypoints1.toList();
    List<KeyPoint> keypoints_sceneList = keypoints2.toList();

    //putting the points of the good matches into above structures
    for(int i = 0; i<goodMatches.size(); i++){
        objList.addLast(keypoints_objectList.get(goodMatches.get(i).queryIdx).pt);
        sceneList.addLast(keypoints_sceneList.get(goodMatches.get(i).trainIdx).pt);
    }

    System.out.println("\nNum. of good matches" +goodMatches.size());

    MatOfDMatch gm = new MatOfDMatch();
    gm.fromList(goodMatches);

    //converting the points into the appropriate data structure
    MatOfPoint2f obj = new MatOfPoint2f();
    obj.fromList(objList);

    MatOfPoint2f scene = new MatOfPoint2f();
    scene.fromList(sceneList);

    //finding the homography matrix
    Mat H = Calib3d.findHomography(obj, scene);

    //LinkedList<Point> cornerList = new LinkedList<Point>();
    Mat obj_corners = new Mat(4,1,CvType.CV_32FC2);
    Mat scene_corners = new Mat(4,1,CvType.CV_32FC2);

    obj_corners.put(0,0, new double[]{0,0});
    obj_corners.put(0,0, new double[]{image1.cols(),0});
    obj_corners.put(0,0,new double[]{image1.cols(),image1.rows()});
    obj_corners.put(0,0,new double[]{0,image1.rows()});

    Core.perspectiveTransform(obj_corners, scene_corners, H);

    //structure to hold the result of the homography matrix
    Mat result = new Mat();

    //size of the new image - i.e. image 1 + image 2
    Size s = new Size(image1.cols()+image2.cols(),image1.rows());

    //using the homography matrix to warp the two images
    Imgproc.warpPerspective(image1, result, H, s);
    int i = image1.cols();
    Mat m = new Mat(result,new Rect(i,0,image2.cols(), image2.rows()));

    image2.copyTo(m);

    Mat img_mat = new Mat();

    Features2d.drawMatches(image1, keypoints1, image2, keypoints2, gm, img_mat, new Scalar(254,0,0),new Scalar(254,0,0) , new MatOfByte(), 2);

    //creating the output file
    boolean imageStitched = Highgui.imwrite("imageStitched.jpg",result);
    boolean imageMatched = Highgui.imwrite("imageMatched.jpg",img_mat);
}


public static void main(String args[]){
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    initialise();
}

Я не могу вставлять изображения или размещать более двух ссылок из-за очков репутации? поэтому я связал неправильно сшитые изображения и изображение, показывающее совпадающие функции между двумя изображениями (чтобы понять проблему):

неправильно сшитое изображение: http://oi61.tinypic.com/11ac01c.jpg обнаруженные функции: http://oi57.tinypic.com/29m3wif.jpg


person user3019612    schedule 07.02.2014    source источник


Ответы (2)


Похоже, у вас много выбросов, которые делают оценку гомографии неверной. Итак, вы можете использовать метод RANSAC, который рекурсивно отклоняет эти выбросы.

Для этого не нужно много усилий, просто используйте третий параметр в функции findHomography как:

Mat H = Calib3d.findHomography(obj, scene, CV_RANSAC);

Изменить

Затем убедитесь, что ваши изображения, передаваемые детектору, являются 8-битными изображениями в оттенках серого, как упоминалось здесь

person Y.AL    schedule 07.02.2014
comment
Я пробовал вышеуказанную функцию как таковую; Мат H = Calib3d.findHomography (obj, scene, Calib3d.RANSAC, 1) - но безуспешно. Я экспериментировал с множеством различных комбинаций алгоритмов для обнаружения, извлечения и сопоставления, но все равно безуспешно. Также пробовал много разных значений ошибки повторного проецирования (4-й параметр для findHomography ()). Не совсем уверен, как двигаться дальше. - person user3019612; 09.02.2014

«Неправильно сшитое изображение», которое вы публикуете, похоже, имеет плохую кондиционированную H-матрицу. Помимо предложений + дервиш, запустите:

cv::determinant(H) > 0.01

Чтобы проверить, подходит ли ваша матрица H для использования. Если матрица плохо подготовлена, вы получите тот эффект, который вы показываете.

Вы рисуете на холсте размером 2x2, в этом случае вы не увидите много конфигураций сшивания, то есть это нормально для изображения A слева от изображения B, но не в противном случае. Попробуйте нарисовать результат на холсте размером 3x3, используя следующий фрагмент:

  // Use the Homography Matrix to warp the images, but offset it to the
  // center of the output canvas. Careful to pre-multiply, not post-multiply.
  cv::Mat Offset = (cv::Mat_<double>(3,3) << 1, 0, 
                    width, 0, 1, height, 0, 0, 1);
  H = Offset * H;

  cv::Mat result;
  cv::warpPerspective(mat_l,
                      result,
                      H,
                      cv::Size(3*width, 3*height));
  // Copy the reference image to the center of the 3x3 output canvas.
  cv::Mat roi = result.colRange(width,2*width).rowRange(height,2*height);
  mat_r.copyTo(roi);

Где width и height - изображения входных изображений, предположительно, одинакового размера. Обратите внимание, что эта деформация предполагает mat_l без изменений (плоскую) и mat_r деформацию, которая будет наложена на нее.

person miguelao    schedule 10.02.2014