这篇文章接着之前的车牌识别,从输入的车图片中分割识别出车牌之后,将进行下一步:车牌号的识别,这里主要使用光学字符识别车牌字符。对每个检测到的车牌,将其每个字符分割出来,然后使用人工神经网络(artificial neural network,ANN)学习算法识别字符。
1.字符分割
将获得的车牌图像进行直方图均衡,然后采用阈值滤波器对图像进行处理,然后查找字符轮廓。
原图像:
阈值图像:
查找轮廓,后画出其外接矩形图像:
然后将字符逐一分割,
分割code:
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <cv.h>
#include <highgui.h>
#include <ml.h>
#include <cvaux.h>
using namespace std;
using namespace cv;
#define HORIZONTAL 1
#define VERTICAL 0
bool verifySizes(Mat r) //验证框出来的区域是否为字符
{
//char sizes 45*77
float aspect = 45.0f / 77.0f; //字符的宽高比为 45/77
float charAspect = (float) r.cols / (float) r.rows;
float error = 0.35;
float minHeight = 15;
float maxHeight = 28;
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;
}
Mat preprocessChar(Mat in)
{
int h = in.rows;
int w = in.cols;
int charSize = 20; //统一字符大小
Mat transformMat = Mat :: eye(2, 3, CV_32F);
int m = max (w, h);
transformMat.at<float>(0,2) = m/2 -w/2;
transformMat.at<float>(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( charSize, charSize));
return out;
}
//计算累积直方图
Mat ProjectedHistogram(Mat img, int t)
{
int sz = (t) ? img.rows :img.cols;
Mat mhist = Mat :: zeros(1, sz, CV_32F);
for (int j =0; j < sz; j++)
{
Mat data = (t)? img.row(j) : img.col(j);
mhist.at<float>(j) = countNonZero(data); //统计这一行/列中的非零元素个数,保存到mhist中
}
double min, max;
minMaxLoc(mhist, &min, &max);
if (max > 0)
{
mhist.convertTo(mhist, -1, 1.0f / max, 0); // 用mhist直方图的最大值,归一化直方图
}
return mhist;
}
Mat getVisualHistogram(Mat *hist, int type)
{
int size =100;
Mat imHist;
if(type == HORIZONTAL)
imHist.create(Size(size, hist->cols), CV_8UC3 );
else
imHist.create(Size(hist->cols, size), CV_8UC3);
imHist = Scalar(55, 55, 55);
for (int i = 0; i < hist->cols; i++)
{
float value = hist->at<float>(i);
int maxval = (int) (value * size);
Point pt1;
Point pt2, pt3, pt4;
if (type == HORIZONTAL)
{
pt1.x = pt3.x = 0;
pt2.x = pt4.x = maxval;
pt1.y = pt2.y = i;
pt3.y = pt4.y = i+1;
line(imHist, pt1, pt2, CV_RGB(220, 220, 220), 1, 8, 0);
line(imHist, pt3, pt4, CV_RGB(34, 34, 34), 1, 8, 0);
pt3.y = pt4.y = i+2;
line(imHist, pt3, pt4, CV_RGB(44, 44, 44), 1, 8, 0);
pt3.y = pt4.y = i+3;
line(imHist, pt3, pt4, CV_RGB(50, 50, 50), 1, 8, 0);
}
else
{
pt1.x = pt2.x = i;
pt3.x = pt4.x = i+1;
pt1.y = pt3.y = 100;
pt2.y = pt4.y = 100 - maxval;
line(imHist, pt1, pt2, CV_RGB(220, 220, 220), 1, 8, 0);
line(imHist, pt3, pt4, CV_RGB(34, 34, 34), 1, 8, 0);
pt3.x = pt4.x = i+2;
line(imHist, pt3, pt4, CV_RGB(44, 44, 44), 1, 8, 0);
pt3.x = pt4.x =i + 3;
line(imHist, pt3, pt4, CV_RGB(50, 50, 50), 1, 8, 0);
}
}
return imHist;
}
void drawVisualFeatures(Mat charcter, Mat hhist, Mat vhist, Mat lowData, int count)
{
Mat img(121, 121, CV_8UC3, Scalar(0,0,0));
Mat ch;
Mat ld;
char res[20];
cvtColor(charcter, ch, CV_GRAY2BGR);
resize(lowData, ld, Size(100, 100), 0, 0, INTER_NEAREST); //将ld从15*15扩大到100*100
cvtColor(ld, ld, CV_GRAY2BGR);
Mat hh = getVisualHistogram(&hhist, HORIZONTAL);
Mat hv = getVisualHistogram(&vhist, VERTICAL);
Mat subImg = img(Rect(0, 101, 20, 20)); //ch:20*20
ch.copyTo(subImg);
subImg = img(Rect(21, 101, 100, 20)); //hh:100*hist.cols
hh.copyTo(subImg);
subImg = img(Rect(0, 0, 20, 100)); //hv:hist.cols*100
hv.copyTo(subImg);
subImg = img(Rect(21, 0, 100, 100)); //ld:100*100
ld.copyTo(subImg);
line( img, Point(0, 100), Point(121, 100), Scalar(0,0,255) );
line( img, Point(20, 0), Point(20, 121), Scalar(0,0,255) );
stringstream ss(stringstream::in | stringstream::out);
ss << "E://opencvcodetext//ANPR//"<<"hist"<< "_" << count <<" .jpg";
imwrite(ss.str(), img);
imshow("visual feature",img); //显示特征
cvWaitKey(0);
}
Mat features(Mat in, int sizeData, int count)
{
//直方图特征
Mat vhist = ProjectedHistogram(in, VERTICAL);
Mat hhist = ProjectedHistogram(in, HORIZONTAL);
Mat lowdata; //低分辨图像特征 sizeData * sizeData
resize(in, lowdata, Size(sizeData, sizeData));
drawVisualFeatures(in, hhist, vhist, lowdata, count); //画出直方图
int numCols = vhist.cols + hhist.cols + lowdata.cols * lowdata.cols;
Mat out = Mat::zeros(1, numCols, CV_32F);
int j = 0;
for (int i =0; i <vhist.cols; i++)
{
out.a