あいぽんプログラマー

Iphoneを持っていますが、主にAndroid開発についての記事を書いています

Opencvを使ってパノラマ写真を作る

Opencvを使ってパノラマ写真を作る

最近画像処理について勉強していて、パノラマ写真ってどうやっているんだろうと思ったので実際にやってみました。

パノラマ写真の作り方

  1. デジカメやスマフォで画像を複数枚撮る。その際に、あまり動かさないで撮る
  2. 撮った画像それぞれの特徴点と特徴量を抽出する
  3. 異なる2枚の特徴点と特徴量を比較し、2枚の画像間のホモグラフィ行列を求める
  4. 求めたホモグラフィ行列を使って2枚の画像を合成する。

実際にやってみる

  • 材料作り
    今回は以下の2枚の写真です。

f:id:goya813:20141130153857j:plain

f:id:goya813:20141130153901j:plain

  • 特徴点、特徴量の抽出
    今回はOpencvに実装されているSift特徴量を使用します。

  • 画像のマッチング
    さきほど抽出した2枚の画像の特徴点と特徴量をマッチングを行いホモグラフィ行列を求めます。マッチングを行った結果が下のようになっています。

f:id:goya813:20141130173409p:plain

  • 画像の合成
    求めたホモグラフィを使って2枚の画像を合成します。合成した結果が下のようになっています。

f:id:goya813:20141130173412p:plain

ソースコード

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <cv.h>
#include <vector>

int main(int argc, char* argv[])
{
    using cv::imread;
    using cv::Mat;
    using std::vector;
    using cv::imshow;
    using cv::waitKey;
    using cv::Size;
    using cv::Vec3b;

    Mat src[2];
    Mat gray[2];
    Mat result;

    src[0] = imread("2.JPG");
    src[1] = imread("1.JPG");
    cv::cvtColor(src[0], gray[0], CV_BGR2GRAY);
    cv::cvtColor(src[1], gray[1], CV_BGR2GRAY);

    cv::SiftFeatureDetector detector(1000);
    cv::SiftDescriptorExtractor extrator;

    vector<cv::KeyPoint> keypoints[2];
    Mat descriptors[2];
    for (int i = 0; i < 2; i++){
        detector.detect(gray[i], keypoints[i]);
        extrator.compute(gray[i], keypoints[i], descriptors[i]);
    }

    vector<cv::DMatch> matches;
    cv::BruteForceMatcher< cv::L2<float> > matcher;
    matcher.match(descriptors[0], descriptors[1], matches);

    vector<cv::Vec2f> points1(matches.size());
    vector<cv::Vec2f> points2(matches.size());

    for( size_t i = 0 ; i < matches.size() ; ++i )
    {
        points1[i][0] = keypoints[0][matches[i].queryIdx].pt.x;
        points1[i][1] = keypoints[0][matches[i].queryIdx].pt.y;

        points2[i][0] = keypoints[1][matches[i].trainIdx].pt.x;
        points2[i][1] = keypoints[1][matches[i].trainIdx].pt.y;
    }
    
    Mat matchedImg;
    drawMatches(src[0], keypoints[0], src[1], keypoints[1], matches, matchedImg);
    imshow("draw img", matchedImg);
    waitKey();

    Mat homo = cv::findHomography(points1, points2, CV_RANSAC);
    cv::warpPerspective(src[0], result, homo, Size(static_cast<int>(src[0].cols * 1.5), static_cast<int>(src[0].rows * 1.1)));
    waitKey();
    for (int y = 0; y < src[0].rows; y++){
        for (int x = 0; x < src[0].cols; x++){
            result.at<Vec3b>(y, x) = src[1].at<Vec3b>(y, x);
        }
    }

    imshow("result img", result);
    waitKey(0);

    return (0);
}

Written with StackEdit.