|
Posted on
2009-10-21 22:25
feisky
阅读( 6887)
评论()
收藏
举报
考虑到现有的数字图像处理都是基于Windows平台,都或多或少使用了Win32 API函数,不能移植到Linux或者嵌入式系统中。为了使程序可移植,采用标准C语言建立了数字图像处理的基本框架,如下图所示:
程序参考了网上一些博客的内容,并进行了改变,建立了符合自己习惯的数据结构。主要实现了bmp格式图像的打开、保存、创建、图像颜色空间转换等功能,暂时还没有添加具体的处理函数。我想,既然有了程序的框架,添加算法只是编写一个个函数的问题。
本程序具体实现的功能如下:
* 打开和保存bmp文件,这里使用自定义数据结构Bitmap,相关函数定义如下: bmp.h: int CreateBitmap(Bitmap* bmp, int width, int height, int bitCount); void ReleaseBitmap(Bitmap* bmp); int CheckPath(char *path); int ReadBitmap(char* path, Bitmap* bmp); int SaveBitmap(char* path, Bitmap* bmp);
* 图像格式转换 basicprocess.h: int RGB2Gray(Bitmap* src, Bitmap* dst); int Gray2RGB(Bitmap* src, Bitmap* dst); int Gray2BW(Bitmap* src, Bitmap* dst, int threshold); void hsv2rgb(float H, float S, float V, float *R, float *G, float *B); void rgb2hsv(float R, float G, float B, float *H, float *S, float* V);
程序源码如下,欢迎大家批评指正。
1 /**//* 2 ****************************************Copyright (c)************************************************** 3 ** Feisky 4 ** http://www.cnblogs.com/feisky/ 5 ** 6 **------------------------------------- File Info ------------------------------------------------------ 7 ** File name: bmp.h 8 ** Last modified Date: 2009-9-25 9 ** Last Version: 1.0 10 ** Descriptions: 位图文件结构及基本函数定义 打开和保存bmp文件 11 ** 12 ** Created by: Feisky 13 ** Created date: 2009-07-25 14 ** Version: 1.0 15 ** Descriptions: Preliminary version. 16 ** 17 **------------------------------------------------------------------------------------------------------ 18 */ 19 #ifndef BMP_H_INCLUDED 20 #define BMP_H_INCLUDED 21 22 #include <ctype.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <malloc.h> 26 #include <string.h> 27 28 /**//** 29 * 位图文件结构及基本函数定义 打开和保存bmp文件 30 */ 31 typedef unsigned short WORD; 32 typedef unsigned long DWORD; 33 typedef long LONG; 34 typedef unsigned char BYTE; 35 36 /**//* 位图文件头结构 14字节 */ 37 typedef struct tagBITMAPFILEHEADER { 38 WORD bfType; 39 DWORD bfSize; 40 WORD bfReserved1; 41 WORD bfReserved2; 42 DWORD bfOffBits; 43 } BITMAPFILEHEADER; 44 45 /**//* 位图信息头结构 40字节 */ 46 typedef struct tagBITMAPINFOHEADER { 47 DWORD biSize; // 结构长度 40B 48 LONG biWidth; 49 LONG biHeight; 50 WORD biPlanes; // 1 51 WORD biBitCount; // 表示颜色要用到的位数 52 DWORD biCompression; // 压缩格式 53 DWORD biSizeImage; // 位图占用字节数=biWidth'(4的整倍数)*biHeight 54 LONG biXPelsPerMeter; // 水平分辨率 55 LONG biYPelsPerMeter; // 垂直分辨率 56 DWORD biClrUsed; // 本图像用到的颜色数 57 DWORD biClrImportant; // 本图像的重要颜色数 58 } BITMAPINFOHEADER; 59 60 /**//* 调色板 4字节 */ 61 typedef struct tagRGBQUAD { 62 BYTE rgbBlue; 63 BYTE rgbGreen; 64 BYTE rgbRed; 65 BYTE rgbReserved; 66 } RGBQUAD; 67 68 /**//* 定义图像信息 */ 69 typedef struct tagBITMAPINFO { 70 BITMAPINFOHEADER bmiHeader; 71 RGBQUAD bmiColors[1]; 72 } BITMAPINFO; 73 74 /**//* 定义位图图像 */ 75 typedef struct _Bitmap 76  { 77 BITMAPFILEHEADER bmfh; 78 BITMAPINFOHEADER bmih; 79 int width; 80 int height; 81 int bitCount; // 8 或者24 82 int imageSize; // 图像数据大小(imageSize=height*widthStep)字节 83 BYTE* imageData;//排列的图像数据 84 int widthStep; //排列的图像行大小 85 }Bitmap; 86 87 /**//** 88 * 位图创建函数 创建一个Bitmap结构,并为图像数据分配空间 89 * 90 * 使用方法: 91 * Bitmap *bmp=(Bitmap*)malloc(sizeof(Bitmap)); 92 * ret=CreateBitmap(bmp,50,50,3); 93 */ 94 int CreateBitmap(Bitmap* bmp, int width, int height, int bitCount) 95  { 96 bmp->width=width; 97 bmp->height=height; 98 bmp->bmih.biWidth=width; 99 bmp->bmih.biHeight=height; 100 101 bmp->widthStep=(int)((width*bitCount+31)/32)*4; //计算排列的宽度 102 bmp->imageSize=bmp->height*bmp->widthStep*sizeof(BYTE);//计算排列的图像大小 103 104 if(bitCount==8) 105 { 106 bmp->bitCount=8; 107 bmp->bmfh.bfType=0x4d42; //注意是4d42 这个地方折磨我一下午啊 108 bmp->bmfh.bfReserved1=0; 109 bmp->bmfh.bfReserved2=0; 110 bmp->bmih.biBitCount=8; 111 bmp->bmih.biSize=40; 112 bmp->bmih.biPlanes=1; 113 bmp->bmfh.bfSize=54+256*4+height*bmp->widthStep; 114 bmp->bmfh.bfOffBits=1078; 115 bmp->bmih.biBitCount=8; 116 bmp->bmih.biCompression=0; 117 bmp->bmih.biSizeImage=bmp->imageSize; 118 bmp->bmih.biClrUsed=0; 119 bmp->bmih.biClrImportant=0; 120 bmp->bmih.biXPelsPerMeter=0; 121 bmp->bmih.biYPelsPerMeter=0; 122 } 123 else if (bitCount==24) 124 { 125 bmp->bitCount=24; 126 bmp->bmfh.bfType=0x4d42; 127 bmp->bmih.biBitCount=24; 128 bmp->bmfh.bfReserved1=0; 129 bmp->bmfh.bfReserved2=0; 130 bmp->bmih.biSize=40; 131 bmp->bmih.biPlanes=1; 132 bmp->bmfh.bfSize=54+height*bmp->widthStep; 133 bmp->bmfh.bfOffBits=54; 134 bmp->bmih.biBitCount=24; 135 bmp->bmih.biSizeImage=bmp->imageSize; 136 bmp->bmih.biClrUsed=0; 137 bmp->bmih.biCompression=0; 138 bmp->bmih.biClrImportant=0; 139 bmp->bmih.biXPelsPerMeter=0; 140 bmp->bmih.biYPelsPerMeter=0; 141 } 142 else 143 { 144 printf("Error(CreateBitmap): only supported 8 or 24 bits bitmap.\n"); 145 return -1; 146 } 147 148 bmp->imageData=(BYTE*)malloc(bmp->imageSize); //分配数据空间 149 if(!(bmp->imageData)) 150 { 151 printf("Error(CreateBitmap): can not allocate bitmap memory.\n"); 152 return -1; 153 } 154 return 0; 155 } 156 157 /**//** 158 * 位图指针释放函数 释放位图数据空间 159 * 160 * 使用方法: 161 * ReleaseBitmap(bmp); 162 */ 163 void ReleaseBitmap(Bitmap* bmp) 164  { 165 free(bmp->imageData); 166 bmp->imageData=NULL; 167 free(bmp); 168 bmp=NULL; 169 } 170 171 /**//** 172 * 路径检查函数:是否为BMP文件,是否可读 173 * 正确返回0,错误返回-1 174 * 175 * 使用方法 176 * ret=CheckPath(path); 177 */ 178 int CheckPath(char *path) 179  { 180 FILE *fd; 181 int len = strlen(path) / sizeof(char); 182 char ext[3]; 183 //check whether the path include the characters "bmp" at end 184 strncpy(ext, &path[len - 3], 3); 185 if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p')) { 186 printf("Error(CheckPath): the extension of the file is not bmp.\n"); 187 return -1; 188 } 189 190 //check whether the file can be read or not 191 fd = fopen(path, "r"); 192 if (!fd) 193 { 194 printf("Error(CheckPath): can not open the file.\n"); 195 return -1; 196 } 197 fclose(fd); 198 199 return 0; 200 } 201 202 /**//** 203 * 从文件中读取位图函数 204 * 正确返回0,错误返回-1 205 * 206 * 使用方法: 207 * bmp=(Bitmap*)malloc(sizeof(Bitmap)); 208 * ret=ReadBitmap(path, bmp); 209 */ 210 int ReadBitmap(char* path, Bitmap* bmp) 211  { 212 int ret; 213 FILE *fd; 214 215 //检查路径是否可读 216 ret=CheckPath(path); 217 if(ret==-1) 218 { 219 printf("Error(ReadBitmap): the path of the image is invalid.\n"); 220 return -1; 221 } 222 223 //打开文件 224 fd=fopen(path,"rb"); 225 if(fd==0) 226 { 227 printf("Error(ReadBitmap): can not open the image.\n"); 228 return -1; 229 } 230 231 //读取文件信息头 14字节 232 fread(&(bmp->bmfh.bfType),sizeof(WORD),1,fd); 233 fread(&(bmp->bmfh.bfSize),sizeof(DWORD),1,fd); 234 fread(&(bmp->bmfh.bfReserved1),sizeof(WORD),1,fd); 235 fread(&(bmp->bmfh.bfReserved2),sizeof(WORD),1,fd); 236 fread(&(bmp->bmfh.bfOffBits),sizeof(DWORD),1,fd); 237 238 //读取位图信息头 40字节 239 fread(&(bmp->bmih.biSize),sizeof(DWORD),1,fd); 240 fread(&(bmp->bmih.biWidth),sizeof(DWORD),1,fd); 241 fread(&(bmp->bmih.biHeight),sizeof(DWORD),1,fd); 242 fread(&(bmp->bmih.biPlanes),sizeof(WORD),1,fd); 243 fread(&(bmp->bmih.biBitCount),sizeof(WORD),1,fd); 244 fread(&(bmp->bmih.biCompression),sizeof(DWORD),1,fd); 245 fread(&(bmp->bmih.biSizeImage),sizeof(DWORD),1,fd); 246 fread(&(bmp->bmih.biXPelsPerMeter),sizeof(DWORD),1,fd); 247 fread(&(bmp->bmih.biYPelsPerMeter),sizeof(DWORD),1,fd); 248 fread(&(bmp->bmih.biClrUsed),sizeof(DWORD),1,fd); 249 fread(&(bmp->bmih.biClrImportant),sizeof(DWORD),1,fd); 250 251 //创建位图结构 252 ret=CreateBitmap(bmp, bmp->bmih.biWidth, bmp->bmih.biHeight, bmp->bmih.biBitCount); 253 if(ret==-1) 254 { 255 printf("Error(CreateBitmap): can not CreateBitmap.\n"); 256 return -1; 257 } 258 259 //读取图像数据 260 //由于4字节对齐格式 261 fseek(fd,bmp->bmfh.bfOffBits,SEEK_SET); //定位到图像数据区 262 ret=fread(bmp->imageData,bmp->imageSize,1,fd); 263 if(ret==0) 264 { 265 if(feof(fd)) //if the file pointer point to the end of the file 266 { 267 } 268 if(ferror(fd)) //if error happened while read the pixel data 269 { 270 printf("Error(ReadBitmap): can not read the pixel data.\n"); 271 fclose(fd); 272 return -1; 273 } 274 } 275 276 //关闭文件 277 fclose(fd); 278 return 0; 279 } 280 281 /**//** 282 * 保存位图到文件中去 283 * 正确返回0,错误返回-1 284 * 285 * 使用方法: 286 * bmp=(Bitmap*)malloc(sizeof(Bitmap)); 287 * ret=SaveBitmap(path, bmp); 288 */ 289 int SaveBitmap(char* path, Bitmap* bmp) 290  { 291 int ret; 292 FILE *fd; 293 294 //检查路径是否正确 295 int len = strlen(path) / sizeof(char); 296 char ext[3]; 297 //check whether the path include the characters "bmp" at end 298 strncpy(ext, &path[len - 3], 3); 299 if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p')) 300 { 301 printf("Error(SaveBitmap): the extension of the file is not bmp.\n"); 302 return -1; 303 } 304 305 //打开文件 306 fd=fopen(path,"wb"); 307 if(fd==0) 308 { 309 printf("Error(SaveBitmap): can not open the image.\n"); 310 return -1; 311 } 312 313 //保存文件信息头 14字节 314 fwrite(&(bmp->bmfh.bfType),sizeof(WORD),1,fd); 315 fwrite(&(bmp->bmfh.bfSize),sizeof(DWORD),1,fd); 316 fwrite(&(bmp->bmfh.bfReserved1),sizeof(WORD),1,fd); 317 fwrite(&(bmp->bmfh.bfReserved2),sizeof(WORD),1,fd); 318 fwrite(&(bmp->bmfh.bfOffBits),sizeof(DWORD),1,fd); 319 320 //保存位图信息头 40字节 321 fwrite(&(bmp->bmih.biSize),sizeof(DWORD),1,fd); 322 fwrite(&(bmp->bmih.biWidth),sizeof(DWORD),1,fd); 323 fwrite(&(bmp->bmih.biHeight),sizeof(DWORD),1,fd); 324 fwrite(&(bmp->bmih.biPlanes),sizeof(WORD),1,fd); 325 fwrite(&(bmp->bmih.biBitCount),sizeof(WORD),1,fd); 326 fwrite(&(bmp->bmih.biCompression),sizeof(DWORD),1,fd); 327 fwrite(&(bmp->bmih.biSizeImage),sizeof(DWORD),1,fd); 328 fwrite(&(bmp->bmih.biXPelsPerMeter),sizeof(DWORD),1,fd); 329 fwrite(&(bmp->bmih.biYPelsPerMeter),sizeof(DWORD),1,fd); 330 fwrite(&(bmp->bmih.biClrUsed),sizeof(DWORD),1,fd); 331 fwrite(&(bmp->bmih.biClrImportant),sizeof(DWORD),1,fd); 332 333 //如果为8位,则 保存调色板 334 RGBQUAD pal[256]; 335 int i; 336 if(bmp->bitCount==8) 337 { 338 for(i=0;i<256;i++) 339 { 340 pal[i].rgbBlue=i; 341 pal[i].rgbGreen=i; 342 pal[i].rgbRed=i; 343 pal[i].rgbReserved=0; 344 } 345 if(fwrite(pal,sizeof(RGBQUAD)*256,1,fd)!=1) 346 { 347 printf("Error(SaveBitmap): can not write Color Palette.\n"); 348 return -1; 349 } 350 } 351 352 353 //保存图像数据 354 ret=fwrite(bmp->imageData,bmp->imageSize,1,fd); 355 if(ret!=1) 356 { 357 printf("Error(SaveBitmap): can not save the pixel data.\n"); 358 return -1; 359 } 360 361 //关闭文件 362 fclose(fd); 363 364 return 0; 365 } 366 367 #endif // BMP_H_INCLUDED 368 369 370 371 372 373 /**//* 374 ****************************************Copyright (c)************************************************** 375 ** Feisky 376 ** http://www.cnblogs.com/feisky/ 377 ** 378 **------------------------------------- File Info ------------------------------------------------------ 379 ** File name: basicprocess.h 380 ** Last modified Date: 2009-9-28 381 ** Last Version: 1.0 382 ** Descriptions: 位图图像基本处理函数 图像格式转换 383 ** 384 ** Created by: Feisky 385 ** Created date: 2009-9-28 386 ** Version: 1.0 387 ** Descriptions: Preliminary version. 388 ** 389 **------------------------------------------------------------------------------------------------------ 390 */ 391 392 #ifndef BASICPROCESS_H_ 393 #define BASICPROCESS_H_ 394 395 #include "bmp.h" 396 #include <math.h> 397 /**//** 398 * <font color="#3f7f5f">位图图像基本处理函数 图像格式转换</font> 399 */ 400 int RGB2Gray(Bitmap* src, Bitmap* dst) 401  { 402 int ret; 403 int n=0,i,j; 404 BYTE r,g,b,gray; 405 406 //检查图像格式是否合法 407 if(src->bitCount!=24) 408 { 409 printf("Error(RGB2Gray): the source image must be in RGB format.\n"); 410 return -1; 411 } 412 413 //为dst图像分配数据空间 414 ret=CreateBitmap(dst,src->width,src->height,8); 415 if(ret==-1) 416 { 417 printf("Error(RGB2Gray): can't create target image.\n"); 418 return -1; 419 } 420 421 //计算灰度数据 422 for(i=0;i<src->height;i++) 423 { 424 n=0; 425 for(j=0;j<src->width*3;j++,n++) 426 { 427 b=*(src->imageData+src->widthStep*(src->height-1-i)+j); 428 j++; 429 g=*(src->imageData+src->widthStep*(src->height-1-i)+j); 430 j++; 431 r=*(src->imageData+src->widthStep*(src->height-1-i)+j); 432 gray=(r*19595 + g*38469 + b*7472) >> 16; 433 *(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=gray; 434 } 435 } 436 437 return 0; 438 } 439 440 /**//** 441 * Gray2RGB 442 * 443 * 使用方法: 444 * bmp=(Bitmap*)malloc(sizeof(Bitmap)); 445 * ret=ReadBitmap(path, bmp); 446 * dstbmp=(Bitmap*)malloc(sizeof(Bitmap)); 447 * ret=Gray2RGB(bmp,dstbmp); 448 */ 449 int Gray2RGB(Bitmap* src, Bitmap* dst) 450  { 451 int ret; 452 int n=0,i,j; 453 BYTE r; 454 455 //检查图像格式是否合法 456 if(src->bitCount!=8) 457 { 458 printf("Error(Gray2RGB): the source image must be in gray scale.\n"); 459 return -1; 460 } 461 462 //为dst图像分配数据空间 463 ret=CreateBitmap(dst,src->width,src->height,24); 464 if(ret==-1) 465 { 466 printf("Error(Gray2RGB): can't create target image.\n"); 467 return -1; 468 } 469 470 //计算灰度数据 471 for(i=0;i<src->height;i++) 472 { 473 n=0; 474 for(j=0;j<src->width;j++,n++) 475 { 476 r=*(src->imageData+src->widthStep*(src->height-1-i)+j); 477 *(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=r; 478 n++; 479 *(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=r; 480 n++; 481 *(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=r; 482 } 483 } 484 485 return 0; 486 } 487 488 /**//** 489 * Gray2BW 图像二值化 490 * 491 * 使用方法: 492 * bmp=(Bitmap*)malloc(sizeof(Bitmap)); 493 * ret=ReadBitmap(path, bmp); 494 * dstbmp=(Bitmap*)malloc(sizeof(Bitmap)); 495 * ret=Gray2BW(bmp,dstbmp); 496 */ 497 int Gray2BW(Bitmap* src, Bitmap* dst, int threshold) 498  { 499 int ret; 500 int n=0,i,j; 501 BYTE r; 502 503 //检查图像格式是否合法 504 if(src->bitCount!=8) 505 { 506 printf("Error(Gray2BW): the source image must be in gray scale.\n"); 507 return -1; 508 } 509 510 //为dst图像分配数据空间 511 ret=CreateBitmap(dst,src->width,src->height,8); 512 if(ret==-1) 513 { 514 printf("Error(Gray2BW): can't create target image.\n"); 515 return -1; 516 } 517 518 //计算灰度数据 519 for(i=0;i<src->height;i++) 520 { 521 for(j=0;j<src->width;j++,n++) 522 { 523 r=*(src->imageData+src->widthStep*(src->height-1-i)+j); 524 if(r>=threshold) 525 { 526 n=255; 527 } 528 else 529 { 530 n=0; 531 } 532 *(dst->imageData+dst->widthStep*(dst->height-1-i)+j)=n; 533 } 534 } 535 536 return 0; 537 } 538 539 /**//** 540 * rgb2hsv 541 * r,g,b values are from 0 to 1 542 * h = [0,360], s = [0,1], v = [0,1] 543 * if s == 0, then h = -1 (undefined) 544 * 使用方法: 545 * rgb2hsv(0.2,0.3,0.3,&x,&y,&z); 546 */ 547 void rgb2hsv(float R, float G, float B, float *H, float *S, float* V) 548  { 549 float min, max, delta,tmp; 550 tmp = R<G?R:G; 551 min = tmp<B?tmp:B; 552 tmp = R>G?R:G; 553 max = tmp>B?tmp:B; 554 *V = max; // v 555 556 delta = max - min; 557 558 if( max != 0 ) 559 *S = delta / max; // s 560 else 561 { 562 // r = g = b = 0 // s = 0, v is undefined 563 *S = 0; 564 *H = -1; 565 return; 566 } 567 if( R == max ) 568 *H = ( G - B ) / delta; // between yellow & magenta 569 else if( G == max ) 570 *H = 2 + ( B - R ) / delta; // between cyan & yellow 571 else 572 *H = 4 + ( R - G ) / delta; // between magenta & cyan 573 574 (*H) *= 60; // degrees 575 if( *H < 0 ) 576 (*H) += 360; 577 } 578 579 580 /**//** 581 * hsv2rgb 582 * r,g,b values are from 0 to 1 583 * h = [0,360], s = [0,1], v = [0,1] 584 * if s == 0, then h = -1 (undefined) 585 * 使用方法: 586 * hsv2rgb(60,0.3,0.5,&x,&y,&z); 587 */ 588 void hsv2rgb(float H, float S, float V, float *R, float *G, float *B) 589  { 590 int i; 591 float f, p, q, t; 592 593 if( S == 0 ) 594 { 595 *R =*G = *B = V; 596 return; 597 } 598 599 H /= 60; // sector 0 to 5 600 i = floor( H ); 601 f = H - i; // factorial part of h 602 p = V * ( 1 - S ); 603 q = V * ( 1 - S * f ); 604 t = V * ( 1 - S * ( 1 - f ) ); 605 606 switch( i ) 607 { 608 case 0: 609 *R = V; 610 *G = t; 611 *B = p; 612 break; 613 case 1: 614 *R = q; 615 *G = V; 616 *B = p; 617 break; 618 case 2: 619 *R = p; 620 *G = V; 621 *B = t; 622 break; 623 case 3: 624 *R = p; 625 *G = q; 626 *B = V; 627 break; 628 case 4: 629 *R = t; 630 *G = p; 631 *B = V; 632 break; 633 default: // case 5: 634 *R = V; 635 *G = p; 636 *B = q; 637 break; 638 } 639 } 640 641 /**//** 642 * 直方图均衡化 643 * 返回 0正确 -1错误 644 */ 645 int HistEqualization(Bitmap* dstBmp, Bitmap* srcBmp) 646  { 647 return 0; 648 } 649 650 /**//* 651 * 中值滤波 652 */ 653 654 int MedFilt(Bitmap* dstBmp, Bitmap* srcBmp) 655  { 656 return 0; 657 } 658 659 #endif /* BASICPROCESS_H_ */
|