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);
	}

时间: 2024-11-04 06:56:59

opencv车牌识别的相关文章

基于opencv的车牌识别系统

前言 学习了很长一段时间了,需要沉淀下,而最好的办法就是做一个东西来应用学习的东西,同时也是一个学习的过程. 概述     OpenCV的全称是:Open Source Computer Vision Library.OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算

使用opencv的SVM和神经网络实现车牌识别

一.前言 本文参考自<深入理解Opencv 实用计算机视觉项目解析>中的自动车牌识别项目,并对其中的方法理解后,再进行实践.深刻认识到实际上要完成车牌区域准确定位.车牌区域中字符的准确分割,字符准确识别这一系列步骤的困难.所以最后的识别效果也是有待进一步提高. 二.程序流程 程序流程如下所示: 相应的main函数如下 #include "carID_Detection.h" int main() { Mat img_input = imread("testCarI

《Mastering Opencv ...读书笔记系列》车牌识别(I)

http://blog.csdn.net/jinshengtao/article/details/17883075/  <Mastering Opencv ...读书笔记系列>车牌识别(I) http://blog.csdn.net/jinshengtao/article/details/17954427   <Mastering Opencv ...读书笔记系列>车牌识别(II) Mastering Opencv ...读书笔记系列>车牌识别(I) 标签: 车牌分割svm西

opencv实现车牌识别之字符识别

简介 在前面已经讲了车牌的定位和对车牌字符的分割,这里继续是最后对车牌的识别. 字符识别 主要是用了两张办法,第一个是前面 <opencv实现车牌识别之失败经验> 这一篇中用到过的,opencv自带的getPSNR函数,这里不再对它进行讲解. 另一种方法是将分割出来的字符和模板字符都分割成9宫格形式,对比比较每个块中,像素占的比例来匹配分辨出字符. 具体代码如下: double proCale(Mat& mat1, int width_1, int height_1, int widt

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

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

移动端车牌识别OCR-结合OpenCV

需求 最近产品那边说APP上要加个车牌识别的功能,用户不用手动输入,我说没问题啊加就加呗.脑子中第一反应就是第三方SDK,最终用了百度车牌识别SDK,完成了需求,集成方法详见"百度SDK文档",好了文章到这里在可以结束了. 文章要是真结束了,提刀的兄弟估计又要砍我了,标题党一个,老是做这些***子放屁的事情,哈哈---.皮一下很开心. 问题 一开始我们确实用的百度车牌识别,但是识别率不是太高,而且车牌图片要上传到百度那边去,也会受网速影响,最重要的是,百度每天只能调用200次,多于20

车牌识别opencv

车牌识别之一:车牌定位http://blog.csdn.net/sing_sing/article/details/5937725 车牌识别之二:字符分割http://blog.csdn.net/sing_sing/article/details/5937751

OpenCV学习之路——车牌识别之车牌定位

去年七月份因为学校项目需要开始接触图像处理,但那时候只是到网上找车牌识别代码,然后加入到自己的项目中,不清楚细节原理. 现在自己重新一步步实现车牌识别. 高斯模糊: 1 Mat Gaussian(Mat &img) { 2 Mat out; 3 GaussianBlur(img, out, Size(3, 3), 4 0, 0, BORDER_DEFAULT); 5 return out; 6 7 } 灰度化: 1 Mat Grayscale(Mat &img) { 2 Mat out;

毕业设计 python opencv实现车牌识别 界面

主要代码参考https://blog.csdn.net/wzh191920/article/details/79589506 GitHub:https://github.com/yinghualuowu 答辩通过了,补完~ 这里主要是用两种方法进行定位识别 # -*- coding: utf-8 -*- __author__ = '樱花落舞' import tkinter as tk from tkinter.filedialog import * from tkinter import ttk