OpenCV 單應矩陣應用:全景圖像融合原理

Jacob的全景圖像融合算法系列
OpenCV 尺度不變特征檢測:SIFT、SURF、BRISK、ORB
OpenCV 匹配興趣點:SIFT庆聘、SURF 和二值描述子
OpenCV 估算圖像的投影關系:基礎矩陣和RANSAC
OpenCV 單應矩陣應用:全景圖像融合原理
圖像融合:拉普拉斯金字塔融合算法

之前的寫了好幾篇文,什么特征點檢測氛谜,匹配掏觉,RANSAC之類的亂七八糟的,就是為了做這個應用值漫。了解原理之后用NI Vision實現(xiàn)澳腹,數(shù)圖的課程設計算是交差了~~全景圖像融合使用到SIFT算子(特征點檢測和匹配)、單應矩陣(立體幾何)和RANSAC(隨機抽樣一致性)之類的內容杨何,了解其中的領域和原理還是需要花點時間的酱塔。


霸氣側漏的全景圖

1.單應矩陣

X是空間中的一點,左右兩邊是射影平面(攝像頭)

單應(Homography)是射影幾何中的概念危虱,又稱為射影變換羊娃。它把一個射影平面上的點(三維齊次矢量)映射到另一個射影平面上。單應是關于三維齊次矢量的一種線性變換埃跷,可以用一個3×3的非奇異矩陣H表示蕊玷,這個矩陣H稱為單應矩陣。使用這個矩陣弥雹,就可以將射影平面上的一個點投影到另一個平面上(圖中的 m 投影到 m‘)垃帅。
線性變換

平面上的點為三維齊次矢量,即
單應矩陣H可以將兩幅圖像關聯(lián)起來

2.與基礎矩陣的區(qū)別

基礎矩陣體現(xiàn)的是兩個圖像間的對極約束(詳細見我之前的一篇文章)剪勿。兩個圖像之間的對極約束與場景的結構無關贸诚,也就是說你拍攝的物體可以是一個球,或者其他奇形怪狀的物體〗垂蹋基礎矩陣不能給出兩幅圖像的像點的一一對應的關系械念,只能給出像點到另一幅圖像的對極線的映射關系。

基礎矩陣F描述的實際是一種點和線的映射關系运悲,而不是點對點的關系龄减,不能給出另一個點的確切位置。

也就說扇苞,三維點如果不是在同一個平面上欺殿,可以使用基礎矩陣F來計算圖像上像點在另一幅圖像上對應的對極線寄纵,而不能使用單應矩陣H得到對應點的確切位置鳖敷。在實際應用中,當被拍攝物體深度Z比較大的時候程拭,可以視為一個平面來處理定踱,也可以使用單應矩陣來進行點對點的映射。

從公式推導中恃鞋,我們可以得到崖媚,當射影平面之間只有旋轉無平移時,也可以使用單應矩陣來進行映射恤浪,這里不進行推導畅哑。

如果拍攝物體不為平面(或不能視為平面來處理)并且射影平面之間不只有旋轉關系時時,強行估算單應矩陣水由,會產生巨大偏差荠呐。

假設強行使用單應矩陣

p'應映射到x2',但被映射到了x2

通過平面P上的匹配點得到了單應矩陣H之后砂客,再用來估計不在平面P上的點 p' 的位置泥张,就會出現(xiàn)這樣的情況。

3.通過匹配點來計算單應矩陣

關于特征點匹配的內容可以看我之前的文章(為了今天算是磨刀三月- -)鞠值,為了提高匹配準確率媚创,這里使用的是SIFT算子配合上RANSAC算法的方式進行估計。

兩圖像上的像點 p1(x1,y1) p2(x2,y2) 是一對匹配的點對彤恶,其單應矩陣為H钞钙,則有

矩陣形式

展開得

第三個方程為約束條件

那么就至少需要4對匹配點(4個方程組)進行計算(任意三點不共線)

4.代碼實現(xiàn)

/********************************************************************
 * Created by 楊幫杰 on 10/12/18
 * Right to use this code in any way you want without
 * warranty, support or any guarantee of it working
 * E-mail: yangbangjie1998@qq.com
 * Association: SCAU 華南農業(yè)大學
 ********************************************************************/

#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/stitching.hpp>

#define PARLIAMENT01 "/home/jacob/圖片/images/parliament1.jpg"
#define PARLIAMENT02 "/home/jacob/圖片/images/parliament2.jpg"

using namespace cv;
using namespace std;

