Coverage Report

Created: 2025-09-27 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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