When will you grow up?

[openCV] SIFT와 SURF를 이용한 WebCam 영상 매칭 본문

02. Study/Computer Vision(openframworks&opencv)

[openCV] SIFT와 SURF를 이용한 WebCam 영상 매칭

미카이 2016. 12. 10. 15:25
이전에 실습했던 SURF 특징점 검출기를 활용하여

WebCam 을 이용하여 실시간 영상 매칭 및 플레이어 영상 매칭을 수행하였다.

여기서 사용된 특징점 검출기는 SURF와 SIFT를 이용하여 수행과정을 비교해보았다.



아래는 사용된 코드 입니다.


//surf matching
#include "stdio.h"
#include "iostream"
#include "vector"
#include "cstdlib"
#include "opencv2/core/core.hpp"
#include "opencv2/core.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/xfeatures2d/nonfree.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
using namespace cv;
using namespace cv::xfeatures2d;

int main()
{

	//필요한 변수 및 객체 선언
	char key = 'a';
	int framecount = 0;


	
	Ptr orb = ORB::create(500);
	Ptr detector = SURF::create(500);
	Ptr extractor = SurfDescriptorExtractor::create();
	FlannBasedMatcher matcher;
	
	Mat frame, des_object, image;
	Mat des_image, img_matches, H;

	std::vector kp_object;
	std::vector obj_corners(4);
	std::vector kp_image;
	std::vector> matches;
	std::vector good_matches;
	std::vector obj;
	std::vector scene;
	std::vector scene_corners(4);


	//레퍼런스 이미지를 로딩합니다.
	Mat object = imread("411.jpg", 1);

	if (!object.data)
	{
		std::cout << "Error reading object " << std::endl;
		return -1;
	}


	//orb->detect(object, kp_object);
	//cv::drawKeypoints(object, keypoints_object, img_object, cv::Scalar(0,255,255));
	//orb->compute(object, kp_object, des_object);

	
	//레퍼런스 이미지에서 특징점 검출될 것을 keypoint에 담는다.
	detector->detect(object, kp_object);
	extractor->compute(object, kp_object, des_object);
	
	
	//비디오 영상을 불러 오거나 캠을 실행시키기 위해 객체를 생성
	VideoCapture cap;
	cap.open("move1.mp4");
	//VideoCapture cap(0);//이런식으로 사용하면 디폴트값으로 실시간 캠을 사용할 수 있다.

	//레퍼런스 이미지로부터 각 코너점들을 얻는다.
	obj_corners[0] = cvPoint(0, 0);
	obj_corners[1] = cvPoint(object.cols, 0);
	obj_corners[2] = cvPoint(object.cols, object.rows);
	obj_corners[3] = cvPoint(0, object.rows);

	//esc키를 입력받기 전에 무한루프를 돌아 실시간 영상 처리를 위한,
	while (key != 27)
	{
		//비디오에서 프레임을 캡처하여 영상을 이미지 이름 'frame'에 저장
		cap >> frame;

		if (framecount < 50)
		{
			framecount++;
			continue;
		}

		//캡쳐된 이미지는 그레이스케일로 변환
		cvtColor(frame, image, CV_RGB2GRAY);

		//캡처된 프레임의 검출기를 통하여 추출.
		detector->detect(image, kp_image);
		extractor->compute(image, kp_image, des_image);

		//참조 및 캡처된 이미지의 일치하는 이미지를 찾습니다.
		matcher.knnMatch(des_object, des_image, matches, 2);

		//기하학적 거리를 곱한 것과 같은 간격을 가진 keypoints 거리를 아래와 같은 거리에서 측정
		for (int i = 0; i < min(des_image.rows - 1, (int)matches.size()); i++)
		{
			if ((matches[i][0].distance < 0.6*(matches[i][1].distance)) && ((int)matches[i].size() <= 2 && (int)matches[i].size() > 0))
			{
				good_matches.push_back(matches[i][0]);
			}
		}

		//good match만 그린다.
		drawMatches(object, kp_object, frame, kp_image, good_matches, img_matches,
			Scalar::all(-1), Scalar::all(-1), std::vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

		//3 good matches are enough to describe an object as a right match.
		//3개의 매칭된것은 오른쪽이미지에 표기되기에 충분하기 때문에 3개이상으로 3개이상일시간 표기한다.
		if (good_matches.size() >= 3)
		{

			for (int i = 0; i < good_matches.size(); i++)
			{
				//good match로 부터 키포인트들을 얻는다.
				obj.push_back(kp_object[good_matches[i].queryIdx].pt);
				scene.push_back(kp_image[good_matches[i].trainIdx].pt);
			}
			try
			{
				H = findHomography(obj, scene, CV_RANSAC);
			}
			catch (Exception e) {}

			perspectiveTransform(obj_corners, scene_corners, H);

			//cam위에 객체 검출된 사각형을 그린다.
			line(img_matches, scene_corners[0] + Point2f(object.cols, 0), scene_corners[1] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
			line(img_matches, scene_corners[1] + Point2f(object.cols, 0), scene_corners[2] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
			line(img_matches, scene_corners[2] + Point2f(object.cols, 0), scene_corners[3] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
			line(img_matches, scene_corners[3] + Point2f(object.cols, 0), scene_corners[0] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
		}

		//검출된 매칭 출력
		imshow("Matching", img_matches);

		//검출된 배열 초기화
		good_matches.clear();

		key = waitKey(1);
	}
	return 0;
}


아래는 입력 영상 입니다



결과 이미지 입니다(위)

SIFT 결과(위)

SURF 결과(위)



SIFT 결과 영상(위)



SURF 결과 영상(위)







(결론)

SIFT와 SURF의 결과는 속도면에서는 SIFT가 조금 더 빠른것을 확인할 수 있었으나 매칭되는 점의 수는 SURF가 더 많은 것을 확인 할 수 있었다.

각 각 마다 장단점이 존재 하므로 자신 프로젝트에 맞는 것을 사용하는 것이 좋을꺼 같다. 어떤것이 좋다 나쁘다 판단은 안되며, 각 상황에 알맞게 사용하면 될거 같다.



Reference

http://robocv.blogspot.kr/2012/02/real-time-object-detection-in-opencv.html

http://thinkpiece.tistory.com/246

http://stackoverflow.com/questions/17570421/object-detection-using-surf

http://docs.opencv.org/trunk/d7/dff/tutorial_feature_homography.html

Comments