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

QQ登录

只需一步,快速开始

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

车牌识别(三)旋转校正

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

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

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

×
本帖最后由 乘简 于 2018-8-2 13:08 编辑
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <math.h>

  5. #define pi 3.14159265
  6. #define RADIAN(angle) ((angle)*pi/180.0)

  7. typedef unsigned long       DWORD;
  8. typedef int                 BOOL;
  9. typedef unsigned char       BYTE;
  10. typedef unsigned short      WORD;
  11. typedef float               FLOAT;
  12. typedef unsigned char       byte;

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

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

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

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

  41. //从源BMP图中,剪切车牌所在区域的新结构
  42. struct Bmp1{
  43.     DWORD width;
  44.     DWORD height;
  45.     BYTE *image;
  46.     int left[10];//保存车牌中7个字的左右列
  47.     int right[10];
  48.     int top[10];//保存车牌上下位置
  49.     int bottom[10];
  50.     int up;
  51.     int down;
  52.     byte strr[7][1024];
  53.     byte string[7];//反回已找到的车牌下标
  54.     float ang;//倾斜角度
  55. };

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

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

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

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

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

  103. void WriteBmp24(char const *fn,byte *bmp,int width,int height)
  104. {
  105.     FILE *infile;
  106.     int w4;
  107.     struct BMP_img img;
  108.     if((infile=fopen(fn,"wb"))==NULL)
  109.     {
  110.         return;
  111.     }
  112.     //一行有多少个字节
  113.     img.lineBytes=((width*3+3)>>2)<<2;//对齐到4字节边界
  114.     w4=img.lineBytes*height;//图像尺寸
  115.     img.bfType[0]='B';img.bfType[1]='M';
  116.     img.size=w4+54;
  117.     img.reser=0;
  118.     img.header_length=54;
  119.     img.infoheader_length=40;
  120.     img.width=width;
  121.     img.height=height;
  122.     img.biplanes=1;
  123.     img.bmp_type=24;
  124.     img.compres=0;
  125.     img.datasize=w4;
  126.     img.bixpm=0;
  127.     img.biypm=0;
  128.     img.clrused=0;
  129.     img.relclrused=0;

  130.     fwrite(&img.bfType,2,1,infile);//printf("\n打开的图为 %d",img->bfType);//B M
  131.     fwrite(&img.size,sizeof(DWORD),1,infile);     //        printf("\nBMP size             :%l",img->size);
  132.     fwrite(&img.reser,sizeof(DWORD),1,infile);//printf("\n保留位:");
  133.     fwrite(&img.header_length,sizeof(DWORD),1,infile); //printf("\nheader length    :%l",img->header_length);
  134.     fwrite(&img.infoheader_length,sizeof(DWORD),1,infile);
  135.     fwrite(&img.width, sizeof(DWORD), 1, infile);
  136.     fwrite(&img.height, sizeof(DWORD), 1, infile);     //printf( "\nwidth   :%l\n  height  :%l ", img->width, img->height);
  137.     fwrite(&img.biplanes, sizeof(WORD), 1, infile);
  138.     fwrite(&img.bmp_type, sizeof(WORD), 1, infile);  // printf("\nBMP Tpye             :%l ", img->bmp_type);
  139.     fwrite(&img.compres, sizeof(DWORD), 1, infile);    //if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
  140.     fwrite(&img.datasize, sizeof(DWORD), 1, infile);//printf("\nBMP Data Size        :%l ",img->datasize);
  141.     fwrite(&img.bixpm, sizeof(DWORD), 1, infile);
  142.     fwrite(&img.biypm, sizeof(DWORD), 1, infile);
  143.     fwrite(&img.clrused, sizeof(DWORD), 1, infile);    //printf("\n实际使用颜色数=%d ",img->clrused);printf(" ");
  144.     fwrite(&img.relclrused, sizeof(DWORD), 1, infile);
  145.     if(img.height*img.width*3==img.datasize)//已经对齐到了4字节
  146.     {
  147.         fwrite(bmp,img.datasize,1,infile);
  148.     }
  149.     else
  150.     {
  151.         for(int i=0;i<img.height;i++)//总共有多少行,需要一行一行保存,因为后面要补零
  152.         {
  153.             fwrite(&bmp[i*img.width*3],img.lineBytes,1,infile);
  154.         }
  155.     }
  156.     fclose(infile);
  157. }

  158. //把二值图保存为24位黑白图
  159. void WriteBmp1(char const *fn,byte *bmp,int width,int height)
  160. {
  161.     int w4;
  162.     struct BMP_img img;
  163.     //一行有多少个字节
  164.     img.lineBytes=((width*3+3)>>2)<<2;//对齐到4字节边界
  165.     w4=img.lineBytes*height;//图像尺寸
  166.     img.bfType[0]='B';img.bfType[1]='M';
  167.     img.size=w4+54;
  168.     img.reser=0;
  169.     img.header_length=54;
  170.     img.infoheader_length=40;
  171.     img.width=width;
  172.     img.height=height;
  173.     img.biplanes=1;
  174.     img.bmp_type=24;
  175.     img.compres=0;
  176.     img.datasize=w4;
  177.     img.bixpm=0;
  178.     img.biypm=0;
  179.     img.clrused=0;
  180.     img.relclrused=0;
  181.    
  182.     FILE *infile;
  183.     if((infile=fopen(fn,"wb"))==NULL)
  184.     {
  185.         return;
  186.     }
  187.     fwrite(&img.bfType,2,1,infile);//printf("\n打开的图为 %d",img->bfType);//B M
  188.     fwrite(&img.size,sizeof(DWORD),1,infile);     //        printf("\nBMP size             :%l",img->size);
  189.     fwrite(&img.reser,sizeof(DWORD),1,infile);//printf("\n保留位:");
  190.     fwrite(&img.header_length,sizeof(DWORD),1,infile); //printf("\nheader length    :%l",img->header_length);
  191.     fwrite(&img.infoheader_length,sizeof(DWORD),1,infile);
  192.     fwrite(&img.width, sizeof(DWORD), 1, infile);
  193.     fwrite(&img.height, sizeof(DWORD), 1, infile);     //printf( "\nwidth   :%l\n  height  :%l ", img->width, img->height);
  194.     fwrite(&img.biplanes, sizeof(WORD), 1, infile);
  195.     fwrite(&img.bmp_type, sizeof(WORD), 1, infile);  // printf("\nBMP Tpye             :%l ", img->bmp_type);
  196.     fwrite(&img.compres, sizeof(DWORD), 1, infile);    //if(img->compres==0) {printf("\nbmp图片为非压缩!");}printf(" ");
  197.     fwrite(&img.datasize, sizeof(DWORD), 1, infile);//printf("\nBMP Data Size        :%l ",img->datasize);
  198.     fwrite(&img.bixpm, sizeof(DWORD), 1, infile);
  199.     fwrite(&img.biypm, sizeof(DWORD), 1, infile);
  200.     fwrite(&img.clrused, sizeof(DWORD), 1, infile);    //printf("\n实际使用颜色数=%d ",img->clrused);printf(" ");
  201.     fwrite(&img.relclrused, sizeof(DWORD), 1, infile);
  202.    
  203.     byte *wbmp=(byte*)malloc(w4);//后面多加两个字节,用于4字节对齐
  204.     for(int i=0,s,w;i<height;i++)
  205.     {
  206.         s=i*width;
  207.         w=i*img.lineBytes;
  208.         for(int j=0;j<width;j++)
  209.         {
  210.             if(bmp[s+j]){
  211.                 wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=bmp[s+j];
  212.             }
  213.             else wbmp[w+j*3]=wbmp[w+j*3+1]=wbmp[w+j*3+2]=0;               
  214.         }
  215.     }
  216.     fwrite(wbmp,img.datasize,1,infile);
  217.     free(wbmp);
  218.     fclose(infile);
  219. }

  220. //把RGB数据转换成HSV空间图像数据
  221. //输入,图像,HSV倍象素,宽,高
  222. void hsvzation(byte *image,struct HSV *hsv,int width,int height)
  223. {
  224.     int i,j,k;
  225.     DWORD l,lk;
  226.     //float min,max,delta,tmp;//h,s,v,m,n;
  227.     int min,max,delta,tmp;
  228.     byte r,g,b;
  229.     for(i=0;i<height;i++)
  230.     {
  231.         l=i*width;
  232.         for(k=0,j=0;j<width*3;k++,j+=3)
  233.         {
  234.             lk=l+k;
  235.             g=image[l*3+j+1];
  236.             b=image[l*3+j];
  237.             r=image[l*3+j+2];

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

  240.             tmp=max(r,g);//取3者最大值
  241.             max=max(tmp,b);
  242.             hsv[lk].V=max;//V保存三者最大值
  243.             delta=max-min;//保存最大值与最小值的差
  244.             if(delta==0)//如果3值相等
  245.             {
  246.                 hsv[lk].H=0;
  247.                 hsv[lk].S=0;//这句是我加的
  248.                 continue;
  249.             }

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

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

  284. //膨胀,image经过蓝低换算过的黑白图,为了消除锯齿,有利于计算旋转角度
  285. void Dilation(byte *image,int width,int height,int type,int num)
  286. {
  287.     int dwWidth=width;
  288.     int dwHeight=height;

  289.     int i=0;
  290.     int j=0;

  291.     BYTE *temp;
  292.     int l;
  293.     int k=0;

  294.     temp=(BYTE*)malloc(dwHeight*dwWidth*sizeof(BYTE));
  295.     memcpy(temp,image,dwHeight*dwWidth*sizeof(byte));
  296.     memset(temp,0,dwWidth*dwHeight*sizeof(BYTE));

  297.     if(type==0)
  298.     {
  299.         //水平方向
  300.         for(i=0;i<dwHeight;i++)
  301.         {
  302.             for(j=(num-1)/2;j<dwWidth-(num-1)/2;j++)
  303.             {
  304.                 l=dwWidth*i+j;//当前点的位置
  305.                 for(k=-(num-1)/2;k<=(num-1)/2;k++)
  306.                 {
  307.                     if(image[l+k]==255)//当前点的前后5点内(num为5时)有一个白点,则当前点为白色
  308.                     {
  309.                         temp[l]=255;
  310.                         break;
  311.                     }
  312.                 }
  313.             }
  314.         }
  315.     }
  316.     else
  317.     {
  318.         //垂直方向(i=2 ~ height-2)
  319.         for(i=(num-1)/2;i<dwHeight-(num-1)/2;i++)
  320.         {
  321.             for(j=0;j<dwWidth;j++)
  322.             {
  323.                 for(k=-(num-1)/2;k<=(num-1)/2;k++)//-2~2,正好num次(当num为5时)
  324.                 {
  325.                     if(image[dwWidth*(i+k)+j]==255)//上下5点内有白色,则本点为白色
  326.                     {
  327.                         temp[dwWidth*i+j]=255;
  328.                         break;
  329.                     }
  330.                 }
  331.             }
  332.         }
  333.     }
  334.     memcpy(image,temp,sizeof(byte)*width*height);
  335.     free(temp);
  336.     temp=NULL;
  337. }

  338. //type为0时,当前与上一比较,相等则为0,不相等,则为白色
  339. //从第一行有白色开始,保留其白色,第二行清掉,。。。
  340. //最后一行,也清掉,最后一行的下一行,保留期白色
  341. void sob(byte *srcBmp,int width,int height,int type)//sob算子边缘检测;取出边界;
  342. {
  343.     int i,j,l,l1;
  344.     int p1[3];
  345.     byte *tempy;
  346.     byte *tempx;
  347.     tempx=(byte *)malloc(sizeof(byte)*width*height);
  348.     if(tempx==NULL)
  349.         exit(-1);
  350.     tempy=(byte *)malloc(sizeof(byte)*width*height);
  351.     if(tempy==NULL)
  352.         exit(-1);

  353.     for (i = 0; i < width; i++)//第一行与最后一行清零
  354.     {
  355.         tempx[i] = 0;
  356.         tempy[i] = 0;
  357.         tempx[width*(height-1)+i] = 0;
  358.         tempy[width*(height-1)+i] = 0;
  359.     }
  360.     for (i = 0; i < height; i++)//第一列与最后一列清零
  361.     {
  362.         tempx[i*width] = 0;
  363.         tempy[i*width] = 0;
  364.         tempx[i*width+width-1] = 0;
  365.         tempy[i*width+width-1] = 0;
  366.     }

  367.     for(i =1; i<height-1; i++)//少循环两行,最上面的行与最下面的行
  368.     {
  369.         l=i*width;
  370.         l1=(i+1)*width;
  371.         for(j=1;j<width-1;j++)//由于使用3×3的模板,为防止越界,所以不处理最下边和最右边的两列像素
  372.         {
  373.             p1[0] = srcBmp[l+j];//当前点
  374.             p1[1] = srcBmp[l+j+1];//后一点
  375.             p1[2] = srcBmp[l1+j];//下一行当前点

  376.             if(p1[0]==p1[2])tempx[l+j]=0;else tempx[l+j]=255;//与下一点比较,如果不全为白色,则x=255

  377.             if(p1[0]==p1[1])tempy[l+j]=0;else tempy[l+j]=255;//与后一点比较,不全为白色,相等为0
  378.         }
  379.     }

  380.     if(type==0)//保留水平线
  381.        memcpy(srcBmp,tempx,sizeof(byte)*width*height);
  382.     if(type==1)//只保留垂直线
  383.        memcpy(srcBmp,tempy,sizeof(byte)*width*height);
  384.     if(type==2)//合并二者的线,就是轮廓
  385.     {
  386.         for(i=0;i<height;i++)
  387.         {
  388.             for(j=0;j<width;j++)
  389.             {
  390.                 tempx[i*width+j]|=tempy[i*width+j];
  391.             }
  392.         }
  393.         memcpy(srcBmp,tempx,sizeof(byte)*width*height);
  394.     }
  395.     free(tempx);
  396.     free(tempy);
  397.     tempx=NULL;
  398.     tempy=NULL;
  399. }

  400. //检测到最长直线的角度,就是车牌的倾斜角度。
  401. int hough(byte *srcBmp,int width,int height)
  402. {
  403.     int kmax=0;
  404.     int yuzhi=0;
  405.     int i,j,k,p;
  406.     float c;
  407.     int mp= (int) (sqrt(width*width + height*height)+0.5);//计算对角线的长
  408.     int ma=180;//180
  409.     int npp[180][1000];
  410.    
  411.     //清零npp
  412.     for(i=0;i<180;i++)
  413.     for(j=0;j<1000;j++)
  414.     npp[i][j]=0;

  415.     /*ap=90*(p+mp);
  416.     int *npp=(int *)malloc(sizeof(int)*ap);//myMalloc(ap,0);
  417.     memset(npp,0x00,sizeof(int)*ap);*/

  418.     for(i=1;i<height;i++)//跳过第0行循环
  419.     {
  420.         for(j=1;j<width;j++)//跳过第0列循环
  421.         {
  422.             if(srcBmp[i*width+j]==255)//如果当前点为白色
  423.             {
  424.                 for(k=1;k<ma;k++)//1~179度
  425.                 {
  426.                     c=pi*k/180.0;//k度的弧长(弧度,r=1),取值范围为(0,pi)之间
  427.                     p=(int)(i*cos(c)+j*sin(c));//cos(c)=(-1~+1)之间,sin(c)=(0~1)之间
  428.                     p=(int)(p/2+mp/2);
  429.                     npp[k][p]=npp[k][p]+1;
  430.                 }
  431.             }
  432.         }
  433.     }
  434.    
  435.     kmax=0;
  436.     for(i=1;i<ma;i++)//1~179度之间遍历
  437.     {
  438.         for(j=1;j<mp;j++)
  439.         {
  440.             if(npp[i][j]>yuzhi)//大于域值
  441.             {
  442.                 yuzhi=npp[i][j];//找到最大域值
  443.                 kmax=i;//记下度数
  444.             }
  445.         }
  446.     }
  447.     return kmax;
  448. }

  449. void Hough(struct Bmp1 *img)
  450. {
  451.     DWORD i,j;
  452.     float ang;
  453.     struct HSV *hsv=(struct HSV *)malloc(sizeof(struct HSV)*img->width*img->height);
  454.     hsvzation(img->image,hsv,img->width,img->height);//计算HSV
  455.     byte *temp=(byte *)malloc(img->height*img->width);
  456.    
  457.     for(i=0;i<img->height;i++)
  458.     {
  459.        for(j=0;j<img->width;j++)
  460.         {
  461.            if((hsv[i*img->width+j].H<230.0)&&(hsv[i*img->width+j].H>180.0)&&(hsv[i*img->width+j].V<250)&&(hsv[i*img->width+j].S>0.6))
  462.            {
  463.               temp[i*img->width+j]=255;
  464.            }
  465.            else
  466.            {
  467.                temp[i*img->width+j]=0;
  468.            }
  469.        }
  470.     }
  471.    
  472.     WriteBmp1("2.bmp",temp,img->width,img->height);//膨胀前
  473.     //膨胀,垂直方向,尺寸5,消除水平线的锯齿
  474.     Dilation(temp,img->width,img->height,1,5);
  475.     WriteBmp1("3.bmp",temp,img->width,img->height);//膨胀后
  476.    
  477.     //留保最上面的连线与最下面的连线,所以最后一个参数为0即可,节省时间
  478.     sob(temp,img->width,img->height,0);
  479.     WriteBmp1("4.bmp",temp,img->width,img->height);//连缘检测后的图像
  480.    
  481.     //计算出角度
  482.     ang=hough(temp,img->width,img->height);
  483.    
  484.     if(ang==1 || ang==179)ang=0;//如果只有1度的角度,可以不用旋转
  485.     if(ang>90)//让其值保持在+-90之间
  486.     {
  487.         ang=ang-180;
  488.     }
  489.     img->ang=ang;
  490.    
  491.     free(hsv);
  492.     free(temp);
  493. }

  494. //旋转图片
  495. byte *RotateRGB(byte *image, float iRotateAngle,int width,int height,int *lwidth,int *lheight)
  496. {
  497.     byte *temp;
  498.     // 循环变量
  499.     int i,j,m,n;
  500.     // 旋转后图像的宽度和高度
  501.     int lNewWidth,lNewHeight;
  502.     // 象素在源DIB中的坐标
  503.     int i0,j0;
  504.     // 旋转角度(弧度)
  505.     float    fRotateAngle;
  506.     // 旋转角度的正弦和余弦
  507.     float    fSina, fCosa;
  508.     // 源图四个角的坐标(以图像中心为坐标系原点)
  509.     float    fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
  510.     // 旋转后四个角的坐标(以图像中心为坐标系原点)
  511.     float    fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
  512.     // 两个中间常量
  513.     float    f1,f2;

  514.     // 将旋转角度从度转换到弧度
  515.     fRotateAngle = (float) RADIAN(iRotateAngle);
  516.     // 计算旋转角度的正弦
  517.     fSina = (float) sin((double)fRotateAngle);
  518.     // 计算旋转角度的余弦
  519.     fCosa = (float) cos((double)fRotateAngle);
  520.     // 计算原图的四个角的坐标(以图像中心为坐标系原点)
  521.     fSrcX1 = (float) (- (width  - 1) / 2);
  522.     fSrcY1 = (float) (  (height - 1) / 2);
  523.     fSrcX2 = (float) (  (width  - 1) / 2);
  524.     fSrcY2 = (float) (  (height - 1) / 2);
  525.     fSrcX3 = (float) (- (width  - 1) / 2);
  526.     fSrcY3 = (float) (- (height - 1) / 2);
  527.     fSrcX4 = (float) (  (width  - 1) / 2);
  528.     fSrcY4 = (float) (- (height - 1) / 2);

  529.     // 计算新图四个角的坐标(以图像中心为坐标系原点)
  530.     fDstX1 =  fCosa * fSrcX1 + fSina * fSrcY1;
  531.     fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
  532.     fDstX2 =  fCosa * fSrcX2 + fSina * fSrcY2;
  533.     fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
  534.     fDstX3 =  fCosa * fSrcX3 + fSina * fSrcY3;
  535.     fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
  536.     fDstX4 =  fCosa * fSrcX4 + fSina * fSrcY4;
  537.     fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;
  538.     // 计算旋转后的图像实际宽度
  539.     lNewWidth  = (int) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);

  540.     // 计算旋转后的图像高度
  541.     lNewHeight = (int) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) )  + 0.5);

  542.     //分配内存,用于保存新图片
  543.     temp=(byte*)malloc(lNewHeight*lNewWidth*3);
  544.     // 两个常数,这样不用以后每次都计算了
  545.     f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina + 0.5 * (width  - 1));
  546.     f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa + 0.5 * (height - 1));

  547.     for(i = 0; i < lNewHeight; i++)
  548.     {
  549.         // 针对图像每列进行操作
  550.         for(m=0,j = 0;j < lNewWidth;m+=3,j++)
  551.         {

  552.             // 计算该象素在源DIB中的坐标
  553.             i0 = (int) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5);
  554.             j0 = (int) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5);

  555.             // 判断是否在源图范围内
  556.             if( (j0 >= 0) && (j0 < width) && (i0 >= 0) && (i0 < height))
  557.             {
  558.                 n=i0*width*3+j0*3;
  559.                 *(temp + lNewWidth * i*3 + m+1)=*(image + n+1);
  560.                 *(temp + lNewWidth * i*3 + m+2)=*(image + n+2);
  561.                 *(temp + lNewWidth * i*3+ m)=*(image + n);
  562.             }
  563.             else
  564.             {
  565.                 // 对于源图中没有的象素,直接赋值为0
  566.                  *(temp + lNewWidth * i*3+ m+1)=0;
  567.                  *(temp + lNewWidth * i*3+ m+2)=0;
  568.                  *(temp + lNewWidth * i*3+ m)=0;
  569.             }
  570.         }
  571.     }
  572.     *lwidth=lNewWidth;
  573.     *lheight=lNewHeight;
  574.     return temp;
  575. }

  576. //旋转
  577. void xuanzhuan(struct Bmp1 *img)
  578. {
  579.     int lwidth=0,lheight=0;
  580.    
  581.     byte *p;
  582.     p=RotateRGB(img->image,img->ang,img->width,img->height,&lwidth,&lheight);
  583.     img->width=lwidth;
  584.     img->height=lheight;
  585.     free(img->image);//释放原来的内存
  586.     img->image=p;
  587. }

  588. int main(int argc, char **argv)
  589. {
  590.     struct BMP_img img;//定义结构
  591.     struct Bmp1 img1;

  592.     //把当前文件夹下的1.bmp文件内容,读到img结构中,并上下镜像
  593.     if(read_img("1.bmp", &img)==0)
  594.     {
  595.         printf("error");
  596.         return 0;
  597.     }
  598.    
  599.     //复制一份到img1中
  600.     img1.image=(byte*)malloc(img.datasize);
  601.     memcpy(img1.image,img.image,img.datasize);
  602.     img1.width=img.width;
  603.     img1.height=img.height;
  604.    
  605.     Hough(&img1);//计算出角度
  606.     xuanzhuan(&img1);//旋转

  607.     //写入镜像后的数据到2.bmp中
  608.     WriteBmp24("5.bmp",img1.image,img1.width,img1.height);
  609.    
  610.     free(img.image);//释放动态分配的内存
  611.     free(img1.image);
  612.    
  613.     printf("请打开2 3 4 5.bmp进行查看\n");
  614.     system("pause");
  615.     return 0;
  616. }
复制代码


旋转后的图

旋转后的图
4.bmp
3.bmp
2.bmp
1.bmp
回复

使用道具 举报

本版积分规则

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

GMT+8, 2024-11-24 11:19 , Processed in 0.035833 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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