ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
2

Bird's Eye Projection in OpenCV

asked 2013-04-24 15:42:14 -0500

joshualan gravatar image

updated 2014-04-20 14:09:50 -0500

ngrennan gravatar image

I'm using OpenCV to try to get a bird's eye projection of this image:http://i.imgur.com/lrqEllT.jpg (this image)
I first find all the inner corners of the chessboard and draw them, as shown here http://i.imgur.com/F0EUtYZ.jpg (image)
I then use warpPerspective() on it but it yields me an extremely tiny warped image as shown here http://i.imgur.com/IidNUlm.png (here). Can anyone figure out what is causing this?

Here is my code:

#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 ;
}

All this code is based on O'Reilly's OpenCV book's bird's eye projection example. I think the yielded picture is correct but I am not certain until I see it for sure.

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
1

answered 2014-03-09 22:19:56 -0500

Wolf gravatar image

updated 2014-03-10 00:44:22 -0500

1) +1 for pointing me to this example. Code of the book works as advertised and was what In was looking for=)

2) Your code also look quite good like in the book. Your output image is transformed correctly, however, it is quite small. I observed the same first. I had to apply negative numbers for Z (around -15) to get a nice size of my transformed image. (The lowest number you used was .1, i. e. still positive). I hope this helps.

Edit: As I converted the original C code of the book to cpp with opencv2 API i noted that adjusting Z did not lead to changes in image size. In the orig example the getPerspectiveTransform call was something like:

CvMat *H = cvCreateMat( 3, 3, CV_32F);
cvGetPerspectiveTransform( objPts, imgPts, H);

H was thereby defined to 32F and

 CV_MAT_ELEM(*H,float,2,2) = Z;

worked. If I created a tmp cv::Mat of H and used opencv2 api it still worked:

cv::Mat lo_homography( H );
lo_homography.at<float>(2,2) = Z;

However, as I changed the getPerspectiveTransform to opencv2 API it did no longer work to set Z:

cv::Mat lo_homography = cv::getPerspectiveTransform( (const cv::Point2f*)objPts,  (const cv::Point2f*)imgPts );
lo_homography.at<float>(2,2) = Z; // does not work

The problem was the type of lo_homography, which is CV_64F. The at call has to be with type double:

lo_homography.at<double>(2,2) = Z; // does work

In think this is also valid for the code in your question;)

edit flag offensive delete link more
0

answered 2015-06-29 05:31:31 -0500

Perhaps instead of:

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 ;

It should be:

objPts[0].x = 0 ;
objPts[0].y = 0 ; objPts[1].x = board_w-1 ;
objPts[1].y = 0 ;
objPts[2].x = 0 ; objPts[2].y = board_h-1 ;
objPts[3].x = board_w-1 ;
objPts[3].y = board_h-1 ;

edit flag offensive delete link more

Question Tools

3 followers

Stats

Asked: 2013-04-24 15:42:14 -0500

Seen: 4,544 times

Last updated: Mar 10 '14