zoukankan      html  css  js  c++  java
  • OpenCV--基于直线检测的文本图像倾斜校正

    图像倾斜矫正的方式有很多种,今天简单介绍一种基于直线检查的倾斜校正。

    这种方法暂时在如下图的文本文件上测试过,不一定能针对所有:

    首先,因为这种图像基本是比较常见的白底黑字,所以首先对这幅图做一个灰度化,灰度化之后做一个二值化,得到二值图像:

    二值化之后,将X轴方向的的像素点连起来,这里我采用的是形态学的膨胀,因为我做二值化的时候采用了取反的操作,这里可以考虑不取反,但是要用腐蚀来做,这里有个技巧,因为是要对X轴来做连接,所以可以在构造形态学核上将Y轴设置为1:

    做了连接后可以使用canny边缘检测做一遍边缘检测,然后再做霍夫变化:

    从上图可以看出来基本上画出来的直线方向跟文字的走向的一致的,然后根据霍夫变换得到的角度来求平均值,这个平均值就是图像要旋转的角度。

    上代码:

    #include <opencv.hpp>
    #include <iostream>
    using namespace cv;
    using namespace std;
    
    void GetContoursPic(const char* pSrcFileName)
    {
    	Mat srcImg = imread(pSrcFileName);
    	imshow("原始图", srcImg);
    	Mat gray, binImg;
    	//灰度化
    	cvtColor(srcImg, gray, COLOR_RGB2GRAY);
    	imshow("灰度图", gray);
    	//二值化
    	threshold(gray, binImg, 50, 255, CV_THRESH_BINARY_INV );
    	imshow("二值化", binImg);
    
    	Mat morphologyDst;
    	cv::morphologyEx(binImg, morphologyDst, cv::MORPH_DILATE, 
    	    cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 1)));
    	imshow("膨胀", morphologyDst);
    
    	Mat cannyDst;
    	Canny(morphologyDst, cannyDst, 150, 200);
    	imshow("Canny", cannyDst);
    
    	vector<Vec2f> lines;
    	HoughLines(cannyDst, lines, 1, CV_PI / 180, 130, 0, 0);
    	Mat houghDst;
    	srcImg.copyTo(houghDst);
    	double meanAngle = 0.0;
    	int numCnt = 0;
    	for (size_t i = 0; i < lines.size(); i++)
    	{
    		float rho = lines[i][0]; //就是圆的半径r
    		float theta = lines[i][1]; //就是直线的角度
    		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(houghDst, pt1, pt2, Scalar(55, 100, 195), 1);
    		
    		theta = theta * 180 / CV_PI - 90;
    		//if (theta > -45 && theta < 45)
    		{
    			meanAngle += theta;
    			numCnt++;
    		}
    	}
    	meanAngle /= numCnt;
    	imshow("霍夫变换", houghDst);
    	cv::Point2f center(srcImg.cols / 2., srcImg.rows / 2.);
    	//获取旋转矩阵(2x3矩阵)
    	cv::Mat rot_mat = cv::getRotationMatrix2D(center, meanAngle, 1.0);
    	cv::Size dst_sz(srcImg.cols, srcImg.rows);
    	Mat warpDst;
    	cv::warpAffine(srcImg, warpDst, rot_mat, dst_sz);
    	imshow("旋转矫正", warpDst);
    
    	cv::waitKey(0);
    }

    结果如下:

    这个方法有几个重要的影响点:

    1、二值化:二值化的阈值选得不好的话结果是不能将前景和背景分离,我试过用OTSU,出来的二值化不是很好,然后检测直线的时候就有一点不太准确,但是基本上也能检测出来:

    2、如果是白底黑字,就用腐蚀,反之有膨胀来做;

    3、边缘检测也很重要,可想而知,不做边缘检测再来做霍夫变换,那得有多少条直线,直接冗余不说,还非常容易干扰检测。

    4、另外,对于一些高度大于宽度的图像,其实可以采用分段检测求平均,以保证每一段的高度小于宽度,因为我的检测主要以X轴为主。

    路漫漫其修远兮

    吾将上下而求索

    上善若水,为而不争。
  • 相关阅读:
    VSFTP日志文件详解
    RocketMQ多master多salve集群搭建
    数据持久化之bind Mounting
    数据持久化之Data Volume
    gitLab 分支保护设置
    docker容器的端口映射
    docker命令之link
    NFS客户端挂载失败之authenticated unmount request from
    docke网络之bridge、host、none
    docke通信之Linux 网络命名空间
  • 原文地址:https://www.cnblogs.com/Bearoom/p/12489396.html
Copyright © 2011-2022 走看看