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 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, 0
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。
原圖
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語言數位影像處理, 全華