opencv车牌识别

网上有很多车牌识别的源代码,很乱,于是自己整理了一份,并把主函数精简到最简单,因为如果主函数里面子函数太多的话,想自己再添加东西进去,不容易,处处是大括号,一会就迷糊了。但是把子函数拉出去的话,就需要把
形参和实参的关系协调好。处理不好就老是出问题,还有就是让主函数中调用子函数时,让谁当实参,也要引起注意!这也是设计子函数形参个数与类别的依据。下面这是作者花了大约一周的时间,对本文的整理,理解,修改,调试并最终定稿的!期望能对广大学习计算机视觉的大学生和爱好者有所帮助。
/**********************************************************************************\
                                车牌识别总思路
    一:载入图像,初步处理,并二值化;                //二值化
二:寻找含有车牌有效信息的区域                    //定位
      1:找上行位置
  2;找下行位置
  3:找左列位置
  4:找右列位置
三:提取ROI并归一化处理                           //ROI
四:分割字符并画白线显示分割区域                  //分割
五:定位每个字符的区域并独立显示                  //显示
                                             *** 迷途中的前进——2015_02_06***
\***************************************************************************************/
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <iostream>
using namespace std;
#define T 27                            //判断一行是不是车牌有效信息的阈值
#define T1 2                            //判断一列是不是车牌有效信息的阈值
#define S(image,x,y) ((uchar*)(image->imageData + image->widthStep*(y)))[(x)]
                                        //S(image,x,y)指该图像(x,y)像素点的像素值,[(x)]是数组,类似于a[i]
    IplImage *src;
IplImage *pImg8u=NULL;             //灰度图
IplImage *pImg8uSmooth=NULL;       //高斯滤波后的图
IplImage *pImgCanny=NULL;          //二值化的图
IplImage *pImg8uROI=NULL;         //感兴趣的图片
IplImage *pImgResize=NULL;        //归一化的灰度图


IplImage *pImgCharOne=NULL;
IplImage *pImgCharTwo=NULL;
IplImage *pImgCharThree=NULL;
IplImage *pImgCharFour=NULL;
IplImage *pImgCharFive=NULL;
IplImage *pImgCharSix=NULL;
IplImage *pImgCharSeven=NULL;




int i,j;
int row_start,row_end;             //用来记录车牌开始,结束行
int col_start,col_end;             //用来记录车牌开始,结束列
    int row[120];                      //row[]存放含有有效车牌信息的第j行,把所有有效行放一个数组里面,统一管理,有利于判断。
int col[340];                      //存放每个字符双边界(列)的位置
int k=0;                           //含有有效车牌信息的行数
int nCharWidth=45;                 //每个字符的列,也就是宽度
int nSpace=12;                     //字符之间的间隙
int nWidth=409;                    //(409,90)分别为感兴趣图像的宽度与高度
int nHeight=90;

void find_UpAndDown_row(IplImage *src_son_row);    
                                 //定义一个子函数,找到图片中含有车牌有效信息的最上行和最下行
void find_LeftAndRight_col(IplImage *src_son_col);    
                                 //定义一个子函数,找到图片中含有车牌有效信息的最左列和最右列
void find_ROI(IplImage *before_ROI,IplImage *after_ROI);
                                //定义一个子函数find_ROI,找到图片中只含有目标区域的部分
void cut_and_drawLine(IplImage *befour_cut_image );
                                //定义一个子函数cut_and_drawLine,对含有车牌有效信息的图片分割出字符,并画出分割线
void show_every_char(IplImage *showChar);
                                //定义一个子函数show_every_char,显示出所有分割出来的字符
