컴퓨터 비전

OpenCV 영상의 기하학적 변환

Jagbbum 2023. 10. 30. 09:39

영상의 기하학적 변환

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

 

이동 변환

- 가로 또는 세로 방향으로 영상을 특정 크기만큼 이동시키는 변환

for (int y = 0; y < src.rows; y++) {
		for (int x = 0; x < src.cols; x++) {
			int x_ = x + 200;
			int y_ = y + 100;

			// 출력 영상의 범위를 벗어나는지 확인
			if (x_ < 0 || x_ >= dst.cols) continue;
			if (y_ < 0 || y_ >= dst.rows) continue;

			dst.at<uchar>(y_, x_) = src.at<uchar>(y, x);
		}
	}

 

전단 변환

- 직사각형 형태의 영상을 한쪽 방향으로 밀어서 평행사변형 모양으로 변형되는 변환. 층밀림 변환

for (int y = 0; y < src.rows; y++) {
		for (int x = 0; x < src.cols; x++) {
			int nx = x;
			int ny = int(y + m*x);
			dst.at<uchar>(ny, nx) = src.at<uchar>(y, x);
		}
	}

 

크기 변환

- 영상의 크기를 원본 영상보다 크게 또는 작게 만드는 변환

void resize1()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

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

	Mat dst = Mat::zeros(src.rows * 2, src.cols * 2, CV_8UC1);

	for (int y = 0; y < src.rows; y++) {
		for (int x = 0; x < src.cols; x++) {
			int x_ = x * 2;
			int y_ = y * 2;

			dst.at<uchar>(y_, x_) = src.at<uchar>(y, x);
		}
	}

	imshow("src", src);
	imshow("dst", dst);
	waitKey();
}
// 순방향 매핑 - 중간중간 빈칸 발생

void resize2()
{
	Mat src = imread("camera.bmp", IMREAD_GRAYSCALE);

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

	Mat dst = Mat::zeros(src.rows * 2, src.cols * 2, src.type());

	for (int y_ = 0; y_ < dst.rows; y_++) {
		for (int x_ = 0; x_ < dst.cols; x_++) {
			int x = x_ / 2;
			int y = y_ / 2;
			dst.at<uchar>(y_, x_) = src.at<uchar>(y, x);
		}
	}

	imshow("src", src);
	imshow("dst", dst);
	waitKey();
} // 백워드 매핑

보간법

- 실수 좌표 상에서의 픽셀 값을 결정하기 위해 주변 픽셀 값을 이용하여 값을 추정하는 방법

 

최근방 이웃 보간법

- 가장 가까운 위치에 있는 픽셀의 값을 참조

 

양선형 보간법

- 실수 좌표를 둘러싸고 있는 네 개의 픽셀 값에 가중치를 곱한 값들의 선형 합으로 결과 영상의 픽셀 값을 구하는 방법

- 계단 현상 감소

 

3차 보간법

- 실수 좌표를 둘러싸고 있는 16개의 픽셀 값에 3차 함수를 이용한 가중치를 부여하여 영상의 픽셀 값을 구하는 방법

void resize(InputArray src, OutputArray dst, Size desuze,
			douvle fx =0, douvle fy =0, int interpolation = INTER_LINEAR);

 

회전 변환

- 영상을 특정 각도만큼 회전시키는 변환

Mat getRotationMatrix2D(Point2f center, double angle, double scale);

 

동차 좌표계

- 차원의 좌표를 1차원 증가시켜 표현하는 방법

 

대칭 변환

- 영상의 상하 대칭, 좌우 대칭, 원점 대칭

void flip(InputArray src, OutputArray dst, int flipCode);

 

어파인 변환 행렬 구하기

Mat getAffineTransform( const Point2f src[], const Point2f dst[] );
Mat getAffineTransform( InputArray src, InputArray dst );

어파인 변환

void warpAffine( InputArray src, OutputArray dst,
                              InputArray M, Size dsize,
                              int flags = INTER_LINEAR,
                              int borderMode = BORDER_CONSTANT,
                              const Scalar& borderValue = Scalar());

 

투시 변환 행렬 구하기

Mat getAffineTransform( InputArray src, InputArray dst );
Mat getPerspectiveTransform(InputArray src, InputArray dst, int solveMethod = DECOMP_LU);

투시 변환

void warpPerspective( InputArray src, OutputArray dst,
                                   InputArray M, Size dsize,
                                   int flags = INTER_LINEAR,
                                   int borderMode = BORDER_CONSTANT,
                                   const Scalar& borderValue = Scalar());

 

버드아이뷰 만들기

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

using namespace std;
using namespace cv;

int main()
{
	VideoCapture cap("../../data/test_video.mp4");

	if (!cap.isOpened()) {
		cerr << "Video open failed!" << endl;
		return -1;
	}

	Mat src;
	while (true) {
		cap >> src;

		if (src.empty())
			break;

		int w = 500, h = 260;

		vector<Point2f> src_pts(4);
		vector<Point2f> dst_pts(4);

		src_pts[0] = Point2f(474, 400);	src_pts[1] = Point2f(710, 400);
		src_pts[2] = Point2f(866, 530); src_pts[3] = Point2f(366, 530);

		dst_pts[0] = Point2f(0, 0);		dst_pts[1] = Point2f(w - 1, 0);
		dst_pts[2] = Point2f(w - 1, h - 1);	dst_pts[3] = Point2f(0, h - 1);

		Mat per_mat = getPerspectiveTransform(src_pts, dst_pts);

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

#if 1
		vector<Point> pts;
		for (auto pt : src_pts) {
			pts.push_back(Point(pt.x, pt.y));
		}
		polylines(src, pts, true, Scalar(0, 0, 255), 2, LINE_AA);
#endif

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

		if (waitKey(10) == 27)
			break;
	}
}

 

리매핑

- 영상의 특정 위치 픽셀을 다른 위치에 재배치하는 일반적인 프로세스

- 어파인 변환, 투시 변환을 포함한 다양한 변환을 리매핑으로 표현 가능

void remap( InputArray src, OutputArray dst,
                         InputArray map1, InputArray map2,
                         int interpolation, int borderMode = BORDER_CONSTANT,
                         const Scalar& borderValue = Scalar());