实现步骤
1.首先对输入图像进行二值变换,然后进行轮廓分析,得到文档轮廓
2.调用approxPolyDP函数进行轮廓逼近,找到四个顶点坐标,这里需要注意一下,使用approxPolyDP函数进行轮廓逼近的时候,最后一个参数是表示轮廓逼近得到轮廓与原来轮廓之后的距离差值,值越小越逼近真实轮廓。我们这里希望得到一个大致近似的矩形即可,所以该值要尽可能的大一点,这个也是使用这个函数的一个编程技巧。
3.得到四个点之后,创建目标点,然后调用findHomography,得到变换矩阵H,基于H完成透视变换得到最终的输出。
第一步的代码实现如下:
Mat src = imread('D:/images/mytest.jpg');
Mat image = src.clone();
Mat gray, binary;
cvtColor(image, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
// 发现轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
findContours(binary, contours, hierachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
int index = -1;
double max = -1;
double angle = 0;
for (int i = 0; i < contours.size(); i++) {
double area = contourArea(contours[i]);
if (area > max) {
max = area;
index = i;
}
}
drawContours(image, contours, index, Scalar(0, 255, 0), 2, 8);
输出如下:
![Image](http://image109.360doc.com/DownloadImg/2022/05/2613/245682951_3_20220526010259146.png)
第二步的代码实现如下:
// 寻找矩形轮廓四个点
Mat approxCurves;
approxPolyDP(contours[index], approxCurves, 100, true);
printf('rows : %d, cols : %d \n', approxCurves.rows, approxCurves.cols);
vector<Point2f> srcPts;
for (int n = 0; n < approxCurves.rows; n++) {
Vec2i pt = approxCurves.at<Vec2i>(n, 0);
printf('pt.x= %d, pt.y = %d \n', pt[0], pt[1]);
srcPts.push_back(Point2f(pt[0], pt[1]));
circle(image, Point(pt[0], pt[1]), 12, Scalar(0, 0, 255), 8, 8, 0);
}
imwrite('D:/result.png', image);
输出如下:
![Image](http://image109.360doc.com/DownloadImg/2022/05/2613/245682951_4_20220526010259552.png)
第三步,透视变换
Mat h = findHomography(srcPts, dstPts);
warpPerspective(src, dst, h, src.size());
imwrite('D:/correct_document.png', dst);
输出如下:
![Image](http://image109.360doc.com/DownloadImg/2022/05/2613/245682951_5_2022052601030068.png)