• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 
17 /*
18  *  sel2.c
19  *
20  *      Contains definitions of simple structuring elements
21  *
22  *          SELA    *selaAddBasic()
23  *               Linear horizontal and vertical
24  *               Square
25  *               Diagonals
26  *
27  *          SELA    *selaAddHitMiss()
28  *               Isolated foreground pixel
29  *               Horizontal and vertical edges
30  *               Slanted edge
31  *
32  *          SELA    *selaAddDwaLinear()
33  *          SELA    *selaAddDwaCombs()
34  *          SELA    *selaAddCrossJunctions()
35  *          SELA    *selaAddTJunctions()
36  */
37 
38 #include <stdio.h>
39 #include <math.h>
40 #include "allheaders.h"
41 
42     /* MSVC can't handle arrays dimensioned by static const integers */
43 #define  L_BUF_SIZE  512
44 
45     /* Linear brick sel sizes, including all those that are required
46      * for decomposable sels up to size 63. */
47 static const l_int32  num_linear = 25;
48 static const l_int32  basic_linear[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20, 21, 25, 30, 31, 35, 40, 41, 45, 50, 51};
49 
50 
51 /*!
52  *  selaAddBasic()
53  *
54  *      Input:  sela (<optional>)
55  *      Return: sela with additional sels, or null on error
56  *
57  *  Notes:
58  *      (1) Adds the following sels:
59  *            - all linear (horiz, vert) brick sels that are
60  *              necessary for decomposable sels up to size 63
61  *            - square brick sels up to size 10
62  *            - 4 diagonal sels
63  */
64 SELA *
selaAddBasic(SELA * sela)65 selaAddBasic(SELA  *sela)
66 {
67 char     name[L_BUF_SIZE];
68 l_int32  i, size;
69 SEL     *sel;
70 
71     PROCNAME("selaAddBasic");
72 
73     if (!sela) {
74         if ((sela = selaCreate(0)) == NULL)
75             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
76     }
77 
78     /*--------------------------------------------------------------*
79      *             Linear horizontal and vertical sels              *
80      *--------------------------------------------------------------*/
81     for (i = 0; i < num_linear; i++) {
82         size = basic_linear[i];
83         sel = selCreateBrick(1, size, 0, size / 2, 1);
84         snprintf(name, L_BUF_SIZE, "sel_%dh", size);
85         selaAddSel(sela, sel, name, 0);
86     }
87     for (i = 0; i < num_linear; i++) {
88         size = basic_linear[i];
89         sel = selCreateBrick(size, 1, size / 2, 0, 1);
90         snprintf(name, L_BUF_SIZE, "sel_%dv", size);
91         selaAddSel(sela, sel, name, 0);
92     }
93 
94     /*-----------------------------------------------------------*
95      *                      2-d Bricks                           *
96      *-----------------------------------------------------------*/
97     for (i = 2; i <= 5; i++) {
98         sel = selCreateBrick(i, i, i / 2, i / 2, 1);
99         snprintf(name, L_BUF_SIZE, "sel_%d", i);
100         selaAddSel(sela, sel, name, 0);
101     }
102 
103     /*-----------------------------------------------------------*
104      *                        Diagonals                          *
105      *-----------------------------------------------------------*/
106         /*  0c  1
107             1   0  */
108     sel = selCreateBrick(2, 2, 0, 0, 1);
109     selSetElement(sel, 0, 0, 0);
110     selSetElement(sel, 1, 1, 0);
111     selaAddSel(sela, sel, "sel_2dp", 0);
112 
113         /*  1c  0
114             0   1   */
115     sel = selCreateBrick(2, 2, 0, 0, 1);
116     selSetElement(sel, 0, 1, 0);
117     selSetElement(sel, 1, 0, 0);
118     selaAddSel(sela, sel, "sel_2dm", 0);
119 
120         /*  Diagonal, slope +, size 5 */
121     sel = selCreate(5, 5, "sel_5dp");
122     sel->cy = 2;
123     sel->cx = 2;
124     selSetElement(sel, 0, 4, 1);
125     selSetElement(sel, 1, 3, 1);
126     selSetElement(sel, 2, 2, 1);
127     selSetElement(sel, 3, 1, 1);
128     selSetElement(sel, 4, 0, 1);
129     selaAddSel(sela, sel, "sel_5dp", 0);
130 
131         /*  Diagonal, slope -, size 5 */
132     sel = selCreate(5, 5, "sel_5dm");
133     sel->cy = 2;
134     sel->cx = 2;
135     selSetElement(sel, 0, 0, 1);
136     selSetElement(sel, 1, 1, 1);
137     selSetElement(sel, 2, 2, 1);
138     selSetElement(sel, 3, 3, 1);
139     selSetElement(sel, 4, 4, 1);
140     selaAddSel(sela, sel, "sel_5dm", 0);
141 
142     return sela;
143 }
144 
145 
146 /*!
147  *  selaAddHitMiss()
148  *
149  *      Input:  sela  (<optional>)
150  *      Return: sela with additional sels, or null on error
151  */
152 SELA *
selaAddHitMiss(SELA * sela)153 selaAddHitMiss(SELA  *sela)
154 {
155 SEL  *sel;
156 
157     PROCNAME("selaAddHitMiss");
158 
159     if (!sela) {
160         if ((sela = selaCreate(0)) == NULL)
161             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
162     }
163 
164 #if 0   /*  use just for testing */
165     sel = selCreateBrick(3, 3, 1, 1, 2);
166     selaAddSel(sela, sel, "sel_bad", 0);
167 #endif
168 
169 
170     /*--------------------------------------------------------------*
171      *                   Isolated foreground pixel                  *
172      *--------------------------------------------------------------*/
173     sel = selCreateBrick(3, 3, 1, 1, 2);
174     selSetElement(sel, 1, 1, 1);
175     selaAddSel(sela, sel, "sel_3hm", 0);
176 
177 
178     /*--------------------------------------------------------------*
179      *                Horizontal and vertical edges                 *
180      *--------------------------------------------------------------*/
181     sel = selCreateBrick(2, 3, 0, 1, 1);
182     selSetElement(sel, 1, 0, 2);
183     selSetElement(sel, 1, 1, 2);
184     selSetElement(sel, 1, 2, 2);
185     selaAddSel(sela, sel, "sel_3de", 0);
186 
187     sel = selCreateBrick(2, 3, 1, 1, 1);
188     selSetElement(sel, 0, 0, 2);
189     selSetElement(sel, 0, 1, 2);
190     selSetElement(sel, 0, 2, 2);
191     selaAddSel(sela, sel, "sel_3ue", 0);
192 
193     sel = selCreateBrick(3, 2, 1, 0, 1);
194     selSetElement(sel, 0, 1, 2);
195     selSetElement(sel, 1, 1, 2);
196     selSetElement(sel, 2, 1, 2);
197     selaAddSel(sela, sel, "sel_3re", 0);
198 
199     sel = selCreateBrick(3, 2, 1, 1, 1);
200     selSetElement(sel, 0, 0, 2);
201     selSetElement(sel, 1, 0, 2);
202     selSetElement(sel, 2, 0, 2);
203     selaAddSel(sela, sel, "sel_3le", 0);
204 
205 
206     /*--------------------------------------------------------------*
207      *                       Slanted edge                           *
208      *--------------------------------------------------------------*/
209     sel = selCreateBrick(13, 6, 6, 2, 0);
210     selSetElement(sel, 0, 3, 2);
211     selSetElement(sel, 0, 5, 1);
212     selSetElement(sel, 4, 2, 2);
213     selSetElement(sel, 4, 4, 1);
214     selSetElement(sel, 8, 1, 2);
215     selSetElement(sel, 8, 3, 1);
216     selSetElement(sel, 12, 0, 2);
217     selSetElement(sel, 12, 2, 1);
218     selaAddSel(sela, sel, "sel_sl1", 0);
219 
220     return sela;
221 }
222 
223 
224 /*!
225  *  selaAddDwaLinear()
226  *
227  *      Input:  sela (<optional>)
228  *      Return: sela with additional sels, or null on error
229  *
230  *  Notes:
231  *      (1) Adds all linear (horizontal, vertical) sels from
232  *          2 to 63 pixels in length, which are the sizes over
233  *          which dwa code can be generated.
234  */
235 SELA *
selaAddDwaLinear(SELA * sela)236 selaAddDwaLinear(SELA  *sela)
237 {
238 char     name[L_BUF_SIZE];
239 l_int32  i;
240 SEL     *sel;
241 
242     PROCNAME("selaAddDwaLinear");
243 
244     if (!sela) {
245         if ((sela = selaCreate(0)) == NULL)
246             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
247     }
248 
249     for (i = 2; i < 64; i++) {
250         sel = selCreateBrick(1, i, 0, i / 2, 1);
251         snprintf(name, L_BUF_SIZE, "sel_%dh", i);
252         selaAddSel(sela, sel, name, 0);
253     }
254     for (i = 2; i < 64; i++) {
255         sel = selCreateBrick(i, 1, i / 2, 0, 1);
256         snprintf(name, L_BUF_SIZE, "sel_%dv", i);
257         selaAddSel(sela, sel, name, 0);
258     }
259     return sela;
260 }
261 
262 
263 /*!
264  *  selaAddDwaCombs()
265  *
266  *      Input:  sela (<optional>)
267  *      Return: sela with additional sels, or null on error
268  *
269  *  Notes:
270  *      (1) Adds all comb (horizontal, vertical) Sels that are
271  *          used in composite linear morphological operations
272  *          up to 63 pixels in length, which are the sizes over
273  *          which dwa code can be generated.
274  */
275 SELA *
selaAddDwaCombs(SELA * sela)276 selaAddDwaCombs(SELA  *sela)
277 {
278 char     name[L_BUF_SIZE];
279 l_int32  i, f1, f2, prevsize, size;
280 SEL     *selh, *selv;
281 
282     PROCNAME("selaAddDwaCombs");
283 
284     if (!sela) {
285         if ((sela = selaCreate(0)) == NULL)
286             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
287     }
288 
289     prevsize = 0;
290     for (i = 4; i < 64; i++) {
291         selectComposableSizes(i, &f1, &f2);
292         size = f1 * f2;
293         if (size == prevsize)
294             continue;
295         selectComposableSels(i, L_HORIZ, NULL, &selh);
296         selectComposableSels(i, L_VERT, NULL, &selv);
297         snprintf(name, L_BUF_SIZE, "sel_comb_%dh", size);
298         selaAddSel(sela, selh, name, 0);
299         snprintf(name, L_BUF_SIZE, "sel_comb_%dv", size);
300         selaAddSel(sela, selv, name, 0);
301         prevsize = size;
302     }
303 
304     return sela;
305 }
306 
307 
308 /*!
309  *  selaAddCrossJunctions()
310  *
311  *      Input:  sela (<optional>)
312  *              hlsize (length of each line of hits from origin)
313  *              mdist (distance of misses from the origin)
314  *              norient (number of orientations; max of 8)
315  *              debugflag (1 for debug output)
316  *      Return: sela with additional sels, or null on error
317  *
318  *  Notes:
319  *      (1) Adds hitmiss Sels for the intersection of two lines.
320  *          If the lines are very thin, they must be nearly orthogonal
321  *          to register.
322  *      (2) The number of Sels generated is equal to @norient.
323  *      (3) If @norient == 2, this generates 2 Sels of crosses, each with
324  *          two perpendicular lines of hits.  One Sel has horizontal and
325  *          vertical hits; the other has hits along lines at +-45 degrees.
326  *          Likewise, if @norient == 3, this generates 3 Sels of crosses
327  *          oriented at 30 degrees with each other.
328  *      (4) It is suggested that @hlsize be chosen at least 1 greater
329  *          than @mdist.  Try values of (@hlsize, @mdist) such as
330  *          (6,5), (7,6), (8,7), (9,7), etc.
331  */
332 SELA *
selaAddCrossJunctions(SELA * sela,l_float32 hlsize,l_float32 mdist,l_int32 norient,l_int32 debugflag)333 selaAddCrossJunctions(SELA      *sela,
334                       l_float32  hlsize,
335                       l_float32  mdist,
336                       l_int32    norient,
337                       l_int32    debugflag)
338 {
339 char       name[L_BUF_SIZE];
340 l_int32    i, j, w, xc, yc;
341 l_float64  pi, halfpi, radincr, radang;
342 l_float64  angle;
343 PIX       *pixc, *pixm, *pixt;
344 PIXA      *pixa;
345 PTA       *pta1, *pta2, *pta3, *pta4;
346 SEL       *sel;
347 
348     PROCNAME("selaAddCrossJunctions");
349 
350     if (hlsize <= 0)
351         return (SELA *)ERROR_PTR("hlsize not > 0", procName, NULL);
352     if (norient < 1 || norient > 8)
353         return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);
354 
355     if (!sela) {
356         if ((sela = selaCreate(0)) == NULL)
357             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
358     }
359 
360     pi = 3.1415926535;
361     halfpi = 3.1415926535 / 2.0;
362     radincr = halfpi / (l_float64)norient;
363     w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5));
364     if (w % 2 == 0)
365         w++;
366     xc = w / 2;
367     yc = w / 2;
368 
369     pixa = pixaCreate(norient);
370     for (i = 0; i < norient; i++) {
371 
372             /* Set the don't cares */
373         pixc = pixCreate(w, w, 32);
374         pixSetAll(pixc);
375 
376             /* Add the green lines of hits */
377         pixm = pixCreate(w, w, 1);
378         radang = (l_float32)i * radincr;
379         pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang);
380         pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi);
381         pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi);
382         pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi);
383         ptaJoin(pta1, pta2, 0, 0);
384         ptaJoin(pta1, pta3, 0, 0);
385         ptaJoin(pta1, pta4, 0, 0);
386         pixRenderPta(pixm, pta1, L_SET_PIXELS);
387         pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
388         ptaDestroy(&pta1);
389         ptaDestroy(&pta2);
390         ptaDestroy(&pta3);
391         ptaDestroy(&pta4);
392 
393             /* Add red misses between the lines */
394         for (j = 0; j < 4; j++) {
395             angle = radang + (j - 0.5) * halfpi;
396             pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)),
397                         yc + (l_int32)(mdist * sin(angle)), 0xff000000);
398         }
399 
400             /* Add dark green for origin */
401         pixSetPixel(pixc, xc, yc, 0x00550000);
402 
403             /* Generate the sel */
404         sel = selCreateFromColorPix(pixc, NULL);
405         sprintf(name, "sel_cross_%d", i);
406         selaAddSel(sela, sel, name, 0);
407 
408         if (debugflag) {
409             pixt = pixScaleBySampling(pixc, 10.0, 10.0);
410             pixaAddPix(pixa, pixt, L_INSERT);
411         }
412         pixDestroy(&pixm);
413         pixDestroy(&pixc);
414     }
415 
416     if (debugflag) {
417         l_int32  w;
418         pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
419         pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 1, 0, 10, 2);
420         pixWrite("/tmp/junkxsel1.png", pixt, IFF_PNG);
421         pixDisplay(pixt, 0, 100);
422         pixDestroy(&pixt);
423         pixt = selaDisplayInPix(sela, 15, 2, 20, 1);
424         pixWrite("/tmp/junkxsel2.png", pixt, IFF_PNG);
425         pixDisplay(pixt, 500, 100);
426         pixDestroy(&pixt);
427         selaWriteStream(stderr, sela);
428     }
429     pixaDestroy(&pixa);
430 
431     return sela;
432 }
433 
434 
435 /*!
436  *  selaAddTJunctions()
437  *
438  *      Input:  sela (<optional>)
439  *              hlsize (length of each line of hits from origin)
440  *              mdist (distance of misses from the origin)
441  *              norient (number of orientations; max of 8)
442  *              debugflag (1 for debug output)
443  *      Return: sela with additional sels, or null on error
444  *
445  *  Notes:
446  *      (1) Adds hitmiss Sels for the T-junction of two lines.
447  *          If the lines are very thin, they must be nearly orthogonal
448  *          to register.
449  *      (2) The number of Sels generated is 4 * @norient.
450  *      (3) It is suggested that @hlsize be chosen at least 1 greater
451  *          than @mdist.  Try values of (@hlsize, @mdist) such as
452  *          (6,5), (7,6), (8,7), (9,7), etc.
453  */
454 SELA *
selaAddTJunctions(SELA * sela,l_float32 hlsize,l_float32 mdist,l_int32 norient,l_int32 debugflag)455 selaAddTJunctions(SELA      *sela,
456                   l_float32  hlsize,
457                   l_float32  mdist,
458                   l_int32    norient,
459                   l_int32    debugflag)
460 {
461 char       name[L_BUF_SIZE];
462 l_int32    i, j, k, w, xc, yc;
463 l_float64  pi, halfpi, radincr, jang, radang;
464 l_float64  angle[3], dist[3];
465 PIX       *pixc, *pixm, *pixt;
466 PIXA      *pixa;
467 PTA       *pta1, *pta2, *pta3;
468 SEL       *sel;
469 
470     PROCNAME("selaAddTJunctions");
471 
472     if (hlsize <= 2)
473         return (SELA *)ERROR_PTR("hlsizel not > 1", procName, NULL);
474     if (norient < 1 || norient > 8)
475         return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);
476 
477     if (!sela) {
478         if ((sela = selaCreate(0)) == NULL)
479             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
480     }
481 
482     pi = 3.1415926535;
483     halfpi = 3.1415926535 / 2.0;
484     radincr = halfpi / (l_float32)norient;
485     w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5));
486     if (w % 2 == 0)
487         w++;
488     xc = w / 2;
489     yc = w / 2;
490 
491     pixa = pixaCreate(4 * norient);
492     for (i = 0; i < norient; i++) {
493         for (j = 0; j < 4; j++) {  /* 4 orthogonal orientations */
494             jang = (l_float32)j * halfpi;
495 
496                 /* Set the don't cares */
497             pixc = pixCreate(w, w, 32);
498             pixSetAll(pixc);
499 
500                 /* Add the green lines of hits */
501             pixm = pixCreate(w, w, 1);
502             radang = (l_float32)i * radincr;
503             pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang);
504             pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1,
505                                          jang + radang + halfpi);
506             pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1,
507                                          jang + radang + pi);
508             ptaJoin(pta1, pta2, 0, 0);
509             ptaJoin(pta1, pta3, 0, 0);
510             pixRenderPta(pixm, pta1, L_SET_PIXELS);
511             pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
512             ptaDestroy(&pta1);
513             ptaDestroy(&pta2);
514             ptaDestroy(&pta3);
515 
516                 /* Add red misses between the lines */
517             angle[0] = radang + jang - halfpi;
518             angle[1] = radang + jang + 0.5 * halfpi;
519             angle[2] = radang + jang + 1.5 * halfpi;
520             dist[0] = 0.8 * mdist;
521             dist[1] = dist[2] = mdist;
522             for (k = 0; k < 3; k++) {
523                 pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])),
524                             yc + (l_int32)(dist[k] * sin(angle[k])),
525                             0xff000000);
526             }
527 
528                 /* Add dark green for origin */
529             pixSetPixel(pixc, xc, yc, 0x00550000);
530 
531                 /* Generate the sel */
532             sel = selCreateFromColorPix(pixc, NULL);
533             sprintf(name, "sel_cross_%d", 4 * i + j);
534             selaAddSel(sela, sel, name, 0);
535 
536             if (debugflag) {
537                 pixt = pixScaleBySampling(pixc, 10.0, 10.0);
538                 pixaAddPix(pixa, pixt, L_INSERT);
539             }
540             pixDestroy(&pixm);
541             pixDestroy(&pixc);
542         }
543     }
544 
545     if (debugflag) {
546         l_int32  w;
547         pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
548         pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2);
549         pixWrite("/tmp/junktsel1.png", pixt, IFF_PNG);
550         pixDisplay(pixt, 0, 100);
551         pixDestroy(&pixt);
552         pixt = selaDisplayInPix(sela, 15, 2, 20, 4);
553         pixWrite("/tmp/junktsel2.png", pixt, IFF_PNG);
554         pixDisplay(pixt, 500, 100);
555         pixDestroy(&pixt);
556         selaWriteStream(stderr, sela);
557     }
558     pixaDestroy(&pixa);
559 
560     return sela;
561 }
562 
563