(原創) 如何使用Standard Library作影像處理? (C/C++) (Image Processing)
在昨天的Blog,我們使用了Standard Library讀寫bmp圖檔,其中的unsigned char *,雖然是一個一維陣列,但骨子是一個二維陣列,該如何實際的做影像處理呢?
先示範一個最簡單的影像處理,產生一個紅色的圖形。
1
/*
2
(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4
Filename : BmpPixelByPixel.cpp
5
Compiler : Visual C++ 8.0 / ANSI C / ISO C++
6
Description : Demo the how to process image pixel by pixel
7
Release : 02/19/2007 1.0
8
*/
9
10
#include "stdio.h"
11
#include "stdlib.h"
12
13
int bmp_read(unsigned char *image, int, int, char *);
14
int bmp_write(unsigned char *image, int, int, char *);
15
16
int main() {
17
unsigned char *image;
18
int xsize = 512;
19
int ysize = 512;
20
21
image = (unsigned char *)malloc((size_t)xsize * ysize * 3);
22
if (image == NULL)
23
return -1;
24
25
for(int y = 0; y != ysize; ++y) {
26
for(int x = 0; x != xsize; ++x) {
27
// set (R,G,B) = (255,0,0)
28
// R
29
*(image + 3 * (y * xsize + x) + 2) = 255;
30
// G
31
*(image + 3 * (y * xsize + x) + 1) = 0;
32
// B
33
*(image + 3 * (y * xsize + x) + 0) = 0;
34
}
35
}
36
37
bmp_write(image, xsize, ysize, "onlyRed");
38
39
free(image);
40
}
41
42
int bmp_read(unsigned char *image, int xsize, int ysize, char *filename) {
43
char fname_bmp[128];
44
sprintf(fname_bmp, "%s.bmp", filename);
45
46
FILE *fp;
47
if (!(fp = fopen(fname_bmp, "rb")))
48
return -1;
49
50
unsigned char header[54];
51
fread(header, sizeof(unsigned char), 54, fp);
52
fread(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);
53
54
fclose(fp);
55
return 0;
56
}
57
58
int bmp_write(unsigned char *image, int xsize, int ysize, char *filename) {
59
unsigned char header[54] = {
60
0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0,
61
54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0,
62
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63
0, 0, 0, 0
64
};
65
66
long file_size = (long)xsize * (long)ysize * 3 + 54;
67
header[2] = (unsigned char)(file_size &0x000000ff);
68
header[3] = (file_size >> 8) & 0x000000ff;
69
header[4] = (file_size >> 16) & 0x000000ff;
70
header[5] = (file_size >> 24) & 0x000000ff;
71
72
long width = xsize;
73
header[18] = width & 0x000000ff;
74
header[19] = (width >> 8) &0x000000ff;
75
header[20] = (width >> 16) &0x000000ff;
76
header[21] = (width >> 24) &0x000000ff;
77
78
long height = ysize;
79
header[22] = height &0x000000ff;
80
header[23] = (height >> 8) &0x000000ff;
81
header[24] = (height >> 16) &0x000000ff;
82
header[25] = (height >> 24) &0x000000ff;
83
84
char fname_bmp[128];
85
sprintf(fname_bmp, "%s.bmp", filename);
86
87
FILE *fp;
88
if (!(fp = fopen(fname_bmp, "wb")))
89
return -1;
90
91
fwrite(header, sizeof(unsigned char), 54, fp);
92
fwrite(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);
93
94
fclose(fp);
95
return 0;
96
}
/* 2
(C) OOMusou 2007 http://oomusou.cnblogs.com3

4
Filename : BmpPixelByPixel.cpp5
Compiler : Visual C++ 8.0 / ANSI C / ISO C++6
Description : Demo the how to process image pixel by pixel7
Release : 02/19/2007 1.08
*/9

10
#include "stdio.h"11
#include "stdlib.h"12

13
int bmp_read(unsigned char *image, int, int, char *);14
int bmp_write(unsigned char *image, int, int, char *);15

16
int main() {17
unsigned char *image;18
int xsize = 512;19
int ysize = 512;20

21
image = (unsigned char *)malloc((size_t)xsize * ysize * 3);22
if (image == NULL) 23
return -1;24
25
for(int y = 0; y != ysize; ++y) {26
for(int x = 0; x != xsize; ++x) {27
// set (R,G,B) = (255,0,0)28
// R29
*(image + 3 * (y * xsize + x) + 2) = 255;30
// G31
*(image + 3 * (y * xsize + x) + 1) = 0;32
// B33
*(image + 3 * (y * xsize + x) + 0) = 0;34
}35
}36
37
bmp_write(image, xsize, ysize, "onlyRed");38
39
free(image);40
}41

42
int bmp_read(unsigned char *image, int xsize, int ysize, char *filename) {43
char fname_bmp[128];44
sprintf(fname_bmp, "%s.bmp", filename);45
46
FILE *fp;47
if (!(fp = fopen(fname_bmp, "rb"))) 48
return -1;49
50
unsigned char header[54];51
fread(header, sizeof(unsigned char), 54, fp);52
fread(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);53
54
fclose(fp);55
return 0;56
}57

58
int bmp_write(unsigned char *image, int xsize, int ysize, char *filename) {59
unsigned char header[54] = {60
0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0,61
54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0, 62
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63
0, 0, 0, 064
};65
66
long file_size = (long)xsize * (long)ysize * 3 + 54;67
header[2] = (unsigned char)(file_size &0x000000ff);68
header[3] = (file_size >> 8) & 0x000000ff;69
header[4] = (file_size >> 16) & 0x000000ff;70
header[5] = (file_size >> 24) & 0x000000ff;71
72
long width = xsize;73
header[18] = width & 0x000000ff;74
header[19] = (width >> 8) &0x000000ff;75
header[20] = (width >> 16) &0x000000ff;76
header[21] = (width >> 24) &0x000000ff;77
78
long height = ysize;79
header[22] = height &0x000000ff;80
header[23] = (height >> 8) &0x000000ff;81
header[24] = (height >> 16) &0x000000ff;82
header[25] = (height >> 24) &0x000000ff;83

84
char fname_bmp[128];85
sprintf(fname_bmp, "%s.bmp", filename);86
87
FILE *fp;88
if (!(fp = fopen(fname_bmp, "wb"))) 89
return -1;90
91
fwrite(header, sizeof(unsigned char), 54, fp);92
fwrite(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);93
94
fclose(fp);95
return 0;96
}
本範例試著用此一維陣列作一個最簡單的影像處理,將圖片由右向左作mirror。
1
/*
2
(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4
Filename : BmpRightSideLeft.cpp
5
Compiler : Visual C++ 8.0 / ANSI C / ISO C++
6
Description : Demo the how to right side to left by standard library
7
Release : 02/04/2007 1.0
8
*/
9
10
#include "stdio.h"
11
#include "stdlib.h"
12
13
int bmp_read(unsigned char *, int , int , char *);
14
int bmp_write(unsigned char *, int , int , char *);
15
int bmp_rightsideleft(unsigned char *, unsigned char *, int , int);
16
17
int main() {
18
unsigned char *ori, *tar;
19
int xsize = 512;
20
int ysize = 512;
21
22
ori = (unsigned char *)malloc((size_t)xsize * ysize * 3);
23
tar = (unsigned char *)malloc((size_t)xsize * ysize * 3);
24
25
bmp_read(ori, xsize, ysize, "clena");
26
bmp_rightsideleft(ori, tar, xsize, ysize);
27
bmp_write(tar, xsize, ysize, "clena_rightsideleft");
28
}
29
30
31
int bmp_read(unsigned char *image, int xsize, int ysize, char *filename) {
32
char fname_bmp[128];
33
sprintf(fname_bmp, "%s.bmp", filename);
34
35
FILE *fp;
36
if (!(fp = fopen(fname_bmp, "rb")))
37
return -1;
38
39
unsigned char header[54];
40
fread(header, sizeof(unsigned char), 54, fp);
41
fread(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);
42
43
fclose(fp);
44
return 0;
45
}
46
47
int bmp_write(unsigned char *image, int xsize, int ysize, char *filename) {
48
unsigned char header[54] = {
49
0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0,
50
54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0,
51
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52
0, 0, 0, 0
53
};
54
55
long file_size = (long)xsize * (long)ysize * 3 + 54;
56
header[2] = (unsigned char)(file_size &0x000000ff);
57
header[3] = (file_size >> 8) & 0x000000ff;
58
header[4] = (file_size >> 16) & 0x000000ff;
59
header[5] = (file_size >> 24) & 0x000000ff;
60
61
long width = xsize;
62
header[18] = width & 0x000000ff;
63
header[19] = (width >> 8) &0x000000ff;
64
header[20] = (width >> 16) &0x000000ff;
65
header[21] = (width >> 24) &0x000000ff;
66
67
long height = ysize;
68
header[22] = height &0x000000ff;
69
header[23] = (height >> 8) &0x000000ff;
70
header[24] = (height >> 16) &0x000000ff;
71
header[25] = (height >> 24) &0x000000ff;
72
73
char fname_bmp[128];
74
sprintf(fname_bmp, "%s.bmp", filename);
75
76
FILE *fp;
77
if (!(fp = fopen(fname_bmp, "wb")))
78
return -1;
79
80
fwrite(header, sizeof(unsigned char), 54, fp);
81
fwrite(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);
82
83
fclose(fp);
84
return 0;
85
}
86
87
int bmp_rightsideleft(unsigned char *ori, unsigned char *tar, int xsize, int ysize) {
88
// x-------
89
// y
90
// |
91
// |
92
// |
93
94
int avgX = (0 + xsize) / 2;
95
for(int y = 0; y != ysize; ++y) {
96
for(int x = 0; x != xsize; ++x) {
97
int tarX = 2 * avgX - x;
98
// R
99
*(tar + 3 * (y * xsize + tarX) + 2) = *(ori + 3 * (y * xsize + x) + 2);
100
// G
101
*(tar + 3 * (y * xsize + tarX) + 1) = *(ori + 3 * (y * xsize + x) + 1);
102
// B
103
*(tar + 3 * (y * xsize + tarX) + 0) = *(ori + 3 * (y * xsize + x) + 0);
104
}
105
}
106
107
return 0;
108
}
/* 2
(C) OOMusou 2007 http://oomusou.cnblogs.com3

4
Filename : BmpRightSideLeft.cpp5
Compiler : Visual C++ 8.0 / ANSI C / ISO C++6
Description : Demo the how to right side to left by standard library7
Release : 02/04/2007 1.08
*/9

