Esempio n. 1
0
Pix* edgeBinarize(Pix* pix){
    FUNCNAME("edgeBinarize");
#if HAS_ADAPTIVE_BINARIZER
    PixAdaptiveBinarizer binarizer(false);
    return binarizer.bradleyAdaptiveThresholding(pix, 0.15, 8);
#endif
    Pix* result;
    pixOtsuAdaptiveThreshold(pix, pixGetWidth(pix), pixGetHeight(pix), 0, 0, 0.1, NULL, &result);
    pixCopyResolution(result, pix);
    return result;
}
Esempio n. 2
0
/*!
 *  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
 */
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\n", 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;
}
Esempio n. 3
0
jint Java_com_googlecode_leptonica_android_Binarize_nativeOtsuAdaptiveThreshold(JNIEnv *env,
                                                                                jclass clazz,
                                                                                jint nativePix,
                                                                                jint sizeX,
                                                                                jint sizeY,
                                                                                jint smoothX,
                                                                                jint smoothY,
                                                                                jfloat scoreFract) {

  PIX *pixs = (PIX *) nativePix;
  PIX *pixd;

  if (pixOtsuAdaptiveThreshold(pixs, (l_int32) sizeX, (l_int32) sizeY, (l_int32) smoothX,
                               (l_int32) smoothY, (l_float32) scoreFract, NULL, &pixd)) {
    return (jint) 0;
  }

  return (jint) pixd;
}
Esempio n. 4
0
int main(int argc,
         char **argv) {
    char *infile;
    l_int32 w, d, threshval, ival, newval;
    l_uint32 val;
    PIX *pixs, *pixg, *pixg2;
    PIX *pix1, *pix2;
    PIXA *pixa;
    static char mainName[] = "binarize_set";

    if (argc != 2)
        return ERROR_INT(" Syntax: binarize_set infile", mainName, 1);
    infile = argv[1];

    pixa = pixaCreate(5);
    pixs = pixRead(infile);
    pixGetDimensions(pixs, &w, NULL, &d);
    pixSaveTiled(pixs, pixa, 1.0, 1, 50, 32);
    pixDisplay(pixs, 100, 0);

#if ALL
    /* 1. Standard background normalization with a global threshold.  */
    pixg = pixConvertTo8(pixs, 0);
    pix1 = pixBackgroundNorm(pixg, NULL, NULL, 10, 15, 100, 50, 255, 2, 2);
    pix2 = pixThresholdToBinary(pix1, 160);
    pixWrite("/tmp/binar1.png", pix2, IFF_PNG);
    pixDisplay(pix2, 100, 0);
    pixSaveTiled(pix2, pixa, 1.0, 1, 50, 32);
    pixDestroy(&pixg);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
#endif

#if ALL
    /* 2. 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.  */
    pixg = pixConvertTo8(pixs, 0);
    pix1 = pixOtsuThreshOnBackgroundNorm(pixg, NULL, 10, 15, 100,
                                         50, 255, 2, 2, 0.10, &threshval);
    fprintf(stderr, "thresh val = %d\n", threshval);
    pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32);
    pixWrite("/tmp/binar2.png", pix1, IFF_PNG);
    pixDisplay(pix1, 100, 200);
    pixDestroy(&pixg);
    pixDestroy(&pix1);
#endif

#if ALL
    /* 3. Background normalization with Otsu threshold estimation and
     * masking for threshold selection.  */
    pixg = pixConvertTo8(pixs, 0);
    pix1 = pixMaskedThreshOnBackgroundNorm(pixg, NULL, 10, 15, 100,
                                           50, 2, 2, 0.10, &threshval);
    fprintf(stderr, "thresh val = %d\n", threshval);
    pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32);
    pixWrite("/tmp/binar3.png", pix1, IFF_PNG);
    pixDisplay(pix1, 100, 400);
    pixDestroy(&pixg);
    pixDestroy(&pix1);
#endif

#if ALL
    /* 4. Background normalization followed by Sauvola binarization */
    if (d == 32)
        pixg = pixConvertRGBToGray(pixs, 0.2, 0.7, 0.1);
    else
        pixg = pixConvertTo8(pixs, 0);
    pixg2 = pixContrastNorm(NULL, pixg, 20, 20, 130, 2, 2);
    pixSauvolaBinarizeTiled(pixg2, 25, 0.40, 1, 1, NULL, &pix1);
    pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32);
    pixWrite("/tmp/binar4.png", pix1, IFF_PNG);
    pixDisplay(pix1, 100, 600);
    pixDestroy(&pixg);
    pixDestroy(&pixg2);
    pixDestroy(&pix1);
#endif

#if ALL
    /* 5. Contrast normalization followed by background normalization, and
     * thresholding. */
    if (d == 32)
        pixg = pixConvertRGBToGray(pixs, 0.2, 0.7, 0.1);
    else
        pixg = pixConvertTo8(pixs, 0);

    pixOtsuAdaptiveThreshold(pixg, 5000, 5000, 0, 0, 0.1, &pix1, NULL);
    pixGetPixel(pix1, 0, 0, &val);
    ival = (l_int32) val;
    newval = ival + (l_int32)(0.6 * (110 - ival));
    fprintf(stderr, "th1 = %d, th2 = %d\n", ival, newval);
    pixDestroy(&pix1);

    pixContrastNorm(pixg, pixg, 50, 50, 130, 2, 2);
    pixg2 = pixBackgroundNorm(pixg, NULL, NULL, 20, 20, 70, 40, 200, 2, 2);

    ival = L_MIN(ival, 110);
    pix1 = pixThresholdToBinary(pixg2, ival);
    pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32);
    pixWrite("/tmp/binar5.png", pix1, IFF_PNG);
    pixDisplay(pix1, 100, 800);
    pixDestroy(&pixg);
    pixDestroy(&pixg2);
    pixDestroy(&pix1);
#endif

    pix1 = pixaDisplayTiledInRows(pixa, 32, w + 100, 1.0, 0, 30, 2);
    pixWrite("/tmp/binar6.png", pix1, IFF_PNG);
    pixDisplay(pix1, 1000, 0);
    pixDestroy(&pix1);
    pixaDestroy(&pixa);

    pixDestroy(&pixs);
    return 0;
}
Esempio n. 5
0
/*!
 *  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
 */
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\n", 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;
}
Esempio n. 6
0
int main(int argc,
         char **argv) {
    char textstr[256];
    l_int32 i, thresh, fgval, bgval;
    l_float32 scorefract;
    L_BMF *bmf;
    PIX *pixs, *pixb, *pixb2, *pixb3, *pixg, *pixp, *pixt1, *pixt2;
    PIXA *pixa;

    pixs = pixRead("1555-7.jpg");
    pixg = pixConvertTo8(pixs, 0);
    bmf = bmfCreate("fonts", 8);
    for (i = 0; i < 3; i++) {
        pixa = pixaCreate(3);
        scorefract = 0.1 * i;
        pixOtsuAdaptiveThreshold(pixg, 2000, 2000, 0, 0, scorefract,
                                 NULL, &pixb);
        pixSaveTiledOutline(pixb, pixa, 0.5, 1, 20, 2, 32);
        pixSplitDistributionFgBg(pixg, scorefract, 1, &thresh, &fgval, &bgval, 1);
        fprintf(stderr, "thresh = %d, fgval = %d, bgval = %d\n", thresh, fgval,
                bgval);

        /* Give gnuplot time to write out the plot */
#ifndef  _WIN32
        sleep(1);
#else
        Sleep(1000);
#endif  /* _WIN32 */

        pixp = pixRead("/tmp/histplot.png");
        pixSaveTiled(pixp, pixa, 1.0, 0, 20, 1);
        pixt1 = pixaDisplay(pixa, 0, 0);
        snprintf(textstr, sizeof(textstr),
                 "Scorefract = %3.1f ........... Thresh = %d", scorefract, thresh);
        pixt2 = pixAddSingleTextblock(pixt1, bmf, textstr, 0x00ff0000,
                                      L_ADD_BELOW, NULL);
        pixDisplay(pixt2, 100, 100);
        snprintf(textstr, sizeof(textstr), "/tmp/otsu.%d.png", i);
        pixWrite(textstr, pixt2, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixp);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixaDestroy(&pixa);
    }

    pixa = pixaCreate(2);
    for (i = 0; i < 2; i++) {
        scorefract = 0.1 * i;
        pixOtsuAdaptiveThreshold(pixg, 300, 300, 0, 0, scorefract,
                                 NULL, &pixb);
        pixb2 = pixAddBlackOrWhiteBorder(pixb, 2, 2, 2, 2, L_GET_BLACK_VAL);
        snprintf(textstr, sizeof(textstr),
                 "Scorefract = %3.1f", scorefract);
        pixb3 = pixAddSingleTextblock(pixb2, bmf, textstr, 1,
                                      L_ADD_BELOW, NULL);
        pixSaveTiled(pixb3, pixa, 2, (i + 1) % 1, 20, 32);
        pixDestroy(&pixb);
        pixDestroy(&pixb2);
    }
    pixb = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/otsu-tiled.jpg", pixb, IFF_PNG);
    pixDestroy(&pixb);
    pixaDestroy(&pixa);

    bmfDestroy(&bmf);
    pixDestroy(&pixs);
    pixDestroy(&pixg);
    return 0;
}