본문 바로가기

3학년/OpenCV

[OpenCV] 14장 지역 특징점 검출과 매칭

 

 

 

14.1 코너 검출

 

14.1.1 해리스 코너 검출 방법

 

특징(feature): 영상으로부터 추출할 수 있는 유용한 정보를 의미. 평균 밝기, 히스토그램, 에지, 직선 성분, 코너 등이 특징이 될 수 있음

 

지역 특징(local feature): 코너처럼 영상 전체가 아닌 일부 영역에서 추출할 수 있는 특징

 

특징점 (feature point): 코너처럼 한 점의 형태로 표현할 수 있는 특징

 

 

void cornerHarris(InputArray src, OutputArray dst, int blockSize, 
		int ksize, double k, int borderType = BORDER_DEFAULT);
  • src: 입력 영상. CV_8UC1 또는 CV_32FC1
  • dst: 해리스 코너 응답 함수 값을 저장할 행렬. src와 크기가 같고 CV_32FC1 타입임
  • blockSize: 행렬 M 연산에 사용할 이웃 픽셀 크기. 픽셀 주변 blockSize x blockSize 윈도우를 설정하여 행렬 M을 계산
  • ksize: 소벨 연산자를 위한 커널 크기
  • k: 해리스 코너 검출 상수
  • borderType: 가장자리 픽셀 확장 방식

 

 

 

