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 * \brief Top-level fast binary morphology with auto-generated sels
29 *
30 * PIX *pixMorphDwa_2()
31 * PIX *pixFMorphopGen_2()
32 */
33
34 #include <string.h>
35 #include "allheaders.h"
36
37 PIX *pixMorphDwa_2(PIX *pixd, PIX *pixs, l_int32 operation, char *selname);
38 PIX *pixFMorphopGen_2(PIX *pixd, PIX *pixs, l_int32 operation, char *selname);
39 l_int32 fmorphopgen_low_2(l_uint32 *datad, l_int32 w,
40 l_int32 h, l_int32 wpld,
41 l_uint32 *datas, l_int32 wpls,
42 l_int32 index);
43
44 static l_int32 NUM_SELS_GENERATED = 76;
45 static char SEL_NAMES[][80] = {
46 "sel_comb_4h",
47 "sel_comb_4v",
48 "sel_comb_5h",
49 "sel_comb_5v",
50 "sel_comb_6h",
51 "sel_comb_6v",
52 "sel_comb_7h",
53 "sel_comb_7v",
54 "sel_comb_8h",
55 "sel_comb_8v",
56 "sel_comb_9h",
57 "sel_comb_9v",
58 "sel_comb_10h",
59 "sel_comb_10v",
60 "sel_comb_12h",
61 "sel_comb_12v",
62 "sel_comb_14h",
63 "sel_comb_14v",
64 "sel_comb_15h",
65 "sel_comb_15v",
66 "sel_comb_16h",
67 "sel_comb_16v",
68 "sel_comb_18h",
69 "sel_comb_18v",
70 "sel_comb_20h",
71 "sel_comb_20v",
72 "sel_comb_21h",
73 "sel_comb_21v",
74 "sel_comb_22h",
75 "sel_comb_22v",
76 "sel_comb_24h",
77 "sel_comb_24v",
78 "sel_comb_25h",
79 "sel_comb_25v",
80 "sel_comb_27h",
81 "sel_comb_27v",
82 "sel_comb_28h",
83 "sel_comb_28v",
84 "sel_comb_30h",
85 "sel_comb_30v",
86 "sel_comb_32h",
87 "sel_comb_32v",
88 "sel_comb_33h",
89 "sel_comb_33v",
90 "sel_comb_35h",
91 "sel_comb_35v",
92 "sel_comb_36h",
93 "sel_comb_36v",
94 "sel_comb_39h",
95 "sel_comb_39v",
96 "sel_comb_40h",
97 "sel_comb_40v",
98 "sel_comb_42h",
99 "sel_comb_42v",
100 "sel_comb_44h",
101 "sel_comb_44v",
102 "sel_comb_45h",
103 "sel_comb_45v",
104 "sel_comb_48h",
105 "sel_comb_48v",
106 "sel_comb_49h",
107 "sel_comb_49v",
108 "sel_comb_50h",
109 "sel_comb_50v",
110 "sel_comb_52h",
111 "sel_comb_52v",
112 "sel_comb_54h",
113 "sel_comb_54v",
114 "sel_comb_55h",
115 "sel_comb_55v",
116 "sel_comb_56h",
117 "sel_comb_56v",
118 "sel_comb_60h",
119 "sel_comb_60v",
120 "sel_comb_63h",
121 "sel_comb_63v"};
122
123 /*!
124 * \brief pixMorphDwa_2()
125 *
126 * \param[in] pixd usual 3 choices: null, == pixs, != pixs
127 * \param[in] pixs 1 bpp
128 * \param[in] operation L_MORPH_DILATE, L_MORPH_ERODE,
129 * L_MORPH_OPEN, L_MORPH_CLOSE
130 * \param[in] sel name
131 * \return pixd
132 *
133 * <pre>
134 * Notes:
135 * (1) This simply adds a border, calls the appropriate
136 * pixFMorphopGen_*(), and removes the border.
137 * See the notes for that function.
138 * (2) The size of the border depends on the operation
139 * and the boundary conditions.
140 * </pre>
141 */
142 PIX *
pixMorphDwa_2(PIX * pixd,PIX * pixs,l_int32 operation,char * selname)143 pixMorphDwa_2(PIX *pixd,
144 PIX *pixs,
145 l_int32 operation,
146 char *selname)
147 {
148 l_int32 bordercolor, bordersize;
149 PIX *pixt1, *pixt2, *pixt3;
150
151 PROCNAME("pixMorphDwa_2");
152
153 if (!pixs)
154 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
155 if (pixGetDepth(pixs) != 1)
156 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);
157
158 /* Set the border size */
159 bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
160 bordersize = 32;
161 if (bordercolor == 0 && operation == L_MORPH_CLOSE)
162 bordersize += 32;
163
164 pixt1 = pixAddBorder(pixs, bordersize, 0);
165 pixt2 = pixFMorphopGen_2(NULL, pixt1, operation, selname);
166 pixt3 = pixRemoveBorder(pixt2, bordersize);
167 pixDestroy(&pixt1);
168 pixDestroy(&pixt2);
169
170 if (!pixd)
171 return pixt3;
172
173 pixCopy(pixd, pixt3);
174 pixDestroy(&pixt3);
175 return pixd;
176 }
177
178
179 /*!
180 * \brief pixFMorphopGen_2()
181 *
182 * \param[in] pixd usual 3 choices: null, == pixs, != pixs
183 * \param[in] pixs 1 bpp
184 * \param[in] operation L_MORPH_DILATE, L_MORPH_ERODE,
185 * L_MORPH_OPEN, L_MORPH_CLOSE
186 * \param[in] sel name
187 * \return pixd
188 *
189 * <pre>
190 * Notes:
191 * (1) This is a dwa operation, and the Sels must be limited in
192 * size to not more than 31 pixels about the origin.
193 * (2) A border of appropriate size (32 pixels, or 64 pixels
194 * for safe closing with asymmetric b.c.) must be added before
195 * this function is called.
196 * (3) This handles all required setting of the border pixels
197 * before erosion and dilation.
198 * (4) The closing operation is safe; no pixels can be removed
199 * near the boundary.
200 * </pre>
201 */
202 PIX *
pixFMorphopGen_2(PIX * pixd,PIX * pixs,l_int32 operation,char * selname)203 pixFMorphopGen_2(PIX *pixd,
204 PIX *pixs,
205 l_int32 operation,
206 char *selname)
207 {
208 l_int32 i, index, found, w, h, wpls, wpld, bordercolor, erodeop, borderop;
209 l_uint32 *datad, *datas, *datat;
210 PIX *pixt;
211
212 PROCNAME("pixFMorphopGen_2");
213
214 if (!pixs)
215 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
216 if (pixGetDepth(pixs) != 1)
217 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);
218
219 /* Get boundary colors to use */
220 bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
221 if (bordercolor == 1)
222 erodeop = PIX_SET;
223 else
224 erodeop = PIX_CLR;
225
226 found = FALSE;
227 for (i = 0; i < NUM_SELS_GENERATED; i++) {
228 if (strcmp(selname, SEL_NAMES[i]) == 0) {
229 found = TRUE;
230 index = 2 * i;
231 break;
232 }
233 }
234 if (found == FALSE)
235 return (PIX *)ERROR_PTR("sel index not found", procName, pixd);
236
237 if (!pixd) {
238 if ((pixd = pixCreateTemplate(pixs)) == NULL)
239 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
240 }
241 else /* for in-place or pre-allocated */
242 pixResizeImageData(pixd, pixs);
243 wpls = pixGetWpl(pixs);
244 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 w = pixGetWidth(pixs) - 64;
251 h = pixGetHeight(pixs) - 64;
252 datas = pixGetData(pixs) + 32 * wpls + 1;
253 datad = pixGetData(pixd) + 32 * wpld + 1;
254
255 if (operation == L_MORPH_DILATE || operation == L_MORPH_ERODE) {
256 borderop = PIX_CLR;
257 if (operation == L_MORPH_ERODE) {
258 borderop = erodeop;
259 index++;
260 }
261 if (pixd == pixs) { /* in-place; generate a temp image */
262 if ((pixt = pixCopy(NULL, pixs)) == NULL)
263 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
264 datat = pixGetData(pixt) + 32 * wpls + 1;
265 pixSetOrClearBorder(pixt, 32, 32, 32, 32, borderop);
266 fmorphopgen_low_2(datad, w, h, wpld, datat, wpls, index);
267 pixDestroy(&pixt);
268 }
269 else { /* not in-place */
270 pixSetOrClearBorder(pixs, 32, 32, 32, 32, borderop);
271 fmorphopgen_low_2(datad, w, h, wpld, datas, wpls, index);
272 }
273 }
274 else { /* opening or closing; generate a temp image */
275 if ((pixt = pixCreateTemplate(pixs)) == NULL)
276 return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
277 datat = pixGetData(pixt) + 32 * wpls + 1;
278 if (operation == L_MORPH_OPEN) {
279 pixSetOrClearBorder(pixs, 32, 32, 32, 32, erodeop);
280 fmorphopgen_low_2(datat, w, h, wpls, datas, wpls, index+1);
281 pixSetOrClearBorder(pixt, 32, 32, 32, 32, PIX_CLR);
282 fmorphopgen_low_2(datad, w, h, wpld, datat, wpls, index);
283 }
284 else { /* closing */
285 pixSetOrClearBorder(pixs, 32, 32, 32, 32, PIX_CLR);
286 fmorphopgen_low_2(datat, w, h, wpls, datas, wpls, index);
287 pixSetOrClearBorder(pixt, 32, 32, 32, 32, erodeop);
288 fmorphopgen_low_2(datad, w, h, wpld, datat, wpls, index+1);
289 }
290 pixDestroy(&pixt);
291 }
292
293 return pixd;
294 }
295