基于opencv4.0文本矫正

上一篇的代码如果然后处理下面图片就会失效,因为没有明显的轮廓信息。

但观察图片就会发现图中每行文字都在一条直线上,所以这时候考虑用霍夫检查,通过画出的每行直线计算角度然后矫正图片。

1.图片灰度化

2.canny运算,找出文字轮廓

3霍夫检测,得到每行直线

4计算角度矫正图片

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
double CalcDegree(Mat &binarysrc);
//度数转换
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,  src.size(), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色  
}
double CalcDegree(Mat &binarysrc)
{

	Mat binary,dstImage,lineimage;
	binarysrc.copyTo(binary);
	binarysrc.copyTo(dstImage);
	binarysrc.copyTo(lineimage);
	cvtColor(binary, binary, COLOR_RGB2GRAY);
	Canny(binary, binary, 50, 200, 3);
	

	// 	vector<Vec2f>lines;
	// 	HoughLines(binary, lines, 1, CV_PI / 180, 200, 0, 0);

	vector<Vec2f> lines;
	HoughLines(binary, lines, 1, CV_PI / 180, 300, 0, 0);//第5个参数就是阈值,阈值越大,检测精度越高
														   //cout << lines.size() << endl;

														   //由于图像不同,阈值不好设定,因为阈值设定过高导致无法检测直线,阈值过低直线太多,速度很慢
														   //所以根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。

	if (!lines.size())
	{
		HoughLines(binary, lines, 1, CV_PI / 180, 200, 0, 0);
	}
	//cout << lines.size() << endl;

	if (!lines.size())
	{
		HoughLines(binary, lines, 1, CV_PI / 180, 150, 0, 0);
	}
	//cout << lines.size() << endl;
	if (!lines.size())
	{
		cout << "没有检测到直线!" << endl;
		return 0;
	}
	
	float sum = 0;
	for (size_t i = 0; i < lines.size(); i++)
	{
		float rho = lines[i][0], thrta = lines[i][1];
		Point pt1, pt2;
		double a = cos(thrta), b = sin(thrta);
		double x0 = a*rho, y0 = b*rho;   //x=ρcosθ y = ρsinθ
		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(lineimage, pt1, pt2, Scalar(0, 255, 0), 1, 0, 0);
		sum += thrta;
	}

	imshow("画线图", lineimage);
	float average = sum / lines.size();
	cout << "average theta:" << average << endl;
	double angle = DegreeTrans(average) - 90;
	Mat dst;
	rotateImage(dstImage, dst, angle);
	imshow("旋转后", dst);
	return angle;

}
int main()
{
	Mat src;
	src = imread("wenzi.jpg", 1);
	if (src.data == 0)
	{
		printf("没有读入图片");
		return 0;
	}
	imshow("原图",src);
	double angle=CalcDegree(src);
	cout << "angle:" << angle;
	waitKey(0);
	return 0;
}

void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )


参数:
image:边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图)

lines:储存着检测到的直线的参数对  的容器 ,其中lines存放两个参数 第一个极坐标中是原点到目标的的距离,第二个是弧度 θ。θ/Π*180为度数。

rho:参数极径  以像素值为单位的分辨率. 我们使用 1 像素.

theta:参数极角  以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)

theta:要”检测” 一条直线所需最少的的曲线交点

srn and stn: 参数默认为0.
 

https://blog.csdn.net/nchfgfb/article/details/70026811 原作者

pt1.x = cvRound(x0 + 1000*(-b))这段代码看得我有点蒙蔽,我就百度一下把人家写好的拿下来放在这里

0_1325123993yZ4k.gif

这里是取了点(x0,y0)在直线上上下1000的距离,那么用cvLine画出来的线段就是从pt1 -> pt2的了。那么pt1->pt2的直线距离就是2000。可以取其他的距离,不一定去1000,如600也可以,具体的数字可以自己定义。

1.这个地方也许会出现检测出来的线段长度比pt1->pt2还大,即包含了我们画的线段 , 这是肯定的。

2. 还会出现本来线段没有pt1->pt2这么长,那么我们画的就会过长了。 也是肯定会出现的情况。

因为:CV_HOUGH_STANDARD方法 只能得出rh0 和 θ的值。 这两个值只能确定直线,而不能确定线段是从哪开始到哪结束。

此方法标准型的霍夫变换检测只能确定线段对应的直线。如果你想得到一条直线的两个端点的具体坐标,可以使用CV_HOUGH_PROBABILISTIC(概率型霍夫变换).

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值