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