实例介绍
【实例截图】
【核心代码】
#include "cv.h" #include "highgui.h" #include "cxcore.h" #include <stdio.h> #include <math.h> #include <string.h> #include <string> #include <iostream> using namespace std; #define POINT_X 18 // 水平方向不重叠点 #define POINT_Y 2 // 垂直方向不重叠点 #define WITH_X 0.1 // 水平方向车牌在图区域 #define WITH_Y 0.2 // 垂直方向车牌在图区域 #define HIGH_WITH_CAR 4.8 //(440/85) // 小车的宽高比 440/140 #define CHARACTER 15 #define TEMPLETENUM 43 CvPoint pt[4]; IplImage* img = 0; IplImage* img0 = 0; IplImage* img2=0; IplImage *src=NULL; IplImage *pImgCanny=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; CvRect res; const int Num_Templete[TEMPLETENUM][CHARACTER]= { {16,19,10,12,10,10,15,18,110,3,2,2,3,3,3}, //0 {9,11,10,10,10,10,9,10,79,2,2,2,0,2,12}, //1 {18,19,3,18,10,10,23,22,123,4,2,2,7,6,8}, //2 {19,21,11,14,4,20,18,22,129,2,2,4,6,6,7}, //3 {2,18,11,22,20,21,11,18,123,2,4,2,6,7,5}, //4 {23,19,20,12,9,20,18,22,143,2,4,4,6,6,6}, //5 {6,13,17,8,15,20,18,20,117,2,2,4,5,7,6}, //6 {21,21,0,20,8,12,9,11,102,2,2,2,2,8,15}, //7 {17,18,18,19,14,20,17,20,143,4,2,4,6,6,6}, //8 {16,18,15,21,7,19,13,7,116,3,2,2,6,6,5}, //9 {10,10,16,16,20,20,18,19,129,2,4,2,8,3,6}, //A {24,20,20,19,22,22,24,20,171,4,8,4,6,6,6}, //B {18,19,20,4,20,8,17,21,127,3,2,4,4,4,4}, //C {23,19,11,20,12,20,22,21,148,3,3,3,4,4,4}, //D {23,19,21,9,22,8,23,23,148,2,2,2,6,6,6}, //E {25,17,20,9,22,8,19,0,120,2,2,2,4,4,4}, //F {17,18,22,14,12,24,18,21,146,4,7,4,4,6,6}, //G {14,20,18,22,17,22,16,20,149,4,1,4,2,2,2}, //H {0,17,0,20,3,20,18,22,100,2,2,4,2,2,2}, //J {19,20,26,10,20,20,20,22,157,4,4,4,3,5,11}, //K {20,0,20,0,20,0,25,20,105,2,2,2,2,2,2}, //L {20,10,27,17,20,10,22,14,140,1,3,3,4,1,5}, //M {21,12,25,17,26,12,18,18,149,3,5,3,5,5,6}, //N {23,19,18,20,21,8,22,0,131,3,3,2,4,4,4}, //P {18,19,20,10,26,15,18,21,147,3,3,4,5,7,5}, //Q {26,19,21,18,21,17,20,21,163,4,3,4,4,6,5}, //R {18,18,18,10,8,17,17,22,128,4,3,4,6,6,6}, //S {22,18,10,10,10,10,10,10,100,2,2,2,33,2,2}, //T {18,12,20,10,20,10,19,21,130,3,3,3,2,2,2}, //U {20,19,20,20,15,14,9,10,127,4,4,2,9,1,8}, //V {21,25,26,28,16,16,21,19,172,6,2,4,13,0,7}, //W {21,21,13,13,12,11,22,21,134,4,2,4,8,0,10}, //X {21,20,10,11,10,10,10,11,103,3,2,2,5,2,6}, //Y {21,23,5,15,15,5,24,20,128,2,2,2,8,8,7}, //Z {13,14,10,10,10,10,13,13,93,2,2,2,29,2,29}, //I {20,20,13,20,19,12,17,20,141,3,3,4,4,4,4}, //O //36 {14,15,17,17,16,10,25,24,138,0,2,4,12,8,9}, //云 //37 {17,20,17,12,33,28,23,20,170,3,4,7,13,6,4}, //苏 {21,21,23,24,24,25,31,27,196,0,9,6,8,6,7}, //京 {19,27,20,34,19,36,24,37,216,4,4,7,13,28,3}, //湘 {17,14,23,27,36,40,26,27,210,4,13,4,16,14,14}, //鲁 {24,24,32,38,34,32,17,22,223,9,6,10,11,12,9}, // 粤 {22,20,33,37,25,24,24,25,210,13,3,6,12,8,7} //蒙 }; //车牌字符 char *PlateCode[TEMPLETENUM] = { "0", "1", "2", "3", "4" , "5","6", "7", "8", "9", "A", "B", "C", "D","E", "F", "G","H", "J", "K", "L", "M", "N","P", "Q", "R", "S", "T", "U", "V", "W","X", "Y", "Z", "I", "O", "云", "苏","京", "湘", "鲁","粤","蒙" }; char *G_PlateChar[7]={"没", "有","找", "到", "车", "牌" ,"!"}; // 车牌号 const char* wndname = "Demo"; char* names[] = { "D:/a_project/image/6.jpg", "D:/a_project/image/7.jpg", "D:/a_project/image/8.jpg", "D:/a_project/image/9.jpg", "D:/a_project/image/10.jpg", "D:/a_project/image/1.jpg", "D:/a_project/image/2.jpg", "D:/a_project/image/3.jpg", "D:/a_project/image/4.jpg", "D:/a_project/image/5.jpg", 0 }; int AdaptiveThreshold(int t, IplImage *Image) //这个为什么要这样做 使用这种方式 原因不清楚 { int t1=0,t2=0,tnew=0,i=0,j=0; int Allt1=0,Allt2=0,accountt1=0,accountt2=0;//Allt1 Allt2 保存两部分的和 for(j=0;j<Image->height;j ) //根据现有T,将图像分为两部分,分别求两部分的平均值t1、t2 { for(i=0;i<Image->width;i ) { if(CV_IMAGE_ELEM(Image,uchar,j,i)<t) { Allt1 =CV_IMAGE_ELEM(Image,uchar,j,i); accountt1 ; } else { Allt2 =CV_IMAGE_ELEM(Image,uchar,j,i); accountt2 ; } } } t1=Allt1/accountt1; t2=Allt2/accountt2; tnew=0.5*(t1 t2); if(tnew==t) //若t1、t2的平均值和t相等,则阈值确定 return tnew; else AdaptiveThreshold(tnew,Image); //不等则以t1、t2的平均值为新阈值迭代 } void Threshold(IplImage *Image, IplImage *Image_O) { //得到图片的最大灰度值和最小灰度值 int thresMax=0,thresMin=255,i=0,j=0,t=0; for(j=0;j<Image->height;j ) for(i=0;i<Image->width;i ) { if(CV_IMAGE_ELEM(Image,uchar,j,i)>thresMax) //像素值 大于 255 thresMax=CV_IMAGE_ELEM(Image,uchar,j,i); //把元素值赋给 thresMax else if(CV_IMAGE_ELEM(Image,uchar,j,i)<thresMin) //如果小于 0 thresMin=CV_IMAGE_ELEM(Image,uchar,j,i); //则 改变thresMin } //int T=(thresMax thresMin)*0.5; //灰度的最大值和最小值的平均 cvCanny(Image,Image_O,AdaptiveThreshold((thresMax thresMin)*0.5,Image),thresMax*0.7,3); //小阈值用来控制边缘连接 大阈值用来控制强边缘的初始化分割 cvCanny只接受单通道的输入 } int PlateAreaSearch(IplImage *pImg_Image) { if (pImg_Image==NULL) { return 0; } // 检测是否有值 IplImage* imgTest =0; int i=0, j=0,k=0,m=0; bool flag=0; int plate_n=0 ,plate_s=0,plate_e=0 ,plate_w=0; //关于车牌的一些变量 int *num_h=new int[max(pImg_Image->width,pImg_Image->height)]; if ( num_h==NULL ) { //cout<<"memory exhausted"<<endl; return 0; // exit(1); } // end if for(i=0;i<pImg_Image->width;i ){num_h[i]=0;} // 初始化 分配的空间 imgTest = cvCreateImage(cvSize(pImg_Image->width,pImg_Image->height),IPL_DEPTH_8U,1); cvCopy(pImg_Image, imgTest); //-- 水平 轮廓细化 for(j=0; j<imgTest->height; j ) { for(i=0;i<imgTest->width-1;i ) { CV_IMAGE_ELEM(imgTest,uchar,j,i)=CV_IMAGE_ELEM(imgTest,uchar,j,i 1)-CV_IMAGE_ELEM(imgTest,uchar,j,i); num_h[j] =CV_IMAGE_ELEM(imgTest,uchar,j,i)/250; } } //以下是她不懂的地方 int temp_1=0; int temp_max =0; int temp_i = 0; //说明这里for 循环 是找出数据量最大的地方 20行 也即是 车牌区域 for(j=0; j<imgTest->height-20; j ) { temp_1=0; for(i=0;i<20;i )//此处for循环 是为了计算20行的总数据量 temp_1 = num_h[i j]; if(temp_1>=temp_max) { temp_max=temp_1; temp_i = j;//记录20行的最大数据量的开始 行 } } k=temp_i;//以下两个while 循环是为了找出 车牌的上下边界 当一行的数据量小于某个数值时 设定此为分界行 while ( ((num_h[k 1]>POINT_X )||(num_h[k 2]>POINT_X )||(num_h[k]>POINT_X )) && k ) k--;//出行边界行 plate_n=k 1;//k 2; k=temp_i 10; while (((num_h[k -1]>POINT_X )||(num_h[k-2]>POINT_X )||(num_h[k]>POINT_X ))&&(k<imgTest->height)) k ; //出下边界行 plate_s=k;//k-2; // 没找到水平分割线,设置为默认值 if ( !(plate_n && plate_s //行为负值 或者 上行大于下行 或者 车牌宽度大于 设定值 则水平分割失败 && (plate_n<plate_s) && ((plate_s-plate_n)*HIGH_WITH_CAR<imgTest->width*(1-WITH_X)))) { //flag=1; // cout<<"水平分割失败"<<endl; return 0; } else//到水平线 { int max_count = 0; int plate_length = (imgTest->width-(plate_s-plate_n)*HIGH_WITH_CAR);//这个地方有点无语,不过也可以理解 plate_w=imgTest->width*WITH_X-1;//车牌宽度 默认 //--垂直方向 for(i=0;i<imgTest->width;i ) for(j=0;j<imgTest->height-1;j )//用的方法是 差分赋值法——我起的名字 应该是为了细化 { CV_IMAGE_ELEM(imgTest,uchar,j,i)=CV_IMAGE_ELEM(imgTest,uchar,j 1,i)-CV_IMAGE_ELEM(imgTest,uchar,j,i); } //下面这一段代码 相当于 拿一个车牌大小的矩形区域 从左往右 滑动,什么时候圈住的数据量最大的时候 // 就代表找到的车牌的左边界 此时 车牌左边界的横坐标是 k //这里 plate_length 有点难理解,它的值是 原图像的宽度减去车牌的宽度差值。 for(k=0;k<plate_length;k ) { for(i=0; i<(int)((plate_s-plate_n)*HIGH_WITH_CAR); i ) for (j=plate_n;j<plate_s;j )//两水平线之间 { num_h[k] =num_h[k] CV_IMAGE_ELEM(imgTest,uchar,j,(i k))/250; } if (num_h[k]>max_count) { max_count = num_h[k]; plate_w = k; } // end if } CvRect ROI_rect; //获得图片感兴趣区域 ROI_rect.x=plate_w; ROI_rect.y=plate_n; ROI_rect.width=(plate_s-plate_n)*HIGH_WITH_CAR; ROI_rect.height=plate_s-plate_n; if ((ROI_rect.width ROI_rect.x)> pImg_Image->width) { ROI_rect.width=pImg_Image->width-ROI_rect.x; // cout<<"垂直方向分割失败!"; return 0; } else { IplImage *pImg8uROI=NULL; //感兴趣的图片 pImg8uROI=cvCreateImage(cvSize(ROI_rect.width,ROI_rect.height), src->depth,src->nChannels); IplImage *pImg8u11=NULL; //车牌区域灰度图 pImg8u11=cvCreateImage(cvSize(40*HIGH_WITH_CAR,40),pImg8uROI->depth,pImg8uROI->nChannels); cvSetImageROI(src,ROI_rect);//将 ROI_rect 设置为感兴趣区域 cvCopy(src,pImg8uROI,NULL);//把感兴趣区域 复制到 pImg8uROI cvResetImageROI(src); //重新设置感兴趣区域 pImgResize=cvCreateImage(cvSize(40*HIGH_WITH_CAR,40),IPL_DEPTH_8U,1); cvResize(pImg8uROI,pImg8u11,CV_INTER_LINEAR); //线性插值 归一化 把车牌变成统一大小 cvCvtColor(pImg8u11,pImgResize,CV_RGB2GRAY); // 转为灰度图 Y=0.299*R 0.587*G 0.114*B Threshold(pImgResize,pImgResize); // 二值化 cvReleaseImage(&pImg8uROI); cvReleaseImage(&pImg8u11); cvReleaseImage(&imgTest); } // end if } // end if // 释放内存 delete []num_h; num_h=NULL; return 1; } int SegmentPlate() { if (pImgResize==NULL) { return 0; } // 没有切割成功,直接弹出 int *num_h=new int[max(pImgResize->width,pImgResize->height)]; // 开辟空间 一般应该是 width 大小 if ( num_h==NULL ) // { cout<<"memory exhausted"<<endl; //MessageBox("字符分割memory exhausted"); return 0; //exit(1); } // end if int i=0,j=0,k=0;//循环变量 12 int letter[14]={0,20,23,43,55,75,78,98,101,121,124,127,147,167}; // 默认分割 bool flag1=0;// 1 2 3 4 5 6 7 // 垂直投影 for(i=0;i<40*HIGH_WITH_CAR;i ) { num_h[i]=0; // 初始化指针 for(j=0;j<17;j ) // 0-16 /40 { num_h[i] =CV_IMAGE_ELEM(pImgResize,uchar,j,i)/45; } for(j=24;j<40;j ) // 24-39 /40 { num_h[i] =CV_IMAGE_ELEM(pImgResize,uchar,j,i)/45; } } // 初定位,定位点 第二个字符末端, int max_count=0; int flag=0; for(i=30;i<40*HIGH_WITH_CAR;i ) { if(num_h[i]<POINT_Y)//小于2 { max_count ; if(max_count==11) { letter[3]=i-11; // find letter[3]//第二字符的开始位置 while( (num_h[i]<POINT_Y)||(num_h[i-1]<POINT_Y) ) i ; letter[4]=i-1; // find letter[4] //第三个字符的开始位置 break;//只要找到 第二个字符的末端 和 第三个字符的开始 就退出循环 } } else { max_count=0; } } // 精定位 for(i=0;i<40*HIGH_WITH_CAR;i )//每一列的 { for(j=17;j<=24;j ) // 17-24 /40 每一列的17 到 24 行相加 { num_h[i] =CV_IMAGE_ELEM(pImgResize,uchar,j,i)/45; } } for(j=letter[3];j>0;j--)//从第二个字符的末端开始 往前找第一个和第二个字符起始位置 { if((num_h[j]<POINT_Y)&&(num_h[j-1]<POINT_Y))//只要有两个列的 17到24 行的值小于 2, { //即找到第二个字符的开始位置 letter[2]=j; // find letter[2] 第二个字符的开始位置 letter[1]=(j>=23)?j-3:letter[1]; //第一个字符的结束位置 letter[0]=(j>=23)?j-23:letter[0]; //第一个字符的起始位置 break; //找到就退出循环 } } j=2; flag=0;flag1=0;//两个标记 for(i=letter[4];i<40*HIGH_WITH_CAR;i ) //从第三个字符的开始位置算起 { if((num_h[i]>POINT_Y)&&(num_h[i-1]>POINT_Y) && !flag ) { flag=1; flag1=0; letter[2*j]=i-1; //这里 只记录字符的开始位置 if(j==6) //判断 最后一个字符的结束位置 是否越界 超出界限,如果没有,则letter[13]=letter[12] 20 { letter[2*j 1]=((letter[2*j] 20)>40*HIGH_WITH_CAR-1)?40*HIGH_WITH_CAR-1:letter[2*j] 20; break;//退出 for循环 } } else if((num_h[i]<POINT_Y)&&(num_h[i-1]<POINT_Y) && !flag1 && flag)//如果是 空白区域 { flag=0; flag1=1; letter[2*j 1]=i-1; j ; //j自动加 1 } // 1 } // 删除角点 1 0 1 for(i=0;i<40*HIGH_WITH_CAR-1;i ) { // 1 删除角点 相当于拿一个半径为1 的圆 去圈 如果四周有两个是1 则自己设置为0 for(j=0;j<39;j ) // 0-16 /40 { if(CV_IMAGE_ELEM(pImgResize,uchar,j,i)&&CV_IMAGE_ELEM(pImgResize,uchar,j,i 1)&&CV_IMAGE_ELEM(pImgResize,uchar,j 1,i)) // 01 CV_IMAGE_ELEM(pImgResize,uchar,j,i)=0; // 1 if(CV_IMAGE_ELEM(pImgResize,uchar,j,i)&& CV_IMAGE_ELEM(pImgResize,uchar,j,i-1) &&CV_IMAGE_ELEM(pImgResize,uchar,j 1,i)) // 10 CV_IMAGE_ELEM(pImgResize,uchar,j,i)=0; // 1 if(CV_IMAGE_ELEM(pImgResize,uchar,j,i)&&CV_IMAGE_ELEM(pImgResize,uchar,j,i-1) &&CV_IMAGE_ELEM(pImgResize,uchar,j-1,i)) // 1 CV_IMAGE_ELEM(pImgResize,uchar,j,i)=0; // 10 if(CV_IMAGE_ELEM(pImgResize,uchar,j,i)&&CV_IMAGE_ELEM(pImgResize,uchar,j,i 1) &&CV_IMAGE_ELEM(pImgResize,uchar,j-1,i)) // 1 CV_IMAGE_ELEM(pImgResize,uchar,j,i)=0; // 01 } } // 分割出字符图片 pImgCharOne=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); pImgCharTwo=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); pImgCharThree=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); pImgCharFour=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); pImgCharFive=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); pImgCharSix=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); pImgCharSeven=cvCreateImage(cvSize(20,40),IPL_DEPTH_8U,1); CvRect ROI_rect1; ROI_rect1.x=0.5*(letter[1] letter[0])-10; //为什么减10 你知道吗~~~ 这个不难 ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharOne,NULL); //获取第1个字符 cvResetImageROI(pImgResize); ROI_rect1.x=0.5*(letter[3] letter[2])-10; ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharTwo,NULL); //获取第2个字符 cvResetImageROI(pImgResize); ROI_rect1.x=0.5*(letter[5] letter[4])-10; ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharThree,NULL); //获取第3个字符 cvResetImageROI(pImgResize); ROI_rect1.x=0.5*(letter[7] letter[6])-10; ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharFour,NULL); //获取第4个字符 cvResetImageROI(pImgResize); ROI_rect1.x=0.5*(letter[9] letter[8])-10; ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharFive,NULL); //获取第5个字符 cvResetImageROI(pImgResize); ROI_rect1.x=0.5*(letter[11] letter[10])-10; ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharSix,NULL); //获取第6个字符 cvResetImageROI(pImgResize); ROI_rect1.x=0.5*(letter[13] letter[12])-10; ROI_rect1.y=0; ROI_rect1.width=20; ROI_rect1.height=40; cvSetImageROI(pImgResize,ROI_rect1); cvCopy(pImgResize,pImgCharSeven,NULL); //获取第7个字符 cvResetImageROI(pImgResize); // 释放内存 delete []num_h; num_h=NULL; } void OnSplitcar() { // TODO: Add your control notification handler code here SegmentPlate(); // 车牌字符分割 cvNamedWindow("one",1); 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("seen",1); cvShowImage("seen",pImgCharSeven); //DrawPicToHDC(pImgCharOne,IDC_ONE); //DrawPicToHDC(pImgCharTwo,IDC_TWO); //DrawPicToHDC(pImgCharThree,IDC_THREE); //DrawPicToHDC(pImgCharFour,IDC_FOUR); //DrawPicToHDC(pImgCharFive,IDC_FIVE); //DrawPicToHDC(pImgCharSix,IDC_SIX); //DrawPicToHDC(pImgCharSeven,IDC_SEVEN); //DrawPicToHDC(pImgCharOne,IDC_ONE); } int CodeRecognize(IplImage *imgTest, int num, int char_num) { if (imgTest==NULL){ return 0;} int i=0,j=0,k=0,t=0;//循环变量 int char_start=0,char_end=0;//*PlateCode[TEMPLETENUM] 车牌字符里字母、数字、汉字起始位置 int num_t[CHARACTER ]={0}; switch(num)//这里这样分 可以提高效率,并且提高了识别率 { case 0: char_start =0; // 数字 char_end = 9; break; case 1: char_start =10; // 英文 char_end = 35; break; case 2: char_start =0; // 英文和数字 char_end = 35; break; case 3: char_start =36; // 中文 char_end = TEMPLETENUM-1; break; default: break; } // 提取前8个特征 前8个特征 可以说是固定位置的值 固定算法 for(k=0; k<8; k ) { for(j=int(k/2)*10; j<int(k/2 1)*10; j ) { for(i=(k%2)*10;i<(k%2 1)*10;i ) { num_t[k] =CV_IMAGE_ELEM(imgTest,uchar,j,i)/255 ; } } num_t[8] = num_t[k]; // 第9个特征 前8个特征的和作为第9个特征值 } for(i=0;i<20;i ) //以下特征也是 固定算法得到的 num_t[9] =CV_IMAGE_ELEM(imgTest,uchar,10,i)/255 ; for(i=0;i<20;i ) num_t[10] =CV_IMAGE_ELEM(imgTest,uchar,20,i)/255 ; for(i=0;i<20;i ) num_t[11] =CV_IMAGE_ELEM(imgTest,uchar,30,i)/255 ; for(j=0;j<40;j ) num_t[12] =CV_IMAGE_ELEM(imgTest,uchar,j,7)/255; for(j=0;j<40;j ) num_t[13] =CV_IMAGE_ELEM(imgTest,uchar,j,10)/255 ; for(j=0;j<40;j ) num_t[14] =CV_IMAGE_ELEM(imgTest,uchar,j,13)/255 ; int num_tt[CHARACTER]={0}; int matchnum=0; //可以说是 匹配度或 相似度 int matchnum_max=0; int matchcode = 0; // 匹配号 //int matchtempnum[10]={0}; j=0; for(k=char_start;k<=char_end;k ) //for(k=40;k<42;k ) { matchnum=0; for(i=0;i<8;i ) //区域的匹配 { // num_tt[i]= abs(num_t[i]-num[k][i]); if (abs(num_t[i]-Num_Templete[k][i])<=2)//与模板里的相应值进行匹配 matchnum ;//两者相减,如果绝对值小于2,标记匹配成功一次 } if(Num_Templete[k][i]-abs(num_t[i])<=8)//对第9个特征进行匹配 matchnum =2; for(i=9;i<CHARACTER;i ) // 横竖的匹配 { if (Num_Templete[k][i]>=5) //特征值 大于5 { if(abs(num_t[i]-Num_Templete[k][i])<=1) matchnum =2; } else if( num_t[i]==Num_Templete[k][i]) { matchnum =2; } } if(matchnum>matchnum_max) { matchnum_max=matchnum; //保留最大的 匹配 matchcode= k; //记录 识别的字符的 索引 //matchtempnum[j]=matchnum_min } } //识别输出 存放输出结果 G_PlateChar[char_num]=PlateCode[matchcode]; //保存下该字符 } void OnShibiecar() { // TODO: Add your control notification handler code here //---------------------- 车牌识别 -----------------------------// CodeRecognize(pImgCharOne,3,0); CodeRecognize(pImgCharTwo,1,1); CodeRecognize(pImgCharThree,2,2); CodeRecognize(pImgCharFour,2,3); CodeRecognize(pImgCharFive,0,4); CodeRecognize(pImgCharSix,0,5); CodeRecognize(pImgCharSeven,0,6); string outFile= ""; int i ; for(i =0;i<7;i ) //把结果放到 outFile CString 里 { outFile = G_PlateChar[i]; } // GetDlgItem(IDC_RESULT)->SetWindowText(outFile); //输出到静态文本 静态文本是IDC_RESULT cout<<outFile<<endl; // MessageBox("我爱你!"); } void FindContours(IplImage* src) { CvMemStorage* storage = cvCreateMemStorage(0); IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3); cvCvtColor(src,dst,CV_GRAY2BGR); CvScalar color = CV_RGB( 255, 0, 0); CvSeq* contours=0; //建立一个空序列存储每个四边形的四个顶点 // CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); //cvFindContours( src, storage, &contours, sizeof(CvContour),CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );//外界边界h_next 和 孔用v_next连接 cvFindContours( src, storage, &contours, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); for( ; contours != 0; contours = contours->h_next) { //使用边界框的方式 CvRect aRect = cvBoundingRect( contours, 1 ); int tmparea=aRect.height*aRect.height; if (((double)aRect.width/(double)aRect.height>3) && ((double)aRect.width/(double)aRect.height<6)&& tmparea>=200&&tmparea<=2500) { cvRectangle(dst,cvPoint(aRect.x,aRect.y),cvPoint(aRect.x aRect.width ,aRect.y aRect.height),color,2); //cvDrawContours( dst, contours, color, color, -1, 1, 8 ); res.x=aRect.x 20; res.y=aRect.y; res.width=aRect.width 25; res.height=aRect.height; } } //IplImage * ps; //CvSize printf("进入函数FindContours()"); printf("%d %d %d %d\n",res.x,res.y,res.width,res.height); // return aRect; cvNamedWindow("ficontour",1); cvShowImage("ficontour",dst); //cvWaitKey(0); //多边形曲线逼近方法 /* //用指定精度逼近多边形曲线 result = cvApproxPoly( contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); if( result->total == 4 && fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 && //cvContourArea计算整个轮廓或部分轮廓的面积 cvCheckContourConvexity(result) ) //CheckContourConvexity { */ return; } int main(int argc, char** argv) { int i=0; IplImage* img3; { // load i-th image // src = cvLoadImage( "car3.jpg", -1 ); src=cvLoadImage( "D:/a_project/image/6.jpg", -1 ); //img2= cvLoadImage( names[i], -1 ); pImgCanny=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1); // 2值化后图片大小初始化 cvCvtColor(src,pImgCanny,CV_RGB2GRAY); //转化为灰度图 openCV函数 Y = 0.299*R 0.587*G 0.114*B // 转为灰度图 Y=0.299*R 0.587*G 0.114*B cvSmooth(pImgCanny,pImgCanny,CV_GAUSSIAN,3,0); //平滑高斯滤波 滤波后的图片保存在 pImgCanny cvNamedWindow("aaa",1); cvShowImage("aaa",pImgCanny); Threshold(pImgCanny,pImgCanny); cvNamedWindow("pImgCanny",1); cvShowImage("pImgCanny",pImgCanny); PlateAreaSearch(pImgCanny); // 车牌定位 cvNamedWindow("bbb",1); cvShowImage("bbb",pImgCanny); OnSplitcar() ; OnShibiecar(); cvWaitKey(0); } }
标签:
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论