当我们遇到一些歪歪扭扭的照片,比如下面这些照片:

这些图片让人看得真不舒服!我们可以用PS来处理?但如果有1000张图,我们只能交给计算机去做!

对于图像矫正的问题,在图像处理领域很多,比如人民币的矫正、文本的矫正、车牌的矫正、身份证矫正等等。这些都是因为拍摄者总不可能100%正确地拍摄好图片,这就要求我们通过后期的图像处理技术将图片还原好,才能进一步做后面的处理,比如数字分割啊数字识别啊,不然歪歪扭扭的文字数字,想识别出来估计就很难了。

为了将图片尽可能地矫正过来,可以使用OpenCV。

算法步骤(基于轮廓提取的矫正算法):

  1. 图片灰度化
  2. 阈值二值化
  3. 检测轮廓
  4. 寻找轮廓的包围矩阵,并且获取角度
  5. 根据角度进行旋转矫正

废话不多说,直接上代码:

#include<iostream>
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;int main()
{Mat srcImage = imread("D:\\Program Files\\OpenCV\\opencv\\sources\\samples\\data\\imageTextR.png");if (srcImage.cols>1000 || srcImage.rows>800) {//图片过大,进行降采样pyrDown(srcImage, srcImage);pyrDown(srcImage, srcImage);pyrDown(srcImage, srcImage);}Mat grayImage, binaryImage;cvtColor(srcImage, grayImage, CV_BGR2GRAY);//转化灰度图adaptiveThreshold(grayImage, binaryImage, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 7, 0);//自适应滤波vector<vector<Point> > contours;//RETR_EXTERNAL:表示只检测最外层轮廓//CHAIN_APPROX_NONE:获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1 findContours(binaryImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//获得矩形包围框,之所以先用boundRect,是为了使用它的area方法求面积,而RotatedRect类不具备该方法float area = boundingRect(contours[0]).area(); int index = 0;for (int i = 1; i<contours.size(); i++){if (boundingRect(contours[i]).area()>area){area = boundingRect(contours[i]).area();index = i;}}Rect maxRect = boundingRect(contours[index]);//找出最大的那个矩形框(即最大轮廓)Mat ROI = binaryImage(maxRect);imshow("maxROI", ROI);RotatedRect rect = minAreaRect(contours[index]);//获取对应的最小矩形框,这个长方形是倾斜的Point2f rectPoint[4];rect.points(rectPoint);//获取四个顶点坐标,这是RotatedRect类定义的方法double angle = rect.angle;//angle += 90;Point2f center = rect.center;drawContours(binaryImage, contours, -1, Scalar(255), CV_FILLED);// srcImage.copyTo(RoiSrcImg,binaryImage);Mat RoiSrcImg = Mat::zeros(srcImage.size(), srcImage.type());srcImage.copyTo(RoiSrcImg);Mat Matrix = getRotationMatrix2D(center, angle, 0.8);//得到旋转矩阵算子,0.8缩放因子warpAffine(RoiSrcImg, RoiSrcImg, Matrix, RoiSrcImg.size(), 1, 0, Scalar(0, 0, 0));imshow("src Image", srcImage);imshow("contours", binaryImage);imshow("recorrected", RoiSrcImg);while (waitKey() != 'q') {}return 0;
}

结果:

函数说明:

OpenCV3学习(9.3)图像轮廓的多边形逼近approxPolyDP、轮廓包围框\圆\椭圆、凸包

OpenCV3学习(5.1)——图像变换之缩放、金字塔、仿射、透射

OpenCV3学习(9.1)图像轮廓查找与绘制函数findContours()与drawContours()

对于人民币图像和发票图像他们有明显的的边界轮廓,采用基于轮廓方法很有效。而文本图像没有。文本图像的背景是白色的,所以我们有时可能没有办法像人民币发票那类有明显边界的矩形物体那样,提取出轮廓并旋转矫正。

经过深入分析可以看出,虽然文本类图像没有明显的边缘轮廓,但是他们有一个很重要的特征,那就是每一行文字都是呈现一条直线形状,而且这些直线都是平行的!

对于这种情况,我们采用另一种方法:基于直线探测的矫正算法

算法步骤:

  1. 用霍夫线变换探测出图像中的所有直线
  2. 计算出每条直线的倾斜角,求他们的平均值
  3. 根据倾斜角旋转矫正
// 基于直线探测的矫正算法
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;#define ERROR 1234//度数转换
double DegreeTrans(double theta)
{double res = theta / CV_PI * 180;return res;
}//逆时针旋转图像degree角度(原尺寸)
void rotateImage(Mat src, Mat& img_rotate, double degree)
{//旋转中心为图像中心    Point2f center;center.x = float(src.cols / 2.0);center.y = float(src.rows / 2.0);int length = 0;length = sqrt(src.cols*src.cols + src.rows*src.rows);//计算二维旋转的仿射变换矩阵  Mat M = getRotationMatrix2D(center, degree, 1);warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色
}//通过霍夫变换计算角度
double CalcDegree(const Mat &srcImage, Mat &dst)
{Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);cvtColor(midImage, dstImage, CV_GRAY2BGR);//通过霍夫变换检测直线vector<Vec2f> lines;HoughLines(midImage, lines, 1, CV_PI / 180, 300, 0, 0);//第5个参数就是阈值,阈值越大,检测精度越高//cout << lines.size() << endl;//由于图像不同,阈值不好设定,因为阈值设定过高导致无法检测直线,阈值过低直线太多,速度很慢//所以根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。if (!lines.size()){HoughLines(midImage, lines, 1, CV_PI / 180, 200, 0, 0);}//cout << lines.size() << endl;if (!lines.size()){HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);}//cout << lines.size() << endl;if (!lines.size()){cout << "没有检测到直线!" << endl;return ERROR;}float sum = 0;//依次画出每条线段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0];float theta = lines[i][1];Point pt1, pt2;//cout << theta << endl;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));//只选角度最小的作为旋转角度sum += theta;line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA); //Scalar函数用于调节线段颜色imshow("直线探测效果图", dstImage);}float average = sum / lines.size(); //对所有角度求平均,这样做旋转效果会更好cout << "average theta:" << average << endl;double angle = DegreeTrans(average) - 90;rotateImage(dstImage, dst, angle);//imshow("直线探测效果图2", dstImage);return angle;
}void ImageRecify(const char* pInFileName, const char* pOutFileName)
{double degree;Mat src = imread(pInFileName);imshow("原始图", src);Mat dst;//倾斜角度矫正degree = CalcDegree(src, dst);if (degree == ERROR){cout << "矫正失败!" << endl;return;}rotateImage(src, dst, degree);cout << "angle:" << degree << endl;imshow("旋转调整后", dst);Mat resulyImage = dst(Rect(0, 0, dst.cols, 500)); //根据先验知识,估计好文本的长宽,再裁剪下来imshow("裁剪之后", resulyImage);imwrite("recified.jpg", resulyImage);
}int main()
{ImageRecify("D:\\Program Files\\OpenCV\\opencv\\sources\\samples\\data\\imageTextR.png", "FinalImage.png");waitKey();return 0;
}

