找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3130|回复: 6

车牌识别(一)根据车牌蓝底二值化图片

[复制链接]
发表于 2018-8-1 10:40:42 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>

  4. typedef unsigned long       DWORD;
  5. typedef int                 BOOL;
  6. typedef unsigned char       BYTE;
  7. typedef unsigned short      WORD;
  8. typedef float               FLOAT;
  9. typedef unsigned char       byte;

  10. #define max(a,b)            (((a) > (b)) ? (a) : (b))
  11. #define min(a,b)            (((a) < (b)) ? (a) : (b))

  12. //BMP图像结构
  13. struct BMP_img
  14. {
  15.     //{BMP头
  16.     BYTE  bfType[2];//类型,判断是否为‘B’,‘M’
  17.     DWORD size;//文件尺寸
  18.     DWORD reser;//保留,为0
  19.     DWORD header_length;//头部长度,也就是数据起始位置
  20.     //}BMP头长度,14字节

  21.     //{信息头40字节
  22.     DWORD infoheader_length;//信息头长度,40
  23.     DWORD width;//图像宽度
  24.     DWORD height;//图像高度
  25.     WORD  biplanes;//颜色平面数,为1
  26.     WORD  bmp_type;/* 8bit 24bit; */
  27.     DWORD compres;//0表示不压缩
  28.     DWORD datasize;//数据长度,size-54
  29.     DWORD bixpm;//水平分辩率
  30.     DWORD biypm;//垂直分辩率
  31.     DWORD clrused;//为0所有颜色,其它的为索引数
  32.     DWORD relclrused;//0表示都重要
  33.     //}信息头结束

  34.     //其它信息
  35.     BYTE *image;//指向一块内存,保存BMP的内容
  36.     DWORD lineBytes;//一行占多少字节
  37. };

  38. //蓝色车牌
  39. struct HSV{
  40.   float H;//H值范围:190 ~ 245
  41.   float S;//S值范围: 0.35 ~ 1,我理解为黑白灰度
  42.   int V;//V值范围: 0.3 ~ 1
  43. };

  44. //文件图文件到内存中
  45. int read_img(char const *fn, struct BMP_img *img)
  46. {
  47.     FILE *infile;
  48.     if((infile=fopen(fn,"rb"))==NULL)return 0;

  49.     fread(&img->bfType,2,1,infile);//BM
  50.     if(!(img->bfType[0]=='B' && img->bfType[1]=='M'))return 0;
  51.     fread(&img->size,sizeof(DWORD),1,infile);
  52.     printf("\nBMP size             :%d",(int)img->size);
  53.     fread(&img->reser,sizeof(DWORD),1,infile);
  54.     printf("\n保留位:");
  55.     fread(&img->header_length,sizeof(DWORD),1,infile);
  56.     printf("\nheader length    :%d",(int)img->header_length);
  57.     fread(&img->infoheader_length,sizeof(DWORD),1,infile);
  58.     fread(&img->width, sizeof(DWORD), 1, infile);
  59.     fread(&img->height, sizeof(DWORD), 1, infile);
  60.     printf( "\nwidth   :%d\n  height  :%d ", (int)img->width, (int)img->height);
  61.     fread(&img->biplanes, sizeof(WORD), 1, infile);
  62.     fread(&img->bmp_type, sizeof(WORD), 1, infile);
  63.     printf("\nBMP Tpye             :%d ", img->bmp_type);
  64.     fread(&img->compres, sizeof(DWORD), 1, infile);
  65.     if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
  66.     fread(&img->datasize, sizeof(DWORD), 1, infile);
  67.     printf("\nBMP Data Size        :%d ",(int)img->datasize);
  68.     fread(&img->bixpm, sizeof(DWORD), 1, infile);
  69.     fread(&img->biypm, sizeof(DWORD), 1, infile);
  70.     fread(&img->clrused, sizeof(DWORD), 1, infile);
  71.     printf("\n实际使用颜色数=%d ",(int)img->clrused);printf(" ");
  72.     fread(&img->relclrused, sizeof(DWORD), 1, infile);

  73.     if(img->bmp_type==24)//24位色,这里只考虑24位色图,其它的不考虑
  74.     {
  75.         img->lineBytes=((img->width*3+3)>>2)<<2;//计算一行需要多少字节,对齐到4字节

  76.         //byte *temp=(byte *)malloc(sizeof(byte) * img->height * img->lineBytes);//分配一块内存,用于读文件
  77.         img->image=(byte *)malloc(img->lineBytes*img->height);//分配一块内存,用于保存图像数据
  78.         if(img->image==NULL) fprintf(stderr, "\n Allocation error for temp in read_bmp() \n");
  79.         fseek(infile, img->header_length, SEEK_SET);//跳过头部,也就是跳到图像位置
  80.         fread(img->image, sizeof(byte), (img->lineBytes)*img->height, infile);//全部读到内存中
  81.     }
  82.     fclose(infile);
  83.     return 1;
  84. }

  85. void WriteBmp1(char const *fn,byte *bmp,int width,int height)
  86. {
  87.     int w4;
  88.         struct BMP_img img;
  89.         //一行有多少个字节
  90.         img.lineBytes=((width*3+3)>>2)<<2;//对齐到4字节边界
  91.         w4=img.lineBytes*height;//图像尺寸
  92.     img.bfType[0]='B';img.bfType[1]='M';
  93.     img.size=w4+54;
  94.     img.reser=0;
  95.     img.header_length=54;
  96.     img.infoheader_length=40;
  97.     img.width=width;
  98.     img.height=height;
  99.     img.biplanes=1;
  100.     img.bmp_type=24;
  101.     img.compres=0;
  102.     img.datasize=w4;
  103.     img.bixpm=0;
  104.     img.biypm=0;
  105.     img.clrused=0;
  106.     img.relclrused=0;
  107.    
  108.     FILE *infile;
  109.     if((infile=fopen(fn,"wb"))==NULL)
  110.     {
  111.         return;
  112.     }
  113.     fwrite(&img.bfType,2,1,infile);//printf("\n打开的图为 %d",img->bfType);//B M
  114.     fwrite(&img.size,sizeof(DWORD),1,infile);     //        printf("\nBMP size             :%l",img->size);
  115.     fwrite(&img.reser,sizeof(DWORD),1,infile);//printf("\n保留位:");
  116.     fwrite(&img.header_length,sizeof(DWORD),1,infile); //printf("\nheader length    :%l",img->header_length);
  117.     fwrite(&img.infoheader_length,sizeof(DWORD),1,infile);
  118.     fwrite(&img.width, sizeof(DWORD), 1, infile);
  119.     fwrite(&img.height, sizeof(DWORD), 1, infile);     //printf( "\nwidth   :%l\n  height  :%l ", img->width, img->height);
  120.     fwrite(&img.biplanes, sizeof(WORD), 1, infile);
  121.     fwrite(&img.bmp_type, sizeof(WORD), 1, infile);  // printf("\nBMP Tpye             :%l ", img->bmp_type);
  122.     fwrite(&img.compres, sizeof(DWORD), 1, infile);    //if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
  123.     fwrite(&img.datasize, sizeof(DWORD), 1, infile);//printf("\nBMP Data Size        :%l ",img->datasize);
  124.     fwrite(&img.bixpm, sizeof(DWORD), 1, infile);
  125.     fwrite(&img.biypm, sizeof(DWORD), 1, infile);
  126.     fwrite(&img.clrused, sizeof(DWORD), 1, infile);    //printf("\n实际使用颜色数=%d ",img->clrused);printf(" ");
  127.     fwrite(&img.relclrused, sizeof(DWORD), 1, infile);
  128.    
  129.     byte *wbmp=(byte*)malloc(w4);
  130.     for(int i=0,s,w;i<height;i++)
  131.     {
  132.                 s=i*width;
  133.                 w=i*img.lineBytes;
  134.         for(int j=0;j<width;j++)
  135.         {
  136.             if(bmp[s+j]){
  137.                 wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=255;
  138.             }
  139.             else wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=0;               
  140.         }
  141.     }
  142.     fwrite(wbmp,img.datasize,1,infile);
  143.     free(wbmp);
  144.     fclose(infile);
  145. }

  146. //把RGB数据转换成HSV空间图像数据
  147. //输入,图像,HSV倍象素,宽,高
  148. void hsvzation(byte *image,struct HSV *hsv,int width,int height)
  149. {
  150.     int i,j,k;
  151.     DWORD l,lk;
  152.     //float min,max,delta,tmp;//h,s,v,m,n;
  153.     int min,max,delta,tmp;
  154.     byte r,g,b;
  155.     for(i=0;i<height;i++)
  156.     {
  157.         l=i*width;
  158.         for(k=0,j=0;j<width*3;k++,j+=3)
  159.         {
  160.             lk=l+k;
  161.             g=image[l*3+j+1];
  162.             b=image[l*3+j];
  163.             r=image[l*3+j+2];

  164.             tmp=min(r,g);//取3者最小值
  165.             min=min(tmp,b);

  166.             tmp=max(r,g);//取3者最大值
  167.             max=max(tmp,b);
  168.             hsv[lk].V=max;//V保存三者最大值
  169.             delta=max-min;//保存最大值与最小值的差
  170.             if(delta==0)//如果3值相等
  171.             {
  172.                 hsv[lk].H=0;
  173.                 hsv[lk].S=0;//这句是我加的
  174.                 continue;
  175.             }

  176.             //如果三值依次是100,150,200,则.S=100/200=0.5
  177.             //如果三值依次是0,50,100,则为1
  178.             //如果三值依次是99,99,100,则为0.01
  179.             //意思就是三值越接近,此值越小,越不接近,此值越大
  180.             //应该是指颜色灰度
  181.             hsv[lk].S=(float)delta/max;

  182.             if(r==max)//如果红色为最大值,说明当前点的颜色偏红
  183.             {
  184.                 //如果三值依次为200,150,100,则.H=50/100=0.5
  185.                 //如果三值依次为100,50,0,则.H还是0.5
  186.                 //如果三值依次为:100,99,99,则为0
  187.                 //如果为100,0,100,则为-1
  188.                 //可以看出,蓝色与绿色越接近,趋向0,否则为趋向+-1
  189.                 hsv[lk].H=(g-b)/(float)delta;//tmp;
  190.             }
  191.             else if(g==max)//如果绿色为最大值
  192.                 hsv[lk].H=2+(b-r);//没看懂,取值范围-253~255
  193.             else//蓝为最大值
  194.             {
  195.                 //和红色最大一样的,[-1,0],[0-1],加上4后,变成【3,5]
  196.                 hsv[lk].H=4+(r-g)/(float)delta;//
  197.             }
  198.             //-1~1 *60=-60~60
  199.             //-253~257,*60=-15180~15420之间
  200.             hsv[lk].H*=60;//(3,5)*60=[180,300]
  201.             
  202.             //可以看到,当其值为【-60,0)时,加上360=【300,360)区间
  203.             //至于那个-15180多的那种结果,加上360也不管用
  204.             if(hsv[lk].H<0)
  205.                 hsv[lk].H+=360;//
  206.             //value=(int)(h+0.5);
  207.         }
  208.     }
  209. }

  210. //根据车牌蓝色范围,二值化车牌
  211. void location(byte *image,int width,int height,int yuzhi,int *HL,int *HH,int *VL,int *VH)
  212. {
  213.     int i,j,n;
  214.     struct HSV *hsv;//float,float,int
  215.     byte *temp1;
  216.     hsv=(struct HSV *)malloc(sizeof(struct HSV)*width*height);//分配HSV倍图像像素大小
  217.     hsvzation(image,hsv,width,height);//根据RGB,计算出HSV的值

  218.     //再分配一块内存,像素个
  219.     temp1=(byte *)malloc(sizeof(byte)*height*width);

  220.     for(i=0;i<height;i++)//循环高度
  221.     {
  222.        for(j=0,n=0;j<width;n+=3,j++)//循环宽度
  223.         {
  224.            if((hsv[i*width+j].H<230.0)&&(hsv[i*width+j].H>180.0)&&(hsv[i*width+j].V<250)&&(hsv[i*width+j].S>0.6))
  225.            {
  226.                temp1[i*width+j]=255;//为白色
  227.            }
  228.            else//为黑色
  229.            {
  230.                temp1[i*width+j]=0;
  231.            }
  232.        }
  233.     }//可以看到,本循环的意思就是把原始图像,黑白化,满足条件为白,否则通通为黑
  234.    
  235.     //写入镜像后的数据到2.bmp中
  236.     WriteBmp1("2.bmp",temp1,width,height);
  237.         
  238.     free(temp1);
  239.     temp1=NULL;
  240.     free(hsv);
  241. }

  242. int main(int argc, char **argv)
  243. {
  244.     struct BMP_img img;//定义结构
  245.     int HL=0,HH=0,VH=0,VL=0;

  246.     //把当前文件夹下的1.bmp文件内容,读到img结构中,并上下镜像
  247.     if(read_img("1.bmp", &img)==0)
  248.     {
  249.         printf("error");
  250.         return 0;
  251.     }
  252.    
  253.     location(img.image,img.width,img.height,15,&HL,&HH,&VL,&VH);//根据蓝底找到车牌所在位置
  254.    
  255.     free(img.image);//释放动态分配的内存
  256.    
  257.     printf("请打开2.bmp进行查看\n");
  258.     system("pause");
  259.     return 0;
  260. }
复制代码


20180730194546492.jpg
20180730194613206.jpg
回复

使用道具 举报

发表于 2018-8-1 14:59:42 | 显示全部楼层
……纯靠代码说话的么!
不过看到了后面的附件我大概明白是咋回事了,那就是先进行二值化处理,再……
不对……你这代码不就是二值化处理么!

点评

要知道,我拿到这份代码时,注释没有,对齐方式也很差,我看了好几天才看懂!还做了很多注释,改进了很多BUG!  发表于 2018-8-2 10:24
回复 赞! 靠!

使用道具 举报

发表于 2018-8-2 15:13:05 | 显示全部楼层
我还以为是你自己写的……
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2018-8-2 15:27:07 | 显示全部楼层
这年头,能把开源软件看懂,都很不错了,方方面面的开源软件都有。。。

可以看得出来,这份代码的作者,也有很多代码不是他自己写的。。。比如旋转图片的代码,就是另一个风格,注释完善。
回复 赞! 靠!

使用道具 举报

发表于 2018-8-26 09:56:34 | 显示全部楼层
不懂,但是点赞
回复 赞! 靠!

使用道具 举报

发表于 2019-5-10 20:00:39 | 显示全部楼层
学习了!
回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 03:07 , Processed in 0.038424 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表