void main()
{
src=cvLoadImage("20.jpg",-1);
pImg8uSmooth=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
pImg8u=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
pImgCanny=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
cvCvtColor(src,pImg8u,CV_RGB2GRAY);                //灰度化
cvSmooth(pImg8u,pImg8uSmooth,CV_GAUSSIAN,3,0,0);   //高斯滤波
cvCanny(pImg8uSmooth,pImgCanny,100,200,3);         //二值化
cvDilate(pImgCanny,pImgCanny,0,1);
cvErode(pImgCanny,pImgCanny,0,1);
cvNamedWindow("cvcanny",1);
cvShowImage("cvcanny",pImgCanny);




row_start=0;
row_end=0;
col_start=0;
col_end=0;
cout<<"图片的高度值(即像素的行数)为:"<<pImgCanny->height<<endl;
cout<<"图片的宽度值(即像素的列数)为:"<<pImgCanny->width<<endl;




find_UpAndDown_row(pImgCanny);   //找到图片中含有车牌有效信息的最上行和最下行
find_LeftAndRight_col(pImgCanny);//找到图片中含有车牌有效信息的最左列和最右列
  find_ROI(pImg8u,pImg8uROI);      //找到图片中只含有目标区域的部分


pImgResize=cvCreateImage(cvSize(nWidth,nHeight),IPL_DEPTH_8U,1);
cvResize(pImg8uROI,pImgResize,CV_INTER_LINEAR); //线性插值
cvNamedWindow("感兴趣图像的宽度与高度",1);
cvShowImage("感兴趣图像的宽度与高度",pImgResize);

cut_and_drawLine(pImgResize );    //对含有车牌有效信息的图片分割出字符,并画出分割线
show_every_char(pImgResize);      //显示出所有分割出来的字符
cvWaitKey(0);


cvReleaseImage(&pImgResize);
cvReleaseImage(&pImg8uROI);
cvReleaseImage(&pImgCharOne);
cvReleaseImage(&pImgCharTwo);
cvReleaseImage(&pImgCharThree);
cvReleaseImage(&pImgCharFour);
cvReleaseImage(&pImgCharFive);
cvReleaseImage(&pImgCharSix);
cvReleaseImage(&pImgCharSeven);


cvDestroyAllWindows();
}


