試試這個方法:
從4個對應計算單應,給你所有的信息圖像平面和地平面座標之間轉換。
這種方法的侷限性是它假設一個統一參數化的圖像平面(針孔相機),所以鏡頭畸變會給你錯誤,如我的例子所見。如果你能夠消除鏡頭失真的影響,你會很好地採用這種方法,我猜。 此外,你會得到一些錯誤的像素座標作爲你的對應關係,如果你提供更多的對應關係,你可以得到更穩定的值。
使用該輸入圖像

在我從一個圖像處理軟件,這將對應於你知道你的形象4分的事實,閱讀4個角一個國際象棋領域。我選擇這些點(標記爲綠色):

現在我已經做了兩兩件事:第一轉化棋盤圖案的座標圖像(0,0),(0,1)等這給出了一個良好的地圖質量視覺印象。第二我從形象轉變爲世界。讀取棋盤座標中對應於(0,0)的圖像位置(87,291)中的最左角位置。如果我轉換那個像素位置,你會期望(0,0)作爲結果。
cv::Point2f transformPoint(cv::Point2f current, cv::Mat transformation)
{
cv::Point2f transformedPoint;
transformedPoint.x = current.x * transformation.at<double>(0,0) + current.y * transformation.at<double>(0,1) + transformation.at<double>(0,2);
transformedPoint.y = current.x * transformation.at<double>(1,0) + current.y * transformation.at<double>(1,1) + transformation.at<double>(1,2);
float z = current.x * transformation.at<double>(2,0) + current.y * transformation.at<double>(2,1) + transformation.at<double>(2,2);
transformedPoint.x /= z;
transformedPoint.y /= z;
return transformedPoint;
}
int main()
{
// image from http://d20uzhn5szfhj2.cloudfront.net/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/5/2/52440-chess-board.jpg
cv::Mat chessboard = cv::imread("../inputData/52440-chess-board.jpg");
// known input:
// image locations/read pixel values
// 478,358
// 570, 325
// 615,382
// 522,417
std::vector<cv::Point2f> imageLocs;
imageLocs.push_back(cv::Point2f(478,358));
imageLocs.push_back(cv::Point2f(570, 325));
imageLocs.push_back(cv::Point2f(615,382));
imageLocs.push_back(cv::Point2f(522,417));
for(unsigned int i=0; i<imageLocs.size(); ++i)
{
cv::circle(chessboard, imageLocs[i], 5, cv::Scalar(0,0,255));
}
cv::imwrite("../outputData/chessboard_4points.png", chessboard);
// known input: this is one field of the chessboard. you could enter any (corresponding) real world coordinates of the ground plane here.
// world location:
// 3,3
// 3,4
// 4,4
// 4,3
std::vector<cv::Point2f> worldLocs;
worldLocs.push_back(cv::Point2f(3,3));
worldLocs.push_back(cv::Point2f(3,4));
worldLocs.push_back(cv::Point2f(4,4));
worldLocs.push_back(cv::Point2f(4,3));
// for exactly 4 correspondences. for more you can use cv::findHomography
// this is the transformation from image coordinates to world coordinates:
cv::Mat image2World = cv::getPerspectiveTransform(imageLocs, worldLocs);
// the inverse is the transformation from world to image.
cv::Mat world2Image = image2World.inv();
// create all known locations of the chessboard (0,0) (0,1) etc we will transform them and test how good the transformation is.
std::vector<cv::Point2f> worldLocations;
for(unsigned int i=0; i<9; ++i)
for(unsigned int j=0; j<9; ++j)
{
worldLocations.push_back(cv::Point2f(i,j));
}
std::vector<cv::Point2f> imageLocations;
for(unsigned int i=0; i<worldLocations.size(); ++i)
{
// transform the point
cv::Point2f tpoint = transformPoint(worldLocations[i], world2Image);
// draw the transformed point
cv::circle(chessboard, tpoint, 5, cv::Scalar(255,255,0));
}
// now test the other way: image => world
cv::Point2f imageOrigin = cv::Point2f(87,291);
// draw it to show which origin i mean
cv::circle(chessboard, imageOrigin, 10, cv::Scalar(255,255,255));
// transform point and print result. expected result is "(0,0)"
std::cout << transformPoint(imageOrigin, image2World) << std::endl;
cv::imshow("chessboard", chessboard);
cv::imwrite("../outputData/chessboard.png", chessboard);
cv::waitKey(-1);
}
產生的圖像是:

,你可以看到有錯誤的數據一些大的量。正如我所說的,這是因爲像素座標稍微錯誤(作爲對應關係)(並且在一個小區域內!),並且由於鏡頭失真導致地平面在圖像上顯示爲真實平面。
成果轉化(87291)世界座標是:
[0.174595, 0.144853]
預期/完美的結果會一直[0,0]
希望這會有所幫助。
計算從圖像到平面座標的單應性。如果相機是靜態的,不是你需要的嗎? – Micka 2014-09-11 13:29:23