cv::rotate(img, img, cv::ROTATE_90_CLOCKWISE);
cv::ROTATE_90_CLOCKWISE
는 시계방향 회전.
cv::ROTATE_90_COUNTERCLOCKWISE
는 반시계방향 회전.
cv::Mat ImageRotateInner(const cv::Mat src, double degree
, cv::Point2f base=cv::Point2f(std::numeric_limits<float>::infinity())) {
if (base.x == std::numeric_limits<float>::infinity()) {
base.x = src.cols / 2;
base.y = src.rows / 2;
}
cv::Mat dst = src.clone();
cv::Mat rot = cv::getRotationMatrix2D(base, degree, 1.0);
cv::warpAffine(src, dst, rot, src.size());
return std::move(dst);
}
내부 회전은 창의 크기가 고정된채(원래 이미지의 크기) 이미지가 중심축을 기준으로 회전한다.
cv::Mat ImageRotateOuter(const cv::Mat src, double degree, cv::Point* out = nullptr) {
cv::Point2d base(src.cols / 2.0, src.rows / 2.0);
cv::Mat rot = cv::getRotationMatrix2D(base, degree, 1.0);
cv::Rect bbox = cv::RotatedRect(base, src.size(), degree).boundingRect();
rot.at<double>(0, 2) += bbox.width / 2.0 - base.x;
rot.at<double>(1, 2) += bbox.height / 2.0 - base.y;
if (out != nullptr){
out->x = bbox.width / 2.0 - base.x;
out->y = bbox.height / 2.0 - base.y;
}
cv::Mat dst;
cv::warpAffine(src, dst, rot, bbox.size());
return std::move(dst);
}
외부 회전은 일단 회전을 하고, 그 회전된 이미지에 Fitting 된 이미지가 생성된다.
내부 회전의 경우 간단하게 회전 공식을 쓰면 부가적인 정보도 같이 회전이 가능하지만,
외부 회전은 내부 변수의 값이 필요하다. (아래 소스코드에서 cv::Point* out)
점 [100,100] 을 같이 회전시키면 아래와 같이 나온다.
#define IMSHOW(IMG) cv::imshow(#IMG,IMG)
int main() {
double angle = 30;
cv::Mat img = cv::imread("SeoYuri.jpg");
cv::Point2d mid(img.cols / 2.0, img.rows / 2.0);
//============
cv::Point pt(100, 100);
cv::Point adding;
cv::Mat inner = ImageRotateInner(img, angle, mid);
cv::Mat outer = ImageRotateOuter(img, angle, &adding);
cv::circle(img, pt, 3, cv::Scalar(255, 0, 255));
cv::Point after;
double rad = -angle*CV_PI / 180.0;
after.x = (pt.x - mid.x)*cos(rad) - (pt.y - mid.y)*sin(rad) + mid.x;
after.y = (pt.x - mid.x)*sin(rad) + (pt.y - mid.y)*cos(rad) + mid.y;
cv::circle(inner, after, 3, cv::Scalar(255, 0, 255));
after.x += adding.x;
after.y += adding.y;
cv::circle(outer, after, 3, cv::Scalar(255, 0, 255));
IMSHOW(img);
IMSHOW(inner);
IMSHOW(outer);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}