基于opencv实现车牌号识别之失败作品

简介

  在csdn上发现了一个http://blog.csdn.net/maotoula/article/details/7680716 ,上面有分析对于一个车牌的识别过程。于是跟着这个流程分析,自己利用opencv
来代码实现了一遍。

图像预处理

  首先拿到如下的车牌照片:
   
  接着对它进行一些预处理,这里做的是简单的将它灰阶二值化:
 uchar* ptr = img_2.ptr(0);  

/********************************************************************/
    for(int i = 0; i < width; i++){
        for(int j=0;j<height;j++){
            s = cvGet2D(&pI,i,j);
            int grayScale = (int)(s.val[0]*0.299 + s.val[1]*0.587 + s.val[2]*0.114);
            ptr[i*height+j] = grayScale;
        }
    }
    cv::namedWindow("img_2");
    cv::imshow("img_2",img_2);
/*********************************************************************/
    for(int i = 0; i < width; i++){
        for(int j=0;j<height;j++){
            if(ptr[i*height+j] > 125){
                ptr[i*height+j] = 255;
            }else{
                ptr[i*height+j] = 0;
            }
        }
    }   
  也就是用之前讲过的算法,先RGB通道图片转化为灰阶图片,然后在利用设置的阀值125,将图片转化为2值图像。生成结果如下:

  

字符分割

  第二步是在二值图像中将其中的7个字符都单独分离出来。我们的测试照片现在已经变成了字体白色,背景黑色,然后上下还有4个白色的铆钉。
因此我们需要做的是消除掉4个铆钉,然后将7个字符单独分离出来。
  1、使用的办法也是如blog所示的,首先将图片水平扫描啊,然后将图片垂直扫描。如图片所示中,我们可以看到,图片中的铆钉所在的行中,它们所在的像素是最少的。
和真实数字之间有着很明显的区别。所以,可以做一个阀值判断,在水平扫描的时候。从头开始,直到像素点多于20的时候,表示真正是字符开始了。然后直到某行像素
低于20时候,表示字符结束了。
int real_width1, real_width2;
    int flag_width[width];

    for(int i = 0; i < width; i++){
        for(int j=0;j<height;j++){
            s = cvGet2D(&pI_2,i,j);
            if(s.val[0] == 255){
                flag += 1;
            }
        }
        flag_width[i] = flag;
        flag = 0;
    }
    for(int i=0;i<width;i++){
        if(flag_width[i] > 20){
            real_width1 = i;
            break;
        }
    }   

    for(int i=width-1;i>0;i--){
        if(flag_width[i] > 20){
            real_width2 = width - i;
        }
    }
    printf("real_width1:%d,real_width2:%d\n",real_width1,real_width2);

  这样最后获得的real_width1和real_width2就表示是字符真正行开始和结束的位置,因此,字符开始和结束的纵坐标也就确定了。
  2、接着找到每一个字符开始和结束的横坐标。由于每个字符之间是分离开的,所以我们可以直接扫描每一列,当发现有255的像素时候,就是第一个字符开始位置,
一只到某一列没有255像素出现时候,表示是第一个字符结束位置,和下一个字符开始扫描的位置,直到所有的7个字符扫描结束。
int real_address[7][2];

    for(int j=0;j<height;j++){
        flag = 0;
        for(int i = real_width1; i < real_width2; i++){
            s = cvGet2D(&pI_2,i,j);
            if(s.val[0]==255){
                if(real_height1 == -1){
                    real_height1 = j;
                }
                flag = 1;
                break;
            }
        }
        if((real_height1 != -1) && (flag ==0)){
            real_height2 = j;
            if(real_height2 - real_height1 < 10){
                real_height1 = -1;
                flag = 0;
                continue;
            }
            real_address[record_number][0] = real_height1;
            real_address[record_number][1] = real_height2;
            real_height1 = -1;
            real_height2 = 0;
            record_number += 1;
        }
    }
    for(int i=0; i<7; i++){
        printf("height1[%d]:%d,height2[%d]:%d\n",i, real_address[i][0], i, real_address[i][1]);
    } 
  这样,7个字符的纵坐标开始和结束位置就都存在了数组real_address中。然后,我们把它们显示出来:
