/src/leptonica/src/dwacomb.2.c
Line | Count | Source |
1 | | /*====================================================================* |
2 | | - Copyright (C) 2001 Leptonica. All rights reserved. |
3 | | - |
4 | | - Redistribution and use in source and binary forms, with or without |
5 | | - modification, are permitted provided that the following conditions |
6 | | - are met: |
7 | | - 1. Redistributions of source code must retain the above copyright |
8 | | - notice, this list of conditions and the following disclaimer. |
9 | | - 2. Redistributions in binary form must reproduce the above |
10 | | - copyright notice, this list of conditions and the following |
11 | | - disclaimer in the documentation and/or other materials |
12 | | - provided with the distribution. |
13 | | - |
14 | | - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 | | - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
16 | | - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
17 | | - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY |
18 | | - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | | - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | | - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | | - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | | - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
23 | | - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
24 | | - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | *====================================================================*/ |
26 | | |
27 | | /*! |
28 | | * Top-level fast binary morphology with auto-generated sels |
29 | | * |
30 | | * PIX *pixMorphDwa_2() |
31 | | * PIX *pixFMorphopGen_2() |
32 | | */ |
33 | | |
34 | | #ifdef HAVE_CONFIG_H |
35 | | #include <config_auto.h> |
36 | | #endif /* HAVE_CONFIG_H */ |
37 | | |
38 | | #include <string.h> |
39 | | #include "allheaders.h" |
40 | | |
41 | | PIX *pixMorphDwa_2(PIX *pixd, PIX *pixs, l_int32 operation, char *selname); |
42 | | PIX *pixFMorphopGen_2(PIX *pixd, PIX *pixs, l_int32 operation, char *selname); |
43 | | l_int32 fmorphopgen_low_2(l_uint32 *datad, l_int32 w, |
44 | | l_int32 h, l_int32 wpld, |
45 | | l_uint32 *datas, l_int32 wpls, |
46 | | l_int32 index); |
47 | | |
48 | | static l_int32 NUM_SELS_GENERATED = 76; |
49 | | static char SEL_NAMES[][80] = { |
50 | | "sel_comb_4h", |
51 | | "sel_comb_4v", |
52 | | "sel_comb_5h", |
53 | | "sel_comb_5v", |
54 | | "sel_comb_6h", |
55 | | "sel_comb_6v", |
56 | | "sel_comb_7h", |
57 | | "sel_comb_7v", |
58 | | "sel_comb_8h", |
59 | | "sel_comb_8v", |
60 | | "sel_comb_9h", |
61 | | "sel_comb_9v", |
62 | | "sel_comb_10h", |
63 | | "sel_comb_10v", |
64 | | "sel_comb_12h", |
65 | | "sel_comb_12v", |
66 | | "sel_comb_14h", |
67 | | "sel_comb_14v", |
68 | | "sel_comb_15h", |
69 | | "sel_comb_15v", |
70 | | "sel_comb_16h", |
71 | | "sel_comb_16v", |
72 | | "sel_comb_18h", |
73 | | "sel_comb_18v", |
74 | | "sel_comb_20h", |
75 | | "sel_comb_20v", |
76 | | "sel_comb_21h", |
77 | | "sel_comb_21v", |
78 | | "sel_comb_22h", |
79 | | "sel_comb_22v", |
80 | | "sel_comb_24h", |
81 | | "sel_comb_24v", |
82 | | "sel_comb_25h", |
83 | | "sel_comb_25v", |
84 | | "sel_comb_27h", |
85 | | "sel_comb_27v", |
86 | | "sel_comb_28h", |
87 | | "sel_comb_28v", |
88 | | "sel_comb_30h", |
89 | | "sel_comb_30v", |
90 | | "sel_comb_32h", |
91 | | "sel_comb_32v", |
92 | | "sel_comb_33h", |
93 | | "sel_comb_33v", |
94 | | "sel_comb_35h", |
95 | | "sel_comb_35v", |
96 | | "sel_comb_36h", |
97 | | "sel_comb_36v", |
98 | | "sel_comb_39h", |
99 | | "sel_comb_39v", |
100 | | "sel_comb_40h", |
101 | | "sel_comb_40v", |
102 | | "sel_comb_42h", |
103 | | "sel_comb_42v", |
104 | | "sel_comb_44h", |
105 | | "sel_comb_44v", |
106 | | "sel_comb_45h", |
107 | | "sel_comb_45v", |
108 | | "sel_comb_48h", |
109 | | "sel_comb_48v", |
110 | | "sel_comb_49h", |
111 | | "sel_comb_49v", |
112 | | "sel_comb_50h", |
113 | | "sel_comb_50v", |
114 | | "sel_comb_52h", |
115 | | "sel_comb_52v", |
116 | | "sel_comb_54h", |
117 | | "sel_comb_54v", |
118 | | "sel_comb_55h", |
119 | | "sel_comb_55v", |
120 | | "sel_comb_56h", |
121 | | "sel_comb_56v", |
122 | | "sel_comb_60h", |
123 | | "sel_comb_60v", |
124 | | "sel_comb_63h", |
125 | | "sel_comb_63v"}; |
126 | | |
127 | | /*! |
128 | | * \brief pixMorphDwa_2() |
129 | | * |
130 | | * \param[in] pixd usual 3 choices: null, == pixs, != pixs |
131 | | * \param[in] pixs 1 bpp |
132 | | * \param[in] operation L_MORPH_DILATE, L_MORPH_ERODE, |
133 | | * L_MORPH_OPEN, L_MORPH_CLOSE |
134 | | * \param[in] sel name |
135 | | * \return pixd |
136 | | * |
137 | | * <pre> |
138 | | * Notes: |
139 | | * (1) This simply adds a border, calls the appropriate |
140 | | * pixFMorphopGen_*(), and removes the border. |
141 | | * See the notes for that function. |
142 | | * (2) The size of the border depends on the operation |
143 | | * and the boundary conditions. |
144 | | * </pre> |
145 | | */ |
146 | | PIX * |
147 | | pixMorphDwa_2(PIX *pixd, |
148 | | PIX *pixs, |
149 | | l_int32 operation, |
150 | | char *selname) |
151 | 0 | { |
152 | 0 | l_int32 bordercolor, bordersize; |
153 | 0 | PIX *pixt1, *pixt2, *pixt3; |
154 | |
|
155 | 0 | if (!pixs) |
156 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd); |
157 | 0 | if (pixGetDepth(pixs) != 1) |
158 | 0 | return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, pixd); |
159 | | |
160 | | /* Set the border size */ |
161 | 0 | bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1); |
162 | 0 | bordersize = 32; |
163 | 0 | if (bordercolor == 0 && operation == L_MORPH_CLOSE) |
164 | 0 | bordersize += 32; |
165 | |
|
166 | 0 | pixt1 = pixAddBorder(pixs, bordersize, 0); |
167 | 0 | pixt2 = pixFMorphopGen_2(NULL, pixt1, operation, selname); |
168 | 0 | pixt3 = pixRemoveBorder(pixt2, bordersize); |
169 | 0 | pixDestroy(&pixt1); |
170 | 0 | pixDestroy(&pixt2); |
171 | |
|
172 | 0 | if (!pixd) |
173 | 0 | return pixt3; |
174 | | |
175 | 0 | pixCopy(pixd, pixt3); |
176 | 0 | pixDestroy(&pixt3); |
177 | 0 | return pixd; |
178 | 0 | } |
179 | | |
180 | | |
181 | | /*! |
182 | | * \brief pixFMorphopGen_2() |
183 | | * |
184 | | * \param[in] pixd usual 3 choices: null, == pixs, != pixs |
185 | | * \param[in] pixs 1 bpp |
186 | | * \param[in] operation L_MORPH_DILATE, L_MORPH_ERODE, |
187 | | * L_MORPH_OPEN, L_MORPH_CLOSE |
188 | | * \param[in] sel name |
189 | | * \return pixd |
190 | | * |
191 | | * <pre> |
192 | | * Notes: |
193 | | * (1) This is a dwa operation, and the Sels must be limited in |
194 | | * size to not more than 31 pixels about the origin. |
195 | | * (2) A border of appropriate size (32 pixels, or 64 pixels |
196 | | * for safe closing with asymmetric b.c.) must be added before |
197 | | * this function is called. |
198 | | * (3) This handles all required setting of the border pixels |
199 | | * before erosion and dilation. |
200 | | * (4) The closing operation is safe; no pixels can be removed |
201 | | * near the boundary. |
202 | | * </pre> |
203 | | */ |
204 | | PIX * |
205 | | pixFMorphopGen_2(PIX *pixd, |
206 | | PIX *pixs, |
207 | | l_int32 operation, |
208 | | char *selname) |
209 | 0 | { |
210 | 0 | l_int32 i, index, found, w, h, wpls, wpld, bordercolor, erodeop, borderop; |
211 | 0 | l_uint32 *datad, *datas, *datat; |
212 | 0 | PIX *pixt; |
213 | |
|
214 | 0 | if (!pixs) |
215 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd); |
216 | 0 | if (pixGetDepth(pixs) != 1) |
217 | 0 | return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, pixd); |
218 | | |
219 | | /* Get boundary colors to use */ |
220 | 0 | bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1); |
221 | 0 | if (bordercolor == 1) |
222 | 0 | erodeop = PIX_SET; |
223 | 0 | else |
224 | 0 | erodeop = PIX_CLR; |
225 | |
|
226 | 0 | found = FALSE; |
227 | 0 | for (i = 0; i < NUM_SELS_GENERATED; i++) { |
228 | 0 | if (strcmp(selname, SEL_NAMES[i]) == 0) { |
229 | 0 | found = TRUE; |
230 | 0 | index = 2 * i; |
231 | 0 | break; |
232 | 0 | } |
233 | 0 | } |
234 | 0 | if (found == FALSE) |
235 | 0 | return (PIX *)ERROR_PTR("sel index not found", __func__, pixd); |
236 | | |
237 | 0 | if (!pixd) { |
238 | 0 | if ((pixd = pixCreateTemplate(pixs)) == NULL) |
239 | 0 | return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); |
240 | 0 | } |
241 | 0 | else /* for in-place or pre-allocated */ |
242 | 0 | pixResizeImageData(pixd, pixs); |
243 | 0 | wpls = pixGetWpl(pixs); |
244 | 0 | wpld = pixGetWpl(pixd); |
245 | | |
246 | | /* The images must be surrounded, in advance, with a border of |
247 | | * size 32 pixels (or 64, for closing), that we'll read from. |
248 | | * Fabricate a "proper" image as the subimage within the 32 |
249 | | * pixel border, having the following parameters: */ |
250 | 0 | w = pixGetWidth(pixs) - 64; |
251 | 0 | h = pixGetHeight(pixs) - 64; |
252 | 0 | datas = pixGetData(pixs) + 32 * wpls + 1; |
253 | 0 | datad = pixGetData(pixd) + 32 * wpld + 1; |
254 | |
|
255 | 0 | if (operation == L_MORPH_DILATE || operation == L_MORPH_ERODE) { |
256 | 0 | borderop = PIX_CLR; |
257 | 0 | if (operation == L_MORPH_ERODE) { |
258 | 0 | borderop = erodeop; |
259 | 0 | index++; |
260 | 0 | } |
261 | 0 | if (pixd == pixs) { /* in-place; generate a temp image */ |
262 | 0 | if ((pixt = pixCopy(NULL, pixs)) == NULL) |
263 | 0 | return (PIX *)ERROR_PTR("pixt not made", __func__, pixd); |
264 | 0 | datat = pixGetData(pixt) + 32 * wpls + 1; |
265 | 0 | pixSetOrClearBorder(pixt, 32, 32, 32, 32, borderop); |
266 | 0 | fmorphopgen_low_2(datad, w, h, wpld, datat, wpls, index); |
267 | 0 | pixDestroy(&pixt); |
268 | 0 | } |
269 | 0 | else { /* not in-place */ |
270 | 0 | pixSetOrClearBorder(pixs, 32, 32, 32, 32, borderop); |
271 | 0 | fmorphopgen_low_2(datad, w, h, wpld, datas, wpls, index); |
272 | 0 | } |
273 | 0 | } |
274 | 0 | else { /* opening or closing; generate a temp image */ |
275 | 0 | if ((pixt = pixCreateTemplate(pixs)) == NULL) |
276 | 0 | return (PIX *)ERROR_PTR("pixt not made", __func__, pixd); |
277 | 0 | datat = pixGetData(pixt) + 32 * wpls + 1; |
278 | 0 | if (operation == L_MORPH_OPEN) { |
279 | 0 | pixSetOrClearBorder(pixs, 32, 32, 32, 32, erodeop); |
280 | 0 | fmorphopgen_low_2(datat, w, h, wpls, datas, wpls, index+1); |
281 | 0 | pixSetOrClearBorder(pixt, 32, 32, 32, 32, PIX_CLR); |
282 | 0 | fmorphopgen_low_2(datad, w, h, wpld, datat, wpls, index); |
283 | 0 | } |
284 | 0 | else { /* closing */ |
285 | 0 | pixSetOrClearBorder(pixs, 32, 32, 32, 32, PIX_CLR); |
286 | 0 | fmorphopgen_low_2(datat, w, h, wpls, datas, wpls, index); |
287 | 0 | pixSetOrClearBorder(pixt, 32, 32, 32, 32, erodeop); |
288 | 0 | fmorphopgen_low_2(datad, w, h, wpld, datat, wpls, index+1); |
289 | 0 | } |
290 | 0 | pixDestroy(&pixt); |
291 | 0 | } |
292 | | |
293 | 0 | return pixd; |
294 | 0 | } |
295 | | |