- UID
- 2285
- 精华
- 积分
- 513
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
本帖最后由 乘简 于 2018-8-4 11:22 编辑
投影法分垂直投影法也水平投影法,水平投影法就是根据每一行白点数,取最大值,去掉小于20%此白点数的上边区域与下边区域。
垂直投影法就是找到连续的白点为1个区域,去掉高度太小的区域,就是每个字的区域,从而可以切出每1个字所在的位置,与模板进行比较
- #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头
- BYTE bfType[2];//类型,判断是否为‘B’,‘M’
- DWORD size;//文件尺寸
- DWORD reser;//保留,为0
- DWORD header_length;//头部长度,也就是数据起始位置
- //}BMP头长度,14字节
- //{信息头40字节
- DWORD infoheader_length;//信息头长度,40
- DWORD width;//图像宽度
- DWORD height;//图像高度
- WORD biplanes;//颜色平面数,为1
- WORD bmp_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;//一行占多少字节
- };
- //从源BMP图中,剪切车牌所在区域的新结构
- struct Bmp1{
- DWORD width;
- DWORD height;
- BYTE *image;
- int left[10];//保存车牌中7个字的左右列
- int right[10];
- int top[10];//保存车牌上下位置
- int bottom[10];
- int up;
- int down;
- byte strr[7][2500];
- byte string[7];//反回已找到的车牌下标
- float ang;//倾斜角度
- };
- //蓝色车牌
- 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[0]=='B' && img->bfType[1]=='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\n height :%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);
- //计算一行需要多少字节,对齐到4字节
- img->lineBytes=(img->width*img->bmp_type+31)/32*4;//printf("\nLineBytes :%l\n",img->lineBytes);
- if(img->bmp_type==24)//24位色
- {
- img->image=(unsigned char *)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);//跳过头部,也就是跳到图像位置
- if(img->datasize==img->width*3)
- fread(img->image, sizeof(unsigned char), (img->lineBytes)*img->height, infile);//全部读到内存中
- else
- {
- for(int i=0;i<img->height;i++)
- {
- fread(&img->image[i*img->width*3], sizeof(unsigned char), img->lineBytes, infile);//全部读到内存中
- }
- }
- }
- fclose(infile);
- return 1;
- }
- //把二值图保存为24位黑白图
- 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[0]='B';img.bfType[1]='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\n height :%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);//后面多加两个字节,用于4字节对齐
- 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[s+j]){
- wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=bmp[s+j];
- }
- else wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=0;
- }
- }
- fwrite(wbmp,img.datasize,1,infile);
- free(wbmp);
- fclose(infile);
- }
- //水平投影,从中间往两边计算,从而去掉最上面与最下面的多余部分
- void shuipingtouying(struct Bmp1 *img,byte *dst)//得到车牌的上下边缘
- {
- byte temp;
- int i,j,m,n;
- int *p=(int*)malloc(img->height*sizeof(int));//申请以行为单位的整型内存数
- for(i=0;i<img->width;i++)//宽度循环
- {
- if((dst[i]==255)||(dst[img->width+i]==255))//如果第一行 或 第二行有白点
- for(j=0;j<img->height;j++)//消除此白点,直到碰到黑点退出
- {
- if(dst[j*img->width+i]==255)
- dst[j*img->width+i]=0;
- else break;
- }
- }
- for(i=0;i<img->width;i++)
- {
- //倒数1,2行中有白点,则消除,否则退出
- if((dst[img->width*(img->height-1)+i]==255)||(dst[img->width*(img->height-2)+i]==255))
- for(j=img->height-1;j>0;j--)
- {
- if(dst[j*img->width+i]==255)
- dst[j*img->width+i]=0;
- else break;
- }
- }
- //记录每一行的白点数
- for(i=0;i<img->height;i++)
- {
- p[i]=0;
- for(j=0;j<img->width;j++)
- {
- if(dst[i*img->width+j]==255)
- p[i]++;
- }
- }
- //找到白点数最多的行
- temp=0;
- for(i=0;i<img->height;i++)
- {
- if(p[i]>temp)
- {
- temp=p[i];
- }
- }
- n=temp/5;//以20%做为阀值
- img->up=0;
- img->down=img->height;
- m=img->height/2;
- for(i=m-1;i>0;i--)//从中间往上下遍历,如果有一行的白点数小于20%,则做为起点与终点
- {
- if(p[i]<n)
- {
- img->up=i+1;//只有第一次,才赋值
- break;
- }
- }
- for(i=m+1;i<img->height;i++)//从下面往中间遍历
- {
- if(p[i]<n)
- {
- img->down=i-1;
- break;
- }
- }
- free(p);
- //删除起始行之前的白点
- for(i=0;i<img->up;i++)
- {
- for(j=0;j<img->width;j++)
- {
- dst[i*img->width+j]=0;
- }
- }
-
- //删除结束行之后的白点
- for(i=img->down+1;i<img->height;i++)
- {
- for(j=0;j<img->width;j++)
- {
- dst[i*img->width+j]=0;
- }
- }
- }
- //垂直投影法
- void cuizhitouying(struct Bmp1 *img,byte *temp)
- {
- DWORD i,j;
- int num,flag;
- int up;
- int down;
- int bd;//当前列白点数
- //计算1个字符的宽度,也就是1块车牌的宽度,把所有字挨紧,空白区域占30%左右
- //然后一块车牌有7个字,所以一个字的宽度大根是width*0.7/7
- num=flag=0;
- up=img->height;//最高一个白点
- down=0;//最低一个白点
- for(i=0;i<img->width;i++)//按宽遍历
- {
- bd=0;
- for(j=0;j<img->height;j++)//按高遍历,也就是1列1列的遍历
- {
- if(temp[j*img->width+i]==255)//记录每列白点数
- {
- bd++;
- if(up>j)up=j;//最高白点
- if(down<j)down=j;//记住最后一个白点的位置
- }
- }
- if(bd)//当前列有白点
- {
- if(flag==0)//还没有记录起点
- {
- flag=1;
- img->left[num]=i;//记录下起点
- }
- }
- else//当前列没白点
- {
- if(flag)//如果已记录了起点
- {
- if((down-up)+1>img->height/2)//找到正确的字符
- {
- img->right[num]=i-1;//记录结束区域
- img->top[num]=up;
- img->bottom[num]=down;
- num++;//查找下一个字符
- }
- flag=0;//记录下一个记点
- up=img->height;
- down=0;
- }
- }
- }
- //如果最后一个没有结束
- if(flag){
- img->right[num]=img->width-1;
- img->top[num]=up;
- img->bottom[num]=down;
- num++;
- }
-
- if(num<7)//位数不够
- {
- printf("car no min error\n");
- }
- else if(num>7)//如果找到多于7个字符,说明里面有一个“川”字
- {
- printf("car no error\n");
- }
- }
- int main(int argc, char **argv)
- {
- struct BMP_img img;//定义结构
- struct Bmp1 img1;
- //把当前文件夹下的1.bmp文件内容,读到img结构中,并上下镜像
- if(read_img("1.bmp", &img)==0)
- {
- printf("error");
- return 0;
- }
-
- img1.width=img.width;
- img1.height=img.height;
- byte *temp=(byte*)malloc(img.width*img.height);
- //24位灰度图转单色灰度图
- for(int i=0;i<img.height;i++)
- {
- for(int j=0;j<img.width;j++)
- {
- temp[i*img.width+j]=img.image[i*img.width*3+j*3];
- }
- }
-
- //水平投影,去掉上下非文字区域
- shuipingtouying(&img1,temp);
-
- //垂直投影,去掉车牌中的点,并计算7个字各在什么位置
- cuizhitouying(&img1,temp);//垂直投影,框住每一个字符
-
- //写入镜像后的数据到2.bmp中
- WriteBmp1("2.bmp",temp,img.width,img.height);
-
- free(img.image);//释放动态分配的内存
- free(temp);
-
- printf("请打开2.bmp进行查看\n");
- system("pause");
- return 0;
- }
复制代码 |
-
-
|