2011-11-11 152 views
7

我正在研究OpenCV中的Panography/Panorama應用程序,我遇到了一個我實際弄不懂的問題。想了解全景照片是什麼樣子的,請看這裏的Panography百科文章:http://en.wikipedia.org/wiki/PanographyOpenCV findHomography問題

到目前爲止,我可以拍攝多張圖像,並將它們拼接在一起,同時使任何圖像成爲我喜歡的參考圖像;這是我的意思。

An example Panography image I've created

然而,正如你所看到的 - 它有很多的問題。我面對的主要問題是圖像被切割(重新:最右邊的圖像,圖像的頂部)。爲了突出爲什麼發生這種情況,我就畫已匹配點,並繪製了其中的轉變將結束行:

The image matches

其中左圖像是參考圖像,右圖像是它被翻譯後的圖像(原文如下) - 我畫了綠線以突出圖像。圖像有以下角點:

TL: [234.759, -117.696] 
TR: [852.226, -38.9487] 
BR: [764.368, 374.84] 
BL: [176.381, 259.953] 

所以我的主要問題是,經過角度已經改變形象:

Original Image

遭受的損失,像這樣:

Cut up image

現在已經足夠的圖像,一些代碼。

我使用的是cv::SurfFeatureDetectorcv::SurfDescriptorExtractorcv::FlannBasedMatcher獲得所有這些點,我計算了比賽和做更重要的是精彩的比賽如下:

/* calculate the matches */ 
for(int i = 0; i < descriptors_thisImage.rows; i++) { 
    double dist = matches[i].distance; 
    if(dist < min_dist) min_dist = dist; 
    if(dist > max_dist) max_dist = dist; 
} 

/* calculate the good matches */ 
for(int i = 0; i < descriptors_thisImage.rows; i++) { 
    if(matches[i].distance < 3*min_dist) { 
     good_matches.push_back(matches[i]); 
    } 
} 

這是非常標準的,併爲此,我跟着教程這裏找到:http://opencv.itseez.com/trunk/doc/tutorials/features2d/feature_homography/feature_homography.html

要複製圖像彼此頂上,我用下面的方法(其中img1img2std::vector<cv::Point2f>

/* set the keypoints from the good matches */ 
for(int i = 0; i < good_matches.size(); i++) { 
    img1.push_back(keypoints_thisImage[ good_matches[i].queryIdx ].pt); 
    img2.push_back(keypoints_referenceImage[ good_matches[i].trainIdx ].pt); 
} 

/* calculate the homography */ 
cv::Mat H = cv::findHomography(cv::Mat(img1), cv::Mat(img2), CV_RANSAC); 

/* warp the image */ 
cv::warpPerspective(thisImage, thisTransformed, H, cv::Size(thisImage.cols * 2, thisImage.rows * 2), cv::INTER_CUBIC); 

/* place the contents of thisImage in gsThisImage */ 
thisImage.copyTo(gsThisImage); 

/* set the values of gsThisImage to 255 */ 
for(int i = 0; i < gsThisImage.rows; i++) { 
    cv::Vec3b *p = gsThisImage.ptr<cv::Vec3b>(i); 
    for(int j = 0; j < gsThisImage.cols; j++) { 
     for(int grb=0; grb < 3; grb++) { 
      p[j][grb] = cv::saturate_cast<uchar>(255.0f); 
     } 
    } 
} 

/* convert the colour to greyscale */ 
cv::cvtColor(gsThisImage, gsThisImage, CV_BGR2GRAY); 

/* warp the greyscale image to create an image mask */ 
cv::warpPerspective(gsThisImage, thisMask, H, cv::Size(thisImage.cols * 2, thisImage.rows * 2), cv::INTER_CUBIC); 

/* stitch the transformed image to the reference image */ 
thisTransformed.copyTo(referenceImage, thisMask); 

所以,我有座標扭曲的圖像將在哪裏結束,我有點創建用於這些轉換的同質矩陣 - 但我無法弄清楚我應該如何去翻譯這些圖像,以便它們不會被切斷。任何幫助或指針非常感謝!

回答

5

首先,您爲什麼不使用新添加的拼接模塊?它完全符合你想要做的事情。

其次,如果你想繼續你的代碼,糾正它很容易。在單應性矩陣中,翻譯表示最後一列的值。

a11 a12 a13 t1 
a21 a22 a23 t2 
a31 a32 a33 t3 
a41 a42 a43 1 

(如果你有一個3x3矩陣,你將錯過a13..a43列和a41..1一行。A33將(應該)變爲1)。

所以,你需要做的是找出你應該放在最後一列,以便圖像對齊。

請檢查這篇文章,解釋(某種程度上相反的問題)如何建立單應性,當你知道相機參數。它會幫助你理解矩陣值的作用。

Opencv virtually camera rotating/translating for bird's eye view

而且一切我告訴你最後一欄只是近似,因爲在最後一列中的值實際上是翻譯加上一些(未成年人)的因素。

+1

啊,我明白了 - 在我運行cv :: warpPerspective之前,我編輯了全息圖中的值?現在非常明顯!非常感謝!另外,我會研究圖像拼接模塊並將其添加爲一個選項(也可以使用GPU和CPU比較差異) - 只是試圖學習OpenCV。 :-) – krslynx

+1

再次感謝! http://krslynx.com/images/ – krslynx

+1

很高興看到你的好成績! – Sam

1

一旦找到矩陣,您應該計算角點的變換並收集變換點的最小值和最大值x和y值。

一旦你有了這個邊框只是(-xmin,-ymin)翻譯所有矩陣並分配結果的圖像是(xmax-xmin)(ymax-ymin)高大,然後繪製所有圖像轉化成。

使用這種方法,您將在拼接周圍產生黑色區域,但無裁剪。

自動查找包含在拼接中的最大矩形(以獲得完全合併的圖像,沒有黑色區域和最小限幅),實現起來會相當麻煩。