void wordshow(int number){
    cv::Mat word;
    int word_width = real_width2 - real_width1;
    int word_height;
    uchar* ptr_word;
    char str[2];

    sprintf(str, "%d", number);

    word_height  = real_address[number][1] - real_address[number][0];
    word = cv::Mat(word_width, word_height, CV_8UC1, 1);
    ptr_word = word.ptr(0);

    for(int i = real_width1; i < real_width2; i++){
        for(int j=real_address[number][0]; j<real_address[number][1]; j++){
            int tmp;
            s = cvGet2D(&pI_2,i,j);
            tmp = (int)s.val[0];
            ptr_word[(i-real_width1) * word_height + (j - real_address[number][0])] = tmp;
        }
    }
    cv::namedWindow(str);
    cv::imshow(str,word);
}
  显示出来的字符分割结果如下:
 
代码下载如下:http://download.csdn.net/detail/u011630458/8414317

归一化处理

  之后,需要对分割出来的7个字符图片做归一化处理,简单的说,就是要将这7张图片从新设置大小为一样的。我这里设置为了40X20
使用的是opencv自带的函数cvResize。
..........
 word2 = cv::Mat(40, 20, CV_8UC1, 1);
 IplImage pI_3 = word;
 IplImage pI_4 = word2;
 cvResize(&pI_3, &pI_4, 1);
.........
  这样就将原来的word图像复制一份到了word2,并设置为了40x20到大小。这样做的目的是方便之后进行模板匹配。我使用的模板图像就是40x20的。

字符识别

  这里使用模板匹配来做字符识别,使用的函数是opencv官方教程中提到过的SSIM,这个函数返回图像的结构相似度指标。这是一个在0-1之间的浮点数(越接近1,
相符程度越高)。
  代码中,在文件夹match_pic下,存放在用来匹配的模板图片。然后将分割出来的7个字符,每一个都使用getMSSIM来对所有的模板图片进行一一匹配,选择出匹配
相似度最高的图片,表示为对应的字符。
  最后识别出来的结果如下:
   
  代码下载位置:http://download.csdn.net/detail/u011630458/8414375

总结

  如果所示,该方法识别率低下。而且中间使用字符提取的方式太简单和无法通用,所以。。只能作为基本的练习。。
时间: 2024-08-26 18:41:48

基于opencv实现车牌号识别之失败作品的相关文章

基于TensorFlow的车牌号识别系统

简介 过去几周我一直在涉足深度学习领域,尤其是卷积神经网络模型.最近,谷歌围绕街景多位数字识别技术发布了一篇不错的paper.该文章描述了一个用于提取街景门牌号的单个端到端神经网络系统.然后,作者阐述了基于同样的网络结构如何来突破谷歌验证码识别系统的准确率. 为了亲身体验神经网络的实现,我决定尝试设计一个可以解决类似问题的系统:车牌号自动识别系统.设计这样一个系统的原因有3点: 我应该能够参照谷歌那篇paper搭建一个同样的或者类似的网络架构:谷歌提供的那个网络架构在验证码识别上相当不错,那么讲

Java基于opencv实现图像数字识别(一)

Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用BufferedImage这个类进行操作:尝试着做了一下,做到灰度化,和二值化就做不下去了:然后几乎就没有啥java的资料了,最多的好像都是c++,惹不起.惹不起...... 我也想尝试着用c++做一下,百度到了c++基于opencv来做图像识别的:但是要下vs啊,十几个g呢,我内存这么小,配置这么麻烦,而且vs

