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

QQ登录

只需一步,快速开始

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

车牌识别(七)缩放锁定文字绽放到模板等同大小

[复制链接]
发表于 2018-8-4 11:46:47 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 乘简 于 2018-8-4 11:47 编辑

由于给定的车牌图片中的文字大小不一,还得进行缩放操作,保存与模板大小一致,再与模板进行比较。

给定的模板为16 x 32像素,所以要把锁定的图片进行缩放操作。
  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. //从源BMP图中,剪切车牌所在区域的新结构
  39. struct Bmp1{
  40.     DWORD width;
  41.     DWORD height;
  42.     BYTE *image;
  43.     int left[10];//保存车牌中7个字的左右列
  44.     int right[10];
  45.     int top[10];//保存车牌上下位置
  46.     int bottom[10];
  47.     int up;
  48.     int down;
  49.     byte strr[7][2500];
  50.     byte string[7];//反回已找到的车牌下标
  51.     float ang;//倾斜角度
  52. };

  53. //蓝色车牌
  54. struct HSV{
  55.   float H;//H值范围:190 ~ 245
  56.   float S;//S值范围: 0.35 ~ 1,我理解为黑白灰度
  57.   int V;//V值范围: 0.3 ~ 1
  58. };

  59. //读图片文件到内存中
  60. int read_img(char const *fn, struct BMP_img *img)
  61. {
  62.     FILE *infile;
  63.     if((infile=fopen(fn,"rb"))==NULL)return 0;

  64.     fread(&img->bfType,2,1,infile);//BM
  65.     if(!(img->bfType[0]=='B' && img->bfType[1]=='M'))return 0;
  66.     fread(&img->size,sizeof(DWORD),1,infile);
  67.     printf("\nBMP size             :%d",(int)img->size);
  68.     fread(&img->reser,sizeof(DWORD),1,infile);
  69.     printf("\n保留位:");
  70.     fread(&img->header_length,sizeof(DWORD),1,infile);
  71.     printf("\nheader length    :%d",(int)img->header_length);
  72.     fread(&img->infoheader_length,sizeof(DWORD),1,infile);
  73.     fread(&img->width, sizeof(DWORD), 1, infile);
  74.     fread(&img->height, sizeof(DWORD), 1, infile);
  75.     printf( "\nwidth   :%d\n  height  :%d ", (int)img->width, (int)img->height);
  76.     fread(&img->biplanes, sizeof(WORD), 1, infile);
  77.     fread(&img->bmp_type, sizeof(WORD), 1, infile);
  78.     printf("\nBMP Tpye             :%d ", img->bmp_type);
  79.     fread(&img->compres, sizeof(DWORD), 1, infile);
  80.     if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
  81.     fread(&img->datasize, sizeof(DWORD), 1, infile);
  82.     printf("\nBMP Data Size        :%d ",(int)img->datasize);
  83.     fread(&img->bixpm, sizeof(DWORD), 1, infile);
  84.     fread(&img->biypm, sizeof(DWORD), 1, infile);
  85.     fread(&img->clrused, sizeof(DWORD), 1, infile);
  86.     printf("\n实际使用颜色数=%d ",(int)img->clrused);printf(" ");
  87.     fread(&img->relclrused, sizeof(DWORD), 1, infile);

  88.     //计算一行需要多少字节,对齐到4字节
  89.     img->lineBytes=(img->width*img->bmp_type+31)/32*4;//printf("\nLineBytes            :%l\n",img->lineBytes);
  90.     if(img->bmp_type==24)//24位色
  91.     {
  92.         img->image=(unsigned char *)malloc(img->lineBytes*img->height);//分配一块内存,用于保存图像数据
  93.         if(img->image==NULL) fprintf(stderr, "\n Allocation error for temp in read_bmp() \n");
  94.         fseek(infile, img->header_length, SEEK_SET);//跳过头部,也就是跳到图像位置
  95.         if(img->datasize==img->width*3)
  96.             fread(img->image, sizeof(unsigned char), (img->lineBytes)*img->height, infile);//全部读到内存中
  97.         else
  98.         {
  99.             for(int i=0;i<img->height;i++)
  100.             {
  101.                 fread(&img->image[i*img->width*3], sizeof(unsigned char), img->lineBytes, infile);//全部读到内存中
  102.             }
  103.         }
  104.     }
  105.     fclose(infile);
  106.     return 1;
  107. }

  108. //把二值图保存为24位黑白图
  109. void WriteBmp1(char const *fn,byte *bmp,int width,int height)
  110. {
  111.     int w4;
  112.     struct BMP_img img;
  113.     //一行有多少个字节
  114.     img.lineBytes=((width*3+3)>>2)<<2;//对齐到4字节边界
  115.     w4=img.lineBytes*height;//图像尺寸
  116.     img.bfType[0]='B';img.bfType[1]='M';
  117.     img.size=w4+54;
  118.     img.reser=0;
  119.     img.header_length=54;
  120.     img.infoheader_length=40;
  121.     img.width=width;
  122.     img.height=height;
  123.     img.biplanes=1;
  124.     img.bmp_type=24;
  125.     img.compres=0;
  126.     img.datasize=w4;
  127.     img.bixpm=0;
  128.     img.biypm=0;
  129.     img.clrused=0;
  130.     img.relclrused=0;
  131.    
  132.     FILE *infile;
  133.     if((infile=fopen(fn,"wb"))==NULL)
  134.     {
  135.         return;
  136.     }
  137.     fwrite(&img.bfType,2,1,infile);//printf("\n打开的图为 %d",img->bfType);//B M
  138.     fwrite(&img.size,sizeof(DWORD),1,infile);     //        printf("\nBMP size             :%l",img->size);
  139.     fwrite(&img.reser,sizeof(DWORD),1,infile);//printf("\n保留位:");
  140.     fwrite(&img.header_length,sizeof(DWORD),1,infile); //printf("\nheader length    :%l",img->header_length);
  141.     fwrite(&img.infoheader_length,sizeof(DWORD),1,infile);
  142.     fwrite(&img.width, sizeof(DWORD), 1, infile);
  143.     fwrite(&img.height, sizeof(DWORD), 1, infile);     //printf( "\nwidth   :%l\n  height  :%l ", img->width, img->height);
  144.     fwrite(&img.biplanes, sizeof(WORD), 1, infile);
  145.     fwrite(&img.bmp_type, sizeof(WORD), 1, infile);  // printf("\nBMP Tpye             :%l ", img->bmp_type);
  146.     fwrite(&img.compres, sizeof(DWORD), 1, infile);    //if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
  147.     fwrite(&img.datasize, sizeof(DWORD), 1, infile);//printf("\nBMP Data Size        :%l ",img->datasize);
  148.     fwrite(&img.bixpm, sizeof(DWORD), 1, infile);
  149.     fwrite(&img.biypm, sizeof(DWORD), 1, infile);
  150.     fwrite(&img.clrused, sizeof(DWORD), 1, infile);    //printf("\n实际使用颜色数=%d ",img->clrused);printf(" ");
  151.     fwrite(&img.relclrused, sizeof(DWORD), 1, infile);
  152.    
  153.     byte *wbmp=(byte*)malloc(w4);//后面多加两个字节,用于4字节对齐
  154.     for(int i=0,s,w;i<height;i++)
  155.     {
  156.         s=i*width;
  157.         w=i*img.lineBytes;
  158.         for(int j=0;j<width;j++)
  159.         {
  160.             if(bmp[s+j]){
  161.                 wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=bmp[s+j];
  162.             }
  163.             else wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=0;               
  164.         }
  165.     }
  166.     fwrite(wbmp,img.datasize,1,infile);
  167.     free(wbmp);
  168.     fclose(infile);
  169. }

  170. //水平投影,从中间往两边计算,从而去掉最上面与最下面的多余部分
  171. void shuipingtouying(struct Bmp1 *img,byte *dst)//得到车牌的上下边缘
  172. {
  173.     byte temp;
  174.     int i,j,m,n;
  175.     int *p=(int*)malloc(img->height*sizeof(int));//申请以行为单位的整型内存数

  176.     for(i=0;i<img->width;i++)//宽度循环
  177.     {
  178.         if((dst[i]==255)||(dst[img->width+i]==255))//如果第一行 或 第二行有白点
  179.         for(j=0;j<img->height;j++)//消除此白点,直到碰到黑点退出
  180.         {
  181.             if(dst[j*img->width+i]==255)
  182.                 dst[j*img->width+i]=0;
  183.             else break;
  184.         }
  185.     }
  186.     for(i=0;i<img->width;i++)
  187.     {
  188.         //倒数1,2行中有白点,则消除,否则退出
  189.         if((dst[img->width*(img->height-1)+i]==255)||(dst[img->width*(img->height-2)+i]==255))
  190.             for(j=img->height-1;j>0;j--)
  191.             {
  192.                 if(dst[j*img->width+i]==255)
  193.                     dst[j*img->width+i]=0;
  194.                 else break;
  195.             }
  196.     }

  197.     //记录每一行的白点数
  198.     for(i=0;i<img->height;i++)
  199.     {
  200.         p[i]=0;
  201.         for(j=0;j<img->width;j++)
  202.         {
  203.             if(dst[i*img->width+j]==255)
  204.                 p[i]++;
  205.         }
  206.     }

  207.     //找到白点数最多的行
  208.     temp=0;
  209.     for(i=0;i<img->height;i++)
  210.     {
  211.         if(p[i]>temp)
  212.         {
  213.           temp=p[i];
  214.         }
  215.     }

  216.     n=temp/5;//以20%做为阀值
  217.     img->up=0;
  218.     img->down=img->height;
  219.     m=img->height/2;
  220.     for(i=m-1;i>0;i--)//从中间往上下遍历,如果有一行的白点数小于20%,则做为起点与终点
  221.     {
  222.         if(p[i]<n)
  223.         {
  224.             img->up=i+1;//只有第一次,才赋值
  225.             break;
  226.         }
  227.     }
  228.     for(i=m+1;i<img->height;i++)//从下面往中间遍历
  229.     {
  230.         if(p[i]<n)
  231.         {
  232.             img->down=i-1;
  233.             break;
  234.         }
  235.     }
  236.     free(p);

  237.     //删除起始行之前的白点
  238.     for(i=0;i<img->up;i++)
  239.     {
  240.         for(j=0;j<img->width;j++)
  241.         {
  242.             dst[i*img->width+j]=0;
  243.         }
  244.     }
  245.    
  246.     //删除结束行之后的白点
  247.     for(i=img->down+1;i<img->height;i++)
  248.     {
  249.         for(j=0;j<img->width;j++)
  250.         {
  251.             dst[i*img->width+j]=0;
  252.         }
  253.     }
  254. }

  255. //垂直投影法
  256. void cuizhitouying(struct Bmp1 *img,byte *temp)
  257. {
  258.     DWORD i,j;
  259.     int num,flag;

  260.     int up;
  261.     int down;
  262.     int bd;//当前列白点数

  263.     //计算1个字符的宽度,也就是1块车牌的宽度,把所有字挨紧,空白区域占30%左右
  264.     //然后一块车牌有7个字,所以一个字的宽度大根是width*0.7/7
  265.     num=flag=0;
  266.     up=img->height;//最高一个白点
  267.     down=0;//最低一个白点
  268.     for(i=0;i<img->width;i++)//按宽遍历
  269.     {
  270.         bd=0;
  271.         for(j=0;j<img->height;j++)//按高遍历,也就是1列1列的遍历
  272.         {
  273.             if(temp[j*img->width+i]==255)//记录每列白点数
  274.             {
  275.                 bd++;
  276.                 if(up>j)up=j;//最高白点
  277.                 if(down<j)down=j;//记住最后一个白点的位置
  278.             }
  279.         }

  280.         if(bd)//当前列有白点
  281.         {
  282.             if(flag==0)//还没有记录起点
  283.             {
  284.                 flag=1;
  285.                 img->left[num]=i;//记录下起点
  286.             }
  287.         }
  288.         else//当前列没白点
  289.         {
  290.             if(flag)//如果已记录了起点
  291.             {
  292.                 if((down-up)+1>img->height/2)//找到正确的字符
  293.                 {
  294.                     img->right[num]=i-1;//记录结束区域
  295.                     img->top[num]=up;
  296.                     img->bottom[num]=down;
  297.                     num++;//查找下一个字符
  298.                 }
  299.                 flag=0;//记录下一个记点
  300.                 up=img->height;
  301.                 down=0;
  302.             }
  303.         }
  304.     }
  305.     //如果最后一个没有结束
  306.     if(flag){
  307.         img->right[num]=img->width-1;
  308.         img->top[num]=up;
  309.         img->bottom[num]=down;
  310.         num++;
  311.     }
  312.         
  313.     if(num<7)//位数不够
  314.     {
  315.         printf("car no min error\n");
  316.     }
  317.     else if(num>7)//如果找到多于7个字符,说明里面有一个“川”字
  318.     {
  319.         printf("car no error\n");
  320.     }
  321. }

  322. //复制单个字符,存进数组中
  323. void strBmp(struct Bmp1 *img,byte *temp)
  324. {
  325.     int i,j,k,n;
  326.     //int w,h;
  327.     for(i=0;i<7;i++)
  328.     {
  329.         n=0;
  330.         for(j=img->top[i];j<=img->bottom[i];j++)//高度循环
  331.         {
  332.             for(k=img->left[i];k<=img->right[i];k++)//宽度循环
  333.             {
  334.                 img->strr[i][n++]=temp[j*img->width+k];
  335.             }
  336.         }
  337.         if(i==0)WriteBmp1("z1.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  338.         if(i==1)WriteBmp1("z2.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  339.         if(i==2)WriteBmp1("z3.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  340.         if(i==3)WriteBmp1("z4.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  341.         if(i==4)WriteBmp1("z5.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  342.         if(i==5)WriteBmp1("z6.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  343.         if(i==6)WriteBmp1("z7.bmp",img->strr[i],img->right[i]-img->left[i]+1,img->bottom[i]-img->top[i]+1);
  344.     }
  345. }

  346. //缩放到指定的宽度与高度
  347. void changeGray(byte *srcBmp,byte *dstBmp,int width,int height,int nWidth,int nHeight)
  348. {
  349.     int i=0,j=0,i0,j0;
  350.     float xx;float yy;
  351.     xx=(float)nWidth/width;//宽度缩放比
  352.     yy=(float)nHeight/height;

  353.     memset(dstBmp,0x00,nHeight*nWidth*sizeof(byte));
  354.     if(width<nWidth/2)//说明为1
  355.     {
  356.         for(i=0;i<nHeight;i++)
  357.         {
  358.             for(j=0;j<width;j++)
  359.             {
  360.                 if(i<=height)
  361.                 {
  362.                     dstBmp[i*nWidth+j]=srcBmp[i*width+j];
  363.                 }
  364.                 else{
  365.                     dstBmp[i*nWidth+j]=srcBmp[(height-1)*width+j];
  366.                 }
  367.             }
  368.         }
  369.     }
  370.     else
  371.     {
  372.         for(i = 0; i <nHeight; i++)
  373.         {
  374.             for(j = 0; j <nWidth; j++)
  375.             {
  376.                 //i0 = (int) ((float)i/yy+0.5);
  377.                 //j0 = (int) ((float)j/xx+0.5);
  378.                 i0 = (int) ((float)i/yy);
  379.                 j0 = (int) ((float)j/xx);
  380.                 if((j0>=0)&&(j0<width)&&(i0>=0)&&(i0<height))
  381.                 // {
  382.                     dstBmp[i*nWidth+j]=srcBmp[i0*width+j0];
  383.                  //}
  384.                  //else
  385.                  //{
  386.                 //    dstBmp[i*nWidth+j]=255;
  387.                  //}
  388.             }
  389.         }
  390.     }
  391. }

  392. void guiyi(struct Bmp1 *img)
  393. {
  394.     int xxx;
  395.     int i;
  396.     int yyy;

  397.     byte *temp=(byte *)malloc(sizeof(byte)*512);
  398.     for(i=0;i<7;i++)
  399.     {
  400.         xxx=img->right[i]-img->left[i]+1;
  401.         yyy=img->bottom[i]-img->top[i]+1;

  402.         changeGray(img->strr[i],temp,xxx,yyy,16,32);

  403.         memcpy(img->strr[i],temp,sizeof(byte)*512);
  404.         if(i==0)WriteBmp1("zz1.bmp",img->strr[i],16,32);
  405.         if(i==1)WriteBmp1("zz2.bmp",img->strr[i],16,32);
  406.         if(i==2)WriteBmp1("zz3.bmp",img->strr[i],16,32);
  407.         if(i==3)WriteBmp1("zz4.bmp",img->strr[i],16,32);
  408.         if(i==4)WriteBmp1("zz5.bmp",img->strr[i],16,32);
  409.         if(i==5)WriteBmp1("zz6.bmp",img->strr[i],16,32);
  410.         if(i==6)WriteBmp1("zz7.bmp",img->strr[i],16,32);
  411.     }
  412. }

  413. int main(int argc, char **argv)
  414. {
  415.     struct BMP_img img;//定义结构
  416.     struct Bmp1 img1;

  417.     //把当前文件夹下的1.bmp文件内容,读到img结构中,并上下镜像
  418.     if(read_img("1.bmp", &img)==0)
  419.     {
  420.         printf("error");
  421.         return 0;
  422.     }
  423.    
  424.     img1.width=img.width;
  425.     img1.height=img.height;
  426.     byte *temp=(byte*)malloc(img.width*img.height);
  427.     //24位灰度图转单色灰度图
  428.     for(int i=0;i<img.height;i++)
  429.     {
  430.         for(int j=0;j<img.width;j++)
  431.         {
  432.             temp[i*img.width+j]=img.image[i*img.width*3+j*3];
  433.         }
  434.     }
  435.    
  436.     //水平投影,去掉上下非文字区域
  437.     shuipingtouying(&img1,temp);
  438.    
  439.     //垂直投影,去掉车牌中的点,并计算7个字各在什么位置
  440.     cuizhitouying(&img1,temp);//垂直投影,框住每一个字符
  441.    
  442.     //写入镜像后的数据到2.bmp中
  443.     WriteBmp1("2.bmp",temp,img.width,img.height);
  444.    
  445.     //把每个文字切出来
  446.     strBmp(&img1,temp);//把车牌字符放到数组里面

  447.     //缩放每个文字,与模板大小相等
  448.     guiyi(&img1);
  449.    
  450.     free(img.image);//释放动态分配的内存
  451.     free(temp);
  452.    
  453.     printf("请打开2.bmp进行查看\n");
  454.     system("pause");
  455.     return 0;
  456. }
复制代码


原图
zz7.bmp
zz6.bmp
zz5.bmp
zz4.bmp
zz3.bmp
zz2.bmp
zz1.bmp
1.bmp
回复

使用道具 举报

本版积分规则

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

GMT+8, 2024-12-22 17:30 , Processed in 0.042296 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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