MFC 에서 OpenCV 의 cvGetQuadrangleSubPix 를 이용한 이미지 회전

C# & MFC

MFC 에서 OpenCV cvGetQuadrangleSubPix 를 이용한 이미지 회전

 

개발환경 : window 7 32bit, Visual Studio 2010, OpenCV 2.3.4

 

행열을 이용해서 이미지를 회전한다. 아래 예제는 45도 회전한 것인데

회전을 하게 되면 픽셀값이 없는 부분이 나타나게 된다. 이것은 화상 경계의

외측에 있는 픽셀값을 확장해서 보여준다.

 

 

(1) 소스설명

 

먼저 cvCloneImage 를 사용해서 이미지를 복사한다.

 

IplImage* pDstImg = 0 ; 
// 복사 
pDstImg = cvCloneImage (m_pImage); 

 

회전을 위한 행렬을 초기화 한다. CvMat 을 사용하며 아래와 같이 초기화 한다.

초기화 함수는 cvInitMatHeader 이다.

float m[6]; 
m [0] = (float)(cos(angle * CV_PI / 180)); 
m [1] = (float)(- sin(angle * CV_PI / 180)); 
m [2] = pDstImg->width * 0.5 ; 
m [3] = -m [1]; 
m [4] = m [0]; 
m [5] = m_pImage->height * 0.5 ; 
cvInitMatHeader (&M, 2, 3, CV_32FC1, m, CV_AUTOSTEP); 

 

2차원 회전행렬 공식은 다음과 같다.

이것을 풀어 쓴다면 아래와 같이 된다.

X' = x * cosθ - y * sinθ

Y' = x * sinθ + y * cosθ

 

위의 공식을 기반으로 소스코드를 해석해보자. Angle 는 회전 각도를 나타낸다.

              | A11 A12 b1 |

map_matrix = |             |

              | A21 A22 b2 |

 

m[0] = A11 = cos(angle*π/180)

m[1] = A12 = -sin(angle*π/180)

m[2] = b1 = 회전 중심의 x 좌표

m[3] = A21 = sin(angle*π/180)

m[4] = A22 = cos(angle*π/180)

m[5] = b2 = 회전 중심의 y 좌표

 

dst(x, y) = src( A11x' + A12y' + b1, A21x' + A22y' + b2 )

 

지정된 회전 행렬에 의해 cvGetQuadrangleSubPix 함수를 사용해서 이미지를

회전 시킨다. M cvInitMatHeader 에서 초기화한 값이다.

 

cvGetQuadrangleSubPix(m_pImage , pDstImg ,  &M ); 

 

(1) 전체소스

 

전체소스는 아래와 같다.

// 이미지 회전 
void CTotalVisionDlg::OnBnClickedBtnTransform()
{
	if (m_pImage == NULL) 
		return;

	int angle = 45 ; 
	float m[6]; 
	IplImage* pDstImg = 0 ; 
	CvMat M ; 

	// 복사 
	pDstImg = cvCloneImage (m_pImage); 

	// 회전을위한 행렬 (아핀 행렬) 요소를 설정하고 CvMat 행렬 M을 초기화 
	m [0] = (float)(cos(angle * CV_PI / 180)); 
	m [1] = (float)(- sin(angle * CV_PI / 180)); 
	m [2] = pDstImg->width * 0.5 ; 
	m [3] = -m [1]; 
	m [4] = m [0]; 
	m [5] = m_pImage->height * 0.5 ; 
	cvInitMatHeader (&M, 2, 3, CV_32FC1, m, CV_AUTOSTEP); 

	// 지정된 회전 행렬은 GetQuadrangleSubPix을 이용해 이미지 전체를 회전 
	cvGetQuadrangleSubPix(m_pImage , pDstImg ,  &M ); 
	
	// 표현 
	CRect rt;
	CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC_CHANGE1);
	pStatic->GetClientRect(rt);
	CDC* pDC = pStatic->GetDC();

	m_cImage.CopyOf(pDstImg); 
	m_cImage.DrawToHDC(pDC->m_hDC, rt); 
	m_cImage.Destroy();

	cvReleaseImage(&pDstImg);
	ReleaseDC(pDC);
}
Posted by 녹두장군