最近做一些图像处理,需要将图像中的一些像素过滤一下,有网友给提了个名词:腐蚀算法。我不是学图像学的,乍一听,觉得很神奇。后来从网上收集了一些VC代码,研究了一下,发现其它也就是那么回事。尤其是腐蚀算法,我在以前的验证码图片去噪声的文章中提到过,只是那是我不知叫什么名词,就从用途出发,叫做“根据周边点数去噪”。腐蚀的原理也一样,就是根据当前点的周边点数(如3X3的,周边就有8个点)来修改当前点的状态的。
代码是我从VC代码中转译过来的,注释都沿用了原作者的文字(别说是剽窃,^_^)。唯一改进的地方是,原代码功能只能处理0和255的二值灰度(搞不懂为什么这样,对于250、128这样的都不行,还不如弄成二值灰度,别弄256灰度了),我将之改成了能根据0~255中任意灰度划界的256灰度图像!
以下是C#代码:
代码是我从VC代码中转译过来的,注释都沿用了原作者的文字(别说是剽窃,^_^)。唯一改进的地方是,原代码功能只能处理0和255的二值灰度(搞不懂为什么这样,对于250、128这样的都不行,还不如弄成二值灰度,别弄256灰度了),我将之改成了能根据0~255中任意灰度划界的256灰度图像!
以下是C#代码:
1
/// <summary>
2 /// 该函数用于对图像进行腐蚀运算。结构元素为水平方向或垂直方向的三个点,
3 /// 中间点位于原点;或者由用户自己定义3×3的结构元素。
4 /// </summary>
5 /// <param name="dgGrayValue">前后景临界值</param>
6 /// <param name="nMode">腐蚀方式:0表示水平方向,1垂直方向,2自定义结构元素。</param>
7 /// <param name="structure"> 自定义的3×3结构元素</param>
8 public void ErosionPic( int dgGrayValue, int nMode, bool [,] structure)
9 {
10 int lWidth = bmpobj.Width;
11 int lHeight = bmpobj.Height;
12 Bitmap newBmp = new Bitmap(lWidth, lHeight);
13
14 int i, j, n, m; //循环变量
15 Color pixel; //像素颜色值
16
17 if (nMode == 0)
18 {
19 //使用水平方向的结构元素进行腐蚀
20 // 由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边
21 // 的两列像素
22 for (j = 0; j < lHeight; j++)
23 {
24 for (i = 1; i < lWidth - 1; i++)
25 {
26 //目标图像中的当前点先赋成黑色
27 newBmp.SetPixel(i, j, Color.Black);
28
29 //如果源图像中当前点自身或者左右有一个点不是黑色,
30 //则将目标图像中的当前点赋成白色
31 if (bmpobj.GetPixel(i - 1, j).R > dgGrayValue ||
32 bmpobj.GetPixel(i, j).R > dgGrayValue ||
33 bmpobj.GetPixel(i + 1, j).R > dgGrayValue)
34 newBmp.SetPixel(i, j, Color.White);
35 }
36 }
37 }
38 else if (nMode == 1)
39 {
40 //使用垂真方向的结构元素进行腐蚀
41 // 由于使用3×1的结构元素,为防止越界,所以不处理最上边和最下边
42 // 的两行像素
43 for (j = 1; j < lHeight - 1; j++)
44 {
45 for (i = 0; i < lWidth; i++)
46 {
47 //目标图像中的当前点先赋成黑色
48 newBmp.SetPixel(i, j, Color.Black);
49
50 //如果源图像中当前点自身或者左右有一个点不是黑色,
51 //则将目标图像中的当前点赋成白色
52 if (bmpobj.GetPixel(i, j - 1).R > dgGrayValue ||
53 bmpobj.GetPixel(i, j).R > dgGrayValue ||
54 bmpobj.GetPixel(i, j + 1).R > dgGrayValue)
55 newBmp.SetPixel(i, j, Color.White);
56 }
57 }
58 }
59 else
60 {
61 if (structure.Length != 9) //检查自定义结构
62 return;
63 //使用自定义的结构元素进行腐蚀
64 // 由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边
65 // 的两列像素和最上边和最下边的两列像素
66 for (j = 1; j < lHeight - 1; j++)
67 {
68 for (i = 1; i < lWidth - 1; i++)
69 {
70 //目标图像中的当前点先赋成黑色
71 newBmp.SetPixel(i, j, Color.Black);
72 //如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色,
73 //则将目标图像中的当前点赋成白色
74 for (m = 0; m < 3; m++)
75 {
76 for (n = 0; n < 3; n++)
77 {
78 if (!structure[m, n])
79 continue;
80 if (bmpobj.GetPixel(i + m - 1, j + n - 1).R > dgGrayValue)
81 {
82 newBmp.SetPixel(i, j, Color.White);
83 break;
84 }
85 }
86 }
87 }
88 }
89 }
90
91 bmpobj = newBmp;
92 }
93
94
95 /// <summary>
96 /// 该函数用于对图像进行细化运算。要求目标图像为灰度图像
97 /// </summary>
98 /// <param name="dgGrayValue"></param>
99 public void ThiningPic( int dgGrayValue)
100 {
101 int lWidth = bmpobj.Width;
102 int lHeight = bmpobj.Height;
103 // Bitmap newBmp = new Bitmap(lWidth, lHeight);
104
105 bool bModified; //脏标记
106 int i, j, n, m; //循环变量
107 Color pixel; //像素颜色值
108
109 //四个条件
110 bool bCondition1;
111 bool bCondition2;
112 bool bCondition3;
113 bool bCondition4;
114
115 int nCount; //计数器
116 int[,] neighbour = new int[5, 5]; //5×5相邻区域像素值
117
118
119
120 bModified = true;
121 while (bModified)
122 {
123 bModified = false;
124
125 //由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素
126 for (j = 2; j < lHeight - 2; j++)
127 {
128 for (i = 2; i < lWidth - 2; i++)
129 {
130 bCondition1 = false;
131 bCondition2 = false;
132 bCondition3 = false;
133 bCondition4 = false;
134
135 if (bmpobj.GetPixel(i, j).R > dgGrayValue)
136 {
137 if(bmpobj.GetPixel(i, j).R<255)
138 bmpobj.SetPixel(i, j, Color.White);
139 continue;
140 }
141
142 //获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表
143 for (m = 0; m < 5; m++)
144 {
145 for (n = 0; n < 5; n++)
146 {
147 neighbour[m, n] = bmpobj.GetPixel(i + m - 2, j + n - 2).R < dgGrayValue ? 1 : 0;
148 }
149 }
150
151 //逐个判断条件。
152 //判断2<=NZ(P1)<=6
153 nCount = neighbour[1, 1] + neighbour[1, 2] + neighbour[1, 3]
154 + neighbour[2, 1] + neighbour[2, 3] +
155 +neighbour[3, 1] + neighbour[3, 2] + neighbour[3, 3];
156 if (nCount >= 2 && nCount <= 6)
157 {
158 bCondition1 = true;
159 }
160
161 //判断Z0(P1)=1
162 nCount = 0;
163 if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1)
164 nCount++;
165 if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1)
166 nCount++;
167 if (neighbour[2, 1] == 0 && neighbour[3, 1] == 1)
168 nCount++;
169 if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1)
170 nCount++;
171 if (neighbour[3, 2] == 0 && neighbour[3, 3] == 1)
172 nCount++;
173 if (neighbour[3, 3] == 0 && neighbour[2, 3] == 1)
174 nCount++;
175 if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1)
176 nCount++;
177 if (neighbour[1, 3] == 0 && neighbour[1, 2] == 1)
178 nCount++;
179 if (nCount == 1)
180 bCondition2 = true;
181
182 //判断P2*P4*P8=0 or Z0(p2)!=1
183 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[2, 3] == 0)
184 {
185 bCondition3 = true;
186 }
187 else
188 {
189 nCount = 0;
190 if (neighbour[0, 2] == 0 && neighbour[0, 1] == 1)
191 nCount++;
192 if (neighbour[0, 1] == 0 && neighbour[1, 1] == 1)
193 nCount++;
194 if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1)
195 nCount++;
196 if (neighbour[2, 1] == 0 && neighbour[2, 2] == 1)
197 nCount++;
198 if (neighbour[2, 2] == 0 && neighbour[2, 3] == 1)
199 nCount++;
200 if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1)
201 nCount++;
202 if (neighbour[1, 3] == 0 && neighbour[0, 3] == 1)
203 nCount++;
204 if (neighbour[0, 3] == 0 && neighbour[0, 2] == 1)
205 nCount++;
206 if (nCount != 1)
207 bCondition3 = true;
208 }
209
210 //判断P2*P4*P6=0 or Z0(p4)!=1
211 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[3, 2] == 0)
212 {
213 bCondition4 = true;
214 }
215 else
216 {
217 nCount = 0;
218 if (neighbour[1, 1] == 0 && neighbour[1, 0] == 1)
219 nCount++;
220 if (neighbour[1, 0] == 0 && neighbour[2, 0] == 1)
221 nCount++;
222 if (neighbour[2, 0] == 0 && neighbour[3, 0] == 1)
223 nCount++;
224 if (neighbour[3, 0] == 0 && neighbour[3, 1] == 1)
225 nCount++;
226 if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1)
227 nCount++;
228 if (neighbour[3, 2] == 0 && neighbour[2, 2] == 1)
229 nCount++;
230 if (neighbour[2, 2] == 0 && neighbour[1, 2] == 1)
231 nCount++;
232 if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1)
233 nCount++;
234 if (nCount != 1)
235 bCondition4 = true;
236 }
237
238 if (bCondition1 && bCondition2 && bCondition3 && bCondition4)
239 {
240 bmpobj.SetPixel(i, j, Color.White);
241 bModified = true;
242 }
243 else
244 {
245 bmpobj.SetPixel(i, j, Color.Black);
246 }
247 }
248 }
249 }
250 // 复制细化后的图像
251 // bmpobj = newBmp;
252 }
253
2 /// 该函数用于对图像进行腐蚀运算。结构元素为水平方向或垂直方向的三个点,
3 /// 中间点位于原点;或者由用户自己定义3×3的结构元素。
4 /// </summary>
5 /// <param name="dgGrayValue">前后景临界值</param>
6 /// <param name="nMode">腐蚀方式:0表示水平方向,1垂直方向,2自定义结构元素。</param>
7 /// <param name="structure"> 自定义的3×3结构元素</param>
8 public void ErosionPic( int dgGrayValue, int nMode, bool [,] structure)
9 {
10 int lWidth = bmpobj.Width;
11 int lHeight = bmpobj.Height;
12 Bitmap newBmp = new Bitmap(lWidth, lHeight);
13
14 int i, j, n, m; //循环变量
15 Color pixel; //像素颜色值
16
17 if (nMode == 0)
18 {
19 //使用水平方向的结构元素进行腐蚀
20 // 由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边
21 // 的两列像素
22 for (j = 0; j < lHeight; j++)
23 {
24 for (i = 1; i < lWidth - 1; i++)
25 {
26 //目标图像中的当前点先赋成黑色
27 newBmp.SetPixel(i, j, Color.Black);
28
29 //如果源图像中当前点自身或者左右有一个点不是黑色,
30 //则将目标图像中的当前点赋成白色
31 if (bmpobj.GetPixel(i - 1, j).R > dgGrayValue ||
32 bmpobj.GetPixel(i, j).R > dgGrayValue ||
33 bmpobj.GetPixel(i + 1, j).R > dgGrayValue)
34 newBmp.SetPixel(i, j, Color.White);
35 }
36 }
37 }
38 else if (nMode == 1)
39 {
40 //使用垂真方向的结构元素进行腐蚀
41 // 由于使用3×1的结构元素,为防止越界,所以不处理最上边和最下边
42 // 的两行像素
43 for (j = 1; j < lHeight - 1; j++)
44 {
45 for (i = 0; i < lWidth; i++)
46 {
47 //目标图像中的当前点先赋成黑色
48 newBmp.SetPixel(i, j, Color.Black);
49
50 //如果源图像中当前点自身或者左右有一个点不是黑色,
51 //则将目标图像中的当前点赋成白色
52 if (bmpobj.GetPixel(i, j - 1).R > dgGrayValue ||
53 bmpobj.GetPixel(i, j).R > dgGrayValue ||
54 bmpobj.GetPixel(i, j + 1).R > dgGrayValue)
55 newBmp.SetPixel(i, j, Color.White);
56 }
57 }
58 }
59 else
60 {
61 if (structure.Length != 9) //检查自定义结构
62 return;
63 //使用自定义的结构元素进行腐蚀
64 // 由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边
65 // 的两列像素和最上边和最下边的两列像素
66 for (j = 1; j < lHeight - 1; j++)
67 {
68 for (i = 1; i < lWidth - 1; i++)
69 {
70 //目标图像中的当前点先赋成黑色
71 newBmp.SetPixel(i, j, Color.Black);
72 //如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色,
73 //则将目标图像中的当前点赋成白色
74 for (m = 0; m < 3; m++)
75 {
76 for (n = 0; n < 3; n++)
77 {
78 if (!structure[m, n])
79 continue;
80 if (bmpobj.GetPixel(i + m - 1, j + n - 1).R > dgGrayValue)
81 {
82 newBmp.SetPixel(i, j, Color.White);
83 break;
84 }
85 }
86 }
87 }
88 }
89 }
90
91 bmpobj = newBmp;
92 }
93
94
95 /// <summary>
96 /// 该函数用于对图像进行细化运算。要求目标图像为灰度图像
97 /// </summary>
98 /// <param name="dgGrayValue"></param>
99 public void ThiningPic( int dgGrayValue)
100 {
101 int lWidth = bmpobj.Width;
102 int lHeight = bmpobj.Height;
103 // Bitmap newBmp = new Bitmap(lWidth, lHeight);
104
105 bool bModified; //脏标记
106 int i, j, n, m; //循环变量
107 Color pixel; //像素颜色值
108
109 //四个条件
110 bool bCondition1;
111 bool bCondition2;
112 bool bCondition3;
113 bool bCondition4;
114
115 int nCount; //计数器
116 int[,] neighbour = new int[5, 5]; //5×5相邻区域像素值
117
118
119
120 bModified = true;
121 while (bModified)
122 {
123 bModified = false;
124
125 //由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素
126 for (j = 2; j < lHeight - 2; j++)
127 {
128 for (i = 2; i < lWidth - 2; i++)
129 {
130 bCondition1 = false;
131 bCondition2 = false;
132 bCondition3 = false;
133 bCondition4 = false;
134
135 if (bmpobj.GetPixel(i, j).R > dgGrayValue)
136 {
137 if(bmpobj.GetPixel(i, j).R<255)
138 bmpobj.SetPixel(i, j, Color.White);
139 continue;
140 }
141
142 //获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表
143 for (m = 0; m < 5; m++)
144 {
145 for (n = 0; n < 5; n++)
146 {
147 neighbour[m, n] = bmpobj.GetPixel(i + m - 2, j + n - 2).R < dgGrayValue ? 1 : 0;
148 }
149 }
150
151 //逐个判断条件。
152 //判断2<=NZ(P1)<=6
153 nCount = neighbour[1, 1] + neighbour[1, 2] + neighbour[1, 3]
154 + neighbour[2, 1] + neighbour[2, 3] +
155 +neighbour[3, 1] + neighbour[3, 2] + neighbour[3, 3];
156 if (nCount >= 2 && nCount <= 6)
157 {
158 bCondition1 = true;
159 }
160
161 //判断Z0(P1)=1
162 nCount = 0;
163 if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1)
164 nCount++;
165 if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1)
166 nCount++;
167 if (neighbour[2, 1] == 0 && neighbour[3, 1] == 1)
168 nCount++;
169 if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1)
170 nCount++;
171 if (neighbour[3, 2] == 0 && neighbour[3, 3] == 1)
172 nCount++;
173 if (neighbour[3, 3] == 0 && neighbour[2, 3] == 1)
174 nCount++;
175 if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1)
176 nCount++;
177 if (neighbour[1, 3] == 0 && neighbour[1, 2] == 1)
178 nCount++;
179 if (nCount == 1)
180 bCondition2 = true;
181
182 //判断P2*P4*P8=0 or Z0(p2)!=1
183 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[2, 3] == 0)
184 {
185 bCondition3 = true;
186 }
187 else
188 {
189 nCount = 0;
190 if (neighbour[0, 2] == 0 && neighbour[0, 1] == 1)
191 nCount++;
192 if (neighbour[0, 1] == 0 && neighbour[1, 1] == 1)
193 nCount++;
194 if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1)
195 nCount++;
196 if (neighbour[2, 1] == 0 && neighbour[2, 2] == 1)
197 nCount++;
198 if (neighbour[2, 2] == 0 && neighbour[2, 3] == 1)
199 nCount++;
200 if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1)
201 nCount++;
202 if (neighbour[1, 3] == 0 && neighbour[0, 3] == 1)
203 nCount++;
204 if (neighbour[0, 3] == 0 && neighbour[0, 2] == 1)
205 nCount++;
206 if (nCount != 1)
207 bCondition3 = true;
208 }
209
210 //判断P2*P4*P6=0 or Z0(p4)!=1
211 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[3, 2] == 0)
212 {
213 bCondition4 = true;
214 }
215 else
216 {
217 nCount = 0;
218 if (neighbour[1, 1] == 0 && neighbour[1, 0] == 1)
219 nCount++;
220 if (neighbour[1, 0] == 0 && neighbour[2, 0] == 1)
221 nCount++;
222 if (neighbour[2, 0] == 0 && neighbour[3, 0] == 1)
223 nCount++;
224 if (neighbour[3, 0] == 0 && neighbour[3, 1] == 1)
225 nCount++;
226 if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1)
227 nCount++;
228 if (neighbour[3, 2] == 0 && neighbour[2, 2] == 1)
229 nCount++;
230 if (neighbour[2, 2] == 0 && neighbour[1, 2] == 1)
231 nCount++;
232 if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1)
233 nCount++;
234 if (nCount != 1)
235 bCondition4 = true;
236 }
237
238 if (bCondition1 && bCondition2 && bCondition3 && bCondition4)
239 {
240 bmpobj.SetPixel(i, j, Color.White);
241 bModified = true;
242 }
243 else
244 {
245 bmpobj.SetPixel(i, j, Color.Black);
246 }
247 }
248 }
249 }
250 // 复制细化后的图像
251 // bmpobj = newBmp;
252 }
253