본문 바로가기
opencv

이미지 회전

by 꼰대코더 2023. 11. 27.

회전시(반시계 방향)의 변환 매트릭스는 아래와 같다.

이 매트릭스가 되는 이유는 아래와 같이 삼각함수로 설명이 가능하다.


x좌표(1, 0)를 θ만큼 회전을 시키면 삼각함수 cosθ = x' / 1 과 sinθ = x' / 1  에 의해 x' = cosθ, sinθ 가 된다.
y좌표(0, 1)를 θ만큼 회전을 시키면 삼각함수 sinθ = y' / 1(음수값이므로 -) 과 cosθ = y' / 1  에 의해 y' = -sinθ, cosθ 가 된다.

여기에 회전후 좌표 이동까지 고려한다면 아래와 같다.

 

이에 상응하는 OpenCV 함수는 아래와 같고 

 

리턴하는 매트릭스는 위의 2 x 3 의 형태가 된다.

 

위의 매트릭스를 이미지에 적용하는 함수는 warpAffine() 이다.

 

1. 일반 회전

cv::Mat image = cv::imread("d:\\rotate.png");

cv::Point2f centre(image.cols / 2., image.rows / 2.);
cv::Mat M = cv::getRotationMatrix2D(centre, 23, 1.0);

cv::Mat image2;
cv::warpAffine(image, image2, M, image.size(), cv::INTER_AREA);

cv::imwrite("d:\\rotate1.jpg", image2);

결과는 반시계 방향으로 23도 회전 되었다.

문제는 최종 사이즈 image.size() 에 의해 컷팅당하는 것이다.

2.  회전 & 전체 표시

cv::Mat image = cv::imread("d:\\rotate.png");

cv::Point2f centre(image.cols / 2., image.rows / 2.);
cv::Mat M = getRotationMatrix2D(centre, 23, 1.0);

cv::Rect2f bbox = cv::RotatedRect(cv::Point2f(), image.size(), static_cast<float>(23)).boundingRect2f();
M.at<double>(0, 2) = M.at<double>(0, 2) + bbox.width / 2.0 - image.cols / 2.0;
M.at<double>(1, 2) = M.at<double>(1, 2) + bbox.height / 2.0 - image.rows / 2.0;

cv::Mat image2;
cv::warpAffine(image, image2, M, bbox, cv::INTER_AREA);

cv::imwrite("d:\\rotate1.jpg", image2);

 

 포인트는 cv::RotatedRect() 함수를 이용하여 회전후의 풀사이즈를 얻어서
매트릭스(M)의 이동계수(매트릭스 각 로우의 맨 마지막)를 풀사이즈와 컷팅사이즈 차분의 절반(센터 좌우 고려) 만큼 더 이동시켜 주면 OK