考虑到现有的数字图像处理都是基于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;100101 bmp->widthStep=(int)((width*bitCount+31)/32)*4; //计算排列的宽度102 bmp->imageSize=bmp->height*bmp->widthStep*sizeof(BYTE);//计算排列的图像大小103104 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 else143 { 144 printf("Error(CreateBitmap): only supported 8 or 24 bits bitmap.\n");145 return -1;146 }147148 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,错误返回-1174 *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 end184 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 }189190 //check whether the file can be read or not191 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);198199 return 0;200} 201 202 /**203 * 从文件中读取位图函数204 * 正确返回0,错误返回-1205 *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;214215 //检查路径是否可读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 }222223 //打开文件224 fd=fopen(path,"rb");225 if(fd==0)226 { 227 printf("Error(ReadBitmap): can not open the image.\n");228 return -1;229 }230231 //读取文件信息头 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);237238 //读取位图信息头 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);250251 //创建位图结构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 }258259 //读取图像数据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 file266 { 267 }268 if(ferror(fd)) //if error happened while read the pixel data269 { 270 printf("Error(ReadBitmap): can not read the pixel data.\n");271 fclose(fd);272 return -1;273 }274 }275276 //关闭文件277 fclose(fd);278 return 0;279} 280 281 /**282 * 保存位图到文件中去283 * 正确返回0,错误返回-1284 *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;293294 //检查路径是否正确295 int len = strlen(path) / sizeof(char);296 char ext[3];297 //check whether the path include the characters "bmp" at end298 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 }304305 //打开文件306 fd=fopen(path,"wb");307 if(fd==0)308 { 309 printf("Error(SaveBitmap): can not open the image.\n");310 return -1;311 }312313 //保存文件信息头 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);319320 //保存位图信息头 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);332333 //如果为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 }351352353 //保存图像数据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 }360361 //关闭文件362 fclose(fd);363364 return 0;365} 366 367 #endif // BMP_H_INCLUDED 368 369 370 371 372 373 /*374****************************************Copyright (c)**************************************************375** Feisky376** http://www.cnblogs.com/feisky/377**378**------------------------------------- File Info ------------------------------------------------------379** File name: basicprocess.h380** Last modified Date: 2009-9-28381** Last Version: 1.0382** Descriptions: 位图图像基本处理函数 图像格式转换383**384** Created by: Feisky385** Created date: 2009-9-28386** Version: 1.0387** 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;405406 //检查图像格式是否合法407 if(src->bitCount!=24)408 { 409 printf("Error(RGB2Gray): the source image must be in RGB format.\n");410 return -1;411 }412413 //为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 }420421 //计算灰度数据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 }436437 return 0;438} 439 440 /**441 * Gray2RGB442 *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;454455 //检查图像格式是否合法456 if(src->bitCount!=8)457 { 458 printf("Error(Gray2RGB): the source image must be in gray scale.\n");459 return -1;460 }461462 //为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 }469470 //计算灰度数据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 }484485 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;502503 //检查图像格式是否合法504 if(src->bitCount!=8)505 { 506 printf("Error(Gray2BW): the source image must be in gray scale.\n");507 return -1;508 }509510 //为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 }517518 //计算灰度数据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 else529 { 530 n=0;531 }532 *(dst->imageData+dst->widthStep*(dst->height-1-i)+j)=n;533 }534 }535536 return 0;537} 538 539 /**540 * rgb2hsv541 * r,g,b values are from 0 to 1542 * 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; // v555556 delta = max - min;557558 if( max != 0 )559 *S = delta / max; // s560 else561 { 562 // r = g = b = 0 // s = 0, v is undefined563 *S = 0;564 *H = -1;565 return;566 }567 if( R == max )568 *H = ( G - B ) / delta; // between yellow & magenta569 else if( G == max )570 *H = 2 + ( B - R ) / delta; // between cyan & yellow571 else572 *H = 4 + ( R - G ) / delta; // between magenta & cyan573574 (*H) *= 60; // degrees575 if( *H < 0 )576 (*H) += 360;577} 578 579 580 /**581 * hsv2rgb582 * r,g,b values are from 0 to 1583 * 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;592593 if( S == 0 )594 { 595 *R =*G = *B = V;596 return;597 }598599 H /= 60; // sector 0 to 5600 i = floor( H );601 f = H - i; // factorial part of h602 p = V * ( 1 - S );603 q = V * ( 1 - S * f );604 t = V * ( 1 - S * ( 1 - f ) );605606 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_ */