Search on the blog

2014年4月23日水曜日

OpenCV日記(8)アフィン変換

 アフィン変換のtutorialを読みました。

アフィン変換とは、線形写像 + 平行移動で表すことの出来る操作です。

アフィン変換を使うと、
  • 回転
  • 平行移動
  • スケーリング
  • 反射
などを行うことが出来ます。

 これは面白そうです。ということでプログラムを作ってみました。
  1. 画像を表示。
  2. 画像上の点を選び、それらが変換後どこに写像するかを選ぶ。
  3. 写像元 - 写像先のマッピングが3点えられた時点で、対応するアフィン変換行列を計算。
  4. アフィン変換実行。
ということが出来るようにしました。

以下デモです。



以下ソースコードです。
#include <iostream>

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

const char* WINDOW_NAME = "Affine Transform Demo";
Mat img, tmp;
Point2f srcTri[3], dstTri[3];
int ptr = 0;
Scalar circleColors[] = {
    Scalar(255, 0, 0),
    Scalar(0, 255, 0),
    Scalar(0, 0, 255)
};

void applyAfineTransform() {

    std::cout << "------------------------------------------" << std::endl;
    std::cout << "Affine Transform begin." << std::endl;
    for (int i = 0; i < 3; i++) {
        std::cout << srcTri[i] << " is mapped to " << dstTri[i] << std::endl;
    }

    /// Get Affine matrix from mapping info
    Mat affine_mat = getAffineTransform(srcTri, dstTri);

    /// Apply Affine transform
    warpAffine(img, img, affine_mat, img.size());
        
    tmp = img.clone();
    imshow(WINDOW_NAME, img);

    std::cout << "Affine Transform end." << std::endl << std::endl;

}

void mouseClick(int event, int x, int y, int flags, void* userdata) {

    if (event != EVENT_LBUTTONDOWN) 
        return;

    Point2f point(x, y);
    
    if (ptr % 2 == 0)
        srcTri[ptr/2] = point;
    else
        dstTri[ptr/2] = point;

    circle(tmp, point, 6, circleColors[ptr/2], -1, 8, 0);
    imshow(WINDOW_NAME, tmp);

    if (++ptr >= 6) {
        ptr = 0;
        applyAfineTransform();
    }

}

int main( int, char** argv ) {

    img = imread(argv[1], 1);
    tmp = img.clone();

    namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
    setMouseCallback(WINDOW_NAME, mouseClick, NULL);
    imshow(WINDOW_NAME, img);

    waitKey(0);

    return 0;
}

0 件のコメント:

コメントを投稿