Search
Duplicate

OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝/ 영상의 기하학적 변환

어파인 변환

영상의 기하학적 변환(geometric transform)은 영상을 구성하는 픽셀의 배치 구조를 변경함으로써 전체 영상의 모양을 바꾸는 작업.
입력 영상에서 (x,y)(x, y) 좌표의 픽셀을 결과 영상의 (x,y)(x', y') 좌표로 변환하는 방법은 다음과 같이 고유의 함수 형태로 나타낼 수 있다.
{x=f1(x,y)y=f2(x,y)\begin{cases} x' = f_{1}(x, y) \\ y' = f_{2}(x, y) \end{cases}

어파인 변환

영상의 기하학적 변환 중에서 어파인 변환(affine transformation)은 영상을 평행 이동시키거나 회전, 크기 변환 등을 통해 만들 수 있는 변환을 통칭한다.
또는 영상을 한쪽 방향으로 밀어서 만든 것 같은 전단 변환도 어파인 변환에 포함된다.
영상에 어파인 변환을 적용할 경우 직선은 그대로 직선으로 나타나고, 직선 간의 길이 비율과 평행 관계가 그대로 유지된다.
어파인 변환은 모두 여섯 개의 파라미터를 이용한 수식으로 정의할 수 있다.
{x=f1(x,y)=ax+by+cy=f2(x,y)=dx+ey+f\begin{cases} x' = f_{1}(x, y) = ax + by + c \\ y' = f_{2}(x, y) = dx + ey + f \end{cases}
위 수식은 행렬을 이용해서 다음과 같은 수식으로 표현할 수도 있다.
(xy)=(abde)(xy)+(cf)\left( \begin{array}{rr} x' \\ y' \end{array} \right) = \left( \begin{array}{rr} a & b \\ d & e \end{array} \right) \left( \begin{array}{rr} x \\ y \end{array} \right) + \left( \begin{array}{rr} c \\ f \end{array} \right)
즉 입력 영상의 좌표를 나타내는 행렬 (xy)\left( \begin{array}{rr} x \\ y \end{array} \right) 앞에 2×2 행렬 (abde)\left( \begin{array}{rr} a & b \\ d & e \end{array} \right) 을 곱하고 그 뒤에 2×1 행렬 (cf)\left( \begin{array}{rr} c \\ f \end{array} \right) 를 더하는 형태로 어파인 변환을 표현한다.
수학적 편의를 위해 입력 영상의 좌표 (x,y)(x, y) 에 가상의 좌표 1을 하나 추가하여 (x,y,1)(x, y, 1) 형태로 바꾸면, 행렬 수식을 다음과 같은 하나의 행렬 곱셈 형태로 바꿀 수 있다.
(xy)=(abcdef)(xy1)\left( \begin{array}{rr} x' \\ y' \end{array} \right) = \left( \begin{array}{rrr} a & b & c \\ d & e & f \end{array} \right) \left( \begin{array}{rrr} x \\ y \\ 1 \end{array} \right)
위 수식에서 여섯 개의 파라미터로 구성된 2×3 행렬 (abcdef)\left( \begin{array}{rrr} a & b & c \\ d & e & f \end{array} \right)를 어파인 변환 행렬 (affine transform matrix)이라고 한다. 즉 어파인 변환은 2×3 실수형 행렬 하나로 표현할 수 있는 것이다.
입력 영상과 어파인 변환 결과 영상으로부터 어파인 변환 행렬을 구하기 위해서는 최소 세 점의 이동 관계를 알아야 한다.
점 하나의 이동 관계로부터 x좌표와 y좌표에 대한 변환 수식 두 개를 얻을 수 있으므로, 점 세 개의 이동 관계로부터 총 여섯 개의 방정식을 구할 수 있다.
그러므로 점 세 개의 이동 관계를 알고 있다면 여섯 개의 원소로 정의되는 어파인 변환 행렬을 구할 수 있다.
아래 그림은 점 세 개의 이동 관계에 의해 결정되는 어파인 변환을 보여준다.
어파인 변환에 의해 직사각형 영상은 평행사변형 형태로 변환될 수 있기 때문에 입력 영상의 좌측 하단 모서리 점이 이동하는 위치는 자동으로 결정된다.
그러므로 어파인 변환은 점 세 개의 이동 관계만으로 정의할 수 있다.
OpenCV는 어파인 변환 행렬을 구하는 함수와 어파인 변환 행렬을 이용하여 실제 영상을 어파인 변환하는 함수를 모두 제공한다.
어파인 변환 행렬을 구하는 함수 이름은 getAffineTransform()으로, 입력 영상에서 세 점의 좌표와 이점들이 이동한 결과 영상의 좌표 세 개를 입력 받아 2×3 어파인 변환 행렬을 계산한다.
2×3 어파인 변환 행렬을 가지고 있을 때 영상을 어파인 변환한 결과 영상을 생성하려면 warpAffine() 함수를 사용한다. wrapAffine() 함수는 src 영상을 어파인 변환하여 dst 영상을 생성한다.
Mat src = imread("tekapo.bmp"); if (src.empty()) { cerr << "Image load failed!" << endl; return; } Point2f srcPts[3], dstPts[3]; srcPts[0] = Point2f(0, 0); srcPts[1] = Point2f(src.cols - 1, 0); srcPts[2] = Point2f(src.cols - 1, src.rows - 1); dstPts[0] = Point2f(50, 50); dstPts[1] = Point2f(src.cols - 100, 100); dstPts[2] = Point2f(src.cols - 50, src.rows - 50); Mat M = getAffineTransform(srcPts, dstPts); Mat dst; warpAffine(src, dst, M, Size()); imshow("src", src); imshow("dst", dst);
C++

이동 변환

영상의 이동 변환(translation transformation)은 영상을 가로 또는 세로 방향으로 일정 크기만큼 이동 시키는 연산을 의미하며, 시프트(shift) 연산이라고도 한다.
입력 영상의 모든 좌표를 xx방향으로 aa만큼,  yy방향으로 bb만큼 이동하는 변환을 수식으로 나타내면 다음과 같다.
{x=x+ay=y+b\begin{cases} x' = x + a \\ y' = y + b \end{cases}
이 수식에서 (x,y)(x, y) 는 입력 영상의 픽셀 좌표이고, (x,y)(x', y') 는 결과 영상의 픽셀 좌표이다. 앞 수식을 행렬을 이용하면 다음과 같이 하나의 식으로 표현할 수 있다.
[xy ]=[1001][xy]+[ab]\left[ \begin{array}{rr} x' \\ y'  \end{array} \right] = \left[ \begin{array}{rr} 1 & 0 \\ 0 & 1 \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} a \\ b \end{array} \right]
앞 수식에서 입력 영상의 좌표를 나타내는 행렬 [xy]\left[ \begin{array}{rr} x \\ y \end{array} \right] 앞의 2×2 행렬과 그 뒤에 더해지는 2×1 행렬을 합쳐서 하나의 2×3 행렬을 구성하면 이동 변환을 나타내는 어파인 변환 행렬을 만들 수 있다.
즉 영상을 xx방향으로 aa만큼,  yy방향으로 bb만큼 이동하는 어파인 변환 행렬 M은 다음과 같다.
M=[10a01b]M = \left[ \begin{array}{rrr} 1 & 0 & a \\ 0 & 1 & b \end{array} \right]
그러므로 OpenCV에서 영상을 이동 변환하려면 앞과 같은 형태의 2×3 실수 행렬 M을 만들고 이를 wrapAffine() 함수 인자로 전달해야 한다.
Mat src = imread("tekapo.bmp"); if (src.empty()) { cerr << "Image load failed!" << endl; return; } Mat M = Mat_<double>({2, 3}, {1, 0, 150, 0, 1, 100}); Mat dst; warpAffine(src, dst, M, Size()); imshow("src", src); imshow("dst", dst);
C++

전단 변환

전단 변환(shear transformation)은 직사각형 형태의 영상을 한쪽 방향으로 밀어서 평행사변형 모양으로 변형되는 변환이며 층밀림 변환이라고도 한다.
전단 변환은 가로 방향 또는 세로 방향으로 각각 정의할 수 있다.
yy 좌표가 증가함에 따라 영상을 가로 방향으로 조금씩 밀어서 만드는 전단 변환 수식은 다음과 같다.
{x=x+mxyy=y\begin{cases} x' = x + m_{x}y \\ y' = y \end{cases}
또는
[xy]=[1mx01][xy]+[00]\left[ \begin{array}{rr} x' \\ y' \end{array} \right] = \left[ \begin{array}{rr} 1 & m_{x} \\ 0 & 1 \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} 0 \\ 0 \end{array} \right]
xx 좌표가 증가함에 따라 영상을 세로 방향으로 조금씩 밀어서 만드는 전단 변환 수식은 다음과 같다.
{x=xy=myx+y\begin{cases} x' = x \\ y' = m_{y}x + y \end{cases}
또는
[xy]=[10my1][xy]+[00]\left[ \begin{array}{rr} x' \\ y' \end{array} \right] = \left[ \begin{array}{rr} 1 & 0 \\ m_{y} & 1 \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} 0 \\ 0 \end{array} \right]
앞의 두 수식에서 mxm_{x}와 mym_{y}는 영상으로 각각 가로 방향과 세로 방향으로 밀림 정도는 나타내는 실수이다. 결국 전단 변환을 나타내는 2×3 어파인 변환 행렬 M은 다음과 같이 나타낼 수 있다.
M=[1mx0010]M = \left[ \begin{array}{rrr} 1 & m_{x} & 0 \\ 0 & 1 & 0 \end{array} \right]
또는
M=[100my10]M = \left[ \begin{array}{rrr} 1 & 0 & 0 \\ m_{y} & 1 & 0 \end{array} \right]
Mat src = imread("tekapo.bmp"); if (src.empty()) { cerr << "Image load failed!" << endl; return; } double mx = 0.3; Mat M = Mat_<double>({2, 3}, {1, mx, 0, 0, 1, 0}); Mat dst; warpAffine(src, dst, M, Size(cvRound(src.cols + src.rows * mx), src.rows)); imshow("src", src); imshow("dst", dst);
C++

크기 변환

영상의 크기 변환(scale transformation)은 영상의 전체적인 크기를 확대 또는 축소하는 변환이다.
원본 영상의 가로 픽셀 크기가 ww이고 결과 영상의 가로 크기가 ww'이기 때문에 가로 방향으로의 크기 변환 비율 sxs_{x}는 sx=wws_{x} = {w' \over w} 수식으로 계산할 수 있다. 마찬가지로 yy방향으로의 크기 변환 비율 sys_{y}는 sy=hhs_{y} = {h' \over h} 수식으로 계산된다.
입력 영상 좌표 (x,y)(x, y)로부터 크기 변환 결과 영상의 좌표 (x,y)(x', y')를 계산하는 수식은 다음과 같다.
{x=sxxy=syy\begin{cases} x' = s_{x}x \\ y' = s_{y}y \end{cases}
또는
[xy ]=[sx00sy][xy]+[00]\left[ \begin{array}{rr} x' \\ y'  \end{array} \right] = \left[ \begin{array}{rr} s_{x} & 0 \\ 0 & s_{y} \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} 0 \\ 0 \end{array} \right]
위 수식에서 sxs_{x} 또는 sys_{y}가 1보다 크면 영상이 확대되고 1보다 작으면 축소 된다.
영상의 크기 변환을 나타내는 어파인 변환 행렬 M은 다음과 같다.
M=[sx000sy0]M = \left[ \begin{array}{rrr} s_{x} & 0 & 0 \\ 0 & s_{y} & 0 \end{array} \right]
그러므로 앞과 같은 어파인 변환 행렬을 생성하고 wrapAffine() 함수를 이용하면 영상의 크기 변환을 수행할 수 있다.
그러나 영상의 크기를 변경하는 작업은 실제 영상 처리 시스템에서 매우 빈번하게 사용되기 때문에 OpenCV는 보다 간단하게 크기를 변경할 수 있는 resize() 함수를 제공한다.
resize() 함수는 src 입력 영상을 dsize 크기로 확대 또는 축소한 dst 영상을 생성한다.
영상의 크기는 dsize 인자를 통해 명시적으로 지정할 수도 있고, 또는 가로 방향 및 세로 방향으로의 크기 변환 비율은 fx와 fy 값을 통해 결정되도록 할 수도 있다.
만약 결과 영상의 크기를 픽셀 단위로 지정하여 크기 변환을 수행하려면 dsize에 0이 아닌 값을 지정하고, fx와 fy는 0으로 설정한다.
만약 입력 영상의 크기를 기준으로 크기 변환 비율을 지정하여 영상을 확대 또는 축소 하려면 dsize 인자에는 Size()를 지정하고 fx와 fy에는 0이 아닌 양의 실수를 지정한다.
이 경우 결과 영상의 크기는 다음과 같이 설정된다.
{dst.rows=round(src.rows×fx)dst.cols=round(src.cols×fy)\begin{cases} dst.rows = round(src.rows \times fx) \\ dst.cols = round(src.cols \times fy) \end{cases}
resize() 함수의 여섯 번쨰 인자 interpolation에는 보간법 알고리즘을 나타내는 InterpolationFlags 열거형 상수를 지정한다.
보간법은 결과 영상의 픽셀 값을 결정하기 위해 입력 영상 주변 픽셀 값을 이용하는 방식을 의미한다.
INTER_NEAREST 방법은 가장 빠르게 동장하지만 결과 영상 화질이 좋지 않다.
INTER_LINEAR 방법읍 연산 속도가 빠르고 화질도 충분히 좋은 편이라서 널리 사용되고 있고, resize() 함수에서 기본값으로 지정되어 있다.
INTER_LINEAR 보다 더 좋은 화질을 원한다면 INTER_CUBIC 또는 INTER_LANCZOS4 상수를 사용하는 것이 좋다.
영사을 축소하는 경우 INTER_AREA 방법을 사용하면 무아레(moire) 현상이 적게 발생하며 화질 면에서 유리하다.
Search
InterpolationFlags 열거형 상수
설명
INTER_LINEAR
Open
양선형 보간법
INTER_CUBIC
Open
3차 보간법
INTER_AREA
Open
픽셀 영역 리샘플링
INTER_LANCZOS4
Open
8×8 이웃 픽셀을 사용하는 란초스(Lanczos 보간법)
Mat src = imread("tekapo.bmp"); if (src.empty()) { cerr << "Image load failed!" << endl; return; } Mat dst1, dst2, dst3, dst4; resize(src, dst1, Size(), 4, 4, INTER_NEAREST); resize(src, dst2, Size(1920, 1280); resize(src, dst3, Size(1920, 1280), 0, 0, INTER_CUBIC); resize(src, dst4, Size(1920, 1280), 0, 0, INTER_LANCZOS4); imshow("src", src); imshow("dst1", dst1(Rect(400, 500, 400, 400))); imshow("dst2", dst2(Rect(400, 500, 400, 400))); imshow("dst3", dst3(Rect(400, 500, 400, 400))); imshow("dst4", dst4(Rect(400, 500, 400, 400)));
C++

회전 변환

영상의 회전 변환(rotation transformation)은 특정 좌표를 기준으로 영상을 원하는 각도만큼 회전하는 변환이다.
영상의 회전 변환에 의해 입력 영상의 점 (x,y)(x, y) 가 이동하는 점의 좌표 (x,y)(x', y')는 다음과 같이 삼각함수를 이용하여 구할 수 있다.
{x=cosθx+sinθyy=sinθx+cosθy\begin{cases} x' = cos \theta \cdot x + sin \theta \cdot y \\ y' = -sin \theta \cdot x + cos \theta \cdot y \end{cases}
또는
[xy ]=[cosθsinθsinθcosθ][xy]+[00]\left[ \begin{array}{rr} x' \\ y'  \end{array} \right] = \left[ \begin{array}{rr} cos \theta & sin \theta \\ - sin \theta & cos \theta \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} 0 \\ 0 \end{array} \right]
영상을 반시계 방향으로 θ\theta만큼 회전하는 어파인 변환 행렬 M은 다음과 같이 정의된다.
M=[cosθsinθ0sinθcosθ0]M = \left[ \begin{array}{rrr} cos \theta & sin \theta & 0 \\ - sin \theta & cos \theta & 0 \end{array} \right]
그러므로 cos() 함수와 sin() 함수를 이용하여 앞과 같은 행렬을 생성하고 warpAffine() 함수를 사용하면 영상을 회전시킬 수 있다.
다만 영상을 회전하는 경우가 많기 떄문에 OpenCV에서는 영상의 회전을 위한 어파인 변환 행렬을 생성하는 getRotationMatrix2D() 함수를 제공한다.
이 함수를 이용하면 영상을 원점이 아닌 특정 좌표를 기준으로 회전시키거나 필요한 경우 크기 변환까지 함께 수행하는 어파인 변환 행렬을 쉽게 만들 수 있다.
getRotationMatrix2D() 함수는 center 점을 기준으로 반시계 방향으로 angle 각도만큼 회전한 후, scale 크기만큼 확대 또는 축소하는 2×3 어파인 변환 행렬을 반환한다.
만약 영상을 시계 방향으로 회전하는 어파인 변환 행렬을 구하고 싶다면 angle 인자에 음수를 지정한다.
getRotationMatrix2D() 함수가 반환하는 어파인 변환 행렬은 다음과 같이 계산된다.
[αβ(1α)center.xβcenter.yβαβcenter.x+(1α)center.y]\left[ \begin{array}{rrr} \alpha & \beta & (1-\alpha) \cdot center.x - \beta \cdot center.y \\ - \beta & \alpha & \beta \cdot center.x + (1 - \alpha) \cdot center.y \end{array} \right]
이 수식에서 α=scalecos(angle)\alpha = scale \cdot cos(angle) 이고, β=scalesin(angle)\beta = scale \cdot sin(angle)를 의미한다.
Mat src = imread("tekapo.bmp"); if (src.empty()) { cerr << "Image load failed!" << endl; return; } Point2f cp(src.cols / 2.f, src.rows / 2.f); Mat M = getRotationMatrix2D(cp, 20, 1); Mat dst; warpAffine(src, dst, M, Size()); imshow("src", src); imshow("dst", dst);
C++

대칭 변환

대칭 변환은 입력 영상과 같은 크기의 결과 영상을 생성하며, 입력 영상의 픽셀과 결과 영상의 픽셀이 일대일로 대응되므로 보간법이 필요하지 않다.
영상의 좌우 대칭 변환에 의한 좌표 변환 수식은 다음과 같다.
{x=w1xy=y\begin{cases} x' = w - 1 - x \\ y' = y \end{cases}
이 수식에서 (x,y)(x, y)는 입력 영상의 픽셀 좌표이고, (x,y)(x', y')는 결과 영상의 픽셀 좌표이며, ww는 입력 영상의 가로 크기이다. 앞 수식을 행렬 형태로 바꿔 쓰면 다음과 같다.
[xy ]=[1001][xy]+[w10]\left[ \begin{array}{rr} x' \\ y'  \end{array} \right] = \left[ \begin{array}{rr} -1 & 0 \\ 0 & -1 \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} w-1 \\ 0 \end{array} \right]
앞의 수식을 정리해서 보면 결국 좌우 대칭은 영상을 xx축 방향으로 -1배 크기 변환한 후 xx축 방향으로 w1w-1 만큼 이동 변환한 것과 같다. 그러므로 좌우 대칭 변환도 어파인 변환의 일종이다.
영상의 상하 대칭 변환도 비슷한 방식으로 생각할 수 있으며 수식으로 정리하면 다음과 같다.
{x=xy=h1y\begin{cases} x' = x \\ y' = h - 1 - y \end{cases}
또는
[xy ]=[1001][xy]+[0h1]\left[ \begin{array}{rr} x' \\ y'  \end{array} \right] = \left[ \begin{array}{rr} 1 & 0 \\ 0 & -1 \end{array} \right] \left[ \begin{array}{rr} x \\ y \end{array} \right] + \left[ \begin{array}{rr} 0 \\ h - 1 \end{array} \right]
OpenCV는 영상의 대칭 변환을 수행하는 flip() 함수를 제공한다. flip() 함수는 영상을 가로 방향, 세로 방향, 또는 가로와 세로 양 방향에 대해 대칭 변환한 영상을 생성한다.
flip() 함수의 대칭 방법은 flipCode의 인자 부호에 따라 결정된다. 일반적으로 영상을 좌우로 대칭 변환하려면 flipCode에 1을 지정하고, 상하 대칭 변환을 하려면 0을 지정한다. 상하 대칭과 좌우 대칭을 모두 수행하려면 -1을 지정한다.
참고로 상하 대칭과 좌우 대칭을 모두 수행한 결과는 입력 영상을 180도 회전한 것과 같다.
(예제는 flip() 함수를 사용하는 것이라 생략)

투시 변환

영상의 기하학적 변환 중에는 어파인 변환보다 자유도가 높은 투시 변환(perspective transform)이 있다. 투시 변환은 직사각형 형태의 영상을 임의의 볼록 사각형 형태로 변경할 수 있는 변환이다.
투시 변환에 의해 원본 영상에 있던 직선은 결과 영상에서 그대로 직선성이 유도되지만, 두 직선의 평행 관계는 깨어질 수 있다.
아래 그림은 점 네 개의 이동 관계에 의해 결정되는 투시 변환을 나타낸다.
투시 변환은 직선의 평행 관계가 유지되지 않기 때문에 결과 영상의 형태가 임의의 사각형으로 나타나게 된다.
점 하나의 이동 관계로부터 x 좌표에 대한 방정식 하나와 y 좌표에 대한 방정식 하나를 얻을 수 있으므로, 점 네 개의 이동 관계로부터 여덟 개의 방정식을 얻을 수 있다.
이 여덟 개의 방정식으로부터 투시 변환을 표현하는 파라미터 정보를 계산할 수 있다.
투시변환은 보통 3×3 크기의 실수 행렬로 표현한다.
투시 변환은 여덟 개의 파라미터로 표현할 수 있지만, 좌표 계산의 편의상 아홉 개의 원소를 갖는 3×3 행렬을 사용한다.
투시 변환을 표현하는 행렬을 MpM_{p} 라고 하면, 입력 영상의 픽셀 좌표 (x,y)(x, y) 가 행렬 MpM_{p} 에 의해 이동하는 결과 영상 픽셀 좌표 (x,y)(x', y')는 다음과 같이 계산된다.
(wxwyw)=Mp(xy1)=(p11p12p13p21p22p23p31p32p33)(xy1)\left( \begin{array}{rrr} wx' \\ wy' \\w \end{array} \right) = M_{p} \left( \begin{array}{rrr} x \\ y \\ 1 \end{array} \right) = \left( \begin{array}{rrr} p_{11} & p_{12} & p_{13} \\ p_{21} & p_{22} & p_{23} \\ p_{31} & p_{32} & p_{33} \end{array} \right) \left( \begin{array}{rrr} x \\ y \\ 1 \end{array} \right)
앞의 행렬 수식에서 입력 좌표와 출력 좌표를 (x,y,1),(wx,wy,w)(x, y, 1), (wx', wy', w) 형태로 표현한 것을 동차 좌표계(homogeneous coordinates)라고 하며, 좌표 계산의 편의를 위해 사용하는 방식이다.
여기서 ww는 결과 영상의 좌표를 표현할 때 사용되는 비례 상수이며 w=p31x+p32y+p33w = p_{31}x + p_{32}y + p_{33} 형태로 계산된다.
그러므로 xx와 yy는 다음과 같이 구할 수 있다.
x=p11x+p12y+p13p31x+p32y+p33, y=p21x+p22y+p23p31x+p32y+p33x' = { p_{11}x + p_{12}y + p_{13} \over p_{31}x + p_{32}y + p_{33} },  y' = { p_{21}x + p_{22}y + p_{23} \over p_{31}x + p_{32}y + p_{33} }
OpenCV는 투시 변환 행렬을 구하는 함수와 투시 변환 행렬을 이용하여 실제 영상을 투시 변환하는 함수를 모두 제공한다.
투시 변환 행렬을 구하는 함수 이름은 getPerspectiveTransform()으로 입력 영상에서 네 점의 좌표와 이 점들이 이동한 결과 영상의 좌표 네 개를 입력 받아 3×3 투시 변환 행렬을 계산한다.
3×3 투시 변환 행렬을 가지고 있을 때, 영상을 투시 변환한 결과 영상을 생성하려면 warpPerspective() 함수를 사용한다. 이 함수는 투시 변환 행렬 M을 이용하여 src 영상으로부터 dst 영사을 생성한다. 이때 전달되는 투시 변환 행렬 M은 CV_32FC1 또는 CV_64FC1 타입이어야 하고 크기는 3×3 이어야 한다.
Mat src; Point2f srcQuad[4], dstQuad[4]; void on_mouse(int event, int x, int y, int flags,void* userdata); int main() { if (src.empty()) { cerr << "Image load failed!" << endl; return; } namedWindow("src"); setMouseCallback("src", on_mouse); imshow("src"); waitKey(0); return 0; } void on_mouse(int event, int x, int y, int flags, void*) { static int cnt = 0; if (event == EVENT_LBUTTONDOWN) { if (cnt < 4) { srcQuad[cnt++] = Point2f(x, y); circle(src, Point(x, y), 5, Scalar(0, 0, 255), -1); imshow("src", src); if (cnt == 4) { int w = 200, h = 300; dstQuad[0] = Point2f(0, 0); dstQuad[1] = Point2f(0, 0); dstQuad[2] = Point2f(0, 0); dstQuad[3] = Point2f(0, 0); Mat pers = getPerspectiveTransform(srcQuad, dstQuad); Mat dst; warpPerspective(src, dst, pers, Size(w, h)); imshow("dst", dst); } } } }
C++
만일 3×3 투시 변환 행렬을 가지고 있을 때, 일부 점들이 투시 변환에 의해 어느 위치로 이동할 것인지 알고 싶다면 perspectiveTransform() 함수를 사용할 수 있다.