结果:

可以看出,基于直线探测的矫正算法在文本处理上效果真的很不错!

最后总结一下两个算法的应用场景:

  • 基于轮廓提取的矫正算法更适用于车牌、身份证、人民币、书本、发票一类矩形形状而且边界明显的物体矫正。

  • 基于直线探测的矫正算法更适用于文本类的矫正。

转载自:https://www.cnblogs.com/skyfsm/p/6902524.html#undefined

代码地址:https://github.com/liuzheCSDN/OpenCV

OpenCV实战1——图像矫正技术相关推荐

  1. 千张照片合成你一张美照-【OpenCV实战二】

    如果你手头有很多很多她的照片,想要给她一个惊喜,你一定要知道这篇文章的威力! OpenCV图像处理其中经典的案例就是千图合成技术,通过对于不同图像的特征提取,再拼合成指定的图像.快去给你的她也搞一个吧 ...

  2. OpenCV实战系列:高通滤波器及其应用

    OpenCV实战系列:高通滤波器及其应用 0. 前言 1. 检测图像边缘 1.2 Sobel 滤波器 1.2 梯度算子 1.3 高斯导数 2. 图像拉普拉斯算子 2.1 拉普拉斯算子 2.2 使用拉普 ...

  3. [OpenCV实战]49 对极几何与立体视觉初探

    本文主要介绍对极几何(Epipolar Geometry)与立体视觉(Stereo Vision)的相关知识.对极几何简单点来说,其目的就是描述是两幅视图之间的内部对应关系,用来对立体视觉进行建模,实 ...

  4. OpenCV实战系列——拟合直线

    OpenCV实战--拟合直线 0. 前言 1. 直线拟合 2. 完整代码 相关链接 0. 前言 在某些计算机视觉应用中,不仅要检测图像中的线条,还要准确估计线条的位置和方向.本节将介绍如何找到最适合给 ...

  5. OpenCV中图像修复技术介绍与演示

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 现实中图像经常出现划伤或者被噪声腐蚀或 ...

  6. 再次升级,985博士整理的71个OpenCV实战项目教程开放下载!

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 近期小白学视觉公众号推出了多篇Python+OpenCV实战项目的 ...

  7. 基于OpenCV实战:3步实现图像降噪

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 在本文中,我们将展示如何通过三个简单的步骤来实现降噪.我们将使用机 ...

  8. 基于OpenCV实战:绘制图像轮廓(附代码)

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 山区和地形图中海拔高的区域划出的线称为地形轮廓,它们提供了地形的高 ...

  9. 基于OpenCV实战:车牌检测

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 拥有思维导图或流程将引导我们朝着探索和寻找实现目标的正确道路的方向 ...

