【问题标题】:Bird's Eye Projection Error in OpenCVOpenCV中的鸟瞰投影错误
【发布时间】:2013-04-24 20:16:29
【问题描述】:

我正在使用 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 书的鸟瞰投影示例。我认为生成的图片是正确的,但在我确定之前我不确定。

【问题讨论】:

    标签: c++ opencv computer-vision perspective


    【解决方案1】:

    首先,我看到您正在覆盖 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' 的转换,假设它们通过 homography 关联。如果要使用 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。

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

    希望这会有所帮助!

    【讨论】:

      【解决方案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 ;
      

      而且效果很好!它会因每个图像而异,因此请根据基本值以及要将图像转换为多大/小来进行调整。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 2016-10-02
        • 1970-01-01
        相关资源
        最近更新 更多