(原創) 如何實現Face Detection? (C/C++) (C) (Image Processing)
Abstract
本文使用C語言實現face detection。
Introduction
使用環境:Visual Studio 2008 / Visual C++ 9.0
Face Detection的應用相當廣,本文使用人臉偵測與辨識系統[1]這篇論文所提出的演算法加以實現,效果相當不錯。
face_detection.c / C
1 /*
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : face_detection.c
5 Compiler : Visual C++ 9.0 / ANSI C
6 Description : Demo the how to implement face detection by C
7 Release : 09/30/2009 1.0
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 int face_detection(const char *fname_s, const char *fname_t) {
13 FILE *fp_s = NULL; // source file handler
14 FILE *fp_t = NULL; // target file handler
15 unsigned int x,y; // for loop counter
16 unsigned int width, height; // image width, image height
17 unsigned char *image_s = NULL; // source image array
18 unsigned char *image_t = NULL; // target image array
19 unsigned char R, G, B; // color of R, G, B
20
21 // face detection
22 double r,g;
23 double Gup, Gdown, Wr;
24
25 unsigned char header[54] = {
26 0x42, // identity : B
27 0x4d, // identity : M
28 0, 0, 0, 0, // file size
29 0, 0, // reserved1
30 0, 0, // reserved2
31 54, 0, 0, 0, // RGB data offset
32 40, 0, 0, 0, // struct BITMAPINFOHEADER size
33 0, 0, 0, 0, // bmp width
34 0, 0, 0, 0, // bmp height
35 1, 0, // planes
36 24, 0, // bit per pixel
37 0, 0, 0, 0, // compression
38 0, 0, 0, 0, // data size
39 0, 0, 0, 0, // h resolution
40 0, 0, 0, 0, // v resolution
41 0, 0, 0, 0, // used colors
42 0, 0, 0, 0 // important colors
43 };
44
45 unsigned int file_size; // file size
46 unsigned int rgb_raw_data_offset; // RGB raw data offset
47
48 fp_s = fopen(fname_s, "rb");
49 if (fp_s == NULL) {
50 printf("fopen fp_s error\n");
51 return -1;
52 }
53
54 // move offset to 10 to find rgb raw data offset
55 fseek(fp_s, 10, SEEK_SET);
56 fread(&rgb_raw_data_offset, sizeof(unsigned int), 1, fp_s);
57 // move offset to 18 to get width & height;
58 fseek(fp_s, 18, SEEK_SET);
59 fread(&width, sizeof(unsigned int), 1, fp_s);
60 fread(&height, sizeof(unsigned int), 1, fp_s);
61 // move offset to rgb_raw_data_offset to get RGB raw data
62 fseek(fp_s, rgb_raw_data_offset, SEEK_SET);
63
64 image_s = (unsigned char *)malloc((size_t)width * height * 3);
65 if (image_s == NULL) {
66 printf("malloc images_s error\n");
67 return -1;
68 }
69
70 image_t = (unsigned char *)malloc((size_t)width * height * 3);
71 if (image_t == NULL) {
72 printf("malloc image_t error\n");
73 return -1;
74 }
75
76 fread(image_s, sizeof(unsigned char), (size_t)(long)width * height * 3, fp_s);
77
78 for(y = 0; y != height; ++y) {
79 for(x = 0; x != width; ++x) {
80 R = *(image_s + 3 * (width * y + x) + 2);
81 G = *(image_s + 3 * (width * y + x) + 1);
82 B = *(image_s + 3 * (width * y + x) + 0);
83
84 r = (double)R / (R + G + B);
85 g = (double)G / (R + G + B);
86
87 Wr = (r-0.33) * (r-0.33) + (g-0.33) * (g-0.33);
88
89 Gup = -1.3767 * r * r + 1.0743 * r + 0.25;
90 Gdown = -0.776 * r * r + 0.5601 * r + 0.18;
91
92 if ((g < Gup) && (g > Gdown) && (Wr > 0.001) && ((R-G)>=15)) {
93 *(image_t + 3 * (width * y + x) + 2) = 255;
94 *(image_t + 3 * (width * y + x) + 1) = 255;
95 *(image_t + 3 * (width * y + x) + 0) = 255;
96 }
97 else {
98 *(image_t + 3 * (width * y + x) + 2) = 0;
99 *(image_t + 3 * (width * y + x) + 1) = 0;
100 *(image_t + 3 * (width * y + x) + 0) = 0;
101 }
102 }
103 }
104
105 // write to new bmp
106 fp_t = fopen(fname_t, "wb");
107 if (fp_t == NULL) {
108 printf("fopen fname_t error\n");
109 return -1;
110 }
111
112 // file size
113 file_size = width * height * 3 + rgb_raw_data_offset;
114 header[2] = (unsigned char)(file_size & 0x000000ff);
115 header[3] = (file_size >> 8) & 0x000000ff;
116 header[4] = (file_size >> 16) & 0x000000ff;
117 header[5] = (file_size >> 24) & 0x000000ff;
118
119 // width
120 header[18] = width & 0x000000ff;
121 header[19] = (width >> 8) & 0x000000ff;
122 header[20] = (width >> 16) & 0x000000ff;
123 header[21] = (width >> 24) & 0x000000ff;
124
125 // height
126 header[22] = height &0x000000ff;
127 header[23] = (height >> 8) & 0x000000ff;
128 header[24] = (height >> 16) & 0x000000ff;
129 header[25] = (height >> 24) & 0x000000ff;
130
131 // write header
132 fwrite(header, sizeof(unsigned char), rgb_raw_data_offset, fp_t);
133 // write image
134 fwrite(image_t, sizeof(unsigned char), (size_t)(long)width * height * 3, fp_t);
135
136 fclose(fp_s);
137 fclose(fp_t);
138
139 return 0;
140 }
141
142 int main() {
143 face_detection("cmaria.bmp", "cmaria_skin.bmp");
144 }
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : face_detection.c
5 Compiler : Visual C++ 9.0 / ANSI C
6 Description : Demo the how to implement face detection by C
7 Release : 09/30/2009 1.0
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 int face_detection(const char *fname_s, const char *fname_t) {
13 FILE *fp_s = NULL; // source file handler
14 FILE *fp_t = NULL; // target file handler
15 unsigned int x,y; // for loop counter
16 unsigned int width, height; // image width, image height
17 unsigned char *image_s = NULL; // source image array
18 unsigned char *image_t = NULL; // target image array
19 unsigned char R, G, B; // color of R, G, B
20
21 // face detection
22 double r,g;
23 double Gup, Gdown, Wr;
24
25 unsigned char header[54] = {
26 0x42, // identity : B
27 0x4d, // identity : M
28 0, 0, 0, 0, // file size
29 0, 0, // reserved1
30 0, 0, // reserved2
31 54, 0, 0, 0, // RGB data offset
32 40, 0, 0, 0, // struct BITMAPINFOHEADER size
33 0, 0, 0, 0, // bmp width
34 0, 0, 0, 0, // bmp height
35 1, 0, // planes
36 24, 0, // bit per pixel
37 0, 0, 0, 0, // compression
38 0, 0, 0, 0, // data size
39 0, 0, 0, 0, // h resolution
40 0, 0, 0, 0, // v resolution
41 0, 0, 0, 0, // used colors
42 0, 0, 0, 0 // important colors
43 };
44
45 unsigned int file_size; // file size
46 unsigned int rgb_raw_data_offset; // RGB raw data offset
47
48 fp_s = fopen(fname_s, "rb");
49 if (fp_s == NULL) {
50 printf("fopen fp_s error\n");
51 return -1;
52 }
53
54 // move offset to 10 to find rgb raw data offset
55 fseek(fp_s, 10, SEEK_SET);
56 fread(&rgb_raw_data_offset, sizeof(unsigned int), 1, fp_s);
57 // move offset to 18 to get width & height;
58 fseek(fp_s, 18, SEEK_SET);
59 fread(&width, sizeof(unsigned int), 1, fp_s);
60 fread(&height, sizeof(unsigned int), 1, fp_s);
61 // move offset to rgb_raw_data_offset to get RGB raw data
62 fseek(fp_s, rgb_raw_data_offset, SEEK_SET);
63
64 image_s = (unsigned char *)malloc((size_t)width * height * 3);
65 if (image_s == NULL) {
66 printf("malloc images_s error\n");
67 return -1;
68 }
69
70 image_t = (unsigned char *)malloc((size_t)width * height * 3);
71 if (image_t == NULL) {
72 printf("malloc image_t error\n");
73 return -1;
74 }
75
76 fread(image_s, sizeof(unsigned char), (size_t)(long)width * height * 3, fp_s);
77
78 for(y = 0; y != height; ++y) {
79 for(x = 0; x != width; ++x) {
80 R = *(image_s + 3 * (width * y + x) + 2);
81 G = *(image_s + 3 * (width * y + x) + 1);
82 B = *(image_s + 3 * (width * y + x) + 0);
83
84 r = (double)R / (R + G + B);
85 g = (double)G / (R + G + B);
86
87 Wr = (r-0.33) * (r-0.33) + (g-0.33) * (g-0.33);
88
89 Gup = -1.3767 * r * r + 1.0743 * r + 0.25;
90 Gdown = -0.776 * r * r + 0.5601 * r + 0.18;
91
92 if ((g < Gup) && (g > Gdown) && (Wr > 0.001) && ((R-G)>=15)) {
93 *(image_t + 3 * (width * y + x) + 2) = 255;
94 *(image_t + 3 * (width * y + x) + 1) = 255;
95 *(image_t + 3 * (width * y + x) + 0) = 255;
96 }
97 else {
98 *(image_t + 3 * (width * y + x) + 2) = 0;
99 *(image_t + 3 * (width * y + x) + 1) = 0;
100 *(image_t + 3 * (width * y + x) + 0) = 0;
101 }
102 }
103 }
104
105 // write to new bmp
106 fp_t = fopen(fname_t, "wb");
107 if (fp_t == NULL) {
108 printf("fopen fname_t error\n");
109 return -1;
110 }
111
112 // file size
113 file_size = width * height * 3 + rgb_raw_data_offset;
114 header[2] = (unsigned char)(file_size & 0x000000ff);
115 header[3] = (file_size >> 8) & 0x000000ff;
116 header[4] = (file_size >> 16) & 0x000000ff;
117 header[5] = (file_size >> 24) & 0x000000ff;
118
119 // width
120 header[18] = width & 0x000000ff;
121 header[19] = (width >> 8) & 0x000000ff;
122 header[20] = (width >> 16) & 0x000000ff;
123 header[21] = (width >> 24) & 0x000000ff;
124
125 // height
126 header[22] = height &0x000000ff;
127 header[23] = (height >> 8) & 0x000000ff;
128 header[24] = (height >> 16) & 0x000000ff;
129 header[25] = (height >> 24) & 0x000000ff;
130
131 // write header
132 fwrite(header, sizeof(unsigned char), rgb_raw_data_offset, fp_t);
133 // write image
134 fwrite(image_t, sizeof(unsigned char), (size_t)(long)width * height * 3, fp_t);
135
136 fclose(fp_s);
137 fclose(fp_t);
138
139 return 0;
140 }
141
142 int main() {
143 face_detection("cmaria.bmp", "cmaria_skin.bmp");
144 }
原圖 (高樹マリア)
執行結果
完整程式碼下載
Face_Detection.7z
Reference
[1] 李棟良、人臉偵測與辨識系統、銘傳大學電腦與通訊工程學系
See Also
(原創) 如何使用ANSI C讀寫24位元的BMP圖檔? (C/C++) (C) (Image Processing)