(原創) 如何使用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
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
/* 2
(C) OOMusou 2007 http://oomusou.cnblogs.com3

4
Filename : BmpReadWriteCPP.cpp5
Compiler : Visual C++ 8.0 / gcc 3.4.2 / BCB 6.0 / ISO C++6
Description : Demo the how to read and write bmp by C++7
Release : 02/28/2007 1.08
*/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 header27
const ifstream::off_type headerSize = 54;28
file.seekg(headerSize, ios::beg);29
// read body30
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
0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0,51
54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0, 52
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53
0, 0, 0, 054
};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 body84
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。
原圖
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語言數位影像處理, 全華



浙公网安备 33010602011771号