分享自己写的车牌字符分割程序(opencv)

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
//本程序只适用于检测八个车牌字符,带点,,出现连粘和断裂的(也就是不是8个字符)会出错
using namespace cv;
using namespace std;
Mat jianqietu,jieguo;
float Valueo=0;
int main()
{
Mat srcImage=imread("15.jpg");
//imshow("原图",srcImage);


//Mat dstImage;
cvtColor(srcImage,srcImage,CV_RGB2GRAY);
//blur(srcImage,srcImage,Size(3,3));
threshold( srcImage, srcImage, 0, 255,CV_THRESH_OTSU);//大津法,自动阈值,图片12,13,14,15,16,17,18,19可以用自动阈值法
//return Valueo  = threshold( srcImage, srcImage, 0, 255,CV_THRESH_OTSU);//希望返回大津法给的自动阈值


//threshold(srcImage,srcImage,130,255,CV_THRESH_BINARY);//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$用图片10阈值要改为90,用图片14阈值要改为160,用图片15阈值要改为130,
medianBlur(srcImage,srcImage,7);
imshow("二值化图",srcImage);
//imshow("s",dstImage);


int *rowwidth=new int[srcImage.rows];//这里用小括号还不行
//int *colheight =new int[srcImage.cols]; 


memset(rowwidth,0,srcImage.rows*4);//############################################3
//memset(colheight,0,srcImage.cols*4);


int value,k=0,m=0,n=0;
for(int i=0;i<srcImage.rows;i++)  
{
        for(int j=0;j<srcImage.cols;j++)    
        {    
   //           k++;//总的像素点k=i*512+j
//if(srcImage.at<uchar>(i,j)==255)//这里是我写的在控制面板输出每一行白点个数,
//{
// m++;//总的白点数
// if(k%512==511){
// printf("第%3d",i);
// printf("行=%3d     ",m-n);}
// if(k%512==0) 
// {
// n=m;
//
// }
//}
            //value=cvGet2D(src,j,i);  
            value=srcImage.at<uchar>(i,j);  
//value1=srcImage.at<uchar>(i,j);
            if(value==255)    
            {    
                rowwidth[i]++;
            }  //
//if (rowwidth[i]%100==0)


        }    
}
Mat histogramImage=Mat::zeros(srcImage.rows,srcImage.cols,CV_8UC1);//相似替换
//Mat histogramImage(srcImage.rows,srcImage.cols,CV_8UC1);
// for(int i=0;i<srcImage.rows;i++)    
  //          for(int j=0;j<srcImage.cols;j++)    
  //          {    
  //              value=0;  //设置为黑色。  
  //              histogramImage.at<uchar>(i,j)=value;    
  //          }    


for(int i=0;i<srcImage.rows;i++)
for(int j=0;j<rowwidth[i];j++)
{
value=255;
histogramImage.at<uchar>(i,j)=value;
}


//******************************************************************************************************取峰值:
int max=0,i=0,one_number=0,one_max=0;
for(int i=0;i<srcImage.rows;i++)
{
if(srcImage.cols-rowwidth[i]>max){max=srcImage.cols-rowwidth[i];one_number=i;one_max=max;}
}
max=0;
//初步输出二峰值
int two_number=0,two_max=0;
for(int i=0;i<srcImage.rows;i++)

         //数字50控制车牌字符的上下端之差不至于小于2倍的50
if(   (srcImage.cols-rowwidth[i]>max)&&( (i>one_number+50)||(i<one_number-50) )  ){max=srcImage.cols-rowwidth[i];two_number=i;two_max=max;}
}
//输出one峰值
printf("one行峰值数%3d\n",one_max);
printf("one行峰值位置%3d\n\n",one_number);
//输出two峰值
printf("two行峰值数%3d\n",two_max);
printf("two行峰值位置%3d\n\n",two_number);


int qian=0,hou=0;//定义ROI区域的前行和后行
if(one_number<two_number){qian=one_number,hou=two_number;}
if(one_number>two_number){qian=two_number,hou=one_number;}


for(i=qian;i<qian+70;i++)//控制上边界,使上边界尽量下移,用以缩小即将裁剪的ROI区域,70控制下移距离不要超过70 
{         
if(  (srcImage.cols-rowwidth[i]== two_max)||(srcImage.cols-rowwidth[i]== one_max)  )qian=i;
}


jianqietu=srcImage(Rect(0,qian,srcImage.cols,hou-qian));//Rect(1,2,3,4),这里1表ROI的起始横坐标,2表起始纵坐标,3表ROI宽,4表ROI高
imshow("去上下边界剪切图",jianqietu);
imshow("白++黑 直方图",histogramImage);
// imshow("l",histogramImage);


//srcImage=jianqietu.clone();


//*********************************************************下面我们来看看垂直投影********************************************************88


int *colheight =new int[srcImage.cols];    
   
