src/selgen.c
SEL *
pixGenerateSelBoundary(PIX     *pixs,
                       l_int32  hitdist,
                       l_int32  missdist,
                       l_int32  hitskip,
                       l_int32  missskip,
                       l_int32  topflag,
                       l_int32  botflag,
                       l_int32  leftflag,
                       l_int32  rightflag,
                       PIX      **ppixe)
{
l_int32  ws, hs, w, h, x, y, ix, iy, i, npt;
PIX     *pixt1, *pixt2, *pixt3, *pixfg, *pixbg;
SEL     *selh, *selm, *sel_3, *sel;
PTA     *ptah, *ptam; 

    PROCNAME("pixGenerateSelBoundary");

    if (ppixe) *ppixe = NULL;
    if (!pixs)
        return (SEL *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4) 
        return (SEL *)ERROR_PTR("dist not in {0 .. 4}", procName, NULL);
    if (hitskip < 0 && missskip < 0)
        return (SEL *)ERROR_PTR("no hits or misses", procName, NULL);

        /* Locate the foreground */
    pixClipToForeground(pixs, &pixt1, NULL);
    if (!pixt1)
        return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL);
    ws = pixGetWidth(pixt1);
    hs = pixGetHeight(pixt1);
    w = ws;
    h = hs;

        /* Crop out a region including the foreground, and add pixels
         * on sides depending on the side flags */
    if (topflag || botflag || leftflag || rightflag) {
        x = y = 0;
        if (topflag) {
            h += missdist + 1;
            y = missdist + 1;
        }
        if (botflag)
            h += missdist + 1;
        if (leftflag) {
            w += missdist + 1;
            x = missdist + 1;
        }
        if (rightflag)
            w += missdist + 1;
        pixt2 = pixCreate(w, h, 1);
        pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
    }
    else {
        pixt2 = pixClone(pixt1);
    }
    if (ppixe)
        *ppixe = pixClone(pixt2);
    pixDestroy(&pixt1);

        /* Identify fg and bg pixels that are exactly hitdist and
         * missdist (rsp) away from the boundary pixels in their set.
         * Then get a subsampled set of these points. */
    sel_3 = selCreateBrick(3, 3, 1, 1, SEL_HIT);
    if (hitskip >= 0) {
        selh = selCreateBrick(2 * hitdist + 1, 2 * hitdist + 1,
                              hitdist, hitdist, SEL_HIT);
        pixt3 = pixErode(NULL, pixt2, selh);
        pixfg = pixErode(NULL, pixt3, sel_3);
        pixXor(pixfg, pixfg, pixt3);
        ptah = pixSubsampleBoundaryPixels(pixfg, hitskip);
        pixDestroy(&pixt3);
        pixDestroy(&pixfg);
        selDestroy(&selh);
    }
    if (missskip >= 0) {
        selm = selCreateBrick(2 * missdist + 1, 2 * missdist + 1,
                              missdist, missdist, SEL_HIT);
        pixt3 = pixDilate(NULL, pixt2, selm);
        pixbg = pixDilate(NULL, pixt3, sel_3);
        pixXor(pixbg, pixbg, pixt3);
        ptam = pixSubsampleBoundaryPixels(pixbg, missskip);
        pixDestroy(&pixt3);
        pixDestroy(&pixbg);
        selDestroy(&selm);
    }
    selDestroy(&sel_3);
    pixDestroy(&pixt2);

        /* Generate the hit-miss sel from these point */
    sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
    if (hitskip >= 0) {
        npt = ptaGetCount(ptah);
        for (i = 0; i < npt; i++) {
            ptaGetIPt(ptah, i, &ix, &iy);
            selSetElement(sel, iy, ix, SEL_HIT);
        }
    }
    if (missskip >= 0) {
        npt = ptaGetCount(ptam);
        for (i = 0; i < npt; i++) {
            ptaGetIPt(ptam, i, &ix, &iy);
            selSetElement(sel, iy, ix, SEL_MISS);
        }
    }

    ptaDestroy(&ptah);
    ptaDestroy(&ptam);
    return sel;
}
/*!
 *  pixGenerateSelBoundary()
 *
 *      Input:  pix (1 bpp, typically small, to be used as a pattern)
 *              hitdist (min distance from fg boundary pixel)
 *              missdist (min distance from bg boundary pixel)
 *              hitskip (number of boundary pixels skipped between hits)
 *              missskip (number of boundary pixels skipped between misses)
 *              topflag (flag for extra pixels of bg added above)
 *              botflag (flag for extra pixels of bg added below)
 *              leftflag (flag for extra pixels of bg added to left)
 *              rightflag (flag for extra pixels of bg added to right)
 *              &pixe (<optional return> input pix expanded by extra pixels)
 *      Return: sel (hit-miss for input pattern), or null on error
 *
 *  Notes:
 *    (1) All fg elements selected are exactly hitdist pixels away from
 *        the nearest fg boundary pixel, and ditto for bg elements.
 *        Valid inputs of hitdist and missdist are 0, 1, 2, 3 and 4.
 *        For example, a hitdist of 0 puts the hits at the fg boundary.
 *        Usually, the distances should be > 0 avoid the effect of
 *        noise at the boundary.
 *    (2) Set hitskip < 0 if no hits are to be used.  Ditto for missskip.
 *        If both hitskip and missskip are < 0, the sel would be empty,
 *        and NULL is returned.
 *    (3) The 4 flags determine whether the sel is increased on that side
 *        to allow bg misses to be placed all along that boundary.
 *        The increase in sel size on that side is the minimum necessary
 *        to allow the misses to be placed at mindist.  For text characters,
 *        the topflag and botflag are typically set to 1, and the leftflag
 *        and rightflag to 0.
 *    (4) The input pix, as extended by the extra pixels on selected sides,
 *        can optionally be returned.  For debugging, call
 *        pixDisplayHitMissSel() to visualize the hit-miss sel superimposed
 *        on the generating bitmap.
 *    (5) This is probably the best of the three sel generators, in the
 *        sense that you have the most flexibility with the smallest number
 *        of hits and misses.
 */


(1) All fg elements selected are exactly hitdist pixels away from
the nearest fg boundary pixel, and ditto for bg elements.
Valid inputs of hitdist and missdist are 0, 1, 2, 3 and 4.
For example, a hitdist of 0 puts the hits at the fg boundary.
Usually, the distances should be > 0 avoid the effect of
noise at the boundary.
(2) Set hitskip < 0 if no hits are to be used.  Ditto for missskip.
If both hitskip and missskip are < 0, the sel would be empty,
and NULL is returned.
(3) The 4 flags determine whether the sel is increased on that side
to allow bg misses to be placed all along that boundary.
The increase in sel size on that side is the minimum necessary
to allow the misses to be placed at mindist.  For text characters,
the topflag and botflag are typically set to 1, and the leftflag
and rightflag to 0.
(4) The input pix, as extended by the extra pixels on selected sides,
can optionally be returned.  For debugging, call
pixDisplayHitMissSel() to visualize the hit-miss sel superimposed
on the generating bitmap.
(5) This is probably the best of the three sel generators, in the
sense that you have the most flexibility with the smallest number
of hits and misses.
( 1 ) All fg elements selected are exactly hitdist pixels away from the nearest fg boundary pixel and ditto for bg elements . Valid inputs of hitdist and missdist are 0 1 2 3 and 4 . For example a hitdist of 0 puts the hits at the fg boundary . Usually the distances should be > 0 avoid the effect of noise at the boundary . ( 2 ) Set hitskip < 0 if no hits are to be used . Ditto for missskip . If both hitskip and missskip are < 0 the sel would be empty and NULL is returned . ( 3 ) The 4 flags determine whether the sel is increased on that side to allow bg misses to be placed all along that boundary . The increase in sel size on that side is the minimum necessary to allow the misses to be placed at mindist . For text characters the topflag and botflag are typically set to 1 and the leftflag and rightflag to 0 . ( 4 ) The input pix as extended by the extra pixels on selected sides can optionally be returned . For debugging call pixDisplayHitMissSel () to visualize the hit - miss sel superimposed on the generating bitmap . ( 5 ) This is probably the best of the three sel generators in the sense that you have the most flexibility with the smallest number of hits and misses .
SEL *
pixGenerateSelBoundary(PIX     *pixs,
                       l_int32  hitdist,
                       l_int32  missdist,
                       l_int32  hitskip,
                       l_int32  missskip,
                       l_int32  topflag,
                       l_int32  botflag,
                       l_int32  leftflag,
                       l_int32  rightflag,
                       PIX      **ppixe)
{
l_int32  ws, hs, w, h, x, y, ix, iy, i, npt;
PIX     *pixt1, *pixt2, *pixt3, *pixfg, *pixbg;
SEL     *selh, *selm, *sel_3, *sel;
PTA     *ptah, *ptam; 
    PROCNAME("pixGenerateSelBoundary");
    if (ppixe) *ppixe = NULL;
    if (!pixs)
        return (SEL *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4) 
        return (SEL *)ERROR_PTR("dist not in {0 .. 4}", procName, NULL);
    if (hitskip < 0 && missskip < 0)
        return (SEL *)ERROR_PTR("no hits or misses", procName, NULL);
    pixClipToForeground(pixs, &pixt1, NULL);
    if (!pixt1)
        return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL);
    ws = pixGetWidth(pixt1);
    hs = pixGetHeight(pixt1);
    w = ws;
    h = hs;
    if (topflag || botflag || leftflag || rightflag) {
        x = y = 0;
        if (topflag) {
            h += missdist + 1;
            y = missdist + 1;
        }
        if (botflag)
            h += missdist + 1;
        if (leftflag) {
            w += missdist + 1;
            x = missdist + 1;
        }
        if (rightflag)
            w += missdist + 1;
        pixt2 = pixCreate(w, h, 1);
        pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
    }
    else {
        pixt2 = pixClone(pixt1);
    }
    if (ppixe)
        *ppixe = pixClone(pixt2);
    pixDestroy(&pixt1);
    sel_3 = selCreateBrick(3, 3, 1, 1, SEL_HIT);
    if (hitskip >= 0) {
        selh = selCreateBrick(2 * hitdist + 1, 2 * hitdist + 1,
                              hitdist, hitdist, SEL_HIT);
        pixt3 = pixErode(NULL, pixt2, selh);
        pixfg = pixErode(NULL, pixt3, sel_3);
        pixXor(pixfg, pixfg, pixt3);
        ptah = pixSubsampleBoundaryPixels(pixfg, hitskip);
        pixDestroy(&pixt3);
        pixDestroy(&pixfg);
        selDestroy(&selh);
    }
    if (missskip >= 0) {
        selm = selCreateBrick(2 * missdist + 1, 2 * missdist + 1,
                              missdist, missdist, SEL_HIT);
        pixt3 = pixDilate(NULL, pixt2, selm);
        pixbg = pixDilate(NULL, pixt3, sel_3);
        pixXor(pixbg, pixbg, pixt3);
        ptam = pixSubsampleBoundaryPixels(pixbg, missskip);
        pixDestroy(&pixt3);
        pixDestroy(&pixbg);
        selDestroy(&selm);
    }
    selDestroy(&sel_3);
    pixDestroy(&pixt2);
    sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
    if (hitskip >= 0) {
        npt = ptaGetCount(ptah);
        for (i = 0; i < npt; i++) {
            ptaGetIPt(ptah, i, &ix, &iy);
            selSetElement(sel, iy, ix, SEL_HIT);
        }
    }
    if (missskip >= 0) {
        npt = ptaGetCount(ptam);
        for (i = 0; i < npt; i++) {
            ptaGetIPt(ptam, i, &ix, &iy);
            selSetElement(sel, iy, ix, SEL_MISS);
        }
    }
    ptaDestroy(&ptah);
    ptaDestroy(&ptam);
    return sel;
}
SEL * pixGenerateSelBoundary ( PIX * pixs , l_int32 hitdist , l_int32 missdist , l_int32 hitskip , l_int32 missskip , l_int32 topflag , l_int32 botflag , l_int32 leftflag , l_int32 rightflag , PIX * * ppixe ) { l_int32 ws , hs , w , h , x , y , ix , iy , i , npt ; PIX * pixt1 , * pixt2 , * pixt3 , * pixfg , * pixbg ; SEL * selh , * selm , * sel_3 , * sel ; PTA * ptah , * ptam ; PROCNAME ( " " ) ; if ( ppixe ) * ppixe = NULL ; if ( ! pixs ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( pixGetDepth ( pixs ) != 1 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( hitskip < 0 && missskip < 0 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; pixClipToForeground ( pixs , & pixt1 , NULL ) ; if ( ! pixt1 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; ws = pixGetWidth ( pixt1 ) ; hs = pixGetHeight ( pixt1 ) ; w = ws ; h = hs ; if ( topflag || botflag || leftflag || rightflag ) { x = y = 0 ; if ( topflag ) { h += missdist + 1 ; y = missdist + 1 ; } if ( botflag ) h += missdist + 1 ; if ( leftflag ) { w += missdist + 1 ; x = missdist + 1 ; } if ( rightflag ) w += missdist + 1 ; pixt2 = pixCreate ( w , h , 1 ) ; pixRasterop ( pixt2 , x , y , ws , hs , PIX_SRC , pixt1 , 0 , 0 ) ; } else { pixt2 = pixClone ( pixt1 ) ; } if ( ppixe ) * ppixe = pixClone ( pixt2 ) ; pixDestroy ( & pixt1 ) ; sel_3 = selCreateBrick ( 3 , 3 , 1 , 1 , SEL_HIT ) ; if ( hitskip >= 0 ) { selh = selCreateBrick ( 2 * hitdist + 1 , 2 * hitdist + 1 , hitdist , hitdist , SEL_HIT ) ; pixt3 = pixErode ( NULL , pixt2 , selh ) ; pixfg = pixErode ( NULL , pixt3 , sel_3 ) ; pixXor ( pixfg , pixfg , pixt3 ) ; ptah = pixSubsampleBoundaryPixels ( pixfg , hitskip ) ; pixDestroy ( & pixt3 ) ; pixDestroy ( & pixfg ) ; selDestroy ( & selh ) ; } if ( missskip >= 0 ) { selm = selCreateBrick ( 2 * missdist + 1 , 2 * missdist + 1 , missdist , missdist , SEL_HIT ) ; pixt3 = pixDilate ( NULL , pixt2 , selm ) ; pixbg = pixDilate ( NULL , pixt3 , sel_3 ) ; pixXor ( pixbg , pixbg , pixt3 ) ; ptam = pixSubsampleBoundaryPixels ( pixbg , missskip ) ; pixDestroy ( & pixt3 ) ; pixDestroy ( & pixbg ) ; selDestroy ( & selm ) ; } selDestroy ( & sel_3 ) ; pixDestroy ( & pixt2 ) ; sel = selCreateBrick ( h , w , h / 2 , w / 2 , SEL_DONT_CARE ) ; if ( hitskip >= 0 ) { npt = ptaGetCount ( ptah ) ; for ( i = 0 ; i < npt ; i ++ ) { ptaGetIPt ( ptah , i , & ix , & iy ) ; selSetElement ( sel , iy , ix , SEL_HIT ) ; } } if ( missskip >= 0 ) { npt = ptaGetCount ( ptam ) ; for ( i = 0 ; i < npt ; i ++ ) { ptaGetIPt ( ptam , i , & ix , & iy ) ; selSetElement ( sel , iy , ix , SEL_MISS ) ; } } ptaDestroy ( & ptah ) ; ptaDestroy ( & ptam ) ; return sel ; }
pixGenerateSelBoundary()
      Input:  pix (1 bpp, typically small, to be used as a pattern)
              hitdist (min distance from fg boundary pixel)
              missdist (min distance from bg boundary pixel)
              hitskip (number of boundary pixels skipped between hits)
              missskip (number of boundary pixels skipped between misses)
              topflag (flag for extra pixels of bg added above)
              botflag (flag for extra pixels of bg added below)
              leftflag (flag for extra pixels of bg added to left)
              rightflag (flag for extra pixels of bg added to right)
              &pixe (<optional return> input pix expanded by extra pixels)
      Return: sel (hit-miss for input pattern), or null on error
pixGenerateSelBoundary () Input : pix ( 1 bpp typically small to be used as a pattern ) hitdist ( min distance from fg boundary pixel ) missdist ( min distance from bg boundary pixel ) hitskip ( number of boundary pixels skipped between hits ) missskip ( number of boundary pixels skipped between misses ) topflag ( flag for extra pixels of bg added above ) botflag ( flag for extra pixels of bg added below ) leftflag ( flag for extra pixels of bg added to left ) rightflag ( flag for extra pixels of bg added to right ) &pixe ( <optional return > input pix expanded by extra pixels ) Return : sel ( hit - miss for input pattern ) or null on error
/* Locate the foreground */ /* Crop out a region including the foreground, and add pixels
         * on sides depending on the side flags */ /* Identify fg and bg pixels that are exactly hitdist and
         * missdist (rsp) away from the boundary pixels in their set.
         * Then get a subsampled set of these points. */ /* Generate the hit-miss sel from these point */