10
#include "stdio.h"11
#include "stdlib.h"12

13
int bmp_read(unsigned char *, int , int , char *);14
int bmp_write(unsigned char *, int , int , char *);15
int bmp_rightsideleft(unsigned char *, unsigned char *, int , int);16

17
int main() {18
unsigned char *ori, *tar;19
int xsize = 512;20
int ysize = 512;21

22
ori = (unsigned char *)malloc((size_t)xsize * ysize * 3);23
tar = (unsigned char *)malloc((size_t)xsize * ysize * 3);24
25
bmp_read(ori, xsize, ysize, "clena");26
bmp_rightsideleft(ori, tar, xsize, ysize);27
bmp_write(tar, xsize, ysize, "clena_rightsideleft");28
}29

30

31
int bmp_read(unsigned char *image, int xsize, int ysize, char *filename) {32
char fname_bmp[128];33
sprintf(fname_bmp, "%s.bmp", filename);34
35
FILE *fp;36
if (!(fp = fopen(fname_bmp, "rb"))) 37
return -1;38
39
unsigned char header[54];40
fread(header, sizeof(unsigned char), 54, fp);41
fread(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);42
43
fclose(fp);44
return 0;45
}46

47
int bmp_write(unsigned char *image, int xsize, int ysize, char *filename) {48
unsigned char header[54] = {49
0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0,50
54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0, 51
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52
0, 0, 0, 053
};54
55
long file_size = (long)xsize * (long)ysize * 3 + 54;56
header[2] = (unsigned char)(file_size &0x000000ff);57
header[3] = (file_size >> 8) & 0x000000ff;58
header[4] = (file_size >> 16) & 0x000000ff;59
header[5] = (file_size >> 24) & 0x000000ff;60
61
long width = xsize;62
header[18] = width & 0x000000ff;63
header[19] = (width >> 8) &0x000000ff;64
header[20] = (width >> 16) &0x000000ff;65
header[21] = (width >> 24) &0x000000ff;66
67
long height = ysize;68
header[22] = height &0x000000ff;69
header[23] = (height >> 8) &0x000000ff;70
header[24] = (height >> 16) &0x000000ff;71
header[25] = (height >> 24) &0x000000ff;72

73
char fname_bmp[128];74
sprintf(fname_bmp, "%s.bmp", filename);75
76
FILE *fp;77
if (!(fp = fopen(fname_bmp, "wb"))) 78
return -1;79
80
fwrite(header, sizeof(unsigned char), 54, fp);81
fwrite(image, sizeof(unsigned char), (size_t)(long)xsize * ysize * 3, fp);82
83
fclose(fp);84
return 0;85
}86

87
int bmp_rightsideleft(unsigned char *ori, unsigned char *tar, int xsize, int ysize) {88
// x-------89
// y90
// |91
// |92
// |93
94
int avgX = (0 + xsize) / 2;95
for(int y = 0; y != ysize; ++y) {96
for(int x = 0; x != xsize; ++x) {97
int tarX = 2 * avgX - x;98
// R99
*(tar + 3 * (y * xsize + tarX) + 2) = *(ori + 3 * (y * xsize + x) + 2);100
// G101
*(tar + 3 * (y * xsize + tarX) + 1) = *(ori + 3 * (y * xsize + x) + 1);102
// B103
*(tar + 3 * (y * xsize + tarX) + 0) = *(ori + 3 * (y * xsize + x) + 0);104
}105
}106
107
return 0;108
}125行到135行為實際的一個pixel一個pixel作影像處理。
原圖

執行結果

Remark
在撰寫處理陣列的迴圈時,應該先從z,再y,最後才是x,為什麼呢?因為當宣告陣列時,是int ia[sizey][sizex],所以是先y,然後才x。
See Also
(原創) 如何使用ANSI C/ISO C++讀寫bmp圖檔? (C/C++)


浙公网安备 33010602011771号