opencv学习——OCR字符分割

1、读取灰度图像,使用threshold将其二值化,选择CV_THRESH_BINARY_INV,使得字符为白色

Mat input = imread("plate.jpg", 0);
Mat img_threshold;
threshold(input, img_threshold, 60, 255, CV_THRESH_BINARY_INV);

输入:

处理结果:

2、使用findContours接口函数找出各字符的轮廓

vector> contours;

findContours(img_contours, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

3、使用boundingRect函数得到各字符的外接矩形,用rectangle抠取字符图像

Rect mr = boundingRect(Mat(*(itc)));
rectangle(result, mr, Scalar(0, 255, 0));

4、使用verifySizes筛选字符图像

bool verifySizes(Mat r)
{
	float aspect = 45.0f / 77.0f;
	float charAspect = (float)r.cols / (float)r.rows;
	float error = 0.35;
	float minHeight = 15;
	float maxHeight = 28;
	//We have a different aspect ratio for number 1, and it can be ~0.2
	float minAspect = 0.2;
	float maxAspect = aspect + aspect*error;
	float area = countNonZero(r);
	float bbArea = r.cols*r.rows;
	float percPixels = area / bbArea;
	if (percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeight && r.rows < maxHeight)
		return true;
	else
		return false;
}

5、对筛选后的字符图像进行预处理

Mat preprocessChar(Mat in)
{
	//Remap image
	int h = in.rows;
	int w = in.cols;
	Mat transformMat = Mat::eye(2, 3, CV_32F);
	int m = max(w, h);
	transformMat.at(0, 2) = m / 2 - w / 2;
	transformMat.at(1, 2) = m / 2 - h / 2;

	Mat warpImage(m, m, in.type());
	warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0));

	Mat out;
	resize(warpImage, out, Size(20, 20));

	return out;
}

6、将预处理后的字符图像及其在原图中的位置保持;因为findcontours算法得出的各字符的轮廓点是随机的,因此需要各字符图像的位置Rect,通过排序,得到真实的车牌字符顺序。

vector> output;
output.push_back(make_pair(auxRoi, mr));

最终结果:

完整代码如下:

#include  
#include 

using namespace std;
using namespace cv;

bool verifySizes(Mat r);
Mat preprocessChar(Mat in);

int main()
{
	vector> output;
	Mat input = imread("plate.jpg", 0);
	Mat img_threshold;
	threshold(input, img_threshold, 60, 255, CV_THRESH_BINARY_INV);
	Mat img_contours;
	img_threshold.copyTo(img_contours);
	vector> contours;
	findContours(img_contours, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	Mat result;
	img_threshold.copyTo(result);
	cvtColor(result, result, CV_GRAY2RGB);
	drawContours(result, contours, 6, Scalar(255, 0, 0), 1);
	vector>::iterator itc = contours.begin();

	while (itc != contours.end())
	{
		Rect mr = boundingRect(Mat(*(itc)));
		rectangle(result, mr, Scalar(0, 255, 0));
		Mat auxRoi = img_threshold(mr);
		if (verifySizes(auxRoi))
		{
			auxRoi = preprocessChar(auxRoi);
			output.push_back(make_pair(auxRoi, mr));
			rectangle(result, mr, Scalar(0, 125, 255));
		}
		itc++;
	}

	imshow("result", result);
	waitKey(0);

	return 0;
}

bool verifySizes(Mat r)
{
	//Char sizes 45x77
	float aspect = 45.0f / 77.0f;
	float charAspect = (float)r.cols / (float)r.rows;
	float error = 0.35;
	float minHeight = 15;
	float maxHeight = 28;
	//We have a different aspect ratio for number 1, and it can be ~0.2
	float minAspect = 0.2;
	float maxAspect = aspect + aspect*error;
	//area of pixels
	float area = countNonZero(r);
	//bb area
	float bbArea = r.cols*r.rows;
	//% of pixel in area
	float percPixels = area / bbArea;

	if (percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeight && r.rows < maxHeight)
		return true;
	else
		return false;
}

Mat preprocessChar(Mat in)
{
	//Remap image
	int h = in.rows;
	int w = in.cols;
	Mat transformMat = Mat::eye(2, 3, CV_32F);
	int m = max(w, h);
	transformMat.at(0, 2) = m / 2 - w / 2;
	transformMat.at(1, 2) = m / 2 - h / 2;

	Mat warpImage(m, m, in.type());
	warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0));

	Mat out;
	resize(warpImage, out, Size(20, 20));

	return out;
}

 

你可能感兴趣的:(opencv,图像处理)