Я использую OpenCV, чтобы попытаться получить проекцию с высоты птичьего полета этого изображения:
Сначала я нахожу все внутренние углы шахматной доски и рисую их, как показано здесь
Затем я использую warpPerspective () на нем, но он дает мне очень маленькое искаженное изображение, как показано здесь . Кто-нибудь может понять, что вызывает это?
Вот мой код:
#include <ros/ros.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <vector>
using namespace cv ;
int main(int argc, char* argv[] ) {
ros::init( argc, argv, "bird_view" ) ;
int board_w = atoi(argv[1]);
int board_h = atoi(argv[2]);
cv::Size board_sz( board_w, board_h );
cv::Mat image = cv::imread( "image.jpg" ) ;
cv::Mat gray_image, tmp, H , birds_image;
cv::Point2f objPts[4], imgPts[4] ;
std::vector<cv::Point2f> corners ;
float Z = 1 ; //have experimented from values as low as .1 and as high as 100
int key = 0 ;
int found = cv::findChessboardCorners( image, board_sz, corners ) ;
if (found) {
cv::drawChessboardCorners(image, board_sz, corners, 1) ;
cvtColor( image, gray_image, CV_RGB2GRAY ) ;
cornerSubPix( gray_image, corners, Size(11, 11), Size(-1, -1),
TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1) ) ;
cv::resize( image, tmp, Size(), .5, .5 ) ;
namedWindow( "IMAGE" ) ;
cv::imshow( "IMAGE" , tmp ) ;
waitKey(0) ;
}
objPts[0].x = 0 ;
objPts[0].y = 0 ;
objPts[1].x = board_w-1 ;
objPts[0].y = 0 ;
objPts[0].x = 0 ;
objPts[0].y = board_h-1 ;
objPts[0].x = board_w-1 ;
objPts[0].y = board_h-1 ;
imgPts[0] = corners.at(0) ;
imgPts[1] = corners.at(board_w-1) ;
imgPts[2] = corners.at((board_h-1) * board_w) ;
imgPts[3] = corners.at((board_h-1) * board_w + board_w-1) ;
H = cv::getPerspectiveTransform( objPts, imgPts ) ;
birds_image = image ;
while ( key != 27 ) {
H.at<float>(2,2) = Z ;
cv::warpPerspective( image, birds_image, H, Size( 2 * image.cols, 2 * tmp.rows ) ,
CV_INTER_LINEAR | CV_WARP_INVERSE_MAP | CV_WARP_FILL_OUTLIERS ) ;
cv::imshow( "IMAGE", birds_image ) ;
cv::waitKey(0) ;
}
return 0 ;
}
Весь этот код основан на примере проекции с высоты птичьего полета книги OpenCV О’Рейли. Я думаю, что приведенная картина верна, но я не уверен, пока не увижу ее наверняка.
Прежде всего, я вижу, что вы перезаписываете objPts [0] и не используете objPts1 до [3]:
objPts[0].x = 0 ;
objPts[0].y = 0 ;
objPts[1].x = board_w-1 ;
objPts[0].y = 0 ;
objPts[0].x = 0 ;
objPts[0].y = board_h-1 ;
objPts[0].x = board_w-1 ;
objPts[0].y = board_h-1 ;
Что теперь getPerspectiveTransform делает, чтобы найти преобразование, которое преобразовало бы множество точек p0 … p3 в p0 ‘… p3’, предполагая, что они связаны гомография. Если вы хотите использовать warpPerspective при таком преобразовании оба набора p0 … p3 и p0 ‘… p3’ должны быть выражены в координатах изображения (в пикселях), а это не так, поскольку objPts выражается в произвольных пространственных координатах.
Вы говорите getPerspectiveTransform что вы хотите следующее отображение между углами вашего шахматного шаблона в координатах изображения (в пикселях) и результирующих координат изображения (в пикселях):
corner0 -> (0,0)
corner1 -> (board_w-1, 0)
corner2 -> (0, board_h-1)
corner3 -> (board_w-1, board_h-1)
Итак, если board_w, скажем, 10, вы отображаете свою шахматную доску на изображение шириной 10 пикселей! Что объясняет результат, который вы получаете.
Чтобы получить то, что вы хотите, вы должны использовать во втором столбце приведенного выше примера координаты изображения (пикселя), которые вы хотите для шахматного рисунка на изображении вида птицы. Например, если вы хотите, чтобы каждый квадрат был размером 10х10 пикселей, умножьте значения на 10.
Кроме того, имейте в виду, что вы не исправляете искажение линзы (которое в любом случае не кажется большим), и рисунок кажется не совсем плоским, поэтому вы можете получить некоторые «дефекты» в результирующем изображении в виде слегка изогнутых линий ,
Надеюсь это поможет!
Итак, благодаря разъяснениям Майло о том, что делает getPerspectiveTransform, я немного изменил то, что сделал при указании точек на карте:
std::vector<cv::Point2f> objPts(4) ;
objPts[0].x = 250 ;
objPts[0].y = 250 ;
objPts[1].x = 250 + (board_w-1) * 25 ;
objPts[1].y = 250 ;
objPts[2].x = 250 ;
objPts[2].y = 250 + (board_h-1) * 25 ;
objPts[3].x = 250 + (board_w-1) * 25 ;
objPts[3].y = 250 + (board_h-1) * 25 ;
И это прекрасно работает! Это будет варьироваться для каждого изображения, поэтому поэкспериментируйте с базовым значением и тем, насколько большим / маленьким вы хотите трансформировать изображение.