/******************************************************************************************\
            定义一个子函数find_UpAndDown_row,找到图片中含有车牌有效信息的最上行和最下行
\******************************************************************************************/
void find_UpAndDown_row(IplImage *src_son_row){
/判断每行是不是含有车牌信息的行是通过查看黑点白点变化的次数来确定的


for(j=0;j<src_son_row->height;j++)          
                                              //遍历整幅图的行和列,寻找包含车牌信息的行数
{
int count=0;                                       //  count/2  记录每行白点(水平的白线看做一个点)的个数
for(i=0;i<src_son_row->width;i++)
{
if(S(src_son_row,i,j)!=S(src_son_row,i+1,j))  //统计行跳数
count++;
if(count>T)                               //把含有车牌有效信息的行j存放到row[k]
{
row[k]=j;
k++;                                  //记录含有有效车牌信息的行数
break;
}
}
//cout<<"count值为:"<<count<<endl;
}
cout<<"有效行k值为:"<<k<<endl;
for(i=0;i<k;i++)                                 //从上边开始,3行连续时认为是起始行
{
if((row[i]==row[i+1]-1)&&(row[i+1]==row[i+2]-1)){
row_start=row[i];
           // cout<<"the start row123:"<<row_start<<endl;
break;
}
}
cout<<"the start row:"<<row_start<<endl;
cvLine(pImg8u,cvPoint(0,row_start),cvPoint(src->width,row_start),cvScalar(255,0,0),1,8,0);
cvNamedWindow("划线_上",1);
cvShowImage("划线_上",pImg8u);


for(i=k-1;i>row_start;i--)     //从下边开始,3行连续时认为是起始行
{
if((row[i]==row[i-1]+1)&&(row[i-1]==row[i-2]+1)){
row_end=row[i];
break;
}
}
cout<<"the end row:"<<row_end<<endl;
cvLine(pImg8u,cvPoint(0,row_end),cvPoint(src->width,row_end),cvScalar(255,0,0),1,8,0);
cvNamedWindow("划线_上下",1);
cvShowImage("划线_上下",pImg8u);
}
/******************************************************************************************\
      定义一个子函数find_LeftAndRight_col,找到图片中含有车牌有效信息的最左列和最右列
\******************************************************************************************/
void find_LeftAndRight_col(IplImage *src_son_col){
/判断每列是不是含有车牌有效信息是查看每列中含有白点像素的个数
bool flag=false;
for(i=10;i<src_son_col->width;i++)           //找到左列开始???i为什么是10???
{
int count=0;
for(j=row_start;j<row_end;j++)
{
if(S(src_son_col,i,j)==255)
count++;
if(count>T1)
{
col_start=i;
flag=true;
break;
}
}
if(flag) break;
}
cout<<"the start col:"<<col_start<<endl;
cvLine(pImg8u,cvPoint(col_start,row_start),cvPoint(col_start,row_end),cvScalar(255,0,0),1,8,0);
cvNamedWindow("划线_左",1);
cvShowImage("划线_左",pImg8u);


flag=false;
for(i=src_son_col->width-10;i>col_start;i--)           //找到右列开始
{
int count=0;
for(j=row_start;j<row_end;j++)
{
if(S(src_son_col,i,j)==255)
count++;
if(count>T1)
{
col_end=i;
flag=true;
break;
}
}
if(flag) break;
}
cout<<"the end col:"<<col_end<<endl;
cvLine(pImg8u,cvPoint(col_end,row_start),cvPoint(col_end,row_end),cvScalar(255,0,0),1,8,0);
cvNamedWindow("划线_左右",1);
cvShowImage("划线_左右",pImg8u);
}
/******************************************************************************************\
              定义一个子函数find_ROI,找到图片中只含有目标区域的部分
\******************************************************************************************/
void find_ROI(IplImage *before_ROI,IplImage *after_ROI){
CvRect ROI_rect;                 //获得图片感兴趣区域
ROI_rect.x=col_start;
ROI_rect.y=row_start;
ROI_rect.width=col_end-col_start;
ROI_rect.height=row_end-row_start;
cvSetImageROI(pImg8u,ROI_rect);
pImg8uROI=cvCreateImage(cvSize(ROI_rect.width,ROI_rect.height),IPL_DEPTH_8U,1);
cvCopy(pImg8u,pImg8uROI);
cvResetImageROI(pImg8u);
}
 /******************************************************************************************\
      定义一个子函数cut_and_drawLine,对含有车牌有效信息的图片分割出字符,并画出分割线
\******************************************************************************************/
 void cut_and_drawLine(IplImage *befour_cut_image ){
///得到每个字符的双边界
//七个字符的间距坐标间距,只看水平方向。分别为:0(0,45),1(57,102),2(136,181),3(193,238)
//                                              4(250,295),5(307,352),6(364,409)
//并存放在col[]里面
for(i=0;i<7;i++)          
{
switch(i){
case 0:                                          //0是省份名占45个像素
case 1:                                          //1是市名的字母占45个像素
col[i*2]=i*nCharWidth+i*nSpace;
cout<<col[i*2]<<endl;
col[i*2+1]=(i+1)*nCharWidth+i*nSpace;
cout<<col[i*2+1]<<endl;
break;                                       //1与2之间有个点宽度是34个像素
case 2:                                          //2---6是剩余的字母和数字各自占45个像素
case 3:
case 4:
case 5:
case 6:
col[i*2]=i*nCharWidth+i*nSpace+22;
cout<<col[i*2]<<endl;
col[i*2+1]=(i+1)*nCharWidth+i*nSpace+22;
cout<<col[i*2+1]<<endl;
break;
}


}
for(i=0;i<14;i++)        //画出每个字符的区域
{
cvLine(befour_cut_image,cvPoint(col[i],0),cvPoint(col[i],nHeight),cvScalar(255,0,0),1,8,0);
//cout<<col[i*2]<<" "<<col[2*i+1]<<" ";
}
//cvNamedWindow("画出每个字符的区域",1);
//cvShowImage("画出每个字符的区域",befour_cut_image);


 }
