在ARM-Linux下实现车牌识别(二)------车牌识别

之前说到,把车牌区域提前出来后,就可以着手识别程序了。先使用SVM判断是不是车牌。这里为了提高运行速度,板子资源有限,程序里我把svm训练部分注释掉了,假设每次都能找到车牌,实际使用时,还是要加上svm的。
      然后对图像进行分割,我们的分类器只能对数字一个一个地识别,所以把每个数字分割出来,每个字符归一化为20*20的字符。
      基本思想是先用findContours()函数把基本轮廓找出来,然后通过简单验证以确认是否为数字的轮廓。对于那些通过验证的轮廓,接下去会用boundingRect()找出它们的包围盒。
      分割完后就可以进行识别了,字符识别使用ANN算法采用三层神经网络,识别需要用到一些xml文件,这些文件需要用分类器和大量样本做训练,提取他们的特征、,让机器去“学习”(利用训练好的XML文件去预测图像中车牌 ),我找的这三个xml数据集,说实话,不太好用,准确率一般般,有兴趣的可以自己训练。

      完整程序如下,里面有详细注释了:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
#include <cvaux.h> 
#include <stdio.h> 
#include <opencv2/gpu/gpu.hpp>
#include <opencv2/ml/ml.hpp>

using namespace cv; 
using namespace std;

//车牌宽高比为520/110=4.727272左右,误差不超过40%
//车牌高度范围在15~125之间,视摄像头距离而定(图像大小)
bool verifySizes_closeImg(const RotatedRect & candidate)
{
    float error = 0.4;//误差40%
    const float aspect = 4.7272;//44/14; //长宽比
    int min = 15*aspect*15;//20*aspect*20; //面积下限,最小区域
    int max = 125*aspect*125;//180*aspect*180;  //面积上限,最大区域
    float rmin = aspect - aspect*error; //考虑误差后的最小长宽比
    float rmax = aspect + aspect*error; //考虑误差后的最大长宽比

    int area = candidate.size.height * candidate.size.width;//计算面积
    float r = (float)candidate.size.width/(float)candidate.size.height;//计算宽高比
    if(r <1)
        r = 1/r;

    if( (area < min || area > max) || (r< rmin || r > rmax)  )//满足条件才认为是车牌候选区域
        return false;
    else
        return true;
}

void RgbConvToGray(const Mat& inputImage,Mat & outpuImage)  //g = 0.3R+0.59G+0.11B
{
    outpuImage = Mat(inputImage.rows ,inputImage.cols ,CV_8UC1);  

    for (int i = 0 ;i<inputImage.rows ;++ i)
    {
        uchar *ptrGray = outpuImage.ptr<uchar>(i); 
        const Vec3b * ptrRgb = inputImage.ptr<Vec3b>(i);
        for (int j = 0 ;j<inputImage.cols ;++ j)
        {
            ptrGray[j] = 0.3*ptrRgb[j][2]+0.59*ptrRgb[j][1]+0.11*ptrRgb[j][0];  
        }
    }
}

void normal_area(Mat &intputImg, vector<RotatedRect> &rects_optimal, vector <Mat>& output_area )
{
    float r,angle;
    for (int i = 0 ;i< rects_optimal.size() ; ++i)
    {
        //旋转区域
        angle = rects_optimal[i].angle;
        r = (float)rects_optimal[i].size.width / (float) (float)rects_optimal[i].size.height;
        if(r<1)
            angle = 90 + angle;//旋转图像使其得到长大于高度图像。
        Mat rotmat = getRotationMatrix2D(rects_optimal[i].center , angle,1);//获得变形矩阵对象
        Mat img_rotated;
        warpAffine(intputImg ,img_rotated,rotmat, intputImg.size(),CV_INTER_CUBIC);
        imwrite("car_rotated.jpg",img_rotated);//得到旋转图像

        //裁剪图像
        Size rect_size = rects_optimal[i].size;
        if(r<1)
            swap(rect_size.width, rect_size.height); //交换高和宽
        Mat  img_crop;
        getRectSubPix(img_rotated ,rect_size,rects_optimal[i].center , img_crop );//图像切割

        //用光照直方图调整所有裁剪得到的图像,使具有相同宽度和高度,适用于训练和分类
        Mat resultResized;
        //别人写的:
        /*resultResized.create(33,144,CV32FC1);
        resize(img_crop , resultResized,resultResized.size() , 0,0,INTER_CUBIC);
        resultResized.convertTo(resultResized, CV32FC1);
        resultResized = resultResized.reshape(1,1);*/

        resultResized.create(33,144,CV_8UC3);//CV32FC1????
        resize(img_crop , resultResized,resultResized.size() , 0,0,INTER_CUBIC);
        Mat grayResult;
        RgbConvToGray(resultResized ,grayResult);
        //blur(grayResult ,grayResult,Size(3,3));
        equalizeHist(grayResult,grayResult);

        output_area.push_back(grayResult);
    }
}

bool char_verifySizes(c
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值