车牌号识别

本文介绍如何使用光学字符识别(OCR)技术结合人工神经网络(ANN)对车牌号码进行识别。首先进行字符分割,通过直方图均衡、阈值处理和轮廓查找。然后利用多层感知器(MLP)作为神经网络模型,提取特征并训练分类器。实验结果显示,虽然存在一些误识别,但整体流程为车牌字符识别提供了有效的方法。
摘要由CSDN通过智能技术生成

这篇文章接着之前的车牌识别,从输入的车图片中分割识别出车牌之后,将进行下一步:车牌号的识别,这里主要使用光学字符识别车牌字符。对每个检测到的车牌,将其每个字符分割出来,然后使用人工神经网络(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
  • 18
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值