/******************************************************************************************\
              定义一个子函数show_every_char,显示出所有分割出来的字符
\******************************************************************************************/
void show_every_char(IplImage *showChar){

pImgCharOne=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);
pImgCharTwo=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);
pImgCharThree=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);
pImgCharFour=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);
pImgCharFive=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);
pImgCharSix=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);
pImgCharSeven=cvCreateImage(cvSize(nCharWidth,nHeight),IPL_DEPTH_8U,1);


CvRect ROI_rect1;
ROI_rect1.x=col[0];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharOne,NULL); //获取第1个字符
cvResetImageROI(showChar);


ROI_rect1.x=col[2];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharTwo,NULL); //获取第2个字符
cvResetImageROI(showChar);


ROI_rect1.x=col[4];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharThree,NULL); //获取第3个字符
cvResetImageROI(showChar);


ROI_rect1.x=col[6];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharFour,NULL); //获取第4个字符
cvResetImageROI(showChar);


ROI_rect1.x=col[8];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharFive,NULL); //获取第5个字符
cvResetImageROI(showChar);


ROI_rect1.x=col[10];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharSix,NULL); //获取第6个字符
cvResetImageROI(showChar);


ROI_rect1.x=col[12];
ROI_rect1.y=0;
ROI_rect1.width=nCharWidth;
ROI_rect1.height=nHeight;
cvSetImageROI(showChar,ROI_rect1);
cvCopy(showChar,pImgCharSeven,NULL); //获取第7个字符
cvResetImageROI(showChar);

cvNamedWindow("分割后的车牌",1);
cvShowImage("分割后的车牌",showChar);
cvNamedWindow("one",CV_WINDOW_AUTOSIZE);
cvShowImage("one",pImgCharOne);
cvNamedWindow("two",1);
cvShowImage("two",pImgCharTwo);
cvNamedWindow("three",1);
cvShowImage("three",pImgCharThree);
cvNamedWindow("four",1);
cvShowImage("four",pImgCharFour);
cvNamedWindow("five",1);
cvShowImage("five",pImgCharFive);
cvNamedWindow("six",1);
cvShowImage("six",pImgCharSix);
cvNamedWindow("seven",1);
cvShowImage("seven",pImgCharSeven);

}





原文连接:http://blog.csdn.net/ding977921830/article/details/43564003


  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
OpenCV是一个广泛用于计算机视觉和图像处理的开源库,它提供了许多用于处理图像和视频的函数和算法。而车牌识别是其中一个应用之一。 车牌识别是一种图像处理技术,用于自动识别不同车辆的车牌号码。这个过程通常分为几个步骤。首先,需要进行车牌检测,即找到图像中车牌所在的位置。这可以通过使用OpenCV中的轮廓检测算法来实现。根据车牌的尺寸、颜色和大致位置,可以提高检测的准确性。然后,对于每个检测到的车牌区域,可以使用特定的算法来提取车牌号码。这可能涉及到字符分割、字符识别等步骤。最后,可以将识别到的车牌号码输出或进行后续的处理。 有一些项目和系统已经利用OpenCV来实现车牌识别。例如,最新的一个项目是2020年5月26日发布的一个基于Spring Boot和Maven的车牌识别系统,它包含车牌检测和车牌号码识别的训练,支持黄、蓝、绿三种车牌的检测和识别。这个项目可以作为参考,使用OpenCV和相关技术来实现车牌识别功能。 综上所述,OpenCV可以用于车牌识别,通过车牌检测和字符识别等步骤,可以实现对车辆车牌号码的自动识别。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [基于OpenCV车牌识别](https://blog.csdn.net/qq_42722197/article/details/122646658)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [spring boot + maven + opencv 车牌识别系统,包含车牌检测、车牌识别训练下载地址](https://download.csdn.net/download/weixin_42686388/12461776)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值