상세 컨텐츠

본문 제목

#OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝 - 11

Programing/OpenCV

by CouqueD'asse 2022. 6. 17. 16:02

본문

8장 영상의 기하학적 변환

 

8.1 어파인 변환

영상의 평행 이동, 확대 및 축소, 회전 등의 조합으로 만들 수 있는 기하학적 변환

 

8.1.1 어파인 변환

영상의 기하학적 변환은 영상을 구성하는 픽셀의 배치 구조를 변경함으로써 전체 영상의 모양을 바꾸는 작업

픽셀 값은 그대로 유지하면서 위치를 변경하는 작업

void affine_transform()
{
	Mat src = imread("tekapo.bmp");
	if (src.empty())
	{
		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);

	waitKey();
	destroyAllWindows();
}

 

8.1.2 이동 변환

영상을 가로 또는 세로 방향으로 일정 크기만큼 이동시키는 연산을 의미하며 시프트 연산이라고도 함

void affine_translation()
{
	Mat src = imread("tekapo.bmp");
	if (src.empty())
	{
		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);

	waitKey();
	destroyAllWindows();
}

 

8.1.3 전단 변환

직사각형 형태의 영상을 한쪽 방향으로 밀어서 평행사변형 모양으로 변형되는 변환이며 층밀림 변환이라고도 함

void affine_shear()
{
	Mat src = imread("tekapo.bmp");
	if (src.empty())
	{
		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);

	waitKey();
	destroyAllWindows();
}

 

8.1.4 크기 변환

영상의 전체적인 크기를 확대 또는 축소하는 변환

void affine_scale()
{
	Mat src = imread("rose.bmp");
	if (src.empty())
	{
		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)));

	waitKey();
	destroyAllWindows();
}

dst1 영상 : 최근방 이웃 보간법을 사용한 결과로 픽셀 자체가 커진 것처럼 보이고 장미꽃 경계선이 매우 거친 느낌

dst2 영상 : 양선형 보간법을 사용한 확대 결과이며 최근방 이웃 보간법에 비해 경계면이 부드럽게 확대되어 화칠이 좋아짐

dst3 영상 : 3차 보간법을 사용하여 미세하게 좋아보이지만 연산 속도 면에서는 느림

dst4 영상 : 란초스 보간법을 사용하여 미세하게 좋아보이지만 연산 속도 면에서는 느림

 

8.1.5 회전 변환

특정 좌표를 기준으로 영상을 원하는 각도만큼 회전하는 변환

void affine_rotation()
{
	Mat src = imread("tekapo.bmp");
	if (src.empty())
	{
		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);

	waitKey();
	destroyAllWindows();
}

 

8.1.6 대칭 변환

입력 영상과 같은 크기의 결과 영상을 생성, 입력 영상의 픽셀과 결과 영상의 픽셀이 일대일로 대응되므로 보간법이 필요하지 않음

 

void affine_flip()
{
	Mat src = imread("eastsea.bmp");
	if (src.empty())
	{
		return;
	}
	imshow("src", src);

	Mat dst;
	int flipCode[] = { 1, 0, -1 };
	for (int i = 0; i < 3; i++)
	{
		flip(src, dst, flipCode[i]);

		String desc = format("flipCode : %d", flipCode[i]);
		putText(dst, desc, Point(10, 30), FONT_HERSHEY_SIMPLEX, 1.0, 
        		Scalar(255, 0, 0), 1, LINE_AA);

		imshow("dst", dst);
		waitKey();
	}
	destroyAllWindows();
}

 

8.2 투시 변환

직사각형 형태의 영상을 임의의 블록 사각형 형태로 변경할 수 있는 변환

원본 영상에 있던 직선은 결과 영상에서 그대로 직선성이 유지되지만, 두 직선의 평행 관계는 깨어질 수 있음

Mat src;
Point2f srcQuad[4], dstQuad[4];

void on_mouse_(int event, int x, int y, int flags, void* userdata);

int main()
{
	src = imread("card.bmp");
	if (src.empty())
	{
		return -1;
	}
	namedWindow("src");
	setMouseCallback("src", on_mouse_);

	imshow("src", src);
	waitKey();

	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(w - 1, 0);
				dstQuad[2] = Point2f(w - 1, h - 1);
				dstQuad[3] = Point2f(0, h - 1);

				Mat pers = getPerspectiveTransform(srcQuad, dstQuad);

				Mat dst;
				warpPerspective(src, dst, pers, Size(w, h));

				imshow("dst", dst);
			}
		}
	}
}

관련글 더보기