(原創) 如何實現Sobel Edge Detector? (Image Processing) (C/C++) (C++/CLI) (C)
Abstract
使用C與C++/CLI實現Sobel Edge Detector。
Introduction
演算法部分我就不多談,請參考Sobel Edge Detector。
Method 1:
sobel_edge.c / C
1 /*
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : sobel_edge.c
5 Compiler : Visual C++ 8.0
6 Description : Demo the how to use sobel detector on gray level image
7 Release : 07/23/2008 1.0
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12
13 #define MASK_N 2
14 #define MASK_X 3
15 #define MASK_Y 3
16 #define WHITE 255
17 #define BLACK 0
18
19 unsigned char *image_s = NULL; // source image array
20 unsigned char *image_t = NULL; // target image array
21 FILE *fp_s = NULL; // source file handler
22 FILE *fp_t = NULL; // target file handler
23
24 unsigned int width, height; // image width, image height
25 unsigned int rgb_raw_data_offset;// RGB raw data offset
26 unsigned char bit_per_pixel; // bit per pixel
27 unsigned short byte_per_pixel; // byte per pixel
28
29 // bitmap header
30 unsigned char header[54] = {
31 0x42, // identity : B
32 0x4d, // identity : M
33 0, 0, 0, 0, // file size
34 0, 0, // reserved1
35 0, 0, // reserved2
36 54, 0, 0, 0, // RGB data offset
37 40, 0, 0, 0, // struct BITMAPINFOHEADER size
38 0, 0, 0, 0, // bmp width
39 0, 0, 0, 0, // bmp height
40 1, 0, // planes
41 24, 0, // bit per pixel
42 0, 0, 0, 0, // compression
43 0, 0, 0, 0, // data size
44 0, 0, 0, 0, // h resolution
45 0, 0, 0, 0, // v resolution
46 0, 0, 0, 0, // used colors
47 0, 0, 0, 0 // important colors
48 };
49
50
51 // sobel mask
52 int mask[MASK_N][MASK_X][MASK_Y] = {
53 {{-1,-2,-1},
54 {0 , 0, 0},
55 {1 , 2, 1}},
56
57 {{-1, 0, 1},
58 {-2, 0, 2},
59 {-1, 0, 1}}
60 };
61
62 int read_bmp(const char *fname_s) {
63 fp_s = fopen(fname_s, "rb");
64 if (fp_s == NULL) {
65 printf("fopen fp_s error\n");
66 return -1;
67 }
68
69 // move offset to 10 to find rgb raw data offset
70 fseek(fp_s, 10, SEEK_SET);
71 fread(&rgb_raw_data_offset, sizeof(unsigned int), 1, fp_s);
72
73 // move offset to 18 to get width & height;
74 fseek(fp_s, 18, SEEK_SET);
75 fread(&width, sizeof(unsigned int), 1, fp_s);
76 fread(&height, sizeof(unsigned int), 1, fp_s);
77
78 // get bit per pixel
79 fseek(fp_s, 28, SEEK_SET);
80 fread(&bit_per_pixel, sizeof(unsigned short), 1, fp_s);
81 byte_per_pixel = bit_per_pixel / 8;
82
83 // move offset to rgb_raw_data_offset to get RGB raw data
84 fseek(fp_s, rgb_raw_data_offset, SEEK_SET);
85
86 image_s = (unsigned char *)malloc((size_t)width * height * byte_per_pixel);
87 if (image_s == NULL) {
88 printf("malloc images_s error\n");
89 return -1;
90 }
91
92 image_t = (unsigned char *)malloc((size_t)width * height * byte_per_pixel);
93 if (image_t == NULL) {
94 printf("malloc image_t error\n");
95 return -1;
96 }
97
98 fread(image_s, sizeof(unsigned char), (size_t)(long)width * height * byte_per_pixel, fp_s);
99
100 return 0;
101 }
102
103 // convert RGB to gray level int
104 int color_to_int(int r, int g, int b) {
105 return (r + g + b) / 3;
106 }
107
108 int sobel(double threshold) {
109 unsigned int x, y, i, v, u; // for loop counter
110 unsigned char R, G, B; // color of R, G, B
111 double val[MASK_N] = {0.0};
112 int adjustX, adjustY, xBound, yBound;
113 double total;
114
115 for(y = 0; y != height; ++y) {
116 for(x = 0; x != width; ++x) {
117 for(i = 0; i != MASK_N; ++i) {
118 adjustX = (MASK_X % 2) ? 1 : 0;
119 adjustY = (MASK_Y % 2) ? 1 : 0;
120 xBound = MASK_X / 2;
121 yBound = MASK_Y / 2;
122
123 val[i] = 0.0;
124 for(v = -yBound; v != yBound + adjustY; ++v) {
125 for (u = -xBound; u != xBound + adjustX; ++u) {
126 if (x + u >= 0 && x + u < width && y + v >= 0 && y + v < height) {
127 R = *(image_s + byte_per_pixel * (width * (y+v) + (x+u)) + 2);
128 G = *(image_s + byte_per_pixel * (width * (y+v) + (x+u)) + 1);
129 B = *(image_s + byte_per_pixel * (width * (y+v) + (x+u)) + 0);
130
131 val[i] += color_to_int(R, G, B) * mask[i][u + xBound][v + yBound];
132 }
133 }
134 }
135 }
136
137 total = 0.0;
138 for (i = 0; i != MASK_N; ++i) {
139 total += val[i] * val[i];
140 }
141
142 total = sqrt(total);
143
144 if (total - threshold >= 0) {
145 // black
146 *(image_t + byte_per_pixel * (width * y + x) + 2) = BLACK;
147 *(image_t + byte_per_pixel * (width * y + x) + 1) = BLACK;
148 *(image_t + byte_per_pixel * (width * y + x) + 0) = BLACK;
149 }
150 else {
151 // white
152 *(image_t + byte_per_pixel * (width * y + x) + 2) = WHITE;
153 *(image_t + byte_per_pixel * (width * y + x) + 1) = WHITE;
154 *(image_t + byte_per_pixel * (width * y + x) + 0) = WHITE;
155 }
156 }
157 }
158
159 return 0;
160 }
161
162 int write_bmp(const char *fname_t) {
163 unsigned int file_size; // file size
164
165 fp_t = fopen(fname_t, "wb");
166 if (fp_t == NULL) {
167 printf("fopen fname_t error\n");
168 return -1;
169 }
170
171 // file size
172 file_size = width * height * byte_per_pixel + rgb_raw_data_offset;
173 header[2] = (unsigned char)(file_size & 0x000000ff);
174 header[3] = (file_size >> 8) & 0x000000ff;
175 header[4] = (file_size >> 16) & 0x000000ff;
176 header[5] = (file_size >> 24) & 0x000000ff;
177
178 // width
179 header[18] = width & 0x000000ff;
180 header[19] = (width >> 8) & 0x000000ff;
181 header[20] = (width >> 16) & 0x000000ff;
182 header[21] = (width >> 24) & 0x000000ff;
183
184 // height
185 header[22] = height &0x000000ff;
186 header[23] = (height >> 8) & 0x000000ff;
187 header[24] = (height >> 16) & 0x000000ff;
188 header[25] = (height >> 24) & 0x000000ff;
189
190 // bit per pixel
191 header[28] = bit_per_pixel;
192
193 // write header
194 fwrite(header, sizeof(unsigned char), rgb_raw_data_offset, fp_t);
195
196 // write image
197 fwrite(image_t, sizeof(unsigned char), (size_t)(long)width * height * byte_per_pixel, fp_t);
198
199 fclose(fp_s);
200 fclose(fp_t);
201
202 return 0;
203 }
204
205 int main() {
206 read_bmp("lena.bmp"); // 24 bit gray level image
207 sobel(90.0);
208 write_bmp("lena_sobel.bmp");
209 }
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : sobel_edge.c
5 Compiler : Visual C++ 8.0
6 Description : Demo the how to use sobel detector on gray level image
7 Release : 07/23/2008 1.0
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12
13 #define MASK_N 2
14 #define MASK_X 3
15 #define MASK_Y 3
16 #define WHITE 255
17 #define BLACK 0
18
19 unsigned char *image_s = NULL; // source image array
20 unsigned char *image_t = NULL; // target image array
21 FILE *fp_s = NULL; // source file handler
22 FILE *fp_t = NULL; // target file handler
23
24 unsigned int width, height; // image width, image height
25 unsigned int rgb_raw_data_offset;// RGB raw data offset
26 unsigned char bit_per_pixel; // bit per pixel
27 unsigned short byte_per_pixel; // byte per pixel
28
29 // bitmap header
30 unsigned char header[54] = {
31 0x42, // identity : B
32 0x4d, // identity : M
33 0, 0, 0, 0, // file size
34 0, 0, // reserved1
35 0, 0, // reserved2
36 54, 0, 0, 0, // RGB data offset
37 40, 0, 0, 0, // struct BITMAPINFOHEADER size
38 0, 0, 0, 0, // bmp width
39 0, 0, 0, 0, // bmp height
40 1, 0, // planes
41 24, 0, // bit per pixel
42 0, 0, 0, 0, // compression
43 0, 0, 0, 0, // data size
44 0, 0, 0, 0, // h resolution
45 0, 0, 0, 0, // v resolution
46 0, 0, 0, 0, // used colors
47 0, 0, 0, 0 // important colors
48 };
49
50
51 // sobel mask
52 int mask[MASK_N][MASK_X][MASK_Y] = {
53 {{-1,-2,-1},
54 {0 , 0, 0},
55 {1 , 2, 1}},
56
57 {{-1, 0, 1},
58 {-2, 0, 2},
59 {-1, 0, 1}}
60 };
61
62 int read_bmp(const char *fname_s) {
63 fp_s = fopen(fname_s, "rb");
64 if (fp_s == NULL) {
65 printf("fopen fp_s error\n");
66 return -1;
67 }
68
69 // move offset to 10 to find rgb raw data offset
70 fseek(fp_s, 10, SEEK_SET);
71 fread(&rgb_raw_data_offset, sizeof(unsigned int), 1, fp_s);
72
73 // move offset to 18 to get width & height;
74 fseek(fp_s, 18, SEEK_SET);
75 fread(&width, sizeof(unsigned int), 1, fp_s);
76 fread(&height, sizeof(unsigned int), 1, fp_s);
77
78 // get bit per pixel
79 fseek(fp_s, 28, SEEK_SET);
80 fread(&bit_per_pixel, sizeof(unsigned short), 1, fp_s);
81 byte_per_pixel = bit_per_pixel / 8;
82
83 // move offset to rgb_raw_data_offset to get RGB raw data
84 fseek(fp_s, rgb_raw_data_offset, SEEK_SET);
85
86 image_s = (unsigned char *)malloc((size_t)width * height * byte_per_pixel);
87 if (image_s == NULL) {
88 printf("malloc images_s error\n");
89 return -1;
90 }
91
92 image_t = (unsigned char *)malloc((size_t)width * height * byte_per_pixel);
93 if (image_t == NULL) {
94 printf("malloc image_t error\n");
95 return -1;
96 }
97
98 fread(image_s, sizeof(unsigned char), (size_t)(long)width * height * byte_per_pixel, fp_s);
99
100 return 0;
101 }
102
103 // convert RGB to gray level int
104 int color_to_int(int r, int g, int b) {
105 return (r + g + b) / 3;
106 }
107
108 int sobel(double threshold) {
109 unsigned int x, y, i, v, u; // for loop counter
110 unsigned char R, G, B; // color of R, G, B
111 double val[MASK_N] = {0.0};
112 int adjustX, adjustY, xBound, yBound;
113 double total;
114
115 for(y = 0; y != height; ++y) {
116 for(x = 0; x != width; ++x) {
117 for(i = 0; i != MASK_N; ++i) {
118 adjustX = (MASK_X % 2) ? 1 : 0;
119 adjustY = (MASK_Y % 2) ? 1 : 0;
120 xBound = MASK_X / 2;
121 yBound = MASK_Y / 2;
122
123 val[i] = 0.0;
124 for(v = -yBound; v != yBound + adjustY; ++v) {
125 for (u = -xBound; u != xBound + adjustX; ++u) {
126 if (x + u >= 0 && x + u < width && y + v >= 0 && y + v < height) {
127 R = *(image_s + byte_per_pixel * (width * (y+v) + (x+u)) + 2);
128 G = *(image_s + byte_per_pixel * (width * (y+v) + (x+u)) + 1);
129 B = *(image_s + byte_per_pixel * (width * (y+v) + (x+u)) + 0);
130
131 val[i] += color_to_int(R, G, B) * mask[i][u + xBound][v + yBound];
132 }
133 }
134 }
135 }
136
137 total = 0.0;
138 for (i = 0; i != MASK_N; ++i) {
139 total += val[i] * val[i];
140 }
141
142 total = sqrt(total);
143
144 if (total - threshold >= 0) {
145 // black
146 *(image_t + byte_per_pixel * (width * y + x) + 2) = BLACK;
147 *(image_t + byte_per_pixel * (width * y + x) + 1) = BLACK;
148 *(image_t + byte_per_pixel * (width * y + x) + 0) = BLACK;
149 }
150 else {
151 // white
152 *(image_t + byte_per_pixel * (width * y + x) + 2) = WHITE;
153 *(image_t + byte_per_pixel * (width * y + x) + 1) = WHITE;
154 *(image_t + byte_per_pixel * (width * y + x) + 0) = WHITE;
155 }
156 }
157 }
158
159 return 0;
160 }
161
162 int write_bmp(const char *fname_t) {
163 unsigned int file_size; // file size
164
165 fp_t = fopen(fname_t, "wb");
166 if (fp_t == NULL) {
167 printf("fopen fname_t error\n");
168 return -1;
169 }
170
171 // file size
172 file_size = width * height * byte_per_pixel + rgb_raw_data_offset;
173 header[2] = (unsigned char)(file_size & 0x000000ff);
174 header[3] = (file_size >> 8) & 0x000000ff;
175 header[4] = (file_size >> 16) & 0x000000ff;
176 header[5] = (file_size >> 24) & 0x000000ff;
177
178 // width
179 header[18] = width & 0x000000ff;
180 header[19] = (width >> 8) & 0x000000ff;
181 header[20] = (width >> 16) & 0x000000ff;
182 header[21] = (width >> 24) & 0x000000ff;
183
184 // height
185 header[22] = height &0x000000ff;
186 header[23] = (height >> 8) & 0x000000ff;
187 header[24] = (height >> 16) & 0x000000ff;
188 header[25] = (height >> 24) & 0x000000ff;
189
190 // bit per pixel
191 header[28] = bit_per_pixel;
192
193 // write header
194 fwrite(header, sizeof(unsigned char), rgb_raw_data_offset, fp_t);
195
196 // write image
197 fwrite(image_t, sizeof(unsigned char), (size_t)(long)width * height * byte_per_pixel, fp_t);
198
199 fclose(fp_s);
200 fclose(fp_t);
201
202 return 0;
203 }
204
205 int main() {
206 read_bmp("lena.bmp"); // 24 bit gray level image
207 sobel(90.0);
208 write_bmp("lena_sobel.bmp");
209 }
Method 2
sobel_edge.cpp / C++/CLI
1 /*
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : sobel_edge.cpp
5 Compiler : C++/CLI / Visual C++ 8.0
6 Description : Demo the how to use sobel detector on gray level image
7 Release : 07/23/2008 1.0
8 */
9
10 #include "stdafx.h"
11 #include <cmath>
12
13 using namespace System::Drawing;
14 using namespace System::Drawing::Imaging;
15
16 const int MASK_N = 2;
17 const int MASK_X = 3;
18 const int MASK_Y = 3;
19
20 // Convert RGB to gray level int
21 int colorToInt(Color %color) {
22 return (color.R + color.G + color.B) / 3;
23 }
24
25 void edgeDetector(Bitmap^ oriImg, Bitmap^ resImg, const int mask[MASK_N][MASK_X][MASK_Y], const double &threshold) {
26 double val[MASK_N] = {0.0};
27
28 for(int y = 0; y != oriImg->Height; ++y) {
29 for(int x = 0; x != oriImg->Width; ++x) {
30 for(int i = 0; i != MASK_N; ++i) {
31 int adjustX = (MASK_X % 2) ? 1 : 0;
32 int adjustY = (MASK_Y % 2) ? 1 : 0;
33 int xBound = MASK_X / 2;
34 int yBound = MASK_Y / 2;
35
36 val[i] = 0.0;
37 for(int v = -yBound; v != yBound + adjustY; ++v) {
38 for (int u = -xBound; u != xBound + adjustX; ++u) {
39 if (x + u >= 0 && x + u < oriImg->Width && y + v >= 0 && y + v < oriImg->Height) {
40 val[i] += colorToInt(oriImg->GetPixel(x + u, y + v)) * mask[i][u + xBound][v + yBound];
41 }
42 }
43 }
44 }
45
46 double total = 0.0;
47 for (int i = 0; i != MASK_N; ++i) {
48 total += val[i] * val[i];
49 }
50
51 total = sqrt(total);
52
53 if (total - threshold >= 0)
54 resImg->SetPixel(x , y, Color::Black);
55 else
56 resImg->SetPixel(x, y, Color::White);
57 }
58 }
59 }
60
61 int main() {
62 const int mask[MASK_N][MASK_X][MASK_Y] = {
63 {{-1,-2,-1},
64 {0 , 0, 0},
65 {1 , 2, 1}},
66
67 {{-1, 0, 1},
68 {-2, 0, 2},
69 {-1, 0, 1}}
70 };
71
72 Bitmap^ oriImg = gcnew Bitmap("lena.bmp");
73 Bitmap^ resImg = gcnew Bitmap(oriImg->Width, oriImg->Height);
74
75 const double threshold = 90.0;
76 edgeDetector(oriImg, resImg, mask, threshold);
77
78 resImg->Save("lena_sobel.bmp");
79
80 return 0;
81 }
2 (C) OOMusou 2007 http://oomusou.cnblogs.com
3
4 Filename : sobel_edge.cpp
5 Compiler : C++/CLI / Visual C++ 8.0
6 Description : Demo the how to use sobel detector on gray level image
7 Release : 07/23/2008 1.0
8 */
9
10 #include "stdafx.h"
11 #include <cmath>
12
13 using namespace System::Drawing;
14 using namespace System::Drawing::Imaging;
15
16 const int MASK_N = 2;
17 const int MASK_X = 3;
18 const int MASK_Y = 3;
19
20 // Convert RGB to gray level int
21 int colorToInt(Color %color) {
22 return (color.R + color.G + color.B) / 3;
23 }
24
25 void edgeDetector(Bitmap^ oriImg, Bitmap^ resImg, const int mask[MASK_N][MASK_X][MASK_Y], const double &threshold) {
26 double val[MASK_N] = {0.0};
27
28 for(int y = 0; y != oriImg->Height; ++y) {
29 for(int x = 0; x != oriImg->Width; ++x) {
30 for(int i = 0; i != MASK_N; ++i) {
31 int adjustX = (MASK_X % 2) ? 1 : 0;
32 int adjustY = (MASK_Y % 2) ? 1 : 0;
33 int xBound = MASK_X / 2;
34 int yBound = MASK_Y / 2;
35
36 val[i] = 0.0;
37 for(int v = -yBound; v != yBound + adjustY; ++v) {
38 for (int u = -xBound; u != xBound + adjustX; ++u) {
39 if (x + u >= 0 && x + u < oriImg->Width && y + v >= 0 && y + v < oriImg->Height) {
40 val[i] += colorToInt(oriImg->GetPixel(x + u, y + v)) * mask[i][u + xBound][v + yBound];
41 }
42 }
43 }
44 }
45
46 double total = 0.0;
47 for (int i = 0; i != MASK_N; ++i) {
48 total += val[i] * val[i];
49 }
50
51 total = sqrt(total);
52
53 if (total - threshold >= 0)
54 resImg->SetPixel(x , y, Color::Black);
55 else
56 resImg->SetPixel(x, y, Color::White);
57 }
58 }
59 }
60
61 int main() {
62 const int mask[MASK_N][MASK_X][MASK_Y] = {
63 {{-1,-2,-1},
64 {0 , 0, 0},
65 {1 , 2, 1}},
66
67 {{-1, 0, 1},
68 {-2, 0, 2},
69 {-1, 0, 1}}
70 };
71
72 Bitmap^ oriImg = gcnew Bitmap("lena.bmp");
73 Bitmap^ resImg = gcnew Bitmap(oriImg->Width, oriImg->Height);
74
75 const double threshold = 90.0;
76 edgeDetector(oriImg, resImg, mask, threshold);
77
78 resImg->Save("lena_sobel.bmp");
79
80 return 0;
81 }
原圖
執行結果
See Also
(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M)
(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2) (TRDB-DC2)