基于opencv2.0的车牌检测与字符分割的代码.doc_第1页
基于opencv2.0的车牌检测与字符分割的代码.doc_第2页
基于opencv2.0的车牌检测与字符分割的代码.doc_第3页
基于opencv2.0的车牌检测与字符分割的代码.doc_第4页
基于opencv2.0的车牌检测与字符分割的代码.doc_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

/*本程序主要实现的是车牌的定位与检测主要是利用申继龙论文里面的方法1、采集得到的图像2、把RGB图像转换成HSI彩色图像3、利用设定的H、S阈值得到二值图像4、对二值图像水平投影获得候选区域5、对候选区域的HSI图像边缘检测*/#include stdafx.h#include opencv2/opencv.hpp #include opencv2/objdetect/objdetect.hpp#include opencv2/features2d/features2d.hpp#include opencv2/highgui/highgui.hpp#include opencv2/calib3d/calib3d.hpp#include opencv2/nonfree/nonfree.hpp#include opencv2/nonfree/features2d.hpp#include opencv2/imgproc/imgproc_c.h#include opencv2/legacy/legacy.hpp#include opencv2/legacy/compat.hpp #include #include #include #include #include #include #include #include #include using namespace std;using namespace cv;#define pi 3.14159265IplImage* srcImage=NULL;/存储原图片IplImage*srcImage1=NULL;/存储原始图片的副本IplImage* HSI=NULL;static IplImage* grayImage=NULL;/存储原图片灰度图static double posdouble=0.0;IplImage* channelOneImage=NULL;IplImage* channelTwoImage=NULL;IplImage* channelThreeImage=NULL;IplImage* plateImage=NULL;/存储车牌图像IplImage* grayPlateImage=NULL;/存储车牌灰度图像vectorcharacterImageList;/存储7个车牌字符图像的容器vectorxList;/存储7个车牌字符的起始和结束位置vectorvectorkeyPointsList;/存储车牌字符特征点的集合vectordescriptorsMatList;/存储每一个车牌字符的特征点描述子矩阵vectorvector contours;/用来存储经过闭开操作处理后的车牌轮廓double GetH(int r,int g,int b)double H=0;/H分量double fenZi=1/2.0*(r-g)+(r-b);double sq=pow(double(r-b),2)+(r-b)*(g-b);double fenMu=sqrt(sq);H=acos(fenZi/fenMu)*180/pi;if(bg)H=360-H;return H;double GetS(int r,int g,int b) double s=0;/S分量int min=r;if(gr)min=g;if(bg)min=b;elseif(bwidth;int height=eleImage-height;for(int col=0;colimageData+col*eleImage-widthStep);/uchar* ptrGray=(uchar*)(grayImage-imageData+col*grayImage-widthStep);/for(int row=0;row=190&H0.3)ptrGrayrow=255;elseptrGrayrow=0;if(I0.25&S0.4)ptrGrayrow=0;cvShowImage(H分量处理后的图像,grayImage);/考虑H分量处理后就提取尽量多的有用的区域vectorvectorcontours;Mat mtx = grayImage;/把IplImage类型转换成Mat类型findContours(mtx,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);Mat result(mtx.size(),CV_8U,Scalar(255);drawContours(result,contours,-1,Scalar(0),2);imshow(轮廓图,result);/以下代买判断是否为蓝色像素点/返回0代表是白色点/返回1代表是蓝色点int IsBlueOrWhite(IplImage* image,int col,int row)CvScalar s; s = cvGet2D(image, col,row);int b=s.val0;int g=s.val1;int r=s.val2;double H=GetH(r,g,b);double S=GetS(r,g,b);double I=GetI(r,g,b);if(H=190&H0.3)return 1;/*if(I0)*/*double grayLevel = r * 0.299 + g * 0.587 + b * 0.114; if (grayLevel = 200)return 0; */bool flagWhite2=(I=0.95)|(I=0.81&I0.95&S=0.61&I=0.8&S=0.61&I=0.8&S=0.51&I=0.6&S(30.0/180.0);bool flagWhite1=(S=0.6);if(flagWhite1|flagWhite2)return 0;return 2;int IsBlueOrWhite(int col,int row)return IsBlueOrWhite(srcImage,col,row);bool IsEdgeOrNot(int col,int row)int flag00=IsBlueOrWhite(col-1,row-1);int flag10=IsBlueOrWhite(col,row-1);int flag20=IsBlueOrWhite(col+1,row-1);int flag01=IsBlueOrWhite(col-1,row); int flag11=IsBlueOrWhite(col,row);int flag21=IsBlueOrWhite(col+1,row);int flag02=IsBlueOrWhite(col-1,row+1); int flag12=IsBlueOrWhite(col,row+1);int flag22=IsBlueOrWhite(col+1,row+1);if(flag00=1&flag10=1&flag20=1)if(flag02=0&flag12=0&flag22=0)return true;/是蓝白边缘if(flag00=0&flag10=0&flag20=0)if(flag02=1&flag12=1&flag22=1)return true;/是蓝白边缘return false;/对是蓝白边缘的一个处理void doIsEdge(int col ,int row)cvSet2D(grayImage, col-1,row,cvScalar(255);cvSet2D(grayImage, col,row,cvScalar(255);cvSet2D(grayImage, col+1,row,cvScalar(255);cvSet2D(grayImage, col-1,row-1,cvScalar(0);cvSet2D(grayImage, col,row-1,cvScalar(0);cvSet2D(grayImage, col+1,row-1,cvScalar(0);cvSet2D(grayImage, col-1,row+1,cvScalar(0);cvSet2D(grayImage, col,row+1,cvScalar(0);cvSet2D(grayImage, col+1,row+1,cvScalar(0);/对不是蓝白边缘的处理void doNotEdge(int col,int row)cvSet2D(grayImage, col-1,row,cvScalar(0);cvSet2D(grayImage, col,row,cvScalar(0);cvSet2D(grayImage, col+1,row,cvScalar(0);cvSet2D(grayImage, col-1,row-1,cvScalar(0);cvSet2D(grayImage, col,row-1,cvScalar(0);cvSet2D(grayImage, col+1,row-1,cvScalar(0);cvSet2D(grayImage, col-1,row+1,cvScalar(0);cvSet2D(grayImage, col,row+1,cvScalar(0);cvSet2D(grayImage, col+1,row+1,cvScalar(0);/边缘检测代码/检测蓝白边缘/通过构造3*3窗口void EdgeDetection()int width=srcImage-width;int height=srcImage-height;for(int col=1;colheight;col+=3)for(int row=1;rowwidth;row+=3)/判断是否为蓝白边缘if(IsEdgeOrNot(col,row)/设置3*3窗口中间一列的所有值为1 其他列为0doIsEdge(col,row);else/设置3*3窗口中所有元素的值为0doNotEdge(col,row);cvShowImage(蓝白边缘检测后的车辆图像,grayImage); /这个函数主要是实现提取每一个字符的sift特征/在提取sift特征我们先对每一个字符图片做尺寸的归一化处理void ExtractSiftFeature() Mat image11= imread(C:/Users/wzafxj/Desktop/车牌车标识别论文/车牌识别论文集锦/字符模板/字符模板/G.bmp,0);SurfFeatureDetector surf(5000);/特征点选取的 hessian 阈值 为3000SurfDescriptorExtractor surfDesc;/SurfDescriptorExtractor是提取特征向量的描述子Mat descriptors;vector keypoints;/存储每个车牌字符的surf特征点CvSize size=cvSize(41,82);CvSize cvsize11=cvSize(30,62);resize(image11,image11,cvsize11);vector matches;DescriptorMatcher *pMatcher = new FlannBasedMatcher; / 使用Flann匹配算法vector keypoints11;surf.detect(image11,keypoints11);/这里是利用surf算法检测关键点Mat descriptors11;surfDpute(image11,keypoints11,descriptors11);imshow(moban,image11); IplImage* pDstImage = cvCreateImage(size, grayPlateImage-depth, grayPlateImage-nChannels); for(int i=0;imatch(descriptors11, descriptors, matches);Mat imageMatches;drawMatches(image11,keypoints11, / 1st image and its keypointsimage,keypoints, / 2nd image and its keypointsmatches,/ the matchesimageMatches,/ the image producedScalar(255,255,255); / color of the lines string winName=WN+i;imshow(winName,imageMatches);/显示已经分割出来的车牌字符void ShowSeparatedCharacterImage()if(characterImageList.size()0)for (int i=0;iheight;IplImage* characterSegImage=NULL;/定义一个临时存储字符图片CvRect roiGrayPlate;CvRect roiCharacter;for(int i=0;idepth,grayPlateImage-nChannels);roiGrayPlate=cvRect(x1,0,width,height);cvSetImageROI(grayPlateImage,roiGrayPlate);roiCharacter=cvRect(0,0,width,height); cvSetImageROI(characterSegImage,roiCharacter);cvCopy(grayPlateImage,characterSegImage);cvResetImageROI(characterSegImage);cvResetImageROI(grayPlateImage);characterImageList.push_back(characterSegImage);/接下来就是对提取出来的字符进行sift特征提取,并且标准库中的字符模板进行sift特征匹配,以达到字符识别的目的/不过进行上面的操作之前我们先把这七个字符显示出来再说ShowSeparatedCharacterImage();/接下来是对分割出来的车牌特征进行sift特征提取/ExtractSiftFeature();/对字符为白色、背景为黑色的车牌做垂直投影/以此来达到字符分割的目的bool VerticalProjectionToPlateImage(IplImage* grayPlateImage)IplImage* paintx=cvCreateImage( cvGetSize(grayPlateImage),IPL_DEPTH_8U, 1 ); cvZero(paintx); int* v=new intgrayPlateImage-width; memset(v,0,grayPlateImage-width*4); /作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法int x,y; CvScalar s,t; /再次提醒 对于图像来说 坐标原点是在图像的左上角/我们定义一个容器来存储车牌字符的每一个起始位置和结束位置/是这样的容器里面的第一个值是第一个字符的起始位置/第二个值既是第一个字符的结束位置,依次类推/但是第二个字符过后的14个像素单位里面可能出现字符点,我们不能提取,这个点就是车牌字符中的那个点 /在字符的检测中,如果x2-x1的长度超过了20,我们就默认这个字符的检测已经结束,就是说已经检测出来这个字符了/注意除了第二个字符和第三个字符之间的距离超过了14个像素点之多外呢,其他每两个字符之间的距离应该也至少有2个像素/因此我们在取值的时候一定要注意到这个问题 比如2 22 27 47 60 80 81 101 102 122 123 143 146 166 167/仔细观察60 80 81 中的81的取值不对 应该跨两个像素点再去取 应该取83 也就是xList的size()为双数的时候 要进行判断/可惜我们还是没有考虑字符“1”的情形/通过仔细观察我们字符 “1” 它的高度至少超过30像素 它的宽度在5左右 主要是它离它后面的一个字符的距离有 10像素左右bool flag1=false;bool flag2=false;int count=0;int x1=0;int x2=0; int countPoint=0;/设置这个是为了对中间因为有一个. 而存在8个多像素没有字符出现的情况 所以我们设置一个这个来判断int countOne=0;/用来对字符 1 的处理bool flagOne=false;/也是用来对字符1的处理bool flagoneOut=false;/为true 代表字符 1出现了for(x=3;xwidth;x+) int countCol=0;for(y=0;yheight;y+) s=cvGet2D(grayPlateImage,y,x); if(s.val0=0) vx+; if(s.val0=255)countCol+; if(xList.size()=4)countPoint+;if(countCol0&flag1=false)if(countPoint0&countPoint0)/xList.back()获得容器的最后一个元素if(x-xList.back()0&countPoint12)/对中间出现 . 的处理 else/如果字符 1 出现在最后一个位子 我们就没有处理的必要了if(xList.size()0)flagOne=true;countOne=0;if(countCol=0&flagOne=false)countOne+;/如果countOne的值达到10左右(单位像素) 且已不再countPoint处理的范围 也就是已经过了中间的那个点if(countOne=12)flagOne=true;countOne=0;/代表很有可能这个字符是1flagoneOut=true;/代表是字符1出现了if(countCol0|(countCol=0&count0&countPoint12)/对中间出现 . 的处理 else/在这里我们加入一个字符1的处理if(flagoneOut=true)count=0;flag1=false;flagoneOut=false;xList.push_back(x);elseif(count0&countPointwidth存储到Xlist里面if(xList.size()width);if(xList.size()=15)xList.pop_back();/删除容器的最后一个元素for(x=0;xwidth;x+) for(y=0;y 90) angle = 90 - (angle % 90); IplImage* dst = NULL; int width = (double)(src-height * sin(angle * CV_PI / 180.0) + (double)(src-width * cos(angle * CV_PI / 180.0 ) + 1; int height = (double)(src-height * cos(angle * CV_PI / 180.0) + (double)(src-width * sin(angle * CV_PI / 180.0 ) + 1; int tempLength = sqrt(double)src-width * src-width + src-height * src-height) + 10; int tempX = (tempLength + 1) / 2 - src-width / 2; int tempY = (tempLength + 1) / 2 - src-height / 2; /这里的tempX和tempY指的是图像的中心像素点int flag = -1; dst = cvCreateImage(cvSize(width, height), src-depth, src-nChannels); cvZero(dst); IplImage* temp = cvCreateImage(cvSize(tempLength, tempLength), src-depth, src-nChannels); /图像temp并没有多大的实际含义,/只不过是说把src图像size稍微扩大一点 /内容和src完全一样cvZero(temp); cvSetImageROI(temp, cvRect(tempX, tempY, src-width, src-height); cvCopy(src, temp, NULL); cvResetImageROI(temp); if (clockwise) flag = 1; float m6; int w = temp-width; int h = temp-height; m0 = (float) cos(flag * angle * CV_PI / 180.); m1 = (float) sin(flag * angle * CV_PI / 180.); m3 = -m1; m4 = m0; / 将旋转中心移至图像中间 m2 = w * 0.5f; m5 = h * 0.5f; / CvMat M = cvMat(2, 3, CV_32F, m); /M是一个3 2 变换矩阵 A|b /m0 m1 m2/ m3 m4 m5 /变换公式如下/dst(x + width(dst) / 2,y + height(dst) / 2)=/(m0x+m1y+b1,m3x+m4y+b2)cvGetQuadrangleSubPix(temp, dst, &M); /提取象素四边形,使用子象素精度 dst提取的是一个四边形cvReleaseImage(&temp); return dst; /获得车牌的倾斜角度然后校正/定义一个容器存储所有的countColvector countColVector;struct maxTotalColAndAngelint maxTotalCol;int angel;vector maxTotalColAndAngelVector;bool less_second(const maxTotalColAndAngel m1, maxTotalColAndAngel m2) return m1.maxTotalCol m2.maxTotalCol;bool GetAngleAndRotate(IplImage* _image)IplImage* dstImage=NULL;/假定车牌的旋转角度控制在30度的范围之内bool _direction=false;/true代表顺时针int _actualAngle=0;/存储最后得到的旋转角度CvScalar s;int maxCount=0;/存储最大的那个投影值bool changeDirection=false;int flag=-2;/-1代表的是往一开始设定的相反的方向旋转 1代表的是旋转的方向是对的 但是已经过了最大值int Xnum=0;/这里我们可以先做下canny二值化来减少计算量for(int _angle=0;_anglewidth-1;x=0;x-)int countCol=0;for(int y=0;yheight;y+)s=cvGet2D(dstImage,y,x); /ptrrow=0;if(s.val00)countCol+;if(countCol0)countColVector.push_back(countCol);sort(countColVector.begin(),countColVector.end();maxTotalColAndAngel _colandangel=0,0;_colandangel.angel=_angle;for (int i=countColVector.size()-1;i=countColVector.size()-2;i-)_colandangel.maxTotalCol+=countColVectori;if(changeDirection=false&_angle=5&_colandangel.maxTotalCol0)maxTotalColAndAngelVector.clear();for (int _angleDetail=_actualAngle-5;_angleDetailwidth-1;x=0;x-)int countCol=0;for(int y=0;yheight;y+)s=cvGet2D(dstImage,y,x); /ptrrow=0;if(s.val00)countCol+;if(countCol0)countColVector.push_back(countCol);sort(countColVector.begin(),countColVector.end();maxTotalColAndAngel _colandangel=0,0;_colandangel.angel=_angleDetail;for (int i=countColVector.size()-1;i=countColVector.size()-2;i-)_colandangel.maxTotalCol+=countColVectori;maxTotalColAndAngelVector.push_back(_colandangel);countColVector.clear();/以便下次存储数据sort(maxTotalColAndAngelVector.begin(),maxTotalColAndAngelVector.end(),less_second);_actualAngle=maxTotalColAndAngelVectormaxTotalColAndAngelVector.size()-1.angel;dstImage=rotateImage(_image,_actualAngle,_direction);imshow(旋转后的车牌图像,(Mat)dstImage);/这里只是水平旋转的结果 /我们把这个水平旋转的角度传给原始的车脸图像,对车脸图像进行旋转IplImage* srcDst=rotateImage(srcImage,_actualAngle,_direction);imshow(车脸图片的旋转,(Mat)srcDst);/下面还要加一个垂直旋转CvSize cvsize=cvSize(172,60);IplImage*plateImage2=cvCreateImage(cvsize,dstImage-depth,dstImage-nChannels);CvRect roiSrc =cvRect(dstImage-width/2-86,dstImage-height/2-30,172,60);cvSetImageROI(dstImage, roiSrc); CvRect roiPlate=cvRect(0,0,172,60);cvSetImageROI(plateImage2,roiPlate);cvCopy(dstImage,plateImage2);cvResetImageROI(dstImage);cvResetImageROI(plateImage2);imshow(裁剪后的图像,(Mat)plateImage2);/去除一些边边框框/我们最好在这里对plateImage2进行垂直旋转/对经过处理后的车牌进行垂直投影处理grayPlateImage=plateImage2;bool flagYN=Verti

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论