src/selgen.c
SEL *
pixGenerateSelRandom(PIX       *pixs,
                     l_float32  hitfract,
                     l_float32  missfract,
                     l_int32    distance,
                     l_int32    toppix,
                     l_int32    botpix,
                     l_int32    leftpix,
                     l_int32    rightpix,
                     PIX      **ppixe)
{
l_int32    ws, hs, w, h, x, y, i, j, thresh;
l_uint32   val;
PIX       *pixt1, *pixt2, *pixfg, *pixbg;
SEL       *seld, *sel;

    PROCNAME("pixGenerateSelRandom");

    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 (hitfract <= 0.0 && missfract <= 0.0)
        return (SEL *)ERROR_PTR("no hits or misses", procName, NULL);
    if (hitfract > 1.0 || missfract > 1.0) 
        return (SEL *)ERROR_PTR("fraction can't be > 1.0", procName, NULL);

    if (distance <= 0)
        distance = DEFAULT_DISTANCE_TO_BOUNDARY;
    if (distance > MAX_DISTANCE_TO_BOUNDARY) {
        L_WARNING("distance too large; setting to max value", procName);
        distance = MAX_DISTANCE_TO_BOUNDARY;
    }

        /* 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 (toppix || botpix || leftpix || rightpix) {
        x = y = 0;
        if (toppix) {
            h += toppix;
            y = toppix;
        }
        if (botpix)
            h += botpix;
        if (leftpix) {
            w += leftpix;
            x = leftpix;
        }
        if (rightpix)
            w += rightpix;
        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 at least 'distance' pixels
         * away from the boundary pixels in their set */
    seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
                          distance, distance, SEL_HIT);
    pixfg = pixErode(NULL, pixt2, seld);
    pixbg = pixDilate(NULL, pixt2, seld);
    pixInvert(pixbg, pixbg);
    selDestroy(&seld);
    pixDestroy(&pixt2);

        /* Generate the sel from a random selection of these points */
    sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
    if (hitfract > 0.0) {
        thresh = (l_int32)(hitfract * (l_float64)RAND_MAX);
        for (i = 0; i < h; i++) {
            for (j = 0; j < w; j++) {
                pixGetPixel(pixfg, j, i, &val);
                if (val) {
                    if (rand() < thresh)
                        selSetElement(sel, i, j, SEL_HIT);
                }
            }
        }
    }
    if (missfract > 0.0) {
        thresh = (l_int32)(missfract * (l_float64)RAND_MAX);
        for (i = 0; i < h; i++) {
            for (j = 0; j < w; j++) {
                pixGetPixel(pixbg, j, i, &val);
                if (val) {
                    if (rand() < thresh)
                        selSetElement(sel, i, j, SEL_MISS);
                }
            }
        }
    }

    pixDestroy(&pixfg);
    pixDestroy(&pixbg);
    return sel;
}
/*!
 *  pixGenerateSelRandom()
 *
 *      Input:  pix (1 bpp, typically small, to be used as a pattern)
 *              hitfract (fraction of allowable fg pixels that are hits)
 *              missfract (fraction of allowable bg pixels that are misses)
 *              distance (min distance from boundary pixel; use 0 for default)
 *              toppix (number of extra pixels of bg added above)
 *              botpix (number of extra pixels of bg added below)
 *              leftpix (number of extra pixels of bg added to left)
 *              rightpix (number of 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) Either of hitfract and missfract can be zero.  If both are zero,
 *        the sel would be empty, and NULL is returned.
 *    (2) No elements are selected that are less than 'distance' pixels away
 *        from a boundary pixel of the same color.  This makes the
 *        match much more robust to edge noise.  Valid inputs of
 *        'distance' are 0, 1, 2, 3 and 4.  If distance is either 0 or
 *        greater than 4, we reset it to the default value.
 *    (3) The 4 numbers for adding rectangles of pixels outside the fg
 *        can be use if the pattern is expected to be surrounded by bg
 *        (white) pixels.  On the other hand, if the pattern may be near
 *        other fg (black) components on some sides, use 0 for those sides.
 *    (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.
 */


(1) Either of hitfract and missfract can be zero.  If both are zero,
the sel would be empty, and NULL is returned.
(2) No elements are selected that are less than 'distance' pixels away
from a boundary pixel of the same color.  This makes the
match much more robust to edge noise.  Valid inputs of
'distance' are 0, 1, 2, 3 and 4.  If distance is either 0 or
greater than 4, we reset it to the default value.
(3) The 4 numbers for adding rectangles of pixels outside the fg
can be use if the pattern is expected to be surrounded by bg
(white) pixels.  On the other hand, if the pattern may be near
other fg (black) components on some sides, use 0 for those sides.
(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.
( 1 ) Either of hitfract and missfract can be zero . If both are zero the sel would be empty and NULL is returned . ( 2 ) No elements are selected that are less than ' distance ' pixels away from a boundary pixel of the same color . This makes the match much more robust to edge noise . Valid inputs of ' distance ' are 0 1 2 3 and 4 . If distance is either 0 or greater than 4 we reset it to the default value . ( 3 ) The 4 numbers for adding rectangles of pixels outside the fg can be use if the pattern is expected to be surrounded by bg ( white ) pixels . On the other hand if the pattern may be near other fg ( black ) components on some sides use 0 for those sides . ( 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 .
SEL *
pixGenerateSelRandom(PIX       *pixs,
                     l_float32  hitfract,
                     l_float32  missfract,
                     l_int32    distance,
                     l_int32    toppix,
                     l_int32    botpix,
                     l_int32    leftpix,
                     l_int32    rightpix,
                     PIX      **ppixe)
{
l_int32    ws, hs, w, h, x, y, i, j, thresh;
l_uint32   val;
PIX       *pixt1, *pixt2, *pixfg, *pixbg;
SEL       *seld, *sel;
    PROCNAME("pixGenerateSelRandom");
    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 (hitfract <= 0.0 && missfract <= 0.0)
        return (SEL *)ERROR_PTR("no hits or misses", procName, NULL);
    if (hitfract > 1.0 || missfract > 1.0) 
        return (SEL *)ERROR_PTR("fraction can't be > 1.0", procName, NULL);
    if (distance <= 0)
        distance = DEFAULT_DISTANCE_TO_BOUNDARY;
    if (distance > MAX_DISTANCE_TO_BOUNDARY) {
        L_WARNING("distance too large; setting to max value", procName);
        distance = MAX_DISTANCE_TO_BOUNDARY;
    }
    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 (toppix || botpix || leftpix || rightpix) {
        x = y = 0;
        if (toppix) {
            h += toppix;
            y = toppix;
        }
        if (botpix)
            h += botpix;
        if (leftpix) {
            w += leftpix;
            x = leftpix;
        }
        if (rightpix)
            w += rightpix;
        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);
    seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
                          distance, distance, SEL_HIT);
    pixfg = pixErode(NULL, pixt2, seld);
    pixbg = pixDilate(NULL, pixt2, seld);
    pixInvert(pixbg, pixbg);
    selDestroy(&seld);
    pixDestroy(&pixt2);
    sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
    if (hitfract > 0.0) {
        thresh = (l_int32)(hitfract * (l_float64)RAND_MAX);
        for (i = 0; i < h; i++) {
            for (j = 0; j < w; j++) {
                pixGetPixel(pixfg, j, i, &val);
                if (val) {
                    if (rand() < thresh)
                        selSetElement(sel, i, j, SEL_HIT);
                }
            }
        }
    }
    if (missfract > 0.0) {
        thresh = (l_int32)(missfract * (l_float64)RAND_MAX);
        for (i = 0; i < h; i++) {
            for (j = 0; j < w; j++) {
                pixGetPixel(pixbg, j, i, &val);
                if (val) {
                    if (rand() < thresh)
                        selSetElement(sel, i, j, SEL_MISS);
                }
            }
        }
    }
    pixDestroy(&pixfg);
    pixDestroy(&pixbg);
    return sel;
}
SEL * pixGenerateSelRandom ( PIX * pixs , l_float32 hitfract , l_float32 missfract , l_int32 distance , l_int32 toppix , l_int32 botpix , l_int32 leftpix , l_int32 rightpix , PIX * * ppixe ) { l_int32 ws , hs , w , h , x , y , i , j , thresh ; l_uint32 val ; PIX * pixt1 , * pixt2 , * pixfg , * pixbg ; SEL * seld , * sel ; PROCNAME ( " " ) ; if ( ppixe ) * ppixe = NULL ; if ( ! pixs ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( pixGetDepth ( pixs ) != 1 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( hitfract <= 0.0 && missfract <= 0.0 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( hitfract > 1.0 || missfract > 1.0 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; if ( distance <= 0 ) distance = DEFAULT_DISTANCE_TO_BOUNDARY ; if ( distance > MAX_DISTANCE_TO_BOUNDARY ) { L_WARNING ( " " , procName ) ; distance = MAX_DISTANCE_TO_BOUNDARY ; } pixClipToForeground ( pixs , & pixt1 , NULL ) ; if ( ! pixt1 ) return ( SEL * ) ERROR_PTR ( " " , procName , NULL ) ; ws = pixGetWidth ( pixt1 ) ; hs = pixGetHeight ( pixt1 ) ; w = ws ; h = hs ; if ( toppix || botpix || leftpix || rightpix ) { x = y = 0 ; if ( toppix ) { h += toppix ; y = toppix ; } if ( botpix ) h += botpix ; if ( leftpix ) { w += leftpix ; x = leftpix ; } if ( rightpix ) w += rightpix ; 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 ) ; seld = selCreateBrick ( 2 * distance + 1 , 2 * distance + 1 , distance , distance , SEL_HIT ) ; pixfg = pixErode ( NULL , pixt2 , seld ) ; pixbg = pixDilate ( NULL , pixt2 , seld ) ; pixInvert ( pixbg , pixbg ) ; selDestroy ( & seld ) ; pixDestroy ( & pixt2 ) ; sel = selCreateBrick ( h , w , h / 2 , w / 2 , SEL_DONT_CARE ) ; if ( hitfract > 0.0 ) { thresh = ( l_int32 ) ( hitfract * ( l_float64 ) RAND_MAX ) ; for ( i = 0 ; i < h ; i ++ ) { for ( j = 0 ; j < w ; j ++ ) { pixGetPixel ( pixfg , j , i , & val ) ; if ( val ) { if ( rand ( ) < thresh ) selSetElement ( sel , i , j , SEL_HIT ) ; } } } } if ( missfract > 0.0 ) { thresh = ( l_int32 ) ( missfract * ( l_float64 ) RAND_MAX ) ; for ( i = 0 ; i < h ; i ++ ) { for ( j = 0 ; j < w ; j ++ ) { pixGetPixel ( pixbg , j , i , & val ) ; if ( val ) { if ( rand ( ) < thresh ) selSetElement ( sel , i , j , SEL_MISS ) ; } } } } pixDestroy ( & pixfg ) ; pixDestroy ( & pixbg ) ; return sel ; }
pixGenerateSelRandom()
      Input:  pix (1 bpp, typically small, to be used as a pattern)
              hitfract (fraction of allowable fg pixels that are hits)
              missfract (fraction of allowable bg pixels that are misses)
              distance (min distance from boundary pixel; use 0 for default)
              toppix (number of extra pixels of bg added above)
              botpix (number of extra pixels of bg added below)
              leftpix (number of extra pixels of bg added to left)
              rightpix (number of 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
pixGenerateSelRandom () Input : pix ( 1 bpp typically small to be used as a pattern ) hitfract ( fraction of allowable fg pixels that are hits ) missfract ( fraction of allowable bg pixels that are misses ) distance ( min distance from boundary pixel ; use 0 for default ) toppix ( number of extra pixels of bg added above ) botpix ( number of extra pixels of bg added below ) leftpix ( number of extra pixels of bg added to left ) rightpix ( number of 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 at least 'distance' pixels
         * away from the boundary pixels in their set */ /* Generate the sel from a random selection of these points */