C++ 中的 4 点 OpenCV 裁剪透视图

Posted

技术标签:

【中文标题】C++ 中的 4 点 OpenCV 裁剪透视图【英文标题】:4 Point OpenCV Crop Perspective In C++ 【发布时间】:2019-11-14 19:57:59 【问题描述】:

我正在寻找一种将图像的透视裁剪 4 点的方法。 我找到了这个来源,但是当我使用它时,结果是错误的。

原始来源: This is original 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;

这是结果:

那么我该如何解决呢?

谢谢。

【问题讨论】:

尝试warpPerspective 而不是warpAffine 你需要一个完整的单应性,而不是仿射扭曲。旋转的矩形只会给你一个适合你的点的矩形,但你不想映射矩形......你想映射四边形。使用所有四个点,而不是三个点——并将它们映射到相应的四个角。使用getPerspectiveTransform() 代替getAffineTransformation() 并使用warpPerspective() 代替warpAffine() 来完成转换。 【参考方案1】:

您错误地将pts 匹配到边界框的点。

reference 对 RotatedRect::points 方法有何看法?:

void cv::RotatedRect::points (Point2f pts[]) const 返回 4 矩形的顶点

参数 pts 存储矩形顶点的点数组。这 顺序是 bottomLefttopLefttopRightbottomRight

在坐标系 XY 中看起来像:

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

这个

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

应该对应(很容易转换为边界框的坐标):

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);

【讨论】:

以上是关于C++ 中的 4 点 OpenCV 裁剪透视图的主要内容,如果未能解决你的问题,请参考以下文章

初学opencv c++学习笔记透视变换--warpPerspective()

C++ OpenCV透视变换改进---直线拟合的应用

Swift 中的 CIDetector 透视和裁剪

OpenCV图像拼接 原理介绍 C++ OpenCV 案例实现

圆形标定板标定的opencv c++实现

使用OpenCV透视变换技术实现坐标变换实践