乘简 发表于 2018-8-1 10:40:42

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned long       DWORD;
typedef int               BOOL;
typedef unsigned char       BYTE;
typedef unsigned short      WORD;
typedef float               FLOAT;
typedef unsigned char       byte;

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

//BMP图像结构
struct BMP_img
{
    //{BMP头
    BYTEbfType;//类型,判断是否为‘B’,‘M’
    DWORD size;//文件尺寸
    DWORD reser;//保留,为0
    DWORD header_length;//头部长度,也就是数据起始位置
    //}BMP头长度,14字节

    //{信息头40字节
    DWORD infoheader_length;//信息头长度,40
    DWORD width;//图像宽度
    DWORD height;//图像高度
    WORDbiplanes;//颜色平面数,为1
    WORDbmp_type;/* 8bit 24bit; */
    DWORD compres;//0表示不压缩
    DWORD datasize;//数据长度,size-54
    DWORD bixpm;//水平分辩率
    DWORD biypm;//垂直分辩率
    DWORD clrused;//为0所有颜色,其它的为索引数
    DWORD relclrused;//0表示都重要
    //}信息头结束

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

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

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

    fread(&img->bfType,2,1,infile);//BM
    if(!(img->bfType=='B' && img->bfType=='M'))return 0;
    fread(&img->size,sizeof(DWORD),1,infile);
    printf("\nBMP size             :%d",(int)img->size);
    fread(&img->reser,sizeof(DWORD),1,infile);
    printf("\n保留位:");
    fread(&img->header_length,sizeof(DWORD),1,infile);
    printf("\nheader length    :%d",(int)img->header_length);
    fread(&img->infoheader_length,sizeof(DWORD),1,infile);
    fread(&img->width, sizeof(DWORD), 1, infile);
    fread(&img->height, sizeof(DWORD), 1, infile);
    printf( "\nwidth   :%d\nheight:%d ", (int)img->width, (int)img->height);
    fread(&img->biplanes, sizeof(WORD), 1, infile);
    fread(&img->bmp_type, sizeof(WORD), 1, infile);
    printf("\nBMP Tpye             :%d ", img->bmp_type);
    fread(&img->compres, sizeof(DWORD), 1, infile);
    if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
    fread(&img->datasize, sizeof(DWORD), 1, infile);
    printf("\nBMP Data Size      :%d ",(int)img->datasize);
    fread(&img->bixpm, sizeof(DWORD), 1, infile);
    fread(&img->biypm, sizeof(DWORD), 1, infile);
    fread(&img->clrused, sizeof(DWORD), 1, infile);
    printf("\n实际使用颜色数=%d ",(int)img->clrused);printf(" ");
    fread(&img->relclrused, sizeof(DWORD), 1, infile);

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

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

void WriteBmp1(char const *fn,byte *bmp,int width,int height)
{
    int w4;
        struct BMP_img img;
        //一行有多少个字节
        img.lineBytes=((width*3+3)>>2)<<2;//对齐到4字节边界
        w4=img.lineBytes*height;//图像尺寸
    img.bfType='B';img.bfType='M';
    img.size=w4+54;
    img.reser=0;
    img.header_length=54;
    img.infoheader_length=40;
    img.width=width;
    img.height=height;
    img.biplanes=1;
    img.bmp_type=24;
    img.compres=0;
    img.datasize=w4;
    img.bixpm=0;
    img.biypm=0;
    img.clrused=0;
    img.relclrused=0;
   
    FILE *infile;
    if((infile=fopen(fn,"wb"))==NULL)
    {
      return;
    }
    fwrite(&img.bfType,2,1,infile);//printf("\n打开的图为 %d",img->bfType);//B M
    fwrite(&img.size,sizeof(DWORD),1,infile);   //      printf("\nBMP size             :%l",img->size);
    fwrite(&img.reser,sizeof(DWORD),1,infile);//printf("\n保留位:");
    fwrite(&img.header_length,sizeof(DWORD),1,infile); //printf("\nheader length    :%l",img->header_length);
    fwrite(&img.infoheader_length,sizeof(DWORD),1,infile);
    fwrite(&img.width, sizeof(DWORD), 1, infile);
    fwrite(&img.height, sizeof(DWORD), 1, infile);   //printf( "\nwidth   :%l\nheight:%l ", img->width, img->height);
    fwrite(&img.biplanes, sizeof(WORD), 1, infile);
    fwrite(&img.bmp_type, sizeof(WORD), 1, infile);// printf("\nBMP Tpye             :%l ", img->bmp_type);
    fwrite(&img.compres, sizeof(DWORD), 1, infile);    //if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
    fwrite(&img.datasize, sizeof(DWORD), 1, infile);//printf("\nBMP Data Size      :%l ",img->datasize);
    fwrite(&img.bixpm, sizeof(DWORD), 1, infile);
    fwrite(&img.biypm, sizeof(DWORD), 1, infile);
    fwrite(&img.clrused, sizeof(DWORD), 1, infile);    //printf("\n实际使用颜色数=%d ",img->clrused);printf(" ");
    fwrite(&img.relclrused, sizeof(DWORD), 1, infile);
   
    byte *wbmp=(byte*)malloc(w4);
    for(int i=0,s,w;i<height;i++)
    {
                s=i*width;
                w=i*img.lineBytes;
      for(int j=0;j<width;j++)
      {
            if(bmp){
                wbmp=wbmp=wbmp=255;
            }
            else wbmp=wbmp=wbmp=0;               
      }
    }
    fwrite(wbmp,img.datasize,1,infile);
    free(wbmp);
    fclose(infile);
}

//把RGB数据转换成HSV空间图像数据
//输入,图像,HSV倍象素,宽,高
void hsvzation(byte *image,struct HSV *hsv,int width,int height)
{
    int i,j,k;
    DWORD l,lk;
    //float min,max,delta,tmp;//h,s,v,m,n;
    int min,max,delta,tmp;
    byte r,g,b;
    for(i=0;i<height;i++)
    {
      l=i*width;
      for(k=0,j=0;j<width*3;k++,j+=3)
      {
            lk=l+k;
            g=image;
            b=image;
            r=image;

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

            tmp=max(r,g);//取3者最大值
            max=max(tmp,b);
            hsv.V=max;//V保存三者最大值
            delta=max-min;//保存最大值与最小值的差
            if(delta==0)//如果3值相等
            {
                hsv.H=0;
                hsv.S=0;//这句是我加的
                continue;
            }

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

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

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

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

    for(i=0;i<height;i++)//循环高度
    {
       for(j=0,n=0;j<width;n+=3,j++)//循环宽度
      {
         if((hsv.H<230.0)&&(hsv.H>180.0)&&(hsv.V<250)&&(hsv.S>0.6))
         {
               temp1=255;//为白色
         }
         else//为黑色
         {
               temp1=0;
         }
       }
    }//可以看到,本循环的意思就是把原始图像,黑白化,满足条件为白,否则通通为黑
   
    //写入镜像后的数据到2.bmp中
    WriteBmp1("2.bmp",temp1,width,height);
      
    free(temp1);
    temp1=NULL;
    free(hsv);
}

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

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


0xAA55 发表于 2018-8-1 14:59:42

……纯靠代码说话的么!
不过看到了后面的附件我大概明白是咋回事了,那就是先进行二值化处理,再……
不对……你这代码不就是二值化处理么!

0xAA55 发表于 2018-8-2 15:13:05

我还以为是你自己写的……

乘简 发表于 2018-8-2 15:27:07

这年头,能把开源软件看懂,都很不错了,方方面面的开源软件都有。。。

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

linxxx 发表于 2018-8-26 09:56:34

不懂,但是点赞

Ink_Hin_fifteen 发表于 2019-5-10 20:00:39

学习了!
页: [1]
查看完整版本: 车牌识别(一)根据车牌蓝底二值化图片