1

我正在使用 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 ;
}

所有这些代码都基于 O'Reilly 的 OpenCV 书的鸟瞰投影示例。我认为生成的图片是正确的,但在我确定之前我不确定。

4

2 回答 2

3

首先,我看到您正在覆盖 objPts[0] 而不是使用 objPts[1] 到 [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 像素宽的图像!这解释了您获得的结果。

为了得到你想要的,你应该在上面示例的第二列中使用你想要的鸟瞰图像中的国际象棋图案的图像(像素)坐标。例如,如果您希望每个正方形为 10x10 像素,请将值乘以 10。

另外,请记住,您没有校正镜头失真(无论如何看起来并不大),并且图案似乎不是完全平坦,因此您可能会在生成的图像中以略微弯曲的线条形式出现一些“瑕疵” .

希望这可以帮助!

于 2013-04-26T13:17:11.213 回答
2

因此,感谢 Milo 对 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 ;

而且效果很好!每个图像都会有所不同,因此请使用基本值以及要将图像转换为多大/小。

于 2013-04-28T21:04:05.023 回答