int main()
{
    Mat image1= imread(PARLIAMENT01,0);
    Mat image2= imread(PARLIAMENT02,0);
    if (!image1.data || !image2.data)
        return 0;

    imshow("Image 1",image1);
    imshow("Image 2",image2);

    vector<KeyPoint> keypoints1;
    vector<KeyPoint> keypoints2;
    Mat descriptors1, descriptors2;

    //創(chuàng)建SIFT檢測器
    Ptr<Feature2D> ptrFeature2D = xfeatures2d::SIFT::create(74);

    //檢測SIFT特征并生成描述子
    ptrFeature2D->detectAndCompute(image1, noArray(), keypoints1, descriptors1);
    ptrFeature2D->detectAndCompute(image2, noArray(), keypoints2, descriptors2);

    cout << "Number of feature points (1): " << keypoints1.size() << endl;
    cout << "Number of feature points (2): " << keypoints2.size() << endl;

    //使用歐氏距離和交叉匹配策略進行圖像匹配
    BFMatcher matcher(NORM_L2, true);
    vector<DMatch> matches;
    matcher.match(descriptors1,descriptors2,matches);

    Mat imageMatches;
    drawMatches(image1,keypoints1,  // 1st image and its keypoints
                image2,keypoints2,  // 2nd image and its keypoints
                matches,            // the matches
                imageMatches,       // the image produced
                Scalar(255,255,255),  // color of the lines
                Scalar(255,255,255),  // color of the keypoints
                vector<char>(),
                2);

    imshow("Matches (pure rotation case)",imageMatches);

    //將keypoints類型轉換為Point2f
    vector<Point2f> points1, points2;
    for (vector<DMatch>::const_iterator it= matches.begin();
         it!= matches.end(); ++it)
    {
        float x= keypoints1[it->queryIdx].pt.x;
        float y= keypoints1[it->queryIdx].pt.y;
        points1.push_back(Point2f(x,y));

        x= keypoints2[it->trainIdx].pt.x;
        y= keypoints2[it->trainIdx].pt.y;
        points2.push_back(Point2f(x,y));
    }

    cout << "number of points: " << points1.size() << " & " << points2.size() << endl;

    //使用RANSAC算法估算單應矩陣
    vector<char> inliers;
    Mat homography= findHomography(
                    points1,points2, // corresponding points
                    inliers,         // outputed inliers matches
                    RANSAC,      // RANSAC method
                    1.);             // max distance to reprojection point

    //畫出局內匹配項
    drawMatches(image1, keypoints1,  // 1st image and its keypoints
                image2, keypoints2,  // 2nd image and its keypoints
                matches,            // the matches
                imageMatches,       // the image produced
                Scalar(255, 255, 255),  // color of the lines
                Scalar(255, 255, 255),  // color of the keypoints
                inliers,
                2);

    imshow("Homography inlier points", imageMatches);

    //用單應矩陣對圖像進行變換
    Mat result;
    warpPerspective(image1, // input image
                    result,         // output image
                    homography,     // homography
                    Size(2*image1.cols,image1.rows)); // size of output image

    //拼接
    Mat half(result,Rect(0,0,image2.cols,image2.rows));
    image2.copyTo(half);

    imshow("Image mosaic",result);

    waitKey();
    return 0;
}

結果如下

興趣點匹配

拼接結果

可以看到通過變換視角,可以對圖像進行拼接声离。當然距離真正的全景圖像的合成還有點距離芒炼,比如說有明顯邊界,扭曲嚴重等問題抵恋。OpenCV3中提供了一個函數(shù)叫stitcher焕议,可以得到比較好的拼接效果。接下來的一段時間就需要我去研究一下里面的實現(xiàn)了,敬請期待吧 →_→!

References:
SLAM入門之視覺里程計(5):單應矩陣
Opencv Sift和Surf特征實現(xiàn)圖像無縫拼接生成全景圖像
opencv計算機視覺編程攻略(第三版) —— Robert Laganiere

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末盅安,一起剝皮案震驚了整個濱河市唤锉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌别瞭,老刑警劉巖窿祥,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蝙寨,居然都是意外死亡晒衩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門墙歪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來听系,“玉大人,你說我怎么就攤上這事虹菲】渴ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵毕源,是天一觀的道長浪漠。 經常有香客問我,道長霎褐,這世上最難降的妖魔是什么址愿? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮冻璃,結果婚禮上响谓,老公的妹妹穿的比我還像新娘。我一直安慰自己俱饿,他們只是感情好歌粥,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拍埠,像睡著了一般失驶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枣购,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天嬉探,我揣著相機與錄音,去河邊找鬼棉圈。 笑死涩堤,一個胖子當著我的面吹牛,可吹牛的內容都是我干的分瘾。 我是一名探鬼主播胎围,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了白魂?” 一聲冷哼從身側響起汽纤,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎福荸,沒想到半個月后蕴坪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡敬锐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年背传,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片台夺。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡径玖,死狀恐怖,靈堂內的尸體忽然破棺而出谒养,到底是詐尸還是另有隱情挺狰,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布买窟,位于F島的核電站,受9級特大地震影響薯定,放射性物質發(fā)生泄漏始绍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一话侄、第九天 我趴在偏房一處隱蔽的房頂上張望亏推。 院中可真熱鬧,春花似錦年堆、人聲如沸吞杭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芽狗。三九已至,卻和暖如春痒蓬,著一層夾襖步出監(jiān)牢的瞬間童擎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工攻晒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留顾复,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓鲁捏,卻偏偏與公主長得像芯砸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354