Java基于opencv实现图像数字识别(二)—基本流程

Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要是表格中数字的识别,但这个不是重点.重点是通过这个我们可以举一反三,来实现我们自己的业务. 图像的识别主要分为两步:图片预处理和图像识别:这两步都很重要 图像预处理: 1. 图像灰度化:二值化 2. 图像降噪,去除干扰线 3. 图像腐蚀.膨胀处理 4. 字符分割 5. 字符归一化 图像识别: 1.

我的毕设-基于OpenCV的图像车牌识别(I)

由于大三以来一直在学路由交换和Linux方面,所以Coding能力大幅下降,加上毕设老师指定了一个完全不会的题目,恍如晴天霹雳,硬着头皮接下了任务,查阅了相关资料以后暂定使用OpenCV+VS2013来完成这个毕设,苦于C++在校根本没学_(:з」∠)_,又是霸王硬上弓,本篇文章可能显得十分小白,请谅解 本随笔随着完成进度的更新而更新 一:环境 Win10+VS2013+OpenCV 3.0 二:下载与安装 OpenCV 3.0下载地址:https://opencv.org/releases.h

AI人工智能之基于OpenCV+face_recognition实现人脸识别

因近期公司项目需求,需要从监控视频里识别出人脸信息.OpenCV非常庞大,其中官方提供的人脸模型分类器也可以满足基本的人脸识别,当然我们也可以训练自己的人脸模型数据,但是从精确度和专业程度上讲OpenCV所提供的人脸识别要弱于face_recognition,所以我们采取OpenCV处理视频流.face_recognition来识别人脸. 为什么选择Python? 博主本身是Java工程师,在公司主要通过Java语言进行开发,起初我们尝试过通过Java+OpenCV的方式来实现,但是效果并不是很

opencv实现车牌识别之车牌号定位_1

简介 按照在哪里跌倒就在哪里爬起来的精神,本章继续做车牌号的检测识别.所有步骤分为3步完成:车牌号定位,车牌号字符分割.字符识别. 本章为第一部分:车牌号定位. 效果演示 正式开始讲解之前,先看下车牌号定位出来的效果演示.注:本文所有图片均来源于网络. 如图所示,定位到车牌号之后,将车牌号用黄色框选起来,同时将该车牌复制为新图片显示出来. 代码及实现原理讲解 图像灰阶/二值化 首先也是常用的操作,将图像灰阶化,然后从像素值为255一侧开始,以累积像素占总像素5%的的地方作为二值化的阀值,进而获得

Android OpenCV集成摄像头图片动态识别车牌号

最近两天开发一个使用OpenCV集成的一个识别车牌号的项目,困难重重,总结一下相关经验,以及开发注意事项: 一.开发环境: Android Studio 个人版本 3.1.4 NDK下载:14b CMake:Android Studio SDK Tools中下载 参考资料:https://github.com/zeusees/HyperLPR   集成有冲突未解决: 很实用的一个Dmeo以这个为例 https://blog.csdn.net/u011686167/article/details/

opencv实现车牌识别之车牌号定位_2

简介 前一篇讲解到了将用蓝色筛选后的图片,再一次灰阶/二值化.现在从这里继续讲解. 矩形检测 因为车牌是一个矩形.所以接着将又一次二值化之后的图片,进行膨胀,之后在进行矩形检测.框选出可能是车牌号的矩形区域. 代码如下: int** car_License_box(Mat& mat1, Mat& mat2, int* number){ Mat threshold_output; vector<vector<Point> > contours; vector<V

不想手动输入车牌号?手机Android端车牌识别助你一臂之力!

关键词:手机车牌识别 Android端车牌识别 移动端车牌识别 车牌识别 随着车辆的暴涨,对车辆的管理也是日益严峻.需要更多灵活的有效的管理方式,伴随着移动端APP的火爆应用,北京易泊时代将原来应用在电脑端的车牌识别技术转移到了手机Android端,手机Android端车牌识别更加灵活,方便,为人们的应用解决了很多实际困难. 手机Android端车牌识别产品描述 手机Android端车牌识别系统是北京易泊时代开发的基于移动平台的证件识别应用程序,支持Android/IOS等多种主流移动操作系统.