点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达本文转自|OpenCV学堂

纸质文档扫描中经常会发生扫描出来的图像有一定角度的偏斜,对后期的文档信息化OCR提取造成很大的干扰,导致OCR识别准确率下降从而影响文档信息化的结果。这个时候可以使用OpenCV对文档进行纠偏,最常见的文本纠偏算法有两种,分别是

  • 基于FFT变换以后频率域梯度

  • 基于离散点求最小外接轮廓

这两种方法各有千秋,相对来说,第二种方法得到的结果更加准确,第一种基于离散傅立叶变换求振幅的方法有时候各种阈值选择在实际项目中会有很大问题。

基于FFT变换以后频率域梯度

主要思路是先把图像转换为灰度图像,然后使用离散傅立叶变换得到图像在频率域空间的振幅,对其二值化之后,使用霍夫直线检测得到角度,然后根据角度完成旋转校正。代码实现如下:

    Mat src = imread("D:/vcprojects/images/rotate_text.png");Mat gray, binary;cvtColor(src, gray, COLOR_BGR2GRAY);//expand input image to optimal sizeMat padded;                            int m = getOptimalDFTSize(gray.rows);int n = getOptimalDFTSize(gray.cols);// on the border add zero valuescopyMakeBorder(gray, padded, 0, m - gray.rows, 0, n - gray.cols, BORDER_CONSTANT, Scalar::all(0));Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };Mat complexI;// Add to the expanded another plane with zerosmerge(planes, 2, complexI);// 离散傅立叶变换dft(complexI, complexI);          // 实部与虚部得到梯度图像// planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))split(complexI, planes);                  magnitude(planes[0], planes[1], planes[0]);Mat magI = planes[0];magI += Scalar::all(1);log(magI, magI);// crop the spectrum, if it has an odd number of rows or columnsmagI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));// rearrange the quadrants of Fourier image  so that the origin is at the image centerint cx = magI.cols / 2;int cy = magI.rows / 2;Mat q0(magI, Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrantMat q1(magI, Rect(cx, 0, cx, cy));  // Top-RightMat q2(magI, Rect(0, cy, cx, cy));  // Bottom-LeftMat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-RightMat tmp;                          // swap quadrants (Top-Left with Bottom-Right)q0.copyTo(tmp);q3.copyTo(q0);tmp.copyTo(q3);q1.copyTo(tmp);                  q2.copyTo(q1);tmp.copyTo(q2);// 归一化与阈值化显示normalize(magI, magI, 0, 1.0, NORM_MINMAX);Mat dst;magI.convertTo(dst, CV_8UC1, 255, 0);threshold(dst, binary, 160, 255, THRESH_BINARY);// 霍夫直线vector<Vec2f> lines;Mat linImg = Mat::zeros(binary.size(), CV_8UC3);HoughLines(binary, lines, 1, (float)CV_PI / 180, 30, 0, 0);int numLines = lines.size();float degree = 0.0;for (int l = 0; l<numLines; l++){float rho = lines[l][0], theta = lines[l][1];float offset = CV_PI / 12.0;if (abs(theta) >  offset && abs(theta)< (CV_PI / 2.0- offset)) {printf("theta : %.2f\n", theta);degree = (theta)*180-90;}Point pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * (a));pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * (a));line(linImg, pt1, pt2, Scalar(0, 255, 0), 3, 8, 0);}imshow("lines", linImg);// 旋转调整Mat rot_mat = getRotationMatrix2D(Point(binary.cols/2, binary.rows/2), degree, 1);Mat rotated;warpAffine(src, rotated, rot_mat, src.size(), cv::INTER_CUBIC, 0, Scalar(255, 255, 255));imshow("input", src);imshow("deskew-demo", rotated);imwrite("D:/deskew_text.png", rotated);

基于离散点求最小外接轮廓

其主要思路是先把图像二值化,得到一系列离散的前景像素点集合,然后利用轮廓的最小外接矩形函数,得到偏斜的矩形大小与角度,通过仿射变换完成校正。代码实现如下:

    Mat src = imread("D:/vcprojects/images/rotate_text.png");Mat gray, binary;cvtColor(src, gray, COLOR_BGR2GRAY);threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);imshow("binary", binary);imwrite("D:/binary_text.png", binary);vector<Point> points;findNonZero(binary, points);RotatedRect box = minAreaRect(points);double angle = box.angle;if (angle < -45.)angle += 90.;printf("angle : %.2f\n", angle);Point2f vertices[4];box.points(vertices);for (int i = 0; i < 4; ++i)line(src, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 255), 2);imshow("box", src);imwrite("D:/box_text.png", src);Mat rot_mat = getRotationMatrix2D(box.center, angle, 1);Mat rotated;warpAffine(src, rotated, rot_mat, src.size(), cv::INTER_CUBIC, 0, Scalar(255, 255, 255));//bitwise_not(rotated, rotated);imshow("deskew-demo", rotated);

运行结果

  • 原图

  • 最小外接矩形

  • 校正之后

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲

在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

