文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么用C++ OpenCV实现文档矫正功能

2023-06-29 12:14

关注

这篇文章主要介绍了怎么用C++ OpenCV实现文档矫正功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么用C++ OpenCV实现文档矫正功能文章都会有所收获,下面我们一起来看看吧。

需求

将一个斜着拍摄的文档矫正成正的,如图所示:

怎么用C++ OpenCV实现文档矫正功能

怎么用C++ OpenCV实现文档矫正功能

思路

读取原始图像,若图像太大可以先进行缩放处理,并获取原始图像的宽和高

对图像进行预处理得到边缘,依次进行灰度处理、高斯模糊、边缘检测、膨胀、腐蚀。

找到最大的轮廓,并提取角点

将找到的四个角点排列成一个固定的顺序,排列后的顺序为:左上角-右上角-左下角-右下角

进行透视变换

若透视变换后有一些毛边,按需要进行裁剪,裁剪后重新调整比例

显示变换后图像

代码

代码中均有详细注释,请仔细阅读

#include <iostream>#include<opencv2/opencv.hpp>#include <opencv2/highgui.hpp>#include <opencv2/imgproc.hpp>using namespace cv;using namespace std;// 一些定义Mat image_origin,     // 原始图像image_gray,       // 灰度处理后的图像image_blur,       // 高斯模糊处理后的图像image_canny,      // 边缘检测后的图像image_dilate,     // 膨胀后的图像image_erode,      // 腐蚀后的图像image_preprocess, // 预处理后的图像image_trans,      // 透视变换后的图像image_crop;      // 裁剪后的图像vector<Point> origin_points,  // 重新排列前的角点  reorder_points; // 重新排列后的角点    int origin_width = 0, origin_height = 0;Mat PreProcess(const Mat& image, int display){// 灰度处理cvtColor(image, image_gray, COLOR_BGR2GRAY);// 高斯模糊GaussianBlur(image_gray, image_blur, Size(3, 3), 3, 0);// 边缘检测(边缘检测前对图像进行一次高斯模糊)Canny(image_blur, image_canny, 50, 150);// 膨胀和腐蚀(有时进行边缘检测的时候,没有被完全填充,或者无法正确检测,可以用膨胀和腐蚀)// 创建一个用于膨胀和腐蚀的内核,后面的数字越大膨胀的越多(数字要用奇数)Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));// 膨胀dilate(image_canny, image_dilate, kernel);// 腐蚀//erode(image_dilate, image_erode, kernel);// 显示预处理效果if(display == 1){imshow("灰度处理后的图像", image_gray);imshow("高斯模糊后的图像", image_blur);imshow("边缘检测后的图像", image_canny);imshow("膨胀后的图像", image_dilate);//imshow("腐蚀后的图像", image_erode);}else if(display == 2){imshow("预处理后的图像", image_dilate);}return image_dilate;}vector<Point> GetMaxContour(const Mat& img_input){vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(img_input, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//// 不全输出,在下文只输出角点//drawContours(image, contours, -1, Scalar(255, 0, 255), 2);// 定义轮廓,大小与contours相同,但内层向量中只有角点(例如三角形就是3,四边形就是4,圆形可能七八个)vector<vector<Point>> corners_contours(contours.size());// 定义边界框,大小与contours相同vector<Rect> bounding_box(contours.size());vector<Point> biggest_contours;double max_area = 0;for (int i = 0; i < contours.size(); i++){// 检测轮廓面积double contour_area = contourArea(contours[i]);//cout << area << endl;// 假设图像中有噪声,需要将其过滤,只保留面积大于1000的轮廓if (contour_area > 1000){// 计算每个轮廓的周长double contour_perimeter = arcLength(contours[i], true);// 使用DP算法计算出轮廓点的个数,规则为周长*0.02approxPolyDP(contours[i], corners_contours[i], 0.02 * contour_perimeter, true);// 找到图像中面积最大的,且角点为4的轮廓if (contour_area > max_area && corners_contours[i].size() == 4 ) {//drawContours(image_origin, conPoly, i, Scalar(255, 0, 255), 5);biggest_contours = { corners_contours[i][0],corners_contours[i][1] ,corners_contours[i][2] ,corners_contours[i][3] };max_area = contour_area;}//// 只绘制角点之间的边框线,Debug用,取消注释可以看到检测出的所有边界框//drawContours(image_origin, corners_contours, i, Scalar(255, 0, 255), 2);//rectangle(image_origin, bounding_box[i].tl(), bounding_box[i].br(), Scalar(0, 255, 0), 5);}}// 返回最大的轮廓return biggest_contours;}void DrawPoints(vector<Point> points, const Scalar& color){for (int i = 0; i < points.size(); i++){circle(image_origin, points[i], 10, color, FILLED);putText(image_origin, to_string(i), points[i], FONT_HERSHEY_PLAIN, 4, color, 4);}}vector<Point> ReorderPoints(vector<Point> points){vector<Point> newPoints;vector<int>  sumPoints, subPoints;// OpenCV中左上顶点为(0,0),右为x轴正向,下为y轴正向。for (int i = 0; i < 4; i++){// 将每个点的xy坐标值相加(x+y),左上角的点的坐标和应该是最小的,右下角的点的坐标和应该是最大的sumPoints.push_back(points[i].x + points[i].y);// 将每个点的xy坐标值相减(x-y),左下角的点的坐标差应该是最小的,右上角的点的坐标差应该是最大的subPoints.push_back(points[i].x - points[i].y);}// 重新排列newPoints.push_back(points[min_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin()]); // 0 和的最小值newPoints.push_back(points[max_element(subPoints.begin(), subPoints.end()) - subPoints.begin()]); // 1 差的最大值newPoints.push_back(points[min_element(subPoints.begin(), subPoints.end()) - subPoints.begin()]); // 2 差的最小值newPoints.push_back(points[max_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin()]); // 3 和的最大值return newPoints;}Mat PerspectiveTrans(const Mat& img, vector<Point> points, float width, float height ){// 前面经过重新排列,四个角点的顺序为:左上角-右上角-左下角-右下角Point2f src[4] = { points[0],points[1],points[2],points[3] };// 变换后的四个角点Point2f dst[4] = { {0.0f,0.0f},{width,0.0f},{0.0f,height},{width,height} };// 创建变换矩阵Mat matrix = getPerspectiveTransform(src, dst);// 透视变换warpPerspective(img, image_trans, matrix, Point(width, height));return image_trans;}int main(){// 1.读取原始图像string path = "res/image_origin.jpg";image_origin = imread(path);//// 若图像太大可以先进行缩放处理//resize(image_origin, image_origin, Size(), 0.5, 0.5);// 获取原始图像的宽和高origin_width  = image_origin.size().width;origin_height = image_origin.size().height;// 2.对图像进行预处理得到边缘,依次进行灰度处理、高斯模糊、边缘检测、膨胀、腐蚀。image_preprocess = PreProcess(image_origin, 0);// 3.找到最大的轮廓,并提取角点origin_points = GetMaxContour(image_preprocess);//DrawPoints(origin_points, Scalar(0, 0, 255)); // 红色// 此时发现,角点的顺序不固定,为了后面进行透视变换时与代码中变换后点集的顺序相同,需要将其排列成一个固定的顺序,排列后的顺序为:左上角-右上角-左下角-右下角reorder_points = ReorderPoints(origin_points);//DrawPoints(reorder_points, Scalar(0, 255, 0)); //绿色// 4.透视变换image_trans = PerspectiveTrans(image_origin, reorder_points, origin_width, origin_height);// 透视变换后有一些毛边,若需要可以进行裁剪// 四周裁剪5像素int cropVal= 5;// 创建一个矩形用来裁剪Rect roi(cropVal, cropVal, origin_width - (2 * cropVal), origin_height - (2 * cropVal));image_crop = image_trans(roi);// 裁剪后重新调整比例resize(image_crop, image_crop, Size(origin_width, origin_height));// 5.显示并输出变换后图像imshow("源图像", image_origin);imshow("最终图像", image_crop);    imwrite("res/image_output.jpg", image_crop);waitKey(0);}

效果

怎么用C++ OpenCV实现文档矫正功能

关于“怎么用C++ OpenCV实现文档矫正功能”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“怎么用C++ OpenCV实现文档矫正功能”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