ann

转自 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. 字符分类

(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. 另外,检测出的字符与原车牌的顺序有乱,应该进行调整(待续)

时间: 2024-10-15 03:18:10

ann的相关文章

[数据挖掘课程笔记]人工神经网络(ANN)

人工神经网络(Artificial Neural Networks)顾名思义,是模仿人大脑神经元结构的模型.上图是一个有隐含层的人工神经网络模型.X = (x1,x2,..,xm)是ANN的输入,也就是一条记录的在m个属性上的值.每个属性对应一个输入节点. 对于输入层来说,输入层的输出Oi就是输入层的输入xi. 对于隐含层的其中一个节点j来说,节点j的输入为ΣOiwij (i的取值为所有与节点j相连的输入层节点).可以发现,节点与节点之间的连接是有一个权重的,这个权重将会影响最后的分类结果.而我

人工神经网络--ANN

神经网络是一门重要的机器学习技术.它是目前最为火热的研究方向--深度学习的基础.学习神经网络不仅可以让你掌握一门强大的机器学习方法,同时也可以更好地帮助你理解深度学习技术. 本文以一种简单的,循序的方式讲解神经网络.适合对神经网络了解不多的同学.本文对阅读没有一定的前提要求,但是懂一些机器学习基础会更好地帮助理解本文. 神经网络是一种模拟人脑的神经网络以期能够实现类人工智能的机器学习技术.人脑中的神经网络是一个非常复杂的组织.成人的大脑中估计有1000亿个神经元之多. 图1 人脑神经网络 那么机

OpenCV——ANN神经网络

ANN-- Artificial Neural Networks 人工神经网络 //定义人工神经网络 CvANN_MLP bp; // Set up BPNetwork's parameters CvANN_MLP_TrainParams params; params.train_method=CvANN_MLP_TrainParams::BACKPROP; params.bp_dw_scale=0.1; params.bp_moment_scale=0.1; //params.train_me

传统神经网络ANN训练算法总结 参考 。 以后研究

http://blog.163.com/yuyang_tech/blog/static/21605008320146451352506/ 传统神经网络ANN训练算法总结 2014-07-04 17:13:52|  分类: deeplearning |  标签:ann  |举报|字号 订阅 下载LOFTER我的照片书  | 原文来自:http://blog.csdn.net/bluebelfast/article/details/17139095 ——————————以下为原文——————————

目前所有的ANN神经网络算法大全

http://blog.sina.com.cn/s/blog_98238f850102w7ik.html 目前所有的ANN神经网络算法大全 (2016-01-20 10:34:17) 转载▼ 标签: it   概述 1 BP神经网络 1.1 主要功能 1.2 优点及其局限性 2 RBF(径向基)神经网络 2.1 主要功能 2.2 优点及其局限性 3 感知器神经网络 3.1 主要功能 3.2 优点及其局限性 4 线性神经网络 4.1 主要功能 4.2优点及其局限性 5自组织神经网络 5.1 自组织

codeforces 557 E Ann and Half-Palindrome

题意是要求出一个串的第k大的半回文子串 半回文串的定义是:若一个串其实位置为1,那么当所有奇数位i,且i<=(s.length+1/2),满足s[i]=s[s.length-i+1]的时候, 那么这个串就是半回文串. 作法就是,把这个串的所有半回文子串建成一个字典树,然后查第k大就好了 #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdli

OpenCV3 SVM ANN Adaboost KNN 随机森林等机器学习方法对OCR分类

转摘自http://www.cnblogs.com/denny402/p/5032839.html opencv3中的ml类与opencv2中发生了变化,下面列举opencv3的机器学习类方法实例: 用途是opencv自带的ocr样本的分类功能,其中神经网络和adaboost训练速度很慢,效果还是knn的最好: 1 #include <opencv2/opencv.hpp> 2 #include <iostream> 3 using namespace std; 4 using n

基于ANN的6种调制信号自动调制识别(2ASK、4ASK、2FSK、4FSK、2PSK、4PSK)

目的: 实现6种(2ASK.4ASK.2FSK.4FSK.2PSK.4PSK)调制信号自动调制识别. 条件:windows 10,MATLAB 2014a 内容: 本实验设计了一个分层结构的MLP神经网络分类器.该分类器使用BP算法,自适应改变判决门限,6种调制信号的整体平均识别率为96.94. 更多内容查看:word版(内附完整源代码)下载地址:http://download.csdn.net/download/lanluyug/9923631 一.数字通信调制信号matlab实现原理 1.1

【转】漫谈ANN(2):BP神经网络

上一次我们讲了M-P模型,它实际上就是对单个神经元的一种建模,还不足以模拟人脑神经系统的功能.由这些人工神经元构建出来的网络,才能够具有学习.联想.记忆和模式识别的能力.BP网络就是一种简单的人工神经网络.我们的第二话就从BP神经网络开始漫谈吧. BP的来源 “时势造英雄”,一个伟大的人物的登场总是建立在历史的需求之下,所以我们剖析一个人,得先看看他的出身时代.同样的道理,在讲BP网络的特性和用途之前,我们需要先了解一下它的来源和诞生原因,以便理解它的重要性. 1.1 最简单的神经网络结构——感