/src/leptonica/src/fmorphgen.1.c
Line | Count | Source (jump to first uncovered line) |
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_1() |
31 | | * PIX *pixFMorphopGen_1() |
32 | | */ |
33 | | |
34 | | #include <string.h> |
35 | | #include "allheaders.h" |
36 | | |
37 | | PIX *pixMorphDwa_1(PIX *pixd, PIX *pixs, l_int32 operation, char *selname); |
38 | | PIX *pixFMorphopGen_1(PIX *pixd, PIX *pixs, l_int32 operation, char *selname); |
39 | | l_int32 fmorphopgen_low_1(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 = 58; |
45 | | static char SEL_NAMES[][80] = { |
46 | | "sel_2h", |
47 | | "sel_3h", |
48 | | "sel_4h", |
49 | | "sel_5h", |
50 | | "sel_6h", |
51 | | "sel_7h", |
52 | | "sel_8h", |
53 | | "sel_9h", |
54 | | "sel_10h", |
55 | | "sel_11h", |
56 | | "sel_12h", |
57 | | "sel_13h", |
58 | | "sel_14h", |
59 | | "sel_15h", |
60 | | "sel_20h", |
61 | | "sel_21h", |
62 | | "sel_25h", |
63 | | "sel_30h", |
64 | | "sel_31h", |
65 | | "sel_35h", |
66 | | "sel_40h", |
67 | | "sel_41h", |
68 | | "sel_45h", |
69 | | "sel_50h", |
70 | | "sel_51h", |
71 | | "sel_2v", |
72 | | "sel_3v", |
73 | | "sel_4v", |
74 | | "sel_5v", |
75 | | "sel_6v", |
76 | | "sel_7v", |
77 | | "sel_8v", |
78 | | "sel_9v", |
79 | | "sel_10v", |
80 | | "sel_11v", |
81 | | "sel_12v", |
82 | | "sel_13v", |
83 | | "sel_14v", |
84 | | "sel_15v", |
85 | | "sel_20v", |
86 | | "sel_21v", |
87 | | "sel_25v", |
88 | | "sel_30v", |
89 | | "sel_31v", |
90 | | "sel_35v", |
91 | | "sel_40v", |
92 | | "sel_41v", |
93 | | "sel_45v", |
94 | | "sel_50v", |
95 | | "sel_51v", |
96 | | "sel_2", |
97 | | "sel_3", |
98 | | "sel_4", |
99 | | "sel_5", |
100 | | "sel_2dp", |
101 | | "sel_2dm", |
102 | | "sel_5dp", |
103 | | "sel_5dm"}; |
104 | | |
105 | | /*! |
106 | | * \brief pixMorphDwa_1() |
107 | | * |
108 | | * \param[in] pixd usual 3 choices: null, == pixs, != pixs |
109 | | * \param[in] pixs 1 bpp |
110 | | * \param[in] operation L_MORPH_DILATE, L_MORPH_ERODE, |
111 | | * L_MORPH_OPEN, L_MORPH_CLOSE |
112 | | * \param[in] sel name |
113 | | * \return pixd |
114 | | * |
115 | | * <pre> |
116 | | * Notes: |
117 | | * (1) This simply adds a border, calls the appropriate |
118 | | * pixFMorphopGen_*(), and removes the border. |
119 | | * See the notes for that function. |
120 | | * (2) The size of the border depends on the operation |
121 | | * and the boundary conditions. |
122 | | * </pre> |
123 | | */ |
124 | | PIX * |
125 | | pixMorphDwa_1(PIX *pixd, |
126 | | PIX *pixs, |
127 | | l_int32 operation, |
128 | | char *selname) |
129 | 0 | { |
130 | 0 | l_int32 bordercolor, bordersize; |
131 | 0 | PIX *pixt1, *pixt2, *pixt3; |
132 | |
|
133 | 0 | if (!pixs) |
134 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd); |
135 | 0 | if (pixGetDepth(pixs) != 1) |
136 | 0 | return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, pixd); |
137 | | |
138 | | /* Set the border size */ |
139 | 0 | bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1); |
140 | 0 | bordersize = 32; |
141 | 0 | if (bordercolor == 0 && operation == L_MORPH_CLOSE) |
142 | 0 | bordersize += 32; |
143 | |
|
144 | 0 | pixt1 = pixAddBorder(pixs, bordersize, 0); |
145 | 0 | pixt2 = pixFMorphopGen_1(NULL, pixt1, operation, selname); |
146 | 0 | pixt3 = pixRemoveBorder(pixt2, bordersize); |
147 | 0 | pixDestroy(&pixt1); |
148 | 0 | pixDestroy(&pixt2); |
149 | |
|
150 | 0 | if (!pixd) |
151 | 0 | return pixt3; |
152 | | |
153 | 0 | pixCopy(pixd, pixt3); |
154 | 0 | pixDestroy(&pixt3); |
155 | 0 | return pixd; |
156 | 0 | } |
157 | | |
158 | | |
159 | | /*! |
160 | | * \brief pixFMorphopGen_1() |
161 | | * |
162 | | * \param[in] pixd usual 3 choices: null, == pixs, != pixs |
163 | | * \param[in] pixs 1 bpp |
164 | | * \param[in] operation L_MORPH_DILATE, L_MORPH_ERODE, |
165 | | * L_MORPH_OPEN, L_MORPH_CLOSE |
166 | | * \param[in] sel name |
167 | | * \return pixd |
168 | | * |
169 | | * <pre> |
170 | | * Notes: |
171 | | * (1) This is a dwa operation, and the Sels must be limited in |
172 | | * size to not more than 31 pixels about the origin. |
173 | | * (2) A border of appropriate size (32 pixels, or 64 pixels |
174 | | * for safe closing with asymmetric b.c.) must be added before |
175 | | * this function is called. |
176 | | * (3) This handles all required setting of the border pixels |
177 | | * before erosion and dilation. |
178 | | * (4) The closing operation is safe; no pixels can be removed |
179 | | * near the boundary. |
180 | | * </pre> |
181 | | */ |
182 | | PIX * |
183 | | pixFMorphopGen_1(PIX *pixd, |
184 | | PIX *pixs, |
185 | | l_int32 operation, |
186 | | char *selname) |
187 | 0 | { |
188 | 0 | l_int32 i, index, found, w, h, wpls, wpld, bordercolor, erodeop, borderop; |
189 | 0 | l_uint32 *datad, *datas, *datat; |
190 | 0 | PIX *pixt; |
191 | |
|
192 | 0 | if (!pixs) |
193 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd); |
194 | 0 | if (pixGetDepth(pixs) != 1) |
195 | 0 | return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, pixd); |
196 | | |
197 | | /* Get boundary colors to use */ |
198 | 0 | bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1); |
199 | 0 | if (bordercolor == 1) |
200 | 0 | erodeop = PIX_SET; |
201 | 0 | else |
202 | 0 | erodeop = PIX_CLR; |
203 | |
|
204 | 0 | found = FALSE; |
205 | 0 | for (i = 0; i < NUM_SELS_GENERATED; i++) { |
206 | 0 | if (strcmp(selname, SEL_NAMES[i]) == 0) { |
207 | 0 | found = TRUE; |
208 | 0 | index = 2 * i; |
209 | 0 | break; |
210 | 0 | } |
211 | 0 | } |
212 | 0 | if (found == FALSE) |
213 | 0 | return (PIX *)ERROR_PTR("sel index not found", __func__, pixd); |
214 | | |
215 | 0 | if (!pixd) { |
216 | 0 | if ((pixd = pixCreateTemplate(pixs)) == NULL) |
217 | 0 | return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); |
218 | 0 | } |
219 | 0 | else /* for in-place or pre-allocated */ |
220 | 0 | pixResizeImageData(pixd, pixs); |
221 | 0 | wpls = pixGetWpl(pixs); |
222 | 0 | wpld = pixGetWpl(pixd); |
223 | | |
224 | | /* The images must be surrounded, in advance, with a border of |
225 | | * size 32 pixels (or 64, for closing), that we'll read from. |
226 | | * Fabricate a "proper" image as the subimage within the 32 |
227 | | * pixel border, having the following parameters: */ |
228 | 0 | w = pixGetWidth(pixs) - 64; |
229 | 0 | h = pixGetHeight(pixs) - 64; |
230 | 0 | datas = pixGetData(pixs) + 32 * wpls + 1; |
231 | 0 | datad = pixGetData(pixd) + 32 * wpld + 1; |
232 | |
|
233 | 0 | if (operation == L_MORPH_DILATE || operation == L_MORPH_ERODE) { |
234 | 0 | borderop = PIX_CLR; |
235 | 0 | if (operation == L_MORPH_ERODE) { |
236 | 0 | borderop = erodeop; |
237 | 0 | index++; |
238 | 0 | } |
239 | 0 | if (pixd == pixs) { /* in-place; generate a temp image */ |
240 | 0 | if ((pixt = pixCopy(NULL, pixs)) == NULL) |
241 | 0 | return (PIX *)ERROR_PTR("pixt not made", __func__, pixd); |
242 | 0 | datat = pixGetData(pixt) + 32 * wpls + 1; |
243 | 0 | pixSetOrClearBorder(pixt, 32, 32, 32, 32, borderop); |
244 | 0 | fmorphopgen_low_1(datad, w, h, wpld, datat, wpls, index); |
245 | 0 | pixDestroy(&pixt); |
246 | 0 | } |
247 | 0 | else { /* not in-place */ |
248 | 0 | pixSetOrClearBorder(pixs, 32, 32, 32, 32, borderop); |
249 | 0 | fmorphopgen_low_1(datad, w, h, wpld, datas, wpls, index); |
250 | 0 | } |
251 | 0 | } |
252 | 0 | else { /* opening or closing; generate a temp image */ |
253 | 0 | if ((pixt = pixCreateTemplate(pixs)) == NULL) |
254 | 0 | return (PIX *)ERROR_PTR("pixt not made", __func__, pixd); |
255 | 0 | datat = pixGetData(pixt) + 32 * wpls + 1; |
256 | 0 | if (operation == L_MORPH_OPEN) { |
257 | 0 | pixSetOrClearBorder(pixs, 32, 32, 32, 32, erodeop); |
258 | 0 | fmorphopgen_low_1(datat, w, h, wpls, datas, wpls, index+1); |
259 | 0 | pixSetOrClearBorder(pixt, 32, 32, 32, 32, PIX_CLR); |
260 | 0 | fmorphopgen_low_1(datad, w, h, wpld, datat, wpls, index); |
261 | 0 | } |
262 | 0 | else { /* closing */ |
263 | 0 | pixSetOrClearBorder(pixs, 32, 32, 32, 32, PIX_CLR); |
264 | 0 | fmorphopgen_low_1(datat, w, h, wpls, datas, wpls, index); |
265 | 0 | pixSetOrClearBorder(pixt, 32, 32, 32, 32, erodeop); |
266 | 0 | fmorphopgen_low_1(datad, w, h, wpld, datat, wpls, index+1); |
267 | 0 | } |
268 | 0 | pixDestroy(&pixt); |
269 | 0 | } |
270 | | |
271 | 0 | return pixd; |
272 | 0 | } |
273 | | |