본문 바로가기

영상처리

[OpenCV] Perspective Transformation을 이용한 이미지 와핑

Perspective Transformation을 이용한 이미지 와핑


오랜만에 포스팅하는군요!


이번 포스팅에서는 Perspective Transformation을 이용한 이미지 와핑 방법을 알아보도록 하겠습니다.


요즘 스마트폰 많이들 사용하실텐데요. 스마트폰 앱 중에서 CamScanner 같은 앱을 이용하여 마치 스캔한 것과 같은 이미지를 얻을 수 있는 걸 많이 보셨을 겁니다.


다음 그림을 보시면 이해가 되실텐데요. 직접 찍은 사진에서 원하는 영역만을 마치 스캔한 것과 효과를 내는 것을 확인할 수 있습니다.


이는 와핑 기법 중 하나로 투영 변환(Perspective Transformation)을 이용한 가장 대표적인 예라고 할 수 있습니다.

 

다음 사진을 이용하여 위처럼 구현해보도록 하겠습니다.

 


위 캡처된 영상에서 A4 용지 부분만 검출하여 이미지를 와핑해보도록 하겠습니다.


OpenCV 내의 WarpPerspective 함수를 이용하여 이미지를 와핑하기 위해서는 입력 영상 내에서 와핑하고자 하는 영역의 네 개의 점과 와핑된 이미지를 저장하고자 하는 영역의 네 개의 점을 이용하여 소위 말하는 변환 행렬을 구해주어야 합니다.


위 이미지에서 와핑하고자 하는 영역의 네 개의 점은 픽셀 좌표로 구할 수 있습니다.

네모박스 안의 값은 차례대로 x, y 좌표입니다.



자 이제 입력 영상에서 와핑하고자 하는 영역의 네 개의 점의 좌표를 구했습니다.

다음은 이 영역을 와핑하여 저장하고자 하는 영역의 네개의 점을 구해야 하는데요. 와핑의 크기는 항상 달라질 수 있기 때문에 사용자가 고정적으로 입력하는 것보다는 와핑 영역의 크기를 이용하여 네 개의 점의 위치를 구할 수 있습니다.


코드로 보면 다음과 같습니다.


Point TopLeft = Point(223, 44);
Point TopRight = Point(496, 44);
Point BottomRight = Point(715, 301);
Point BottomLeft = Point(13, 322);

vector<Point> rect;
rect.push_back(TopLeft);    // 왼쪽 위
rect.push_back(TopRight);    // 오른쪽 위
rect.push_back(BottomRight);    // 오른쪽 아래
rect.push_back(BottomLeft);    // 왼쪽 아래

double w1 = sqrt( pow(BottomRight.x - BottomLeft.x, 2)
	+ pow(BottomRight.x - BottomLeft.x, 2) );
double w2 = sqrt( pow(TopRight.x - TopLeft.x, 2)
	+ pow(TopRight.x - TopLeft.x, 2) );

double h1 = sqrt( pow(TopRight.y - BottomRight.y, 2)
	+ pow(TopRight.y - BottomRight.y, 2) );
double h2 = sqrt( pow(TopLeft.y - BottomLeft.y, 2)
	+ pow(TopLeft.y - BottomLeft.y, 2) );

double maxWidth = (w1 < w2) ? w1 : w2;
double maxHeight = (h1 < h2) ? h1 : h2;

Point2f src[4], dst[4];
src[0] = Point2f(TopLeft.x, TopLeft.y);
src[1] = Point2f(TopRight.x, TopRight.y);
src[2] = Point2f(BottomRight.x, BottomRight.y);
src[3] = Point2f(BottomLeft.x, BottomLeft.y);

dst[0] = Point2f(0, 0);
dst[1] = Point2f(maxWidth-1, 0);
dst[2] = Point2f(maxWidth-1, maxHeight-1);
dst[3] = Point2f(0, maxHeight-1);

일단 입력 영상에서 얻은 점들을 이용하여 최대 width와 최대 height를 이용해서 저장하고자 하는 영역의 크기를 설정하는 부분입니다. dst 배열이 저장하고자 하는 영역의 점들입니다.


여기까지 완료하였으면 다음 줄에 다음과 같이 한 줄만 추가해주면 변환행렬을 구할 수 있습니다.


transformMatrix = getPerspectiveTransform(src, dst);


변환행렬을 구했으니 다음은 이미지를 와핑하면 끝입니다.


와핑은 warpPerspective함수를 이용하면 쉽게 할 수 있습니다.

코드로 보면 다음과 같습니다.


warpPerspective(srcFrame, dstFrame, transformMatrix, Size(maxWidth, maxHeight));


여기서 srcFrame은 입력이고 dstFrame은 저장할 변수입니다. transforMatrix는 위에서 구한 변환 행렬이고 maxWidth와 maxHeight는 위에서 구한 값입니다.


결과를 보도록 하겠습니다.




제가 원하는 영역만 와핑된 것을 확인할 수 있습니다!


이상 포스팅 마치도록 하겠습니다.