[OpenCV] Stitching 직접 구현하기

OpenJR·2022년 6월 2일
0

2D 이미지에서 Keypoints과 Discriptor를 검출하고, 이를 통해 이미지 스티칭하는 방법의 파이프라인을 공부해보았다.
확실한 이해를 위해 OpenCV에서 제공하는 Stitching API를 사용하지 않고 직접 구현해 보았다.

사용 라이브러리

Opencv

작업 설명

1. ORBSIFT를 사용하여, 두 사진의 Feature Points를 검출.

ORB와 SIFT의 소요 시간과 정확성을 비교하기 위해 두 번의 작업을 진행해보았다.

  cv::Ptr<cv::Feature2D> detector = cv::SIFT::create();
  // cv::Ptr<cv::Feature2D> detector = cv::ORB::create();

  cv::Mat desc1, desc2;
  std::vector<cv::KeyPoint> keypoints1, keypoints2;

  detector->detectAndCompute(src1, cv::Mat(), keypoints1, desc1);
  detector->detectAndCompute(src2, cv::Mat(), keypoints2, desc2);

2. 검출된 Feature Points들을 FlannBasedMatcher를 사용해 매칭.

FlannBasedMatcher를 사용하기 위해선 Discriptor를 CV_32F 데이터 타입으로 무조건 바꿔 주어야 한다.

  desc1.convertTo(desc1, CV_32F);
  desc2.convertTo(desc2, CV_32F);
  
  cv::Ptr<cv::DescriptorMatcher> matcher = cv::FlannBasedMatcher::create();
  std::vector<cv::DMatch> matches;
  matcher->match(desc1, desc2, matches);

3. 매칭된 매치들의 Distance가 작은 순부터 20개의 포인트로 필터링.

Distance가 작을 수록 좋은 값이라고 배웠던 것 같은데 나중 결과를 보면 꼭 그렇지만은 않은 것 같다.

  std::sort(matches.begin(), matches.end());
  std::vector<cv::DMatch> good_matches(matches.begin(), matches.begin() + 20);

4. 매칭된 이미지 픽셀의 좌표들을 사용해 Homograpy 계산.

  std::vector<cv::Point2f> pts1, pts2;
  for (size_t i = 0; i < good_matches.size(); i++) {
    pts1.push_back(keypoints1[good_matches[i].queryIdx].pt);
    pts2.push_back(keypoints2[good_matches[i].trainIdx].pt);
  }
  cv::Mat H = cv::findHomography(pts2, pts1, cv::RANSAC);

5. Homograpy를 사용해 이미지를 Stitching.

결과

1. SIFT

20개의 필터링된 포인트들 만으로도 RANSAC을 통해 Homography가 잘 추출되어 스티칭이 잘 된다. 하지만 시간이 오래 걸린다.

2. ORB

시간은 3배 감소 하였지만 필터링된 20개의 포인트로는 Homography가 잘 추출되지 않으며, 필터링 되지 않은 포인트들로는 스티칭이 잘 이루어졌다.

profile
Jacob

2개의 댓글

comment-user-thumbnail
2023년 12월 16일

유익한 정보 감사합니다!
그런데 혹시 5번째에서 이미지를 붙이는 건 어떻게 하셨는지 알 수 있을까요? warpPerspective을 써서 두 번째 이미지를 변환하는 것까지는 했는데 그 다음은 도저히 모르겠네요...

1개의 답글