void corner_harris()
{
	Mat src = imread("building.jpg", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat harris;
	cornerHarris(src, harris, 3, 3, 0.04);

	Mat harris_norm;
	normalize(harris, harris_norm, 0, 255, NORM_MINMAX, CV_8U);

	Mat dst;
	cvtColor(src, dst, COLOR_GRAY2BGR);

	for (int j = 1; j < harris.rows - 1; j++) {
		for (int i = 1; i < harris.cols - 1; i++) {
			if (harris_norm.at<uchar>(j, i) > 120) {
				if (harris.at<float>(j, i) > harris.at<float>(j - 1, i) &&
					harris.at<float>(j, i) > harris.at<float>(j + 1, i) &&
					harris.at<float>(j, i) > harris.at<float>(j, i - 1) &&
					harris.at<float>(j, i) > harris.at<float>(j, i + 1) ) {
					circle(dst, Point(i, j), 5, Scalar(0, 0, 255), 2);
				}
			}
		}
	}

	imshow("src", src);
	imshow("harris_norm", harris_norm);
	imshow("dst", dst);

	waitKey(0);
	destroyAllWindows();
}
  • 3행:building.jpg 영상을 그레이스케일 형식으로 불러와 src에 저장
  • 10~11행: src 영상으로부터 해리스 코너 응답 함수 행렬 harris를 구함
  • 13~14행: harris 행렬 원소 값 범위를 0 부터 255로 정규화하고, 타입을 CV_8UC1으로 변환하여 harris_norm에 저장. harris_norm은 그레이스케일 영상 형식을 따르며, 해리스 코너 응답 함수 분포를 영상 형태로 화면에 표시하기 위해 만듦
  • 16행~17행: src 영상을 3채널 컬러 영상으로 변환하여 dst에 저장
  • 21행: harris_norm 영상에서 값이 120보다 큰 픽셀을 코너로 간주 
  • 22~27행: 간단한 비최대 억제를 수행. (i, j) 위치에서 주변 네 개의 픽셀을 비교하여 지역 최대한 경우에만 dst 영상에 빨간색 원으로 코너를 표시

 

 

 

 

 

 

14.1.2 FAST 코너 검출 방법

 

 

 

FAST: 영상의 모든 픽셀에서 픽셀을 둘러싸고 있는 16개의 주변 픽셀과 밝기를 비교하여 코너 여부를 판별

 

void FAST(InputArray image, std::vector<KeyPoint>& keypoints, int threshold, 
	bool nomaxSuppression = true);
  • image: 입력 그레이스케일 영상
  • keypoints: 검출된 특징점을 표현하는 KeyPoint 객체의 벡터. KeyPoint::pt 멤버 변수에 코너 점 좌표가 저장
  • threshold: 중심 픽셀 값과 주변 픽셀 값과의 차이 임계값
  • nomaxSuppression: 비최대 억제 수행 여부. true이면 비최대 억제를 수행

 

 

 

void corner_fast()
{
	Mat src = imread("building.jpg", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	vector<KeyPoint> keypoints;
	FAST(src, keypoints, 60, true);

	Mat dst;
	cvtColor(src, dst, COLOR_GRAY2BGR);

	for (KeyPoint kp : keypoints) {
		Point pt(cvRound(kp.pt.x), cvRound(kp.pt.y));
		circle(dst, pt, 5, Scalar(0, 0, 255), 2);
	}

	imshow("src", src);
	imshow("dst", dst);

	waitKey(0);
	destroyAllWindows();
}
  • 3행: building.jpg 영상을 그레이스케일 형식으로 불러와 src에 저장
  • 10~11행: src 영상에서 FAST 방법으로 코너 점을 검출. 밝기 차이 임계값으로 60을 지정. 비최대 억제를 수행하도록 설정. 검출된 모든 코너 점 좌표는 keypoints 변수에 저장
  • 13~14행: src 영상으 3채널 컬러 영상으로 변환하여 dst에 저장
  • 16~19행: 검출된 모든 코너 점에 반지름이 5인 빨간색 원을 그림

 

 

 

 

 

 

14.2 크기 불변 특징점 검출과 기술

 

 

14.2.1 크기 불변 특징점 알고리즘

 

 

 

SIFT: 크기가 다른 영상에서도 지속적으로 검출될 수 있는 크기 불변 특징. 크기 불변 특징 변환의 약자. 

 

 

 

 

14.2.2 OpenCV 특징점 검출과 기술

 

 

class KeyPoint
{
public:
	KeyPoint();
    KeyPoint(Point2f _pt, float _size, float _angle = -1, float _response = 0, int _octave = 0, 
    int _class_id = -1);
    
    
    Point2f pt;
    float size;
    float angle;
    float response;
    int octave;
    int class_id;
};
  • 4~6행: KeyPoint 클래스 생성자 및 멤버 함수
  • 9행: KeyPoint::pt 멤버 변수는 특징점 좌표를 나타냄
  • 10행: KeyPoint::size 멤버 변수는 특징점 크기(지름)을 나타냄
  • 11행: KeyPoint::angle 멤버 변수는 특징점의 주된 방향(각도)를 나타냄
  • 12행: KeyPoint::response 멤버 변수는 특징점 반응성을 나타내며 좋은 특징점을 선별하는 용도로 사용
  • 13행: KeyPoint::octave 멤버 변수는 특징점이 추출된 옥타브(피라미드 단계)를 나타냄
  • 14행: KeyPoint::class_id 멤버 변수는 특징점이 포함된 객체 번호를 나타냄

 

 

 

 

static Ptr<ORB> ORB::create(int nfeatures = 500, float scaleFactor = 1.2f, int nlevels = 8, 
		int edgeThreshold = 31, int firstLevel = 0, int WTA_K = 2, 
        	ORB::ScoreType scoreType = ORB::HARRIS_SCORE,
        	int patchSize = 31, int fastThreshold = 20);
  • nfeatures: 검출할 최대 특징 개수
  • scaleFactor: 피라미드 생성 비율(영상 축소 비율)
  • nlevels: 피라미드 단계 개수
  • edgeThreshold: 특징을 검출하지 않을 영상 가장자리 픽셀 크기
  • firstLevel: 항상 0을 지정
  • WTA_K: BRIEF 기술자 계산 시 사용할 점의 개수. 2, 3, 4 중 하나를 지정
  • scoreType: 특징점 점수 결정 방법. ORB::HARRIS_SCORE 또는 ORB::FAST_SCORE 둘 중 하나를 지정
  • patchSize: BRIEF 기술자 계산 시 사용할 패치 크기
  • fastThreshold: FAST 코너 검출 방법에서 사용되는 임계값
  • 반환값: ORB 객체를 참조하는 Ptr 스마트 포인터 객체

 

 

virtual void Feature2D::detect(InputArray image,
	std::vector<KeyPoint>& keypoints, InputArray mask = noArray());
  • image: 입력 영상
  • keypoints: 검출된 키포인트 정보
  • mask: 마스크 행렬. 마스크 행렬 원소가 0이 아닌 위치에서만 특징점을 검출

 

 

virtual void Feature2D::compute(InputArray image,
	std::vector<KeyPoint>& keypoints, OutputArray descriptors);
  • image: 입력 영상
  • keypoints: 미리 검출해 둔 키포인트 정보
  • descriptors: 계산된 기술자 행렬. i 번째 행은 i 번째 키포인트의 기술자를 나타냄

 

 

virtual void Feature2D::detectAndCompute(InputArray image, InputArray mask, 
	std::vector<KeyPoint>& keypoints, OutputArray desriptors, bool useProvidedKeyPoints = false);
  • image: 입력 영상
  • mask: 마스크 행렬. 마스크 행렬 원소가 0이 아닌 위치에서만 특징점을 검출
  • keypoints: 검출된 키포인트 정보
  • descriptors: 계산된 기술자 행렬
  • useProvidedKeypoints: 이 값이 true이면 keypoints 인자로 전달된 키포인트 정보를 이용하여 기술자를 계산

 

 

void drawKeypoints(InputArray image, const std::vector<KeyPoint>& keypoints, 
	InputOutputArray outImage, const Scalar& color = Scalar::all(-1), 
    	DrawMatchesFlags flags = DrawMatchesFlags::DEFAULT);
  • image: 입력 영상
  • keypoints: 입력 영상에서 검출된 키포인트
  • outImage: 키포인트가 그려진 출력 영상
  • color: 키포인트 색상. 이 값이 Scalar::all(-1)이면 각 특징점을 임의의 색상으로 그림
  • flags: 키포인트 그리기 방법. DrawMatchesFlags 열거형 상수 중 하나를 지정

 

 

 

void detect_keypoints()
{
	Mat src = imread("box_in_scene.png", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Ptr<Feature2D> feature = ORB::create();

	vector<KeyPoint> keypoints;
	feature->detect(src, keypoints);

	Mat desc;
	feature->compute(src, keypoints, desc);

	cout << "keypoints.size(): " << keypoints.size() << endl;
	cout << "desc.size(): " << desc.size() << endl;

	Mat dst;
	drawKeypoints(src, keypoints, dst, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

	imshow("src", src);
	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}
  • 10행: ORB 클래스 객체를 생성하여 feature 스마트 포인터에 저장
  • 12~13행: ORB 키포인트를 검출하여 keypoints 벡터에 저장
  • 15~16행: ORB 키포인트 기술자를 계산하여 desc 행렬에 저장
  • 18~19행: keypoints 에 저장된 키포인트 개수와 desc 행렬 크기를 콘솔 창에 출력
  • 21~22행: 입력 영상 src에 키포인트를 그린 결과를 dst에 저장. 키포인트 그리는 방식을 DrawMatchesFlags::DRAW_RICH_KEYPOINTS로 지정하여 키포인트 위치, 크기, 방향 정보를 함께 나타내도록 설정

 

 

 

 

14.3 특징점 매칭

 

14.3.1 OpenCV 특징점 매칭

 

 

class DMatch
{
public: 
	DMatch()
    DMatch(int _queryIdx, int _trainIdx, floats _distance);
    DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance);
    
    int queryIdx;
    int trainIdx;
    int imgIdx;
    
    float distance;
    
    bool operator<(const DMatch &m) const;
};
  • 4~6행: DMatch 클래스 생성자
  • 8행: DMatch::queryIdx 멤버 변수는 질의 기술자 번호를 나타냄
  • 9행: DMatch::trainIdx 멤버 변수는 훈련 기술자 번호를 나타냄
  • 10행: DMatch::imgIdx 멤버 변수는 훈련 영상 번호를 나타냄. 여러 장의 영상을 훈련 영상으로 설정한 경우에 사용
  • 12행: DMatch::distance 멤버 변수는 두 기술자 사이의 거리를 나타냄
  • 14행: DMatch 클래스에 대한 크기 비교 연산자 재정의이며, DMatch::distance 멤버 변수 값을 이용하여 크기를 비교

 

 

 

static Ptr<BFMatcher> BFMatcher::create(int normType = NORM_L2, bool crossCheck = fasle);
  • normType: 기술자 거리 측정 방식. NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2 중 하나를 지정
  • crossCheck: 이 값이 true 이면 i 번째 질의 기술자와 가장 유사한 훈련 기술자가 j이고, j번째 훈련 기술자와 가장 유사한 질의 기술자가 i인 경우에만 매칭 결과로 반환
  • 반환값: BFMatcher 객체를 참조하는 Ptr 스마트 포인터 객체

 

static Ptr<FlannBasedMatcher> FlannBasedMatcher::create();
  • 반환값: FlannBasedMatcher 객체를 참조하는 Ptr 스마트 포인터 객체

 

void DecriptorMatcher::match(InputArray queryDecsriptors, InputArray trainDescriptors,
	std::vector<DMatch>& matches, InputArray mask = noArray()) const;
  • queryDescriptors: 질의 기술자 집합
  • trainDescriptors: 훈련 기술자 집합
  • matches: 매칭 결과
  • mask: 서로 매칭 가능한 질의 기술자와 훈련 기술자를 지정할 때 사용. 행 개수는 질의 기술자 개수와 같아야 하고, 열 개수는 훈련 기술자 개수와 같아야 한다.

 

 

void drawMatches(InputArray img1, const std::vector<KeyPoint>& keyPoints1, InputArray img2, 
	const std::vector<KeyPoint>& keypoint2, const std::vector<DMatch>& matches1to2,
    	InputOutputArray outImg, const Scalar& matchColor = Scalar::all(-1),
        const Scalar& singlePointColor = Scalar::all(-1),
        const std::vector<char>& matchesMask = std::vector<char>(),
        DrawMatchesFlags flags = DrawMatchesFlags::DEFAULT);
  • img1: 첫번째 입력 영상
  • keypoints1: 첫 번째 입력 영상에서 검출된 특징점
  • img2: 두 번째 입력 영상
  • keypoints2: 두 번째 입력 영상에서 검출된 특징점
  • matches1to2: 첫 번재 입력 영상에서 두 번째 입력 영상으로의 매칭 정보
  • outImg: 출력 영상
  • matchColor: 매칭된 특징점과 직선 색상. 만약 Scalar::all(-1) 을 지정하면 임의의 색상으로 그림
  • singlePointColor: 매칭되지 않은 특징점 색상. 만약 Scalar::all(-1)을 지정하면 임의의 색상으로 그림
  • matchesMask: 매칭 정보를 선택하여 그릴 때 사용할 마스크. 만약 std::vector<char>()를 지정하면 모든 매칭 결과를 그림
  • flags: 매칭 정보 그리기 방법. DrawMatchesFlags 열거형 상수를 지정

 

 

void keypoint_matching()
{
	Mat src1 = imread("box.png", IMREAD_GRAYSCALE);
	Mat src2 = imread("box_in_scene.png", IMREAD_GRAYSCALE);

	if (src1.empty() || src2.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Ptr<Feature2D> feature = ORB::create();

	vector<KeyPoint> keypoints1, keypoints2;
	Mat desc1, desc2;
	feature->detectAndCompute(src1, Mat(), keypoints1, desc1);
	feature->detectAndCompute(src2, Mat(), keypoints2, desc2);
	cout << "desc1.size(): " << desc1.size() << endl;
	cout << "desc2.size(): " << desc2.size() << endl;

	Ptr<DescriptorMatcher> matcher = BFMatcher::create(NORM_HAMMING);

	vector<DMatch> matches;
	matcher->match(desc1, desc2, matches);

	Mat dst;
	drawMatches(src1, keypoints1, src2, keypoints2, matches, dst);

	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}
  • 3~4행: 두 장의 영상을 각각 src1과 src2에 저장
  • 11행: ORB 클래스 객체를 생성
  • 13~16행: src1과 src2 영상에서 각각 특징점을 검출하고 시술자를 계산. 각 영상의 기술자는 desc1과 desc2 행렬에 저장
  • 18행: BRMatcher 클래스 객체를 생성. 기술자 거리 계산 방식은 해밍 거리를 사용
  • 20~21행: desc1과 desc2 기술자를 서로 매칭하여 그 결과를 matches에 저장
  • 23~24행: matches 정보를 이용하여 매칭 결과 영상 dst를 생성

 

 

 

 

 

 

void good_matching()
{
	Mat src1 = imread("box.png", IMREAD_GRAYSCALE);
	Mat src2 = imread("box_in_scene.png", IMREAD_GRAYSCALE);

	if (src1.empty() || src2.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Ptr<Feature2D> feature = ORB::create();

	vector<KeyPoint> keypoints1, keypoints2;
	Mat desc1, desc2;
	feature->detectAndCompute(src1, Mat(), keypoints1, desc1);
	feature->detectAndCompute(src2, Mat(), keypoints2, desc2);

	Ptr<DescriptorMatcher> matcher = BFMatcher::create(NORM_HAMMING);

	vector<DMatch> matches;
	matcher->match(desc1, desc2, matches);

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

	Mat dst;
	drawMatches(src1, keypoints1, src2, keypoints2, good_matches, dst,
		Scalar::all(-1), Scalar::all(-1), vector<char>(),
		DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}
  • 3~21행: 위의 코드 keypoint_matching() 함수와 같다
  • 23행: 두 영상의 특징점 매칭 결과를 정렬
  • 24행: 정렬된 매칭 결과에서 상위 50개 매칭 결과를 good_matches에 저장
  • 26~29행: good_matches를 이용하여 매칭 결과 영상을 생성. drawMatches() 함수의 10번째 인자에 DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS 상수를 지정하여 매칭되지 않은 특징점은 화면에 표시하지않음

 

 

 

 

14.3.2 호모그래피와 영상 매칭

 

 

호모그래피: 수학적으로 하나의 평면을 다른 평면으로 투시 변환하는 것과 같은 관계에 있음

 

 

 

Mat findHomography(InputArray srcPoints, InputArray dstPoints, int method = 0, 
	doubleransacReporjThreshold = 3, OutputArray mask = noArray(), const int maxIters = 2000, 
    	const double confidence = 0.995);
  • srcPoints: 원본 평면상의 점 좌표. CV_32FC2 타입의 Mat 객체 또는 vector<Point2f> 타입의 변수를 지정
  • dstPoints: 목표 평면상의 점 좌표. CV_32FC2 타입의 Mat 객체 또는 vector<Point2f> 타입의 변수를 지정
  • method: 호모 그래피 형렬 계산 방법. 다음 방법 중 하나를 지정
    • 0 - 모든 점을 사용하는 일반적인 방법. 최소자승법
    • LMEDS - 최소 메디안 제곱 방법
    • RANSAC - RANSAC 방법
    • RHQ - PROSAC 방법
  • ransacReprojThreshold: 최대 허용 재투영 에러. 이 값 이내로 특징점이 재투영되는 경우에만 정상치로 간주. RANSAC과 RHO 방법에서만 사용
  • mask: 호모그래피 계산에 사용된 점들을 알려주는 출력 마스크 행렬. LMEDS와 RANSAC 방법에서만 사용
  • maxIters: RANSAC 최대 반복 횟수
  • confidence: 신뢰도 레벨. 0에서 1 사이의 실수를 지정
  • 반환값: CV_64FC1 타입의 3x3 호모그래피 행렬을 반환. 만약 호모그래피를 계산할 수 없는 상황이라면 비어 있는 Mat 객체가 반환

 

 

void find_homography()
{
	Mat src1 = imread("box.png", IMREAD_GRAYSCALE);
	Mat src2 = imread("box_in_scene.png", IMREAD_GRAYSCALE);

	if (src1.empty() || src2.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Ptr<Feature2D> feature = ORB::create();

	vector<KeyPoint> keypoints1, keypoints2;
	Mat desc1, desc2;
	feature->detectAndCompute(src1, Mat(), keypoints1, desc1);
	feature->detectAndCompute(src2, Mat(), keypoints2, desc2);

	Ptr<DescriptorMatcher> matcher = BFMatcher::create(NORM_HAMMING);

	vector<DMatch> matches;
	matcher->match(desc1, desc2, matches);

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

	Mat dst;
	drawMatches(src1, keypoints1, src2, keypoints2, good_matches, dst,
		Scalar::all(-1), Scalar::all(-1), vector<char>(),
		DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

	vector<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);
	}

	Mat H = findHomography(pts1, pts2, RANSAC);

	vector<Point2f> corners1, corners2;
	corners1.push_back(Point2f(0, 0));
	corners1.push_back(Point2f(src1.cols - 1.f, 0));
	corners1.push_back(Point2f(src1.cols - 1.f, src1.rows - 1.f));
	corners1.push_back(Point2f(0, src1.rows - 1.f));
	perspectiveTransform(corners1, corners2, H);

	vector<Point> corners_dst;
	for (Point2f pt : corners2) {
		corners_dst.push_back(Point(cvRound(pt.x + src1.cols), cvRound(pt.y)));
	}

	polylines(dst, corners_dst, true, Scalar(0, 255, 0), 2, LINE_AA);

	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}
  • 31~35행: good_matches 매칭 결과에 저장된 질의 영상과 훈련 영상의 특징점 좌표를 추출하여 vector<Point2f> 타입의 변수 pts1, pts2에 저장
  • 37행: pts1 점들이 pts2 점들로 이동하는 호모그래피 행렬을 구하여 H에 저장. 호모그래피 계산 방법은 RANSAC 알고리즘 사용
  • 39~44행: src1 영상의 네 모서리 점을 corners1에 저장한 후, 호모그래피 행렬 H를 이용하여 이 점들이 이동하는 위치를 계산하여 corners2에 저장
  • 46~49행: 매칭 결과 영상 dst에서 corner2 점들이 위치하는 좌표를 corners_dst에 저장
  • 51행: 매칭 결과 영상 dst에서 box,png 스낵 박스가 있는 위치에 녹색으로 사각형을 그림

 

 

 

 

 

 

14.4 영상 이어 붙이기

 

 

static Ptr<Stitcher> Stitcher::create(Mode mode = Stitcher::PANORAMA);
  • mode: 이어 붙이기 방식. Stitcher::PANORAMA 또는 Stitcher::SCANS를 지정
  • 반환값: Stitcher 객체를 참조하는 Ptr 스마트 포인터 객체

 

 

Stitcher::Status Stitcher::stitch(InputArrayOfArrays images, OutputArray pano);
  • image: 입력 영상의 벡터. vector<Mat> 타입을 사용
  • pano: 출력 파노라마 영상
  • 반환값: 함수 동작 결과 코드. 이 값이 Stitcher::Status::OK 이면 정상 동작을 의미

 

 

 

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
	if (argc < 3) {
		cerr << "Usage: stitching.exe <image_file1> <image_file2> [<image_file3> ...]" << endl;
		return -1;
	}

	vector<Mat> imgs;
	for (int i = 1; i < argc; i++) {
		Mat img = imread(argv[i]);

		if (img.empty()) {
			cerr << "Image load failed!" << endl;
			return -1;
		}

		imgs.push_back(img);
	}

	Ptr<Stitcher> stitcher = Stitcher::create();

	Mat dst;
	Stitcher::Status status = stitcher->stitch(imgs, dst);

	if (status != Stitcher::Status::OK) {
		cerr << "Error on stitching!" << endl;
		return -1;
	}

	imwrite("result.jpg", dst);

	imshow("dst", dst);

	waitKey();
	return 0;
}
  • 9~12행: 명령행 인자 개수가 3보다 작으면 프로그램 사용법을 콘솔 창에 출력하고 프로그램을 종료
  • 14~24행: 명령행 인자로 전달된 영상 파일을 각각 불러와서 vector<Mat> 타입의 변수 imgs 에 추가. 만약 영상 파일을 불러오지 못하면 에러 메시지를 출력하고 프로그램을 종료
  • 26행: Stitcher 객체를 생성
  • 28~29행: imgs에 저장된 입력 영상을 이어 붙여서 결과 영상 dst를 생성
  • 31~34행: 영상 이어붙이기가 실패하면 에러 메시지를 출력하고 프로그램을 종료
  • 36행: 결과 영상을 result.jpg 파일로 저장
  • 38행: 결과영상을 dst창에 나타냄

 

 

 

 

 

 

'3학년 > OpenCV' 카테고리의 다른 글

[OpenCV] 15장 머신 러닝  (0) 2023.07.03
[OpenCV] 13장 객체 검출  (0) 2023.07.03
[OpenCV] 12장 레이블링과 외곽선 검출  (0) 2023.07.02
[OpenCV] 11장 이진화와 모폴로지  (0) 2023.07.02
[OpenCV] 10장 컬러 영상 처리  (0) 2023.07.02