memset(colheight,0,srcImage.cols*4);  //数组必须赋初值为零,否则出错。无法遍历数组。  


    for(int i=0;i<srcImage.rows;i++)   

        for(int j=0;j<srcImage.cols;j++)    
        {    
            //value=cvGet2D(src,j,i);  
            value=srcImage.at<uchar>(i,j);  
            if(value==255)    
            {    
                colheight[j]++; //统计每列的白色像素点   *********************************************数组用法 
            }    
  
}
}    
       
        for(int i=0;i<srcImage.rows;i++)    
     for(int j=0;j<srcImage.cols;j++)    
     {    
         value=0;  //设置为黑色。  
         histogramImage.at<uchar>(i,j)=value;    
     }    
     //imshow("d",histogramImage);  
     for(int i=0;i<srcImage.cols;i++)    
         for(int j=0;j<colheight[i];j++)    
         {    
             value=255;  //设置为白色  
             histogramImage.at<uchar>(j,i)=value;  
         }    
         //imshow("C",srcImage);
  int max2=0,kongzhi=30;//kongzhi用来控制车牌字符的左右端之差不至于小于2倍的kongzhi
  int cols_one_number=0,cols_one_number2=0,cols_one_number3=0,cols_one_number4=0;
  int    cols_one_max=0,  cols_one_max2=0,    cols_one_max3=0,   cols_one_max4=0;
  //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  for(int i=srcImage.cols;i>0;i--)//用i--,就能从右往左选左边界,这样的左边界尽量会靠右,更准确
  {
  if(srcImage.rows-colheight[i]>max2&&(i<70) )//控制即将分割的ROI的左边界
{max2=srcImage.rows-colheight[i];cols_one_number=i;cols_one_max=max2;}
  }
  max2=0;
  //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  for(int i=0;i<srcImage.cols;i++)
 
  if(   (srcImage.rows-colheight[i]>max2)&&(i>srcImage.cols-100 ) )//控制即将分割的ROI的右边界
  {max2=srcImage.rows-colheight[i];cols_one_number2=i,cols_one_max2=max2;}
  }
 
  //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  printf("第一大行峰值数%3d\n",cols_one_max);
  printf("第一大行峰值位置%3d\n\n",cols_one_number);
 
  printf("第二大行峰值数%3d\n",cols_one_max2);
  printf("第二大行峰值位置%3d\n\n",cols_one_number2);
  jieguo=srcImage(Range(qian-2,hou+2),Range(cols_one_number-2,cols_one_number2+2));//2用来控制ROI不要太靠边哦
  //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
     imshow("去掉上下左右边界",jieguo);
  imshow("垂直投影仪",histogramImage); 
  imwrite("我最终的ROI区域.jpg",jieguo);
  //printf("OTSU自动阈值Value返回值%3f\n\n",Valueo);
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 这里我要试图做几次纵向的分割  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
int before=0,after=0,h=0;//控制纵向黑色峰值的左右边界,h作为下面hang[6]的内容
int hang[9]={0,0,0,0,0,0,0,0,0};//准备存几个纵向的分割线条
for(int i=0;i<srcImage.cols;i++)
 
  if(   (srcImage.rows-colheight[i]>srcImage.rows-20) )//如果纵向的黑色峰值大于行高减20,则,,,,,
  {   
  
before=i;
for(i;srcImage.rows-colheight[i]>srcImage.rows-20;i++)
{
//if((srcImage.rows-colheight[i]<srcImage.rows-20)||(srcImage.rows-colheight[i]==srcImage.rows-20)  ) //我这个if语句完全不起作用?。。。。
//{after=i;
//hang[h]=int((before+after)/2);
   //         //printf("hang[h]的值,有吗?%d\n",hang[h]);
//break;}
}
after=i; 
hang[h]=int((before+after)/2);//我这样是想从字符间空当的中间分割,不至于太挨着边了
            printf("cccc字符间空当的中间坐标,%d\n", hang[h]);//输出九个间隔,后面没输出来这里却行,歪打正着了,,,哈哈哈哈
h++;
}
  }
printf("hang[h]的值,有吗?%d\n",hang[2]);//,此处用作实验输出,无实际 意义。试了下,可以有效输出数组的值了,这里的hang[]可能是贴边的,所以数值跟上面有出入


// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  这里我要来分割字符了  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Mat img1,img2,img3,img4,img5,img6,img7,img8;
img1=srcImage(Range(qian-2,hou+2),Range(hang[0],hang[1]));
 img2=srcImage(Range(qian-2,hou+2),Range(hang[1],hang[2]));
  img3=srcImage(Range(qian-2,hou+2),Range(hang[2],hang[3]));
   img4=srcImage(Range(qian-2,hou+2),Range(hang[3],hang[4]));
img5=srcImage(Range(qian-2,hou+2),Range(hang[4],hang[5]));
 img6=srcImage(Range(qian-2,hou+2),Range(hang[5],hang[6]));
  img7=srcImage(Range(qian-2,hou+2),Range(hang[6],hang[7]));
   img8=srcImage(Range(qian-2,hou+2),Range(hang[7],hang[8]));

imshow("第1个字符小块",img1);
imshow("第2个字符小块",img2);
imshow("第3个字符小块",img3);
imshow("第4个字符小块",img4);
imshow("第5个字符小块",img5);
imshow("第6个字符小块",img6);
imshow("第7个字符小块",img7);
imshow("第8个字符小块",img8);


  //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    下面是查找外轮廓矩形  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
vector<vector<Point>>contours;
vector<Vec4i> hierarchy;


threshold( jieguo, jieguo, 100, 255, THRESH_BINARY );
findContours(jieguo, contours, hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));
    printf("轮廓个数:%d",contours.size());
    //int idx = 0;
//char szName[56] = {0};
vector<vector<Point>> contours_poly(contours.size());
vector<Rect> boundRect(contours.size());


for( int i = 0; i < contours.size(); i++ )
     { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );//逼近多边形曲线
       boundRect[i] = boundingRect( Mat(contours_poly[i]) );//寻找外部矩形边界
       
     }


Mat drawing = Mat::zeros( jieguo.size(), CV_8UC3 );
for(int unsigned i=0;i<contours.size();i++)
{
drawContours( drawing, contours_poly, i, Scalar(0,0,255), 1, 8, vector<Vec4i>(), 0, Point() );
 rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), Scalar(0,222,255), 2, 8, 0 );    //显示矩形的外框,,这个tl和br我也是醉了,,
}


//imshow("攒公开",jieguo);
imshow("&&&&&&&&&&&&&",drawing);
waitKey(0);
return 0;


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值