如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)

Abstract
若要做影像處理,第一件事情就是要能將圖片讀進來變成array,才能套用各種演算法,之前我的作法是用.NET的GDI+,方便雖方便,但缺點就是被綁死在.NET平台,如作SW/HW CoDesign的SystemC,不能使用.NET,又如嵌入式系統,只能在Linux上使用gcc,有沒有僅使用C/C++ standard library,就能夠讀入圖形檔的方式呢?

Introduction
以下這個範例,是個純C的程式,在C++也沒有問題,只需最基本的stdio.h和stdlib.h,唯一的缺憾是只能讀取bmp格式,但若要作影像處理或電腦視覺則已經足夠,也可在SystemC和gcc下編譯。

C語言 / BmpReadWriteC.c

 1  /*  
 2  (C) OOMusou 2007  http://oomusou.cnblogs.com
 3 
 4  Filename    : BmpReadWriteC.c
 5  Compiler    : Visual C++ 8.0 / ANSI C
 6  Description : Demo the how to read and write bmp by standard library
 7  Release     : 02/03/2007 1.0
 8  */
 9 
10  #include  < stdio.h >
11  #include  < stdlib.h >
12 
13  int  bmp_read(unsigned  char   * image,  int  xsize,  int  ysize,  const   char   * filename) {
14     char  fname_bmp[ 128 ];
15    FILE  * fp;
16    unsigned  char  header[ 54 ];
17      
18    sprintf(fname_bmp,  " %s.bmp " , filename);
19      
20     if  ( ! (fp  =  fopen(fname_bmp,  " rb " ))) 
21       return   - 1 ;
22        
23    fread(header,  sizeof (unsigned  char ),  54 , fp);
24    fread(image,  sizeof (unsigned  char ), (size_t)( long )xsize  *  ysize  *   3 , fp);
25      
26    fclose(fp);
27     return   0 ;
28  }
29 
30  int  bmp_write(unsigned  char   * image,  int  xsize,  int  ysize,  char   * filename) {
31    unsigned  char  header[ 54 =  {
32       0x42 0x4d 0 0 0 0 0 0 0 0 ,
33       54 0 0 0 40 0 0 0 0 0 0 0 0 0 0 0 1 0 24 0
34       0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
35       0 0 0 0
36    };
37     long  file_size  =  ( long )xsize  *  ( long )ysize  *   3   +   54 ;
38     long  width, height;
39     char  fname_bmp[ 128 ];
40    FILE  * fp;
41      
42    header[ 2 =  (unsigned  char )(file_size  & 0x000000ff );
43    header[ 3 =  (file_size  >>   8 &   0x000000ff ;
44    header[ 4 =  (file_size  >>   16 &   0x000000ff ;
45    header[ 5 =  (file_size  >>   24 &   0x000000ff ;
46      
47    width  =  xsize;
48    header[ 18 =  width  &   0x000000ff ;
49    header[ 19 =  (width  >>   8 & 0x000000ff ;
50    header[ 20 =  (width  >>   16 & 0x000000ff ;
51    header[ 21 =  (width  >>   24 & 0x000000ff ;
52      
53    height  =  ysize;
54    header[ 22 =  height  & 0x000000ff ;
55    header[ 23 =  (height  >>   8 & 0x000000ff ;
56    header[ 24 =  (height  >>   16 & 0x000000ff ;
57    header[ 25 =  (height  >>   24 & 0x000000ff ;
58 
59    sprintf(fname_bmp,  " %s.bmp " , filename);
60      
61     if  ( ! (fp  =  fopen(fname_bmp,  " wb " ))) 
62       return   - 1 ;
63        
64    fwrite(header,  sizeof (unsigned  char ),  54 , fp);
65    fwrite(image,  sizeof (unsigned  char ), (size_t)( long )xsize  *  ysize  *   3 , fp);
66      
67    fclose(fp);
68     return   0 ;
69  }
70 
71  int  main() {
72    unsigned  char   * image;
73     int  xsize  =   512 ;
74     int  ysize  =   512 ;
75 
76    image  =  (unsigned  char   * )malloc((size_t)xsize  *  ysize  *   3 );
77     if  (image  ==  NULL) 
78       return   - 1 ;
79        
80    bmp_read(image, xsize, ysize,  " clena " );
81    bmp_write(image, xsize, ysize,  " clena_clone_C " );
82      
83    free(image);
84  }


純C的程式好處是compiler門檻低,但現在C++的compiler已經很普遍,而且以上的寫法,缺點就是不能用image[y][x].R這種subscripting的寫法,所以我試著用vector以及C++新的fstream讀取bmp檔。
C++ / BmpReadWriteCPP.cpp

  1 /* 
  2(C) OOMusou 2007 http://oomusou.cnblogs.com
  3
  4Filename    : BmpReadWriteCPP.cpp
  5Compiler    : Visual C++ 8.0 / gcc 3.4.2 / BCB 6.0 / ISO C++
  6Description : Demo the how to read and write bmp by C++
  7Release     : 02/28/2007 1.0
  8*/

  9 #include  < iostream >
 10 #include  < fstream >
 11 #include  < vector >
 12
 13 using   namespace  std;
 14
 15 struct  Color  {
 16  int R;
 17  int G;
 18  int B;
 19}
;
 20
 21 bool  bmpRead(vector < vector < Color >   >   & imageVec,  const   char *  fileName)  {
 22  ifstream file(fileName,ios::in | ios::binary);
 23  if (!file)
 24    return false;
 25    
 26  // skip header
 27  const ifstream::off_type headerSize = 54;
 28  file.seekg(headerSize, ios::beg);
 29  // read body
 30  for(size_t y = 0; y != imageVec.size(); ++y) {
 31    for(size_t x = 0; x != imageVec[0].size(); ++x) {
 32      char chR,chG,chB;
 33      file.get(chB).get(chG).get(chR);
 34      
 35      imageVec[y][x].B = chB;
 36      imageVec[y][x].G = chG;
 37      imageVec[y][x].R = chR;
 38    }

 39  }

 40  
 41  file.close();
 42  
 43  return true;
 44}

 45
 46 bool  bmpWrite(vector < vector < Color >   >   & imageVec,  const   char *  fileName)  {
 47  const int headerSize = 54;
 48  
 49  char header[headerSize] = {
 50      0x420x4d00000000,
 51        54000400000000000010240
 52        00000000000000000000
 53        0000
 54    }
;
 55    
 56  int ysize = imageVec.size();
 57  int xsize = imageVec[0].size();
 58    
 59  long file_size = (long)ysize * xsize * 3 + 54;
 60  header[2= (unsigned char)(file_size &0x000000ff);
 61  header[3= (file_size >> 8& 0x000000ff;
 62  header[4= (file_size >> 16& 0x000000ff;
 63  header[5= (file_size >> 24& 0x000000ff;
 64    
 65  long width = xsize;
 66  header[18= width & 0x000000ff;
 67  header[19= (width >> 8&0x000000ff;
 68  header[20= (width >> 16&0x000000ff;
 69  header[21= (width >> 24&0x000000ff;
 70    
 71  long height = ysize;
 72  header[22= height &0x000000ff;
 73  header[23= (height >> 8&0x000000ff;
 74  header[24= (height >> 16&0x000000ff;
 75  header[25= (height >> 24&0x000000ff;
 76    
 77  ofstream file(fileName,ios::out | ios::binary);
 78  if (!file)
 79    return false;
 80  
 81  // write header  
 82  file.write(header, headerSize);
 83  // write body
 84  for(size_t y = 0; y != imageVec.size(); ++y) {
 85    for(size_t x = 0; x != imageVec[0].size(); ++x) {
 86      char chB = imageVec[y][x].B;
 87      char chG = imageVec[y][x].G;
 88      char chR = imageVec[y][x].R;
 89      
 90      file.put(chB).put(chG).put(chR);
 91    }

 92  }

 93  
 94  file.close();
 95  
 96  return true;
 97}

 98
 99 int  main()  {
100  const size_t sizey = 512;
101  const size_t sizex = 512;
102  
103  vector<vector<Color> > imageVec(sizey, vector<Color>(sizex));
104  if (!bmpRead(imageVec, "clena.bmp")) {
105    cout << "Read image error!!" << endl;
106    return -1;
107  }

108    
109  if (!bmpWrite(imageVec, "clena_clone_cpp.bmp")) {
110    cout << "Write image error!!" << endl;
111    return -1;
112  }

113}


87行

char  chB  =  imageVec[y][x].B;


使用了subscripting的寫法,將來做影像處理是不是更好寫呢?

22行

bool  bmpRead(vector < vector < Color >   >   & imageVec,  const   char *  fileName)


也只要傳vector reference就好了,不用再傳sizey,sizex。

原圖
 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)

Remark
若要詳細研究BMP格式,在Charles Petzold的Programming Windows[2] Ch.15有詳細完整的介紹。

Conclusion
C++的寫法還是比C人性化很多,而且可以使用subscripting方式做影像處理,若您的compiler許可,建議用C++的寫法。

See Also
(原創) 如何使用ANSI C讀寫24位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何使用ANSI C讀寫32位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何使用ANSI C讀寫24/32位元的BMP圖檔? (C/C++) (C) (Image Processing)
(原創) 如何使用C++/CLI读/写jpg檔? (C++/CLI)
(原創) 如何用程序的方式载入jpg图形文件? (C#/ASP.NET)
(原創) 由一維陣列模擬二維陣列(多維陣列) (C/C++) (C)
(原創) 如何動態建立二維陣列(多維陣列)? (C/C++) (C)

Reference
Charles Petzold 1998, Programming Windows, Microsoft Press
吳上立 / 林宏墩 編著,C語言數位影像處理, 全華

你可能感兴趣的:(process)