2009. 10. 27.

[OpenCV] 사진을 엉망으로 만들어보자.


프로젝트를 진행하면서 사진을 뭉게버리는 작업이 필요로했다.
처음에는 smudge algorithm을 구현하고자 했지만 나의 머리에는 한계가 있었다.
논문을 읽어도 머리속에 들어오지 않고 기본적인 openCV의 지식도 없는 상황이라 무엇을 어떻게 해야할지 몰라서
생각했던것이 이미지에서 원의 영역을 잡아서 회전을 시켜보자는 생각으로 만들어나갔다.
기본적으로 사진을 회전하는 예제코드를 보고 시작하니 의외로 어렵지 않게 진행이 되었다.

중심점 (x, y)좌표로부터 반지름이 r인 원을 t각도만큼 회전을 시킨다고 생각했을 때.
원 전체를 t각도만큼 회전을 시킨다면 부드럽지않고 원모양만큼 그저 회전되었다는 느낌밖에 들지 않을 것이다.
따라서 중심으로부터 멀어지면 멀어질수록 회전이 적게되고 중심으로 가까워질수록 회전이 많이 되도록 적용을 하였다.
T = t - ( x / r * t )   (T : 회전될 각도, x : 중심으로부터의 거리, 0<=x<=r)

변형될 image table을 M이라고 하고 원래 image table을 A라고 하고, 원안에 있는 임의의점을 (i, j)라고 둔다. 이 경우 M[i][j]에는 A의 어디에 있는 값을 넣어야하는가를 고민해야했다.
일단 회전될 T값은
T = ((t- (sqrt( pow(x-i,2) + pow(y-j,2))/r*t ))*(PI/180)
가 된다. 그리고 M[i][j]에 들어갈 값은
A[(i-x)*cos(T) - (j-y)*sin(T) + x][(i-x)*sin(T)+(j-y)*cos(T)+y]
가 될 것이다.
이것을 토대로 아래와 같은 코드를 만들었다.


void ImageController::rotationImage(int x, int y, int scale, int angle, int dir)
{
int i, j;
double new_x, new_y, var;
double M_PI = 3.141592654;

IplImage* sourceImage = NULL;
if( modifyImage == NULL ) {
sourceImage = originalImage;
} else {
sourceImage = modifyImage;
}

int height = sourceImage->height;
int width = sourceImage->width;
IplImage *dst_image =
cvCreateImage(cvGetSize(sourceImage), sourceImage->depth, sourceImage->nChannels);

cvSetZero( dst_image );


IplImage *rot_r = cvCreateImage( cvGetSize(sourceImage), IPL_DEPTH_8U, 1 );
IplImage *rot_g = cvCreateImage( cvGetSize(sourceImage), IPL_DEPTH_8U, 1 );
IplImage *rot_b = cvCreateImage( cvGetSize(sourceImage), IPL_DEPTH_8U, 1 );

IplImage *temp_r = cvCreateImage( cvGetSize(sourceImage), IPL_DEPTH_8U, 1 );
IplImage *temp_g = cvCreateImage( cvGetSize(sourceImage), IPL_DEPTH_8U, 1 );
IplImage *temp_b = cvCreateImage( cvGetSize(sourceImage), IPL_DEPTH_8U, 1 );

double radius, sin_value, cos_value;

int centerX = height / 2;
int centerY = width / 2;

cvCvtPixToPlane( sourceImage, rot_r, rot_g, rot_b, NULL );
cvCvtPixToPlane( sourceImage, temp_r, temp_g, temp_b, NULL );

for(i=0; i<height; i++) {
for(j=0; j<width; j++) {

if( sqrt( pow((double)(x-i),2.0) + pow((double)(y-j),2.0) ) <= (double)scale ) {

radius = (( (double)angle - (sqrt( pow((double)(x-i),2.0) + pow((double)(y-j),2.0) )/(double)scale*(double)angle) ))*(M_PI/180.0);
radius *= dir;
sin_value = sin(radius);
cos_value = cos(radius);
new_x = (i-x)*cos_value -(j-y)*sin_value + x;
new_y = (i-x)*sin_value +(j-y)*cos_value + y;

var = cvGetReal2D( rot_r, new_x, new_y);
cvSetReal2D( temp_r, i, j, var );
var = cvGetReal2D( rot_g, new_x, new_y);
cvSetReal2D( temp_g, i, j, var );
var = cvGetReal2D( rot_b, new_x, new_y);
cvSetReal2D( temp_b, i, j, var );
} else {
var = cvGetReal2D( rot_r, i, j);
cvSetReal2D( temp_r, i, j, var );
var = cvGetReal2D( rot_g, i, j);
cvSetReal2D( temp_g, i, j, var );
var = cvGetReal2D( rot_b, i, j);
cvSetReal2D( temp_b, i, j, var );
}
}
}
cvCvtPlaneToPix( temp_r, temp_g, temp_b, NULL, dst_image );

cvReleaseImage(&rot_r);
cvReleaseImage(&rot_g);
cvReleaseImage(&rot_b);
cvReleaseImage(&temp_r);
cvReleaseImage(&temp_g);
cvReleaseImage(&temp_b);
if( modifyImage != NULL ) {
cvReleaseImage( &modifyImage );
}

modifyImage = dst_image;
}



실행결과

사진 : 375*500 pixel
x = 300, y = 200, scale = 100, angle = 30, dir = -1


댓글 없음:

댓글 쓰기