cv::warpPerspective only shows part of warped image

Einar Sundgren picture Einar Sundgren · Mar 6, 2014 · Viewed 7.7k times · Source

Im changing an image from front perspective to a bids eye view by using getHomography and warpPerspective.

It works in that the image warps to the desired perspective but the crop is off. It moves the warped image largely outside the image box. I assume the reason is because the operation results in negative coordinates.

I have calculated the points for calculation of the translation matrix manually and not by using any of opencv:s functions for doing that since i.e. the chessboard functions failed to detect the proper points.

I guess this can be fixed by doing additional changes to the transformation matrix. But how is that done? Also, is there a way to make sure the transformed image is centered along the x-axis and then let the y-axis be adjusted to a desired position?

Code snippet that does the job now:

cv::Mat image; // image is loaded with the original image

cv::Mat warpPers; // The container for the resulting image
cv::Mat H;

std::vector<cv::Point2f> src;
std::vector<cv::Point2f> dst;

// In reality several more points.
src.push_back(cv::Point2f(264,301));
src.push_back(cv::Point2f(434,301));
src.push_back(cv::Point2f(243,356));
src.push_back(cv::Point2f(476,356));

dst.push_back(cv::Point2f(243,123));
dst.push_back(cv::Point2f(476,123));
dst.push_back(cv::Point2f(243,356));
dst.push_back(cv::Point2f(476,356));

H = cv::findHomography(src, dst, CV_RANSAC);

cv::warpPerspective(image, 
newPers,
H,
cv::Size(3000,3000),
cv::INTER_NEAREST | CV_WARP_FILL_OUTLIERS
);

cv::namedWindow("Warped persp", cv::WINDOW_AUTOSIZE );
cv::imshow( "Warped persp", newPers);

Answer

user3529407 picture user3529407 · Apr 13, 2014

Opencv gives very convenient way to do perpective transform. The only thing you have to do is take care of the homography return by findHomography. Indeed, maybe some points of the image you provide go in the negative part of the x or y axis. So you have to do some check before warp the image.

step 1: find the homography H with findHomography you will get a classic structure for homography

H = [ h00, h01, h02;
      h10, h11, h12;
      h20, h21,   1];

step 2: search the position of image's corners after warping

So let me define the order for the corner:

(0,0) ________ (0, w)
     |        |
     |________|
(h,0)          (h,w)

To do that, just create a matrix like that:

P = [0, w, w, 0;
     0, 0, h, h;
     1, 1, 1, 1]

Make the product with H and get the warped coordinates:

P' = H * P

step 3: check the minimum in x and y with these new 4 points and get the size of warped image After, you have done the product you will receive something like that:

P' = [s1*x1, s2*x2, s3*x3, s4*x4;
      s1*y1, s2*y2, s3*y3, s4*y4;
      s1   , s2   , s3   , s4]

So to obtain, new valid coordinate just divide line 1 and 2 by the line 3

After that check the minimum for the column on the first line, and the minimum for the row on the second line (use cvReduce)

to find the bounding box that will contains the image (ie the dimension of the dst matrix for the warpPerspective function) just find with cvReduce the maximum over each line

let minx be the minimum on the first row (ie for column), maxx (the maximum for the 1 row) miny and maxy for the second row.

So the size of the warped image should be cvSize(maxx-minx, maxy-miny)

step 4: add a correction to the homography Check if minx and/or miny is/are negative, if minx < 0 then add -minx to h02 and if miny < 0, then add -miny to h12

so H should be:

H = [ h00, h01, h02-minx; //if minx <0
      h10, h11, h12-miny; //if miny <0
      h20, h21,   1];

step 5: warp the image