最新文章

  1. asio 异步demo
  2. NDK 获取android的imei和serial number
  3. 简单计算机面试题库及答案_试讲可以看教案吗?必看的面试考前问题解答
  4. openmpi安装_Intel Parallel Studio XE 2019安装设置
  5. FastDFS学习总结(1)--FastDFS安装和部署
  6. 计算机tlv简介_TLV编码格式详解
  7. 车联网正在大跨步发展,但安全问题仍为最大难关
  8. Atitti 模板匹配 Listjava.awt.Point matchTemplate(
  9. 电子密码锁设计-单片机课程设计
  10. 接口解读:你的姓名+身份证号撑起了超11亿元市场规模,你造吗?
  11. oracle修改默认值语句,Oracle 常用的修改语句
  12. python在线问卷调查系统_GitHub - imze/surveySystem: 问卷调查系统
  13. Html5实现的语音搜索功能
  14. 详解java人力外包的费用组成
  15. C语言————文件的打开(知识点总结+举例)
  16. C++/OpenCV实现图像目标识别与分类
  17. 怎么利用计算机制作分形图片,一个能徒手绘制分形图的人 天才之击
  18. oracle集群服务创建表空间,Oracle数据库集群添加表空间操作规范
  19. 工序外协与委外加工区别
  20. 在stm32f103上运行nuttx,添加app和driver的流程

热门文章

  1. Android开发入门一之Android应用程序架构详解
  2. css animation 触发,在JavaScript中触发CSS动画
  3. 基于javaweb的黑马旅游网站来源_喜讯丨创业黑马(重庆)科技孵化中心今日开业!助力重庆高新区打造人工智能创新高地...
  4. windows下开启 PHP扩展Redis
  5. [源码和文档分享]基于AVL树表示的集合ADT实现与应用
  6. 我的邮箱又收到了一封信,这一次,关乎爱情
  7. TCP/IP网络编程之多种I/O函数
  8. JavaScript常用数组操作
  9. 表单提交数据大小的限制
  10. UML从需求到实现----用例