目的:在图片中放入一张A4纸(以倾斜角度),通过图片扫描的手法我们可以实现文档的俯视图(即正对着看图像)

#include <iostream>
#include <opencv2/highgui.hpp> // 说是说gui 具体什么gui 不清楚
#include <opencv2/imgcodecs.hpp> // 图像头文件
#include <opencv2/imgproc.hpp> // 图像处理头文件
using namespace std;
using namespace cv;// 变量
Mat imgOriginal, imgGray, imgCanny, imgThre, imgBlur, imgDil;
vector<Point> initalPoints; // 初始点
vector<Point> finalPoints; // 初始点经过固定排序之后的点
float w = 420, h = 596;
// 函数
Mat preProcessing(Mat& img); //图像预处理函数
vector<Point> getContours(Mat imgDil,Mat& imgOriginal);// 获取轮廓函数void drawPoints(vector<Point> points, Scalar color,Mat imgOriginal);// 描点函数vector<Point> reorder(vector<Point> initalPoints); // 修改点的顺序,改为想要的 0 1 2 3Mat getWarp(Mat imgOriginal, vector<Point> finalPoints, float w,float h);int main()
{string path = "resources/paper.jpg"; // 导入图形的时候,先要在右边点击显示所有文件!!!Mat imgOriginal = imread(path); // 在opencv 中所有的图像信息都使用Mat //resize(imgOriginal, imgOriginal, Size(), 0.5, 0.5); // 将原始图像缩小0.5倍// pre-processing imgThre = preProcessing(imgOriginal);// get-contours - biggestinitalPoints = getContours(imgThre, imgOriginal);for (int i = 0; i < initalPoints.size(); i++){cout << initalPoints[i].x << "," << initalPoints[i].y << endl;}finalPoints = reorder(initalPoints);//drawPoints(finalPoints, Scalar(0, 255, 0), imgOriginal);// warp image Mat imgWarp = getWarp(imgOriginal, finalPoints, w, h);// crop  因为图像边缘存在非文档的东西// 此类东西容易影响文档扫描的精度int cropNum = 5;Rect roi(cropNum, cropNum,w-2* cropNum,h-2* cropNum);Mat imgCrop = imgWarp(roi);imshow("Image", imgOriginal);imshow("Image Dilation", imgThre);imshow("Image Warp", imgWarp);imshow("Image Crop", imgCrop);waitKey(0); // 延时,0即相当于无穷大
}
/*image pre-process isn't error**/
Mat preProcessing(Mat& img)
{cvtColor(img, imgGray, COLOR_BGR2GRAY); // OPencv 中含有BGR 协议而不是RGB协议、// 高斯滤噪 模糊GaussianBlur(imgGray, imgBlur, Size(3, 3), 3, 0); // 该Size 图像具体哪里来的,不是很清楚// Canny 边缘检测, 在进行Canny边缘检测之前我们一般会进行高斯滤波Canny(imgBlur, imgCanny, 25, 75); // 后面两个参数即Canny 边缘检测的阈值// How to dilate and erode an image // dilate : increase the thickness to convenietly detect  即增加边线的厚度,使其显示的更加明显// erode :  decrease the thicknessMat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); // 更改Size 的大小便更改了放大倍数 注意Size 只能选择奇数dilate(imgCanny, imgDil, kernel); // 使用getStructruingElement 创建kernelreturn imgDil;
}vector<Point> getContours(Mat imgDil,Mat& imgOriginal)
{vector<vector<Point>> contours;vector<Vec4i> hierarchy; // Vec4i 即代表该向量内有4个 int 变量typedef    Vec<int, 4>   Vec4i;   这四个向量每一层级代表一个轮廓findContours(imgDil, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // CV_CHAIN_APPROX_SIMPLE - 简单的链式接近法vector<vector<Point>> conpoly(contours.size());// conpoly(paprameter1) ,paprameter1便代表vector对象的行数,而其列数中的vector 是使用了point点集但其只包含图形的拐角点集vector<Point> biggest; // 定义最大轮廓// 为了滤除微小噪声,因此计算area 的面积int maxArea = 0; // 遍历临时变量,用以查找最大轮廓for (int i = 0; i < contours.size(); i++) // 关于contours.size()为什么是返回二维数组的行,因为 vector::size()函数只接受vector 对象的调用而contours的所有行(不管列)均为其对象{int area = contourArea(contours[i]);//cout << area << endl;// area > 1000 的目的是为了滤除图像中的微小瑕疵if (area > 1000){float peri = arcLength(contours[i], true);// 该函数计算轮廓的长度,后面的bool值表面轮廓曲线是否闭合若为true 则轮廓曲线闭合approxPolyDP(contours[i], conpoly[i], 0.02 * peri, true); //  conpoly[i]是输出array   0.02*peri 这个参数理解不了就不要理解!!! 最后一个参数仍然是询问是否闭合// 判断图像中最大的矩形if (area > maxArea&& conpoly[i].size()==4) // 若面积最大,则将其点值赋值给biggest 其中 biggest 为 point 向量{//drawContours(imgOriginal, conpoly, i, Scalar(255, 0, 255), 2); // 只需要绘制最大图形即可maxArea = area;biggest = { conpoly[i][0],conpoly[i][1],conpoly[i][2],conpoly[i][3] };}//rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5);}}return biggest;
}
void drawPoints(vector<Point> points, Scalar color, Mat imgOriginal)
{for (int i = 0; i < points.size(); i++){circle(imgOriginal,points[i],10,color,FILLED);putText(imgOriginal, to_string(i), points[i], FONT_HERSHEY_PLAIN, 4, color,4);}
}
// vector 容器pushback 函数是在vector 容器的尾部添加元素
vector<Point> reorder(vector<Point> initalPoints)
{vector<Point> tempPoints; // 设置中间变量vector<double> sumPoints, subPoints;int sumMinIndex, sumMaxIndex; //  查找sum的最大(3)最小值(0)索引int subMinIndex, subMaxIndex; // 查找sub的最大()最小值()索引for (int i = 0; i < 4; i++){sumPoints.push_back(initalPoints[i].x + initalPoints[i].y); // 和值最大为第四个点//和值最小为第一个点 // 而 2 3 点则是通过y - x 进行判断subPoints.push_back(initalPoints[i].x - initalPoints[i].y);}sumMinIndex = min_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin(); // 0subMaxIndex = max_element(subPoints.begin(), subPoints.end()) - subPoints.begin(); //1subMinIndex = min_element(subPoints.begin(), subPoints.end()) - subPoints.begin();sumMaxIndex = max_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin();// 3tempPoints.push_back(initalPoints[sumMinIndex]); // 0 即最小元素 tempPoints.push_back(initalPoints[subMaxIndex]); tempPoints.push_back(initalPoints[subMinIndex]);tempPoints.push_back(initalPoints[sumMaxIndex]);return tempPoints;
}
Mat getWarp(Mat imgOriginal, vector<Point> finalPoints, float w, float h)
{Point2f src1[4] = { finalPoints[0],finalPoints[1],finalPoints[2],finalPoints[3] };Point2f src2[4] = { {0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h} };Mat martix = getPerspectiveTransform(src1, src2);Mat imgWarp;warpPerspective(imgOriginal, imgWarp, martix,Size(w,h));return imgWarp;
}

运行结果:

8、Opencv实现文档扫描相关推荐

  1. 使用Python+OpenCV构建文档扫描程序

    首先给各位展示原始图片: 使用自己搭建的文档扫描程序扫描效果如下图: 图一:查找轮廓 图二:边缘检测 图三:应用透视变换和阈值

  2. 计算机视觉-OpenCV(文档扫描OCR识别)

    一.边缘检测 二.获取轮廓 三.变换 四.OCR识别 import cv2 import numpy as np import argparse import pytesseract import o ...

  3. 使用python+opencv实现文档扫描

    一.扫描文档的步骤 捕获图像 检测边缘 提取所需对象/定义轮廓 对提取的对象进行透视变换 提取文本内容(此处不做处理) 1.scanner.py import cv2 import numpy as ...

  4. python使用opencv实现文档扫描并提取文字

    目的 将输入文档使用透视变换将不规则图形变换,然后使用tesseract库进行识别文字 变换前图形 变换后图形 步骤 1.加载原图并显示 2.重新调整大小 3.灰度处理 4.滤波 5.边缘检测 6.找 ...

  5. 深入学习OpenCV文档扫描OCR识别及答题卡识别判卷(文档扫描,图像矫正,透视变换,OCR识别)

    人工智能学习离不开实践的验证,推荐大家可以多在FlyAI-AI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力.FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台.每周免费提供 ...

  6. OpenCV OCR实战 文档扫描与文字检测

    本文讲述使用OpenCV- python以及easyocr库实现文档扫描与文字检测的思路和具体实现过程. 目录 知识准备 项目概述 实现过程 代码讲解 1.读入图片并进行预处理(灰度转换,高斯滤波) ...

  7. opencv项目实战(2)——文档扫描OCR识别

    文章目录 思路 文档扫描 代码 运行结果 文字识别 预处理 代码 运行结果 Debug 记录 思路 STEP 1: 边缘检测 STEP 2: 获取轮廓 STEP 3: 变换 文档扫描 代码 scan. ...

  8. OpenCV计算机视觉实战(Python)| 10、项目实战:文档扫描OCR识别

    文章目录 简介 总结 1. 介绍 2. 流程 3. 程序 4. 知识点总结 简介 本节为<OpenCV计算机视觉实战(Python)>版第10讲,项目实战:文档扫描OCR识别,的总结. 总 ...

  9. Opencv实战——OCR文档扫描

    文章目录 前言 一.安装Tesseract-OCR 二.文档扫描 1.需要透视变换的图像 2.直接Tesseract-OCR 总结 前言 这里实现文档扫描主要是依靠Tesseract,Tesserac ...

最新文章

  1. 网络传输数据格式的选择
  2. 项目拆分子工程(简单版)
  3. c语言memcopy_C语言中memcpy 函数的用法详解
  4. Flume实战监听文件夹内文件变化
  5. 【什么是数据隐私?安全与隐私的区别?】差分隐私代码实现系列(一)
  6. 12.16直播:藏在华为物联网操作系统里的“秘密”
  7. java系列7:构造方法
  8. 2021年末IT公司市值排行榜
  9. 直观理解图片的EXIF orientation
  10. win7共享无法关闭密码保护解决方法
  11. 千万级中文公开免费聊天语料数据分享
  12. Mac启动台缺少已下载应用软件图标
  13. WAP中利用截取手机号码达到自动登入的一段源码(转)
  14. UDP-Based 多路径乱序传输
  15. STM32的串口硬件流控(RS232/RS485)
  16. 怎么用python画出Excel表格数据的残差图
  17. html怎么设置文艺字体,用CSS让你的文字更有文艺范
  18. 问题 A: 相约HNUST
  19. 防止被反编译获取源码,PB加密,PBD加密,杜绝PB程序反编译 下载
  20. 2020年海思所有芯片合集参考说明

热门文章

  1. ios,android,windows,专家告诉你,iOS、Android、Windows哪个系统最安全
  2. unity 血条功能
  3. 【现代机器人学】学习笔记九:运动规划
  4. Guava类库学习--Table(双键的Map)等
  5. PAT (Basic Level) Practice (中文)1095 解码PAT准考证 (25 分)
  6. windows系统端口被占用
  7. 《麦肯锡工作法》麦肯锡精英的39个习惯
  8. bashrc报错和bashrc中添加conda
  9. wget下载onedrive文件不403 forbidden的方法(简单有效含例子)
  10. 腾讯A股模拟炒股自动化