实战:基于OpenCV实现偏斜文档校正相关推荐

  1. 使用OpenCV实现偏斜文档校正

    在这篇文章中: 使用OpenCV实现偏斜文档校正 基于FFT变换以后频率域梯度 基于离散点求最小外接轮廓 运行结果 使用OpenCV实现偏斜文档校正 纸质文档扫描中经常会发生扫描出来的图像有一定角度的 ...

  2. MFC中 给基于CFormView的单文档添加背景图片

    关于基于CFormView的单文档应用程序,添加一个图片背景的方法之一如下: 下面是利用LoadImage实现.(先在程序目录中添加背景图片back.bmp) 1.在view类中添加类成员变量:(为C ...

  3. (一)JAVA基于OPENXML的word文档插入、合并、替换操作系列之基础篇

    (一)JAVA基于OPENXML的word文档插入.合并.替换操作系列之基础篇 前言 什么是Open Xml? Open XML SDK 这系列笔记要做点什么? 涉及技术点 关于word.openxm ...

  4. (五)、JAVA基于OPENXML的word文档插入、合并、替换操作系列之word文件合并[支持多文件]

    (五).JAVA基于OPENXML的word文档插入.合并.替换操作系列之word文件合并[支持多文件] 二.word合并的多种方案简单比较 三.基于Open Xml WordprocessingML ...

  5. 使用Python,OpenCV构建移动文档扫描仪

    使用Python,OpenCV构建移动文档扫描仪 1. 效果图 2. 步骤 3. 源码 参考 1. 效果图 图1,鸟瞰图 图2,角度不太一样,鸟瞰图的效果也不一致: 2. 步骤 使用OpenCV构建文 ...

  6. elasticsearch实战三部曲之二:文档操作

    本文是<elasticsearch实战三部曲>系列的第二篇,上一篇文章我们动手熟悉了索引相关的基本操作,现在一起来熟悉文档相关的操作: 系列文章链接 <elasticsearch实战 ...

  7. java openxml 操作 word,(三)、JAVA基于OPENXML的word文档插入、合并、替换操作系列之html转word...

    (三).JAVA基于OPENXML的word文档插入.合并.替换操作系列之html转word 系列笔记传送门 富文本转word文档 准备待转换内容 内容清理与格式化 转换成word文档 输出结果展示 ...

  8. 使用xsl将xml转化为HTML文档,基于XSL将XML文档转换为HTML格式文档的方法与流程

    技术特征: 1.一种基于XSL将XML文档转换为HTML格式文档的方法,其特征在于,包括: S1,新建一个与XML文档同名的HTML格式文档: S2,定义转换算法,实现XML文档到HTML格式文档的转 ...

  9. 95. 基于Notes/Domino的文档工作流系统(七)

    本文继续剖析基于Notes/Domino的文档工作流系统的设计和代码,以方便用户能应用和创建自己的工作流.(CSDN的下载资源一旦上传就不能修改,很不方便,现已将下载地址改到GitHub,若发现下载有 ...

最新文章

  1. php time 毫秒_PHP获取当前时间的毫秒数
  2. 内核模式下的文件操作
  3. Navicat使用教程:使用Navicat Query Analyzer优化查询性能(第1部分)
  4. python实现dns欺骗_DNS欺骗攻击
  5. Spring自学教程-注解的使用(三)
  6. 《Java并发性和多线程介绍》-Java TheadLocal
  7. webstorm 使用别名(@)import @import 时异常的问题
  8. 广度优先搜索——USACO08FEB(洛谷 P2895)
  9. 解决Vue循环中子组件不实时更新的问题
  10. 浏览器Browser截屏截长图使用记录220813
  11. 极客书的编程教程合集
  12. Shell编程(三)grep sed awk文本处理三剑客
  13. 如何基于 RISC-V CPU 集成一个 RISC-V SoC 呢?(下)
  14. React-Native 知识点小结
  15. 查看JS代码中\x68等加密数据内容的解决办法
  16. React新生命周期--getDerivedStateFromProps、getSnapshotBeforeUpdate
  17. CSS3 文本多列 分栏
  18. fck java_java FCK学习使用
  19. 【vue基础】黑马vue视频笔记(二)
  20. 如何快速将pdf转换成cad呢?

热门文章

  1. 飞天AI平台到底哪里与众不同?听听它的架构者怎么说
  2. 你绝没用过的一款高级空间可视化工具
  3. 程序员拯救乐坛?OpenAI用“逆天”GPT2.0搞了个AI音乐生成器
  4. 一文详解启发式对话中的知识管理 | 公开课笔记
  5. 6月Python热文Top10,精选自1000篇文章
  6. AI一分钟|美国第一家!Waymo商业自动驾驶打车服务正式获批
  7. 看完2017年这10大AI失败案例,就知道什么是人工智障了
  8. ​双十一剁手后,听蒋涛谈谈AI人才多么吸金:2018年社招AI人才平均月薪竟高达4万,算法红利期还有2年
  9. 这些SpringBoot天生自带Buff工具类你都用过哪些?
  10. 早就听闻阿里开源的 Arthas 在做 Java 应用诊断上十分牛逼,没失望