#findHomographyとは
2枚の画像間のホモグラフィ行列の推定に使う関数です.
OpenCVのリファレンスを見ると以下の3つのパターンで使用できることがわかります.
cv::Mat findHomography(const Mat& srcPoints, const Mat& dstPoints, Mat& status, int method=0, double ransacReprojThreshold=3)
cv::Mat findHomography(const Mat& srcPoints, const Mat& dstPoints, vector<uchar>& status, int method=0, double ransacReprojThreshold=3)
cv::Mat findHomography(const Mat& srcPoints, const Mat& dstPoints, int method=0, double ransacReprojThreshold=3)
##パラメータ
srcPoints -> 元平面の点群の座標. CV_32FC2 型の行列,あるいは vector<Point2f>で入力
dstPoints -> 目的平面の点群の座標. CV_32FC2 型の行列,あるいは vector<Point2f>で入力
method -> ホモグラフィ行列を求めるための手法
method入力値 | 説明 |
---|---|
0 | 点の組をすべて利用する通常の手法 |
CV_RANSAC | RANSACアルゴリズムに基づくロバストな手法 |
CV_LMEDS | LMedS推定(Least-Median)によるロバストな手法 |
ransacReprojThreshold ->点の組を,インライア値(外れ値ではないもの)として扱うために許容される逆投影誤差の最大値(これは,RANSACメソッドでのみ利用されます).srcPoints と dstPoints がピクセル単位で表されているならば,このパラメータは1から10の範囲内の値が妥当です.
status -> ロバスト手法( CV_RANSAC または CV_LMEDS )を利用した場合に,オプションとして出力されるマスク. 入力マスク値は無視されることに注意してください.
#RANSACで使用した点のみを出力する
RANSACかLMEDSを使ったときに出力されるstatusには,マッチ点数分の{0,1}が出力されます.
1の点は使用された点(inliner)で,0の点は使用されていない点(outliner)です.
##表示プログラム
対応点の表示とRANSACで選ばれたインライアの対応点の表示をするプログラムはこんな感じです
(汚くてごめんなさい).
#include<iostream>
#include<vector>
#include<string>
#include<fstream>
#include"OpenCV3.h" //OpenCV読み込み自作ヘッダ
using namespace std;
using namespace cv;
int main(void)
{
Mat Src1 = imread("graf1.png");
Mat Src2 = imread("graf3.png");
//キーポイント検出と特徴量記述
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;
Mat descriptors1, descriptors2;
cv::Ptr<cv::AKAZE> akaze = cv::AKAZE::create();
akaze->detectAndCompute(Src1, cv::Mat(), keypoints1, descriptors1);
akaze->detectAndCompute(Src2, cv::Mat(), keypoints2, descriptors2);
//マッチング(knnマッチング)
vector<vector<cv::DMatch>> knnmatch_points;
cv::BFMatcher match(cv::NORM_HAMMING);
match.knnMatch(descriptors1, descriptors2, knnmatch_points, 2);
//対応点を絞る
const double match_par = 0.6; //候補点を残す場合のしきい値
vector<cv::DMatch> goodMatch;
//KeyPoint -> Point2d
vector<cv::Point2f> match_point1;
vector<cv::Point2f> match_point2;
for (size_t i = 0; i < knnmatch_points.size(); ++i) {
double distance1 = knnmatch_points[i][0].distance;
double distance2 = knnmatch_points[i][1].distance;
//第二候補点から距離値が離れている点のみ抽出(いい点だけ残す)
if (distance1 <= distance2 * match_par) {
goodMatch.push_back(knnmatch_points[i][0]);
match_point1.push_back(keypoints1[knnmatch_points[i][0].queryIdx].pt);
match_point2.push_back(keypoints2[knnmatch_points[i][0].trainIdx].pt);
}
}
//ホモグラフィ行列推定
cv::Mat masks;
cv::Mat H = cv::findHomography(match_point1, match_point2, masks, cv::RANSAC, 3);
//RANSACで使われた対応点のみ抽出
vector<cv::DMatch> inlinerMatch;
for (size_t i = 0; i < masks.rows; ++i) {
uchar *inliner = masks.ptr<uchar>(i);
if (inliner[0] == 1) {
inlinerMatch.push_back(goodMatch[i]);
}
}
//対応点の表示
cv::Mat drawmatch;
cv::drawMatches(Src1, keypoints1, Src2, keypoints2, goodMatch,drawmatch);
imwrite("match_point.jpg",drawmatch);
//インライアの対応点のみ表示
cv::Mat drawMatch_inliner;
cv::drawMatches(Src1,keypoints1,Src2,keypoints2,inlinerMatch,drawMatch_inliner);
imwrite("match_inliner.jpg",drawMatch_inliner);
imshow("DrawMatch", drawmatch);
imshow("Inliner", drawMatch_inliner);
waitKey();
return 0;
}
##出力結果
cv::findHomographyに入れる前の対応点
cv::findHomographyに入れた後(RANSACで求めたインライア)の対応点
こんな感じで表示,または利用ができます.