src/binarize.c
PIX *
pixMaskedThreshOnBackgroundNorm(PIX       *pixs,
                                PIX       *pixim,
                                l_int32    sx,
                                l_int32    sy,
                                l_int32    thresh,
                                l_int32    mincount,
                                l_int32    smoothx,
                                l_int32    smoothy,
                                l_float32  scorefract,
                                l_int32   *pthresh)
{
l_int32   w, h;
l_uint32  val;
PIX      *pixn, *pixm, *pixd, *pixt1, *pixt2, *pixt3, *pixt4;

    PROCNAME("pixMaskedThreshOnBackgroundNorm");

    if (pthresh) *pthresh = 0;
    if (!pixs || pixGetDepth(pixs) != 8)
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
    if (pixGetColormap(pixs))
        return (PIX *)ERROR_PTR("pixs is colormapped", procName, NULL);
    if (sx < 4 || sy < 4)
        return (PIX *)ERROR_PTR("sx and sy must be >= 4", procName, NULL);
    if (mincount > sx * sy) {
        L_WARNING("mincount too large for tile size", procName);
        mincount = (sx * sy) / 3;
    }

        /* Standard background normalization */
    pixn = pixBackgroundNorm(pixs, pixim, NULL, sx, sy, thresh,
                             mincount, 255, smoothx, smoothy);
    if (!pixn)
        return (PIX *)ERROR_PTR("pixn not made", procName, NULL);

        /* Special background normalization for adaptation to quickly
         * varying background.  Threshold on the very light parts,
         * which tend to be near significant edges, and dilate to
         * form a mask over regions that are typically text.  The
         * dilation size is chosen to cover the text completely,
         * except for very thick fonts. */
    pixt1 = pixBackgroundNormFlex(pixs, 7, 7, 1, 1, 20);
    pixt2 = pixThresholdToBinary(pixt1, 240);
    pixInvert(pixt2, pixt2);
    pixm = pixMorphSequence(pixt2, "d21.21", 0);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

        /* Use Otsu to get a global threshold estimate for the image,
         * which is stored as a single pixel in pixt3. */
    pixGetDimensions(pixs, &w, &h, NULL);
    pixOtsuAdaptiveThreshold(pixs, w, h, 0, 0, scorefract, &pixt3, NULL);
    if (pixt3 && pthresh) {
        pixGetPixel(pixt3, 0, 0, &val);
        *pthresh = val;
    }
    pixDestroy(&pixt3);

        /* Threshold the background normalized images differentially,
         * using a high value correlated with the background normalization
         * for the part of the image under the mask (i.e., near the
         * darker, thicker foreground), and a value that depends on the Otsu
         * threshold for the rest of the image.  This gives a solid
         * (high) thresholding for the foreground parts of the image,
         * while allowing the background and light foreground to be
         * reasonably well cleaned using a threshold adapted to the
         * input image. */
    pixd = pixThresholdToBinary(pixn, val + 30);  /* for bg and light fg */
    pixt4 = pixThresholdToBinary(pixn, 190);  /* for heavier fg */
    pixCombineMasked(pixd, pixt4, pixm);
    pixDestroy(&pixt4);
    pixDestroy(&pixm);
    pixDestroy(&pixn);

    if (!pixd)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    else
        return pixd;
}
/*!
 *  pixMaskedThreshOnBackgroundNorm()
 *
 *      Input:  pixs (8 bpp grayscale; not colormapped)
 *              pixim (<optional> 1 bpp 'image' mask; can be null)
 *              sx, sy (tile size in pixels)
 *              thresh (threshold for determining foreground)
 *              mincount (min threshold on counts in a tile)
 *              smoothx (half-width of block convolution kernel width)
 *              smoothy (half-width of block convolution kernel height)
 *              scorefract (fraction of the max Otsu score; typ. ~ 0.1)
 *              &thresh (<optional return> threshold value that was
 *                       used on the normalized image)
 *      Return: pixd (1 bpp thresholded image), or null on error
 *
 *  Notes:
 *      (1) This begins with a standard background normalization.
 *          Additionally, there is a flexible background norm, that
 *          will adapt to a rapidly varying background, and this
 *          puts white pixels in the background near regions with
 *          significant foreground.  The white pixels are turned into
 *          a 1 bpp selection mask by binarization followed by dilation.
 *          Otsu thresholding is performed on the input image to get an
 *          estimate of the threshold in the non-mask regions.
 *          The background normalized image is thresholded with two
 *          different values, and the result is combined using
 *          the selection mask.
 *      (2) Note that the numbers 255 (for bgval target) and 190 (for
 *          thresholding on pixn) are tied together, and explicitly
 *          defined in this function.
 *      (3) See pixBackgroundNorm() for meaning and typical values
 *          of input parameters.  For a start, you can try:
 *            sx, sy = 10, 15
 *            thresh = 100
 *            mincount = 50
 *            smoothx, smoothy = 2
 */


(1) This begins with a standard background normalization.
Additionally, there is a flexible background norm, that
will adapt to a rapidly varying background, and this
puts white pixels in the background near regions with
significant foreground.  The white pixels are turned into
a 1 bpp selection mask by binarization followed by dilation.
Otsu thresholding is performed on the input image to get an
estimate of the threshold in the non-mask regions.
The background normalized image is thresholded with two
different values, and the result is combined using
the selection mask.
(2) Note that the numbers 255 (for bgval target) and 190 (for
thresholding on pixn) are tied together, and explicitly
defined in this function.
(3) See pixBackgroundNorm() for meaning and typical values
of input parameters.  For a start, you can try:
sx, sy = 10, 15
thresh = 100
mincount = 50
smoothx, smoothy = 2
( 1 ) This begins with a standard background normalization . Additionally there is a flexible background norm that will adapt to a rapidly varying background and this puts white pixels in the background near regions with significant foreground . The white pixels are turned into a 1 bpp selection mask by binarization followed by dilation . Otsu thresholding is performed on the input image to get an estimate of the threshold in the non - mask regions . The background normalized image is thresholded with two different values and the result is combined using the selection mask . ( 2 ) Note that the numbers 255 ( for bgval target ) and 190 ( for thresholding on pixn ) are tied together and explicitly defined in this function . ( 3 ) See pixBackgroundNorm () for meaning and typical values of input parameters . For a start you can try : sx sy = 10 15 thresh = 100 mincount = 50 smoothx smoothy = 2
PIX *
pixMaskedThreshOnBackgroundNorm(PIX       *pixs,
                                PIX       *pixim,
                                l_int32    sx,
                                l_int32    sy,
                                l_int32    thresh,
                                l_int32    mincount,
                                l_int32    smoothx,
                                l_int32    smoothy,
                                l_float32  scorefract,
                                l_int32   *pthresh)
{
l_int32   w, h;
l_uint32  val;
PIX      *pixn, *pixm, *pixd, *pixt1, *pixt2, *pixt3, *pixt4;
    PROCNAME("pixMaskedThreshOnBackgroundNorm");
    if (pthresh) *pthresh = 0;
    if (!pixs || pixGetDepth(pixs) != 8)
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
    if (pixGetColormap(pixs))
        return (PIX *)ERROR_PTR("pixs is colormapped", procName, NULL);
    if (sx < 4 || sy < 4)
        return (PIX *)ERROR_PTR("sx and sy must be >= 4", procName, NULL);
    if (mincount > sx * sy) {
        L_WARNING("mincount too large for tile size", procName);
        mincount = (sx * sy) / 3;
    }
    pixn = pixBackgroundNorm(pixs, pixim, NULL, sx, sy, thresh,
                             mincount, 255, smoothx, smoothy);
    if (!pixn)
        return (PIX *)ERROR_PTR("pixn not made", procName, NULL);
    pixt1 = pixBackgroundNormFlex(pixs, 7, 7, 1, 1, 20);
    pixt2 = pixThresholdToBinary(pixt1, 240);
    pixInvert(pixt2, pixt2);
    pixm = pixMorphSequence(pixt2, "d21.21", 0);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixGetDimensions(pixs, &w, &h, NULL);
    pixOtsuAdaptiveThreshold(pixs, w, h, 0, 0, scorefract, &pixt3, NULL);
    if (pixt3 && pthresh) {
        pixGetPixel(pixt3, 0, 0, &val);
        *pthresh = val;
    }
    pixDestroy(&pixt3);
    pixd = pixThresholdToBinary(pixn, val + 30);  
    pixt4 = pixThresholdToBinary(pixn, 190);  
    pixCombineMasked(pixd, pixt4, pixm);
    pixDestroy(&pixt4);
    pixDestroy(&pixm);
    pixDestroy(&pixn);
    if (!pixd)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    else
        return pixd;
}
PIX * pixMaskedThreshOnBackgroundNorm ( PIX * pixs , PIX * pixim , l_int32 sx , l_int32 sy , l_int32 thresh , l_int32 mincount , l_int32 smoothx , l_int32 smoothy , l_float32 scorefract , l_int32 * pthresh ) { l_int32 w , h ; l_uint32 val ; PIX * pixn , * pixm , * pixd , * pixt1 , * pixt2 , * pixt3 , * pixt4 ; PROCNAME ( " " ) ; if ( pthresh ) * pthresh = 0 ; if ( ! pixs || pixGetDepth ( pixs ) != 8 ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( pixGetColormap ( pixs ) ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( sx < 4 || sy < 4 ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( mincount > sx * sy ) { L_WARNING ( " " , procName ) ; mincount = ( sx * sy ) / 3 ; } pixn = pixBackgroundNorm ( pixs , pixim , NULL , sx , sy , thresh , mincount , 255 , smoothx , smoothy ) ; if ( ! pixn ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; pixt1 = pixBackgroundNormFlex ( pixs , 7 , 7 , 1 , 1 , 20 ) ; pixt2 = pixThresholdToBinary ( pixt1 , 240 ) ; pixInvert ( pixt2 , pixt2 ) ; pixm = pixMorphSequence ( pixt2 , " " , 0 ) ; pixDestroy ( & pixt1 ) ; pixDestroy ( & pixt2 ) ; pixGetDimensions ( pixs , & w , & h , NULL ) ; pixOtsuAdaptiveThreshold ( pixs , w , h , 0 , 0 , scorefract , & pixt3 , NULL ) ; if ( pixt3 && pthresh ) { pixGetPixel ( pixt3 , 0 , 0 , & val ) ; * pthresh = val ; } pixDestroy ( & pixt3 ) ; pixd = pixThresholdToBinary ( pixn , val + 30 ) ; pixt4 = pixThresholdToBinary ( pixn , 190 ) ; pixCombineMasked ( pixd , pixt4 , pixm ) ; pixDestroy ( & pixt4 ) ; pixDestroy ( & pixm ) ; pixDestroy ( & pixn ) ; if ( ! pixd ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; else return pixd ; }
pixMaskedThreshOnBackgroundNorm()
      Input:  pixs (8 bpp grayscale; not colormapped)
              pixim (<optional> 1 bpp 'image' mask; can be null)
              sx, sy (tile size in pixels)
              thresh (threshold for determining foreground)
              mincount (min threshold on counts in a tile)
              smoothx (half-width of block convolution kernel width)
              smoothy (half-width of block convolution kernel height)
              scorefract (fraction of the max Otsu score; typ.
pixMaskedThreshOnBackgroundNorm () Input : pixs ( 8 bpp grayscale ; not colormapped ) pixim ( <optional > 1 bpp ' image ' mask ; can be null ) sx sy ( tile size in pixels ) thresh ( threshold for determining foreground ) mincount ( min threshold on counts in a tile ) smoothx ( half - width of block convolution kernel width ) smoothy ( half - width of block convolution kernel height ) scorefract ( fraction of the max Otsu score ; typ .
/* Standard background normalization */ /* Special background normalization for adaptation to quickly
         * varying background.  Threshold on the very light parts,
         * which tend to be near significant edges, and dilate to
         * form a mask over regions that are typically text.  The
         * dilation size is chosen to cover the text completely,
         * except for very thick fonts. */ /* Use Otsu to get a global threshold estimate for the image,
         * which is stored as a single pixel in pixt3. */ /* Threshold the background normalized images differentially,
         * using a high value correlated with the background normalization
         * for the part of the image under the mask (i.e., near the
         * darker, thicker foreground), and a value that depends on the Otsu
         * threshold for the rest of the image.  This gives a solid
         * (high) thresholding for the foreground parts of the image,
         * while allowing the background and light foreground to be
         * reasonably well cleaned using a threshold adapted to the
         * input image. */ /* for bg and light fg */ /* for heavier fg */