0

I'm looking for a way to crop perspective an image by 4 points. I found this source but when I use from that the result is wrong.

Original source : This is original source

What's the problem?

This is my source :

int main()

{

cv::Mat src = cv::imread("E:\\aaaaaa.jpg");


vector<Point> not_a_rect_shape;
not_a_rect_shape.push_back(Point(2224, 257));
not_a_rect_shape.push_back(Point(372, 393));
not_a_rect_shape.push_back(Point(338, 1498));
not_a_rect_shape.push_back(Point(2397, 1414));

// For debugging purposes, draw green lines connecting those points 
// and save it on disk
const Point* point = &not_a_rect_shape[0];
int n = (int)not_a_rect_shape.size();
Mat draw = src.clone();
polylines(draw, &point, &n, 1, true, Scalar(0, 255, 0), 3, LINE_AA);
imwrite("E:\\draw.jpg", draw);

// Assemble a rotated rectangle out of that info
RotatedRect box = minAreaRect(cv::Mat(not_a_rect_shape));
std::cout << "Rotated box set to (" << box.boundingRect().x << "," << box.boundingRect().y << ") " << box.size.width << "x" << box.size.height << std::endl;

Point2f pts[4];

box.points(pts);

// Does the order of the points matter? I assume they do NOT.
// But if it does, is there an easy way to identify and order 
// them as topLeft, topRight, bottomRight, bottomLeft?

cv::Point2f src_vertices[3];
src_vertices[0] = pts[0];
src_vertices[1] = pts[1];
src_vertices[2] = pts[3];
//src_vertices[3] = not_a_rect_shape[3];

Point2f dst_vertices[3];
dst_vertices[0] = Point(0, 0);
dst_vertices[1] = Point(box.boundingRect().width - 1, 0);
dst_vertices[2] = Point(0, box.boundingRect().height - 1);

/* Mat warpMatrix = getPerspectiveTransform(src_vertices, dst_vertices);

cv::Mat rotated;
cv::Size size(box.boundingRect().width, box.boundingRect().height);
warpPerspective(src, rotated, warpMatrix, size, INTER_LINEAR, BORDER_CONSTANT);*/
Mat warpAffineMatrix = getAffineTransform(src_vertices, dst_vertices);

cv::Mat rotated;
cv::Size size(box.boundingRect().width, box.boundingRect().height);
warpAffine(src, rotated, warpAffineMatrix, size, INTER_LINEAR, BORDER_CONSTANT);

imwrite("E:\\rotated.jpg", rotated);


return 0;

}

And this is result : enter image description here

enter image description here

enter image description here

So How can I fix it?

Thank you.

  • Try `warpPerspective` instead of `warpAffine` – fabda01 Nov 15 '19 at 09:30
  • You need a full homography, not an affine warp. A rotated rect is only going to give you a rectangle that fits your points inside it, but you don't want to map the rectangle...you want to map the quadrilateral. Use all four points, not three---and map them to the corresponding four corners. Use [`getPerspectiveTransform()`](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga20f62aa3235d869c9956436c870893ae) instead of `getAffineTransformation()` and use `warpPerspective()` instead of `warpAffine()` to complete the transform. – alkasm Nov 15 '19 at 09:34

1 Answers1

2

You matched pts to points of bounding box wrongly.

What does reference say about RotatedRect::points method ?:

void cv::RotatedRect::points ( Point2f pts[] ) const returns 4 vertices of the rectangle

Parameters pts The points array for storing rectangle vertices. The order is bottomLeft, topLeft, topRight, bottomRight.

in coordinates system XY it looks like:

   (0,0)--------------------------------> x
   |
   |              topLeft ----- topRight
   |             /                        \
   |            /                          \
   |    bottomLeft --------------------- bottomRight
  \ /
   y

This

src_vertices[0] = pts[0]; // bottomLeft
src_vertices[1] = pts[1]; // topLeft
src_vertices[2] = pts[3]; // bottomRight

should correspond to that (it is easy translation to bounding box's coordinates):

Point2f dst_vertices[3];
dst_vertices[0] = Point(0, box.boundingRect().height);
dst_vertices[1] = Point(0, 0);
dst_vertices[2] = Point(box.boundingRect().width, box.boundingRect().height);
rafix07
  • 17,659
  • 2
  • 14
  • 24