Leptonica 1.68
C Image Processing Library

sel2.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 
00017 /*
00018  *  sel2.c
00019  *
00020  *      Contains definitions of simple structuring elements
00021  *
00022  *          SELA    *selaAddBasic()
00023  *               Linear horizontal and vertical
00024  *               Square
00025  *               Diagonals
00026  *
00027  *          SELA    *selaAddHitMiss()
00028  *               Isolated foreground pixel
00029  *               Horizontal and vertical edges
00030  *               Slanted edge
00031  *
00032  *          SELA    *selaAddDwaLinear()
00033  *          SELA    *selaAddDwaCombs()
00034  *          SELA    *selaAddCrossJunctions()
00035  *          SELA    *selaAddTJunctions()
00036  */
00037 
00038 #include <stdio.h>
00039 #include <math.h>
00040 #include "allheaders.h"
00041 
00042     /* MSVC can't handle arrays dimensioned by static const integers */
00043 #define  L_BUF_SIZE  512
00044 
00045     /* Linear brick sel sizes, including all those that are required
00046      * for decomposable sels up to size 63. */
00047 static const l_int32  num_linear = 25;
00048 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};
00049 
00050 
00051 /*! 
00052  *  selaAddBasic()
00053  *
00054  *      Input:  sela (<optional>)
00055  *      Return: sela with additional sels, or null on error
00056  *
00057  *  Notes:
00058  *      (1) Adds the following sels:
00059  *            - all linear (horiz, vert) brick sels that are
00060  *              necessary for decomposable sels up to size 63
00061  *            - square brick sels up to size 10
00062  *            - 4 diagonal sels
00063  */
00064 SELA *
00065 selaAddBasic(SELA  *sela)
00066 {
00067 char     name[L_BUF_SIZE];
00068 l_int32  i, size;
00069 SEL     *sel;
00070 
00071     PROCNAME("selaAddBasic");
00072 
00073     if (!sela) {
00074         if ((sela = selaCreate(0)) == NULL)
00075             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
00076     }
00077 
00078     /*--------------------------------------------------------------*
00079      *             Linear horizontal and vertical sels              *
00080      *--------------------------------------------------------------*/
00081     for (i = 0; i < num_linear; i++) {
00082         size = basic_linear[i];
00083         sel = selCreateBrick(1, size, 0, size / 2, 1);
00084         snprintf(name, L_BUF_SIZE, "sel_%dh", size);
00085         selaAddSel(sela, sel, name, 0);
00086     }
00087     for (i = 0; i < num_linear; i++) {
00088         size = basic_linear[i];
00089         sel = selCreateBrick(size, 1, size / 2, 0, 1);
00090         snprintf(name, L_BUF_SIZE, "sel_%dv", size);
00091         selaAddSel(sela, sel, name, 0);
00092     }
00093 
00094     /*-----------------------------------------------------------*
00095      *                      2-d Bricks                           *
00096      *-----------------------------------------------------------*/
00097     for (i = 2; i <= 5; i++) {
00098         sel = selCreateBrick(i, i, i / 2, i / 2, 1);
00099         snprintf(name, L_BUF_SIZE, "sel_%d", i);
00100         selaAddSel(sela, sel, name, 0);
00101     }
00102 
00103     /*-----------------------------------------------------------*
00104      *                        Diagonals                          *
00105      *-----------------------------------------------------------*/
00106         /*  0c  1
00107             1   0  */ 
00108     sel = selCreateBrick(2, 2, 0, 0, 1);
00109     selSetElement(sel, 0, 0, 0);
00110     selSetElement(sel, 1, 1, 0);
00111     selaAddSel(sela, sel, "sel_2dp", 0);
00112 
00113         /*  1c  0
00114             0   1   */ 
00115     sel = selCreateBrick(2, 2, 0, 0, 1);
00116     selSetElement(sel, 0, 1, 0);
00117     selSetElement(sel, 1, 0, 0);
00118     selaAddSel(sela, sel, "sel_2dm", 0);
00119 
00120         /*  Diagonal, slope +, size 5 */
00121     sel = selCreate(5, 5, "sel_5dp");
00122     sel->cy = 2;
00123     sel->cx = 2;
00124     selSetElement(sel, 0, 4, 1);
00125     selSetElement(sel, 1, 3, 1);
00126     selSetElement(sel, 2, 2, 1);
00127     selSetElement(sel, 3, 1, 1);
00128     selSetElement(sel, 4, 0, 1);
00129     selaAddSel(sela, sel, "sel_5dp", 0);
00130 
00131         /*  Diagonal, slope -, size 5 */
00132     sel = selCreate(5, 5, "sel_5dm");
00133     sel->cy = 2;
00134     sel->cx = 2;
00135     selSetElement(sel, 0, 0, 1);
00136     selSetElement(sel, 1, 1, 1);
00137     selSetElement(sel, 2, 2, 1);
00138     selSetElement(sel, 3, 3, 1);
00139     selSetElement(sel, 4, 4, 1);
00140     selaAddSel(sela, sel, "sel_5dm", 0);
00141 
00142     return sela;
00143 }
00144 
00145 
00146 /*!
00147  *  selaAddHitMiss()
00148  *
00149  *      Input:  sela  (<optional>)
00150  *      Return: sela with additional sels, or null on error
00151  */
00152 SELA *
00153 selaAddHitMiss(SELA  *sela)
00154 {
00155 SEL  *sel;
00156 
00157     PROCNAME("selaAddHitMiss");
00158 
00159     if (!sela) {
00160         if ((sela = selaCreate(0)) == NULL)
00161             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
00162     }
00163 
00164 #if 0   /*  use just for testing */
00165     sel = selCreateBrick(3, 3, 1, 1, 2);
00166     selaAddSel(sela, sel, "sel_bad", 0);
00167 #endif
00168 
00169 
00170     /*--------------------------------------------------------------*
00171      *                   Isolated foreground pixel                  *
00172      *--------------------------------------------------------------*/
00173     sel = selCreateBrick(3, 3, 1, 1, 2);
00174     selSetElement(sel, 1, 1, 1);
00175     selaAddSel(sela, sel, "sel_3hm", 0);
00176 
00177 
00178     /*--------------------------------------------------------------*
00179      *                Horizontal and vertical edges                 *
00180      *--------------------------------------------------------------*/
00181     sel = selCreateBrick(2, 3, 0, 1, 1);
00182     selSetElement(sel, 1, 0, 2);
00183     selSetElement(sel, 1, 1, 2);
00184     selSetElement(sel, 1, 2, 2);
00185     selaAddSel(sela, sel, "sel_3de", 0);
00186 
00187     sel = selCreateBrick(2, 3, 1, 1, 1);
00188     selSetElement(sel, 0, 0, 2);
00189     selSetElement(sel, 0, 1, 2);
00190     selSetElement(sel, 0, 2, 2);
00191     selaAddSel(sela, sel, "sel_3ue", 0);
00192 
00193     sel = selCreateBrick(3, 2, 1, 0, 1);
00194     selSetElement(sel, 0, 1, 2);
00195     selSetElement(sel, 1, 1, 2);
00196     selSetElement(sel, 2, 1, 2);
00197     selaAddSel(sela, sel, "sel_3re", 0);
00198 
00199     sel = selCreateBrick(3, 2, 1, 1, 1);
00200     selSetElement(sel, 0, 0, 2);
00201     selSetElement(sel, 1, 0, 2);
00202     selSetElement(sel, 2, 0, 2);
00203     selaAddSel(sela, sel, "sel_3le", 0);
00204 
00205 
00206     /*--------------------------------------------------------------*
00207      *                       Slanted edge                           *
00208      *--------------------------------------------------------------*/
00209     sel = selCreateBrick(13, 6, 6, 2, 0);
00210     selSetElement(sel, 0, 3, 2);
00211     selSetElement(sel, 0, 5, 1);
00212     selSetElement(sel, 4, 2, 2);
00213     selSetElement(sel, 4, 4, 1);
00214     selSetElement(sel, 8, 1, 2);
00215     selSetElement(sel, 8, 3, 1);
00216     selSetElement(sel, 12, 0, 2);
00217     selSetElement(sel, 12, 2, 1);
00218     selaAddSel(sela, sel, "sel_sl1", 0);
00219 
00220     return sela;
00221 }
00222 
00223 
00224 /*!
00225  *  selaAddDwaLinear()
00226  *
00227  *      Input:  sela (<optional>)
00228  *      Return: sela with additional sels, or null on error
00229  *
00230  *  Notes:
00231  *      (1) Adds all linear (horizontal, vertical) sels from
00232  *          2 to 63 pixels in length, which are the sizes over
00233  *          which dwa code can be generated.
00234  */
00235 SELA *
00236 selaAddDwaLinear(SELA  *sela)
00237 {
00238 char     name[L_BUF_SIZE];
00239 l_int32  i;
00240 SEL     *sel;
00241 
00242     PROCNAME("selaAddDwaLinear");
00243 
00244     if (!sela) {
00245         if ((sela = selaCreate(0)) == NULL)
00246             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
00247     }
00248 
00249     for (i = 2; i < 64; i++) {
00250         sel = selCreateBrick(1, i, 0, i / 2, 1);
00251         snprintf(name, L_BUF_SIZE, "sel_%dh", i);
00252         selaAddSel(sela, sel, name, 0);
00253     }
00254     for (i = 2; i < 64; i++) {
00255         sel = selCreateBrick(i, 1, i / 2, 0, 1);
00256         snprintf(name, L_BUF_SIZE, "sel_%dv", i);
00257         selaAddSel(sela, sel, name, 0);
00258     }
00259     return sela;
00260 }
00261 
00262 
00263 /*!
00264  *  selaAddDwaCombs()
00265  *
00266  *      Input:  sela (<optional>)
00267  *      Return: sela with additional sels, or null on error
00268  *
00269  *  Notes:
00270  *      (1) Adds all comb (horizontal, vertical) Sels that are
00271  *          used in composite linear morphological operations
00272  *          up to 63 pixels in length, which are the sizes over
00273  *          which dwa code can be generated.
00274  */
00275 SELA *
00276 selaAddDwaCombs(SELA  *sela)
00277 {
00278 char     name[L_BUF_SIZE];
00279 l_int32  i, f1, f2, prevsize, size;
00280 SEL     *selh, *selv;
00281 
00282     PROCNAME("selaAddDwaCombs");
00283 
00284     if (!sela) {
00285         if ((sela = selaCreate(0)) == NULL)
00286             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
00287     }
00288 
00289     prevsize = 0;
00290     for (i = 4; i < 64; i++) {
00291         selectComposableSizes(i, &f1, &f2);
00292         size = f1 * f2;
00293         if (size == prevsize)
00294             continue;
00295         selectComposableSels(i, L_HORIZ, NULL, &selh);
00296         selectComposableSels(i, L_VERT, NULL, &selv);
00297         snprintf(name, L_BUF_SIZE, "sel_comb_%dh", size);
00298         selaAddSel(sela, selh, name, 0);
00299         snprintf(name, L_BUF_SIZE, "sel_comb_%dv", size);
00300         selaAddSel(sela, selv, name, 0);
00301         prevsize = size;
00302     }
00303 
00304     return sela;
00305 }
00306 
00307 
00308 /*!
00309  *  selaAddCrossJunctions()
00310  *
00311  *      Input:  sela (<optional>)
00312  *              hlsize (length of each line of hits from origin)
00313  *              mdist (distance of misses from the origin)
00314  *              norient (number of orientations; max of 8)
00315  *              debugflag (1 for debug output)
00316  *      Return: sela with additional sels, or null on error
00317  *
00318  *  Notes:
00319  *      (1) Adds hitmiss Sels for the intersection of two lines.
00320  *          If the lines are very thin, they must be nearly orthogonal
00321  *          to register.
00322  *      (2) The number of Sels generated is equal to @norient.
00323  *      (3) If @norient == 2, this generates 2 Sels of crosses, each with
00324  *          two perpendicular lines of hits.  One Sel has horizontal and
00325  *          vertical hits; the other has hits along lines at +-45 degrees.
00326  *          Likewise, if @norient == 3, this generates 3 Sels of crosses
00327  *          oriented at 30 degrees with each other.
00328  *      (4) It is suggested that @hlsize be chosen at least 1 greater
00329  *          than @mdist.  Try values of (@hlsize, @mdist) such as
00330  *          (6,5), (7,6), (8,7), (9,7), etc.
00331  */
00332 SELA *
00333 selaAddCrossJunctions(SELA      *sela,
00334                       l_float32  hlsize,
00335                       l_float32  mdist,
00336                       l_int32    norient,
00337                       l_int32    debugflag)
00338 {
00339 char       name[L_BUF_SIZE];
00340 l_int32    i, j, w, xc, yc;
00341 l_float64  pi, halfpi, radincr, radang;
00342 l_float64  angle;
00343 PIX       *pixc, *pixm, *pixt;
00344 PIXA      *pixa;
00345 PTA       *pta1, *pta2, *pta3, *pta4;
00346 SEL       *sel;
00347 
00348     PROCNAME("selaAddCrossJunctions");
00349 
00350     if (hlsize <= 0)
00351         return (SELA *)ERROR_PTR("hlsize not > 0", procName, NULL);
00352     if (norient < 1 || norient > 8)
00353         return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);
00354 
00355     if (!sela) {
00356         if ((sela = selaCreate(0)) == NULL)
00357             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
00358     }
00359 
00360     pi = 3.1415926535;
00361     halfpi = 3.1415926535 / 2.0;
00362     radincr = halfpi / (l_float64)norient;
00363     w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5));
00364     if (w % 2 == 0)
00365         w++;
00366     xc = w / 2;
00367     yc = w / 2;
00368 
00369     pixa = pixaCreate(norient);
00370     for (i = 0; i < norient; i++) {
00371 
00372             /* Set the don't cares */
00373         pixc = pixCreate(w, w, 32);
00374         pixSetAll(pixc);
00375 
00376             /* Add the green lines of hits */
00377         pixm = pixCreate(w, w, 1);
00378         radang = (l_float32)i * radincr;
00379         pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang);
00380         pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi);
00381         pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi);
00382         pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi);
00383         ptaJoin(pta1, pta2, 0, 0);
00384         ptaJoin(pta1, pta3, 0, 0);
00385         ptaJoin(pta1, pta4, 0, 0);
00386         pixRenderPta(pixm, pta1, L_SET_PIXELS);
00387         pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
00388         ptaDestroy(&pta1);
00389         ptaDestroy(&pta2);
00390         ptaDestroy(&pta3);
00391         ptaDestroy(&pta4);
00392 
00393             /* Add red misses between the lines */
00394         for (j = 0; j < 4; j++) {
00395             angle = radang + (j - 0.5) * halfpi;
00396             pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)),
00397                         yc + (l_int32)(mdist * sin(angle)), 0xff000000);
00398         }
00399 
00400             /* Add dark green for origin */
00401         pixSetPixel(pixc, xc, yc, 0x00550000);
00402 
00403             /* Generate the sel */
00404         sel = selCreateFromColorPix(pixc, NULL);
00405         sprintf(name, "sel_cross_%d", i);
00406         selaAddSel(sela, sel, name, 0);
00407 
00408         if (debugflag) {
00409             pixt = pixScaleBySampling(pixc, 10.0, 10.0);
00410             pixaAddPix(pixa, pixt, L_INSERT);
00411         }
00412         pixDestroy(&pixm);
00413         pixDestroy(&pixc);
00414     }
00415     
00416     if (debugflag) {
00417         l_int32  w;
00418         pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
00419         pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 1, 0, 10, 2);
00420         pixWriteTempfile("/tmp", "xsel1.png", pixt, IFF_PNG, 0);
00421         pixDisplay(pixt, 0, 100);
00422         pixDestroy(&pixt);
00423         pixt = selaDisplayInPix(sela, 15, 2, 20, 1);
00424         pixWriteTempfile("/tmp", "xsel2.png", pixt, IFF_PNG, 0);
00425         pixDisplay(pixt, 500, 100);
00426         pixDestroy(&pixt);
00427         selaWriteStream(stderr, sela);
00428     }
00429     pixaDestroy(&pixa);
00430 
00431     return sela;
00432 }
00433 
00434 
00435 /*! 
00436  *  selaAddTJunctions()
00437  *
00438  *      Input:  sela (<optional>)
00439  *              hlsize (length of each line of hits from origin)
00440  *              mdist (distance of misses from the origin)
00441  *              norient (number of orientations; max of 8)
00442  *              debugflag (1 for debug output)
00443  *      Return: sela with additional sels, or null on error
00444  *
00445  *  Notes:
00446  *      (1) Adds hitmiss Sels for the T-junction of two lines.
00447  *          If the lines are very thin, they must be nearly orthogonal
00448  *          to register.
00449  *      (2) The number of Sels generated is 4 * @norient.
00450  *      (3) It is suggested that @hlsize be chosen at least 1 greater
00451  *          than @mdist.  Try values of (@hlsize, @mdist) such as
00452  *          (6,5), (7,6), (8,7), (9,7), etc.
00453  */
00454 SELA *
00455 selaAddTJunctions(SELA      *sela,
00456                   l_float32  hlsize,
00457                   l_float32  mdist,
00458                   l_int32    norient,
00459                   l_int32    debugflag)
00460 {
00461 char       name[L_BUF_SIZE];
00462 l_int32    i, j, k, w, xc, yc;
00463 l_float64  pi, halfpi, radincr, jang, radang;
00464 l_float64  angle[3], dist[3];
00465 PIX       *pixc, *pixm, *pixt;
00466 PIXA      *pixa;
00467 PTA       *pta1, *pta2, *pta3;
00468 SEL       *sel;
00469 
00470     PROCNAME("selaAddTJunctions");
00471 
00472     if (hlsize <= 2)
00473         return (SELA *)ERROR_PTR("hlsizel not > 1", procName, NULL);
00474     if (norient < 1 || norient > 8)
00475         return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);
00476 
00477     if (!sela) {
00478         if ((sela = selaCreate(0)) == NULL)
00479             return (SELA *)ERROR_PTR("sela not made", procName, NULL);
00480     }
00481 
00482     pi = 3.1415926535;
00483     halfpi = 3.1415926535 / 2.0;
00484     radincr = halfpi / (l_float32)norient;
00485     w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5));
00486     if (w % 2 == 0)
00487         w++;
00488     xc = w / 2;
00489     yc = w / 2;
00490 
00491     pixa = pixaCreate(4 * norient);
00492     for (i = 0; i < norient; i++) {
00493         for (j = 0; j < 4; j++) {  /* 4 orthogonal orientations */
00494             jang = (l_float32)j * halfpi;
00495 
00496                 /* Set the don't cares */
00497             pixc = pixCreate(w, w, 32);
00498             pixSetAll(pixc);
00499 
00500                 /* Add the green lines of hits */
00501             pixm = pixCreate(w, w, 1);
00502             radang = (l_float32)i * radincr;
00503             pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang);
00504             pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1,
00505                                          jang + radang + halfpi);
00506             pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1,
00507                                          jang + radang + pi);
00508             ptaJoin(pta1, pta2, 0, 0);
00509             ptaJoin(pta1, pta3, 0, 0);
00510             pixRenderPta(pixm, pta1, L_SET_PIXELS);
00511             pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
00512             ptaDestroy(&pta1);
00513             ptaDestroy(&pta2);
00514             ptaDestroy(&pta3);
00515 
00516                 /* Add red misses between the lines */
00517             angle[0] = radang + jang - halfpi;
00518             angle[1] = radang + jang + 0.5 * halfpi;
00519             angle[2] = radang + jang + 1.5 * halfpi;
00520             dist[0] = 0.8 * mdist;
00521             dist[1] = dist[2] = mdist;
00522             for (k = 0; k < 3; k++) {
00523                 pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])),
00524                             yc + (l_int32)(dist[k] * sin(angle[k])),
00525                             0xff000000);
00526             }
00527 
00528                 /* Add dark green for origin */
00529             pixSetPixel(pixc, xc, yc, 0x00550000);
00530 
00531                 /* Generate the sel */
00532             sel = selCreateFromColorPix(pixc, NULL);
00533             sprintf(name, "sel_cross_%d", 4 * i + j);
00534             selaAddSel(sela, sel, name, 0);
00535 
00536             if (debugflag) {
00537                 pixt = pixScaleBySampling(pixc, 10.0, 10.0);
00538                 pixaAddPix(pixa, pixt, L_INSERT);
00539             }
00540             pixDestroy(&pixm);
00541             pixDestroy(&pixc);
00542         }
00543     }
00544 
00545     if (debugflag) {
00546         l_int32  w;
00547         pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
00548         pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2);
00549         pixWriteTempfile("/tmp", "tsel1.png", pixt, IFF_PNG, 0);
00550         pixDisplay(pixt, 0, 100);
00551         pixDestroy(&pixt);
00552         pixt = selaDisplayInPix(sela, 15, 2, 20, 4);
00553         pixWriteTempfile("/tmp", "tsel2.png", pixt, IFF_PNG, 0);
00554         pixDisplay(pixt, 500, 100);
00555         pixDestroy(&pixt);
00556         selaWriteStream(stderr, sela);
00557     }
00558     pixaDestroy(&pixa);
00559 
00560     return sela;
00561 }
00562 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines