基於標准C語言的數字圖像處理基本框架


考慮到現有的數字圖像處理都是基於Windows平台,都或多或少使用了Win32 API函數,不能移植到Linux或者嵌入式系統中。為了使程序可移植,采用標准C語言建立了數字圖像處理的基本框架,如下圖所示:

uml

程序參考了網上一些博客的內容,並進行了改變,建立了符合自己習慣的數據結構。主要實現了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    *= max; // v
555
556    delta = max - min;
557
558    if( max != 0 )
559      *= delta / max; // s
560    else
561    {
562       // r = g = b = 0 // s = 0, v is undefined
563      *= 0;
564      *= -1;
565      return;
566    }

567    if( R == max )
568        *= ( G - B ) / delta; // between yellow & magenta
569   else if( G == max )
570        *= 2 + ( B - R ) / delta; // between cyan & yellow
571   else
572       *= 4 + ( R - G ) / delta; // between magenta & cyan
573
574    (*H) *= 60// degrees
575    if*< 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        *=*= *= 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        *= V;
610        *= t;
611        *= p;
612       break;
613    case 1:
614       *= q;
615       *= V;
616       *= p;
617       break;
618    case 2:
619       *= p;
620       *= V;
621       *= t;
622       break;
623    case 3:
624       *= p;
625       *= q;
626       *= V;
627       break;
628    case 4:
629       *= t;
630       *= p;
631       *= V;
632       break;
633    default// case 5:
634       *= V;
635       *= p;
636       *= 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_ */


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com