[opencv] image rotate

Computer Vision에 관한 글을 쓸땐 항상 예시 사진을 무엇으로 할지 고민하는데 그 점이 좋다.
(좋은게 좋은거라고)

opencv를 제대로 파질 않았지만, 확실한건 하나 있다.

바로 이미지의 자료형이 IplImage , cv::Mat 이렇게 2가지가 있는데, 전자는 C언어용인거 같고, 후자는 C++ 용인거 같다. 그럴수 밖에없다.

근데 이게 호환이 되니까, 막 함수들을 섞어 쓰고 이러는데

글쎄..

아무튼! 나는 namespace cv; 에 있는 함수들로 가겠다.

1. 내부 회전

내부 회전은 창의 크기가 고정된채(원래 이미지의 크기) 이미지가 중심축을 기준으로 회전한다.

2. 외부 회전

외부 회전은 일단 회전을 하고, 그 회전된 이미지에 Fitting 된 이미지가 생성된다.

내부 회전의 경우 간단하게 회전 공식을 쓰면 부가적인 정보도 같이 회전이 가능하지만,

외부 회전은 내부 변수의 값이 필요하다. (아래 소스코드에서 cv::Point* out)

[100,100] 을 같이 회전시키면 아래와 같이 나온다.

#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core.hpp>

#ifdef _DEBUG
#pragma comment(lib,"opencv_world310d.lib")
#else
#pragma comment(lib,"opencv_world310.lib")
#endif

using namespace std;

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);
}
cv::Mat ImageRotateInner(const cv::Mat src, double degree, cv::Point2d base) {  
    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);
}
#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;
}