tekapo.png
0.42MB

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

 

dst(x, y) = src(map_x ( x, y ), map_y( x,y ))


//출력영상의 x,y 좌표에서 픽셀 값을 입력영상에서 참조한다.  참조할 픽셀의 x좌표를 map_x , y좌표를 map_y로 표현하여 참조

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

 

 

이동 변환

map_x(x,y) = x - 200    // map_x 함수 : 입력영상 ,  우측  x는 출력영상

map_y(x, y) = y - 100

==> x축 200, y축 100 픽셀 이동

 

eg. x' : 출력 , x:입력

x = x' -200

y = y' - 100 

==>  x' = x+200 ,  y'= y+100   으로 x축으로 200, y축으로 100 픽셀이동

 

상하대칭

map_x(x,y) = x   // x좌표 변환 없음

map_y(x,y) = h - 1 - y      // ( h-1 == y좌표값의 최댓값)

 

영상의 세로크기 -1 에서 y좌표 빼는 형태로 수식 작성 시 y값이 0에 가까울 경우 map_y에 함수 반환값이 h -1에 가깝게 나타나고  y값이 점점  커져서 h에 가깝게 되는 경우 map_y 함수가 반환하는 값은 0에 가까운 값을 반환

 

 

크기변환

map_x(x,y) [입력] = x [출력] /2

map_y(x, y) [입력]= y[출력] /2

==> 가로, 세로 2배 확대.       

(x,y) 에서 x는 0 ~(  2W -1 )   y는 0 ~ ( 2h -1 ) 까지 증가하는 형태로 해당 함수가 정의되야함.

 

 

if x' == 출력 ,  x == 입력 이라하면

x = x'/2   -> x' = 2x

y = y'/2   ->  y' = 2y

 

 

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

dst: map1과 같은 크기 , src와 같은 타입

map1: 결과 영상의 각 픽셀이 참조할 입력 영상의 (x,y) 좌표 또는 x좌표를 담고 있는 행렬.

CV_16SC2, CV_32FC2 또는 CV_32FC1 

 

map2: 결과 영상의 (x,y) 좌표가 참조할 입력영상의 y좌표를 담고 있는 행렬. CV_16UC1 또는 CV_32FC1.

interpolation: 보간법  [ default: INTER_LINEAR ,  좀 더 좋은 영상 나오게 하고싶을시 CUBIC으로 지정하기]

borderMode: 가장자리 픽셀 확장 방식

borderValue: BORDER_CONSTANT일 때 사용할 상수 값

 

 

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

using namespace std;
using namespace cv;


#define TC  2
int main()
{
	Mat src = imread("tekapo.png");

	if (src.empty()) {
		cerr << "Image laod failed!" << endl;
		return -1;
	}
	int w = src.cols;
	int h = src.rows;


#if TC ==1

	Mat map1 = Mat::zeros(h, w, CV_32FC1);
	Mat map2 = Mat::zeros(h, w, CV_32FC1);
	for (int y = 0; y < h; y++) {
		for (int x = 0; x < w; x++) {
			map1.at<float>(y, x) = (float)x;
			//map2.at<float>(y, x) = (float)y;   // x, y (출력영상) 을 map1값 (입력영상)과 동일하게 설정함으로써 입력/출력 영상을 동일한 형태로 만듦
			//map2.at<float>(y, x) = (float)h - 1 - y; // 상하반전   y값이 커지면서 0에 가까운 값을 참조하여 결과 영상을 출력
			map2.at<float>(y,x) = (float)y + 10 * sin(x/32.f);  //  sin 형태  y좌표 그대로,  x좌표 증가함에 따라 sin 커브를 그리는 식으로 픽셀 값 참조.
		}
	}
	Mat dst;
	//remap(src, dst, map1, map2, INTER_LINEAR);
	remap(src, dst, map1, map2, INTER_LINEAR, BORDER_DEFAULT);  // 픽셀값 0으로 채워지지 않코, 비슷한 픽셀값으로 채워짐에 따라 자연스러운 결과물이 나옴.

	//remap(src, dst, map1, map2, INTER_CUBIC, BORDER_DEFAULT);
#elif TC ==2  // remap 함수를 통해 영상 확대할 경우 
	Mat map1 = Mat::zeros(h*2, w*2, CV_32FC1);
	Mat map2 = Mat::zeros(h * 2, w * 2, CV_32FC1);
	for (int y = 0; y < h * 2; y++) {
		for (int x = 0; x < w * 2; x++) {
			map1.at<float>(y, x) = (float)x/2;  // 확대의 경우 나누기 2를 해야함. 곱하기 2는 아님.
			map2.at<float>(y, x) = (float)y / 2; 
			
			
		}
	}
	Mat dst;
	//remap(src, dst, map1, map2, INTER_LINEAR);
	remap(src, dst, map1, map2, INTER_LINEAR, BORDER_DEFAULT);  // 픽셀값 0으로 채워지지 않코, 비슷한 픽셀값으로 채워짐에 따라 자연스러운 결과물이 나옴.

	//remap(src, dst, map1, map2, INTER_CUBIC, BORDER_DEFAULT);

#endif
	imshow("src", src);
	imshow("dst", dst);
	waitKey();

}

+ Recent posts