转自 http://blog.csdn.net/yiluoyan/article/details/45308785
这篇文章接着之前的车牌识别,从输入的车图片中分割识别出车牌之后,将进行下一步:车牌号的识别,这里主要使用光学字符识别车牌字符。对每个检测到的车牌,将其每个字符分割出来,然后使用人工神经网络(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.at<float>(j) = vhist.at<float>(i);
j++;
}
for (int i = 0; i < hhist.cols; i++)
{
out.at<float>(j) = hhist.at<float>(i);
j++;
}
for (int x = 0; x <lowdata.cols; x++)
{
for (int y = 0; y < lowdata.rows; y++)
{
out.at<float>(j) = (float)lowdata.at<unsigned char>(x, y);
j++;
}
}
return out;
}
int main(int argc, char const *argv[])
{
Mat input = imread("E://opencvcodetext//ANPR//img_2.jpg");
cvtColor(input,input,CV_RGB2GRAY);
imshow("srcimg",input);
Mat img_threshold; //存放二值化后的车牌
threshold(input, img_threshold, 60, 255, CV_THRESH_BINARY_INV); //CV_THRESH_BINARY_INV参数可将白色点变为黑色,黑色点变为白色
imshow("阈值化车牌",img_threshold);
Mat img_contours ; //存放车牌号轮廓
img_threshold.copyTo(img_contours); //复制图像
//查找字符的轮廓
vector < vector <Point> > contours; //使用向量格式存储轮廓
findContours(img_contours, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//把找到的轮廓画出来
Mat result;
input.copyTo(result); //先复制车牌图像
cvtColor(result, result, CV_GRAY2BGR); //转为彩色图像,方便看轮廓
vector <vector <Point> >::iterator itc = contours.begin();//定义一个迭代器访问轮廓
int i = 0;
while (itc != contours.end())
{
Rect mr = boundingRect( Mat(* itc)); //创建框图
rectangle(result, mr, Scalar(255, 0, 0), 2);
Mat auxRoi(img_threshold, mr); //根据轮廓裁剪出字符
if (verifySizes(auxRoi)) //判断是否是字符
{
auxRoi = preprocessChar(auxRoi); //对字符进行处理
//sprintf(res, "train_data_%d,jpg",i);
i++;
stringstream ss(stringstream::in | stringstream::out);
ss << "E://opencvcodetext//ANPR//"<<"train_data"<< "_" << i <<" .jpg";
imwrite(ss.str(), auxRoi);
//imwrite(res,auxRoi);
rectangle(result, mr, Scalar(0, 255, 0),2);
Mat f = features(auxRoi, 15, i); //提取字符的直方图特征
}
++itc;
}
imwrite("E://opencvcodetext//ANPR//result1.jpg",result);
imshow("car_plate",result);
cvWaitKey(20);
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
2.人工神经网络(ANN)
分类字符这一步将使用人工神经网络,即使用多层感知器(Multi-Layer Perceptron, MLP). MLP 由一个输入层、一个输出层和一个或多个隐藏层的 神经网络组成。每层有一个或多个神经元痛前一层和后一层相连。
如下图是一个3层的神经元感知器,有3个输入和2个输出,以及包含5个神经元的隐藏层。
每个神经元通过输入权重加上一个偏移项来计算输出值,并由所选择的激励函数进行转换。神经元结构为:
常见的激励函数有S型、高斯型、上图的hadrlim型。单层的单个神经元可以将输入向量分为两类,而一个有S个神经元的感知机,可以将输入向量分为2^S类
神经网络的详细理论可以参考:http://blog.csdn.net/zzwu/article/details/575050
3.特征提取及训练分类器
与SVM分类类似,使用ANN算法识别字符同样需要建立分类器、训练分类器,最后使用分类器识别字符。这里我们使用的特征不是像素值,而是分割字符水平和竖直的累积直方图与字符的低分辨率图像。
对每一个字符,通过使用countNonZero函数来按行或按列统计非零像素值个数,将其保存在mhist中,并对mhist进行归一化处理。
得到的特征图像如下图所示:(左下角为字符图像原始大小20*20,由上角为低分辨率采样后放大的图像100*100,右下角为水平直方图,左上角为垂直直方图)
提取特征完毕后,将特征与对应的标注写到xml文件中,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
//针对书本的西班牙车牌,一共有30个字符(10个数字和20个字母),下面的数组存储的是每个字符的图片个数
const int numFilesChar[] = {35, 40, 42, 41, 42, 33, 30, 31, 49, 44, 30, 24, 21, 20, 34, 9, 10, 3, 11, 3, 15, 4, 9, 12, 10, 21, 18, 8, 15, 7};
const char strCharacters[] = {'0','1','2','3','4','5','6','7','8','9','B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'};
const int numCharacters = 30;
//下面这些参数是自己试验的时候设置的一个较为简单的验证
//const int numFilesChar[] = {1, 1, 1, 1, 1, 1, 1};
//const char strCharacters[] = {'1','2','5','7', 'D', 'T', 'Z'};
//const int numCharacters = 7;
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);
/*sprintf(res, "hist%d.jpg",count);
imwrite(res, 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.at<float>(j) = vhist.at<float>(i);
j++;
}
for (int i = 0; i < hhist.cols; i++)
{
out.at<float>(j) = hhist.at<float>(i);
j++;
}
for (int x = 0; x <lowdata.cols; x++)
{
for (int y = 0; y < lowdata.rows; y++)
{
out.at<float>(j) = (float)lowdata.at<unsigned char>(x, y);
j++;
}
}
return out;
}
Mat Features(Mat in, int sizeData)
{
Mat vhist = ProjectedHistogram(in, VERTICAL);
Mat hhist = ProjectedHistogram(in, HORIZONTAL);
Mat lowData;
resize( in, lowData, Size (sizeData, sizeData));
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.at <float> (j) = vhist.at<float>(i);
j++;
}
for (int i =0; i < hhist.cols; i++)
{
out.at<float>(j) = (float) hhist.at <float> (i);
j++;
}
for (int x = 0; x < lowData.cols; x++)
{
for (int y = 0; y < lowData.rows; y++)
{
out.at<float>(j) = (float) lowData.at<unsigned char>(x,y);
j++;
}
}
return out;
}
int main(int argc, char const *argv[])
{
//char *path = "E://opencvcodetext//ANPR//characters";
Mat classes;
Mat trainingDataf5;
Mat trainingDataf10;
Mat trainingDataf15;
Mat trainingDataf20;
vector <int> trainingLabels;
for (int i = 0; i < numCharacters; i++)
{
int numFiles = numFilesChar[i];
for (int j = 0; j < numFiles; j++)
{
cout << "Character " << strCharacters[i] << " files" << j <<"\n";
stringstream ss (stringstream::in |stringstream::out);
ss << "E://opencvcodetext//ANPR//characters//" << strCharacters[i] <<"1.jpg";
Mat img = imread(ss.str(), 0);
//Mat img = imread("E://opencvcodetext//ANPR//characters//21.jpg",0);
imshow("char",img);
Mat f5 = Features(img, 5);
Mat f10 = Features(img, 10);
Mat f15 = Features(img, 15);
Mat f20 = Features(img, 20);
trainingDataf5.push_back(f5);
trainingDataf10.push_back(f10);
trainingDataf15.push_back(f15);
trainingDataf20.push_back(f20);
trainingLabels.push_back(i); //每一幅字符图片所对应的字符类别索引下标
}
}
//将矩阵转换成浮点矩阵
trainingDataf5.convertTo(trainingDataf5, CV_32FC1);
trainingDataf10.convertTo(trainingDataf10, CV_32FC1);
trainingDataf15.convertTo(trainingDataf15,CV_32FC1);
trainingDataf20.convertTo(trainingDataf20,CV_32FC1);
Mat (trainingLabels).convertTo(classes, CV_32FC1);
FileStorage fs("E://opencvcodetext//ANPR//characters//OCR.xml",FileStorage::WRITE);
fs << "trainingDataF5" << trainingDataf5;
fs << "trainingDataF10" << trainingDataf10;
fs <<"trainingDataF15" << trainingDataf15;
fs << "trainingDataF20" << trainingDataf20;
fs <<"classes" <<classes;
cvWaitKey(20);
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 字符分类
(1) 得到ANN训练文件xml后,利用OpenCV中的CvANN_MLP类来使用ANN算法,识别字符。先通过create函数初始化该类,初始化时需要指定神经网络的层数、神经元数、激励函数、alpha和beta。
(2)训练完ANN分类器后,可以使用predict函数来对特征向量分类,该函数返回一行,大小为类的数量,该向量的每一个元素安阳了输入样本属于每个类的概率。字符的类别有向量中的最大值确定。
分类的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
CvANN_MLP ann;
//针对书本的西班牙车牌,一共有30个字符(10个数字和20个字母),下面的数组存储的是每个字符的图片个数
const int numFilesChar[] = {35, 40, 42, 41, 42, 33, 30, 31, 49, 44, 30, 24, 21, 20, 34, 9, 10, 3, 11, 3, 15, 4, 9, 12, 10, 21, 18, 8, 15, 7};
const char strCharacters[] = {'0','1','2','3','4','5','6','7','8','9','B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'};
const int numCharacters = 30;
//const int numFilesChar[] = {1, 1, 1, 1, 1, 1, 1};
//const char strCharacters[] = {'1','2','5','7', 'D', 'T', 'Z'};
//const int numCharacters = 7;
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;
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);
/*sprintf(res, "hist%d.jpg",count);
imwrite(res, 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.at<float>(j) = vhist.at<float>(i);
j++;
}
for (int i = 0; i < hhist.cols; i++)
{
out.at<float>(j) = hhist.at<float>(i);
j++;
}
for (int x = 0; x <lowdata.cols; x++)
{
for (int y = 0; y < lowdata.rows; y++)
{
out.at<float>(j) = (float)lowdata.at<unsigned char>(x, y);
j++;
}
}
return out;
}
Mat Features(Mat in, int sizeData)
{
Mat vhist = ProjectedHistogram(in, VERTICAL);
Mat hhist = ProjectedHistogram(in, HORIZONTAL);
Mat lowData;
resize( in, lowData, Size (sizeData, sizeData));
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.at <float> (j) = vhist.at<float>(i);
j++;
}
for (int i =0; i < hhist.cols; i++)
{
out.at<float>(j) = (float) hhist.at <float> (i);
j++;
}
for (int x = 0; x < lowData.cols; x++)
{
for (int y = 0; y < lowData.rows; y++)
{
out.at<float>(j) = (float) lowData.at<unsigned char>(x,y);
j++;
}
}
return out;
}
void train(Mat TrainData, Mat classes, int nlayers)
{
Mat layerSizes(1, 3, CV_32SC1);
layerSizes.at< int > (0) = TrainData.cols;
layerSizes.at <int> (1) = nlayers;
layerSizes.at < int > (2) = numCharacters;
ann.create(layerSizes, CvANN_MLP :: SIGMOID_SYM, 1, 1);
Mat trainClasses;
trainClasses.create(TrainData.rows, numCharacters, CV_32FC1);
for (int i =0; i < trainClasses.rows; i++)
{
for (int k = 0; k < trainClasses.cols; k++)
{
if( k == classes.at< int> (i))
trainClasses.at <float>(i,k)=1;
else
trainClasses.at<float>(i, k) = 0;
}
}
Mat weights( 1, TrainData.rows, CV_32FC1, Scalar::all(1));
ann.train( TrainData, trainClasses, weights);
//trained = true;
}
int Classify (Mat f)
{
int result = -1;
Mat output( 1, numCharacters, CV_32FC1);
ann.predict(f, output);
Point maxLoc;
double maxVal;
minMaxLoc(output, 0, &maxVal, 0, &maxLoc);
return maxLoc.x;
}
int main(int argc, char const *argv[])
{
//char *path = "E://opencvcodetext//ANPR//characters";
Mat classes;
Mat trainingData;
FileStorage fs;
fs.open("E:/opencvcodetext/ANPR/OCR.xml",FileStorage::READ);
fs [ "TrainingDataF10"] >> trainingData;
fs ["classes" ]>> classes;
train(trainingData, classes, 10); //训练神经网络
Mat input = imread("E:/opencvcodetext/ANPR/img_2.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat img_threshold ;
threshold( input, img_threshold, 60, 255, CV_THRESH_BINARY_INV);
Mat img_contours;
img_threshold.copyTo(img_contours);
vector < vector <Point> > contours;
findContours( img_contours, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
vector < vector <Point> > :: iterator itc = contours.begin();
while (itc != contours.end())
{
Rect mr = boundingRect( Mat (*itc));
Mat auxRoi (img_threshold, mr);
if (verifySizes(auxRoi))
{
auxRoi = preprocessChar(auxRoi);
Mat f = Features(auxRoi, 10);
int charcter = Classify(f);
printf("%c", strCharacters[charcter]);
}
++itc;
}
printf("\n");
cvWaitKey(20);
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
实验结果:这里的顺序改变了,应该要还原字符的位置。。而且识别也不是百分百的准确,出现了错误:将 7 识别为 T 了。
原图:
识别:
最后,写一下调试程序的错误总结:
1. 二值黑白图像不等同于灰度图像
2. 图像的像素值是unsight char的
3. 在测试时,注意提取特征的一一对应,注意TrainingDataF10以及后面的 Features(auxRoi, 10) 的关系。
4. 另外,检测出的字符与原车牌的顺序有乱,应该进行调整(待续)