src/binarize.c
PIX *
pixOtsuThreshOnBackgroundNorm(PIX       *pixs,
                              PIX       *pixim,
                              l_int32    sx,
                              l_int32    sy,
                              l_int32    thresh,
                              l_int32    mincount,
                              l_int32    bgval,
                              l_int32    smoothx,
                              l_int32    smoothy,
                              l_float32  scorefract,
                              l_int32   *pthresh)
{
l_int32   w, h;
l_uint32  val;
PIX      *pixn, *pixt, *pixd;

    PROCNAME("pixOtsuThreshOnBackgroundNorm");

    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, bgval, smoothx, smoothy);
    if (!pixn)
        return (PIX *)ERROR_PTR("pixn not made", procName, NULL);

        /* Just use 1 tile for a global threshold, which is stored
         * as a single pixel in pixt. */
    pixGetDimensions(pixn, &w, &h, NULL);
    pixOtsuAdaptiveThreshold(pixn, w, h, 0, 0, scorefract, &pixt, &pixd);
    pixDestroy(&pixn);

    if (pixt && pthresh) {
        pixGetPixel(pixt, 0, 0, &val);
        *pthresh = val;
    }
    pixDestroy(&pixt);

    if (!pixd)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    else
        return pixd;
}
/*!
 *  pixOtsuThreshOnBackgroundNorm()
 *
 *      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)
 *              bgval (target bg val; typ. > 128)
 *              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 does background normalization followed by Otsu
 *          thresholding.  Otsu binarization attempts to split the
 *          image into two roughly equal sets of pixels, and it does
 *          a very poor job when there are large amounts of dark
 *          background.  By doing a background normalization first,
 *          to get the background near 255, we remove this problem.
 *          Then we use a modified Otsu to estimate the best global
 *          threshold on the normalized image.
 *      (2) See pixBackgroundNorm() for meaning and typical values
 *          of input parameters.  For a start, you can try:
 *            sx, sy = 10, 15
 *            thresh = 100
 *            mincount = 50
 *            bgval = 255
 *            smoothx, smoothy = 2
 */


(1) This does background normalization followed by Otsu
thresholding.  Otsu binarization attempts to split the
image into two roughly equal sets of pixels, and it does
a very poor job when there are large amounts of dark
background.  By doing a background normalization first,
to get the background near 255, we remove this problem.
Then we use a modified Otsu to estimate the best global
threshold on the normalized image.
(2) See pixBackgroundNorm() for meaning and typical values
of input parameters.
( 1 ) This does background normalization followed by Otsu thresholding . Otsu binarization attempts to split the image into two roughly equal sets of pixels and it does a very poor job when there are large amounts of dark background . By doing a background normalization first to get the background near 255 we remove this problem . Then we use a modified Otsu to estimate the best global threshold on the normalized image . ( 2 ) See pixBackgroundNorm () for meaning and typical values of input parameters .
PIX *
pixOtsuThreshOnBackgroundNorm(PIX       *pixs,
                              PIX       *pixim,
                              l_int32    sx,
                              l_int32    sy,
                              l_int32    thresh,
                              l_int32    mincount,
                              l_int32    bgval,
                              l_int32    smoothx,
                              l_int32    smoothy,
                              l_float32  scorefract,
                              l_int32   *pthresh)
{
l_int32   w, h;
l_uint32  val;
PIX      *pixn, *pixt, *pixd;
    PROCNAME("pixOtsuThreshOnBackgroundNorm");
    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, bgval, smoothx, smoothy);
    if (!pixn)
        return (PIX *)ERROR_PTR("pixn not made", procName, NULL);
    pixGetDimensions(pixn, &w, &h, NULL);
    pixOtsuAdaptiveThreshold(pixn, w, h, 0, 0, scorefract, &pixt, &pixd);
    pixDestroy(&pixn);
    if (pixt && pthresh) {
        pixGetPixel(pixt, 0, 0, &val);
        *pthresh = val;
    }
    pixDestroy(&pixt);
    if (!pixd)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    else
        return pixd;
}
PIX * pixOtsuThreshOnBackgroundNorm ( PIX * pixs , PIX * pixim , l_int32 sx , l_int32 sy , l_int32 thresh , l_int32 mincount , l_int32 bgval , l_int32 smoothx , l_int32 smoothy , l_float32 scorefract , l_int32 * pthresh ) { l_int32 w , h ; l_uint32 val ; PIX * pixn , * pixt , * pixd ; 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 , bgval , smoothx , smoothy ) ; if ( ! pixn ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; pixGetDimensions ( pixn , & w , & h , NULL ) ; pixOtsuAdaptiveThreshold ( pixn , w , h , 0 , 0 , scorefract , & pixt , & pixd ) ; pixDestroy ( & pixn ) ; if ( pixt && pthresh ) { pixGetPixel ( pixt , 0 , 0 , & val ) ; * pthresh = val ; } pixDestroy ( & pixt ) ; if ( ! pixd ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; else return pixd ; }
pixOtsuThreshOnBackgroundNorm()
      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)
              bgval (target bg val; typ.
pixOtsuThreshOnBackgroundNorm () 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 ) bgval ( target bg val ; typ .
/* Just use 1 tile for a global threshold, which is stored
         * as a single pixel in pixt. */