コード例 #1
0
ファイル: morphseq.c プロジェクト: ErfanHasmin/scope-ocr
/*!
 *  pixGrayMorphSequence()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (controls debug display of each result in the sequence:
 *                       0: no output
 *                       > 0: gives horizontal separation in pixels between
 *                            successive displays
 *                       < 0: pdf output; abs(dispsep) is used for naming)
 *              dispy (if dispsep > 0, this gives the y-value of the
 *                     UL corner for display; otherwise it is ignored)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This works on 8 bpp grayscale images.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) This only uses brick SELs.
 *      (4) A new image is always produced; the input image is not changed.
 *      (5) This contains an interpreter, allowing sequences to be
 *          generated and run.
 *      (6) The format of the sequence string is defined below.
 *      (7) In addition to morphological operations, the composite
 *          morph/subtract tophat can be performed.
 *      (8) Sel sizes (width, height) must each be odd numbers.
 *      (9) Intermediate results can optionally be displayed
 *      (10) The sequence string is formatted as follows:
 *            - An arbitrary number of operations,  each separated
 *              by a '+' character.  White space is ignored.
 *            - Each operation begins with a case-independent character
 *              specifying the operation:
 *                 d or D  (dilation)
 *                 e or E  (erosion)
 *                 o or O  (opening)
 *                 c or C  (closing)
 *                 t or T  (tophat)
 *            - The args to the morphological operations are bricks of hits,
 *              and are formatted as a.b, where a and b are horizontal and
 *              vertical dimensions, rsp. (each must be an odd number)
 *            - The args to the tophat are w or W (for white tophat)
 *              or b or B (for black tophat), followed by a.b as for
 *              the dilation, erosion, opening and closing.
 *           Example valid sequences are:
 *             "c5.3 + o7.5"
 *             "c9.9 + tw9.9"
 */
PIX *
pixGrayMorphSequence(PIX         *pixs,
                     const char  *sequence,
                     l_int32      dispsep,
                     l_int32      dispy)
{
char    *rawop, *op, *fname;
char     buf[256];
l_int32  nops, i, valid, w, h, x, pdfout;
PIX     *pixt1, *pixt2;
PIXA    *pixa;
SARRAY  *sa;

    PROCNAME("pixGrayMorphSequence");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (!sequence)
        return (PIX *)ERROR_PTR("sequence not defined", procName, NULL);

        /* Split sequence into individual operations */
    sa = sarrayCreate(0);
    sarraySplitString(sa, sequence, "+");
    nops = sarrayGetCount(sa);
    pdfout = (dispsep < 0) ? 1 : 0;

        /* Verify that the operation sequence is valid */
    valid = TRUE;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
        op = stringRemoveChars(rawop, " \n\t");
        switch (op[0])
        {
        case 'd':
        case 'D':
        case 'e':
        case 'E':
        case 'o':
        case 'O':
        case 'c':
        case 'C':
            if (sscanf(&op[1], "%d.%d", &w, &h) != 2) {
                fprintf(stderr, "*** op: %s invalid\n", op);
                valid = FALSE;
                break;
            }
            if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
                fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be odd\n",
                        op, w, h);
                valid = FALSE;
                break;
            }
/*            fprintf(stderr, "op = %s; w = %d, h = %d\n", op, w, h); */
            break;
        case 't':
        case 'T':
            if (op[1] != 'w' && op[1] != 'W' &&
                op[1] != 'b' && op[1] != 'B') {
                fprintf(stderr,
                        "*** op = %s; arg %c must be 'w' or 'b'\n", op, op[1]);
                valid = FALSE;
                break;
            }
            sscanf(&op[2], "%d.%d", &w, &h);
            if (w < 1 || (w & 1) == 0 || h < 1 || (h & 1) == 0 ) {
                fprintf(stderr,
                        "*** op: %s; w = %d, h = %d; must both be odd\n",
                        op, w, h);
                valid = FALSE;
                break;
            }
/*            fprintf(stderr, "op = %s", op); */
            break;
        default:
            fprintf(stderr, "*** nonexistent op = %s\n", op);
            valid = FALSE;
        }
        FREE(op);
    }
    if (!valid) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence invalid", procName, NULL);
    }

        /* Parse and operate */
    pixa = NULL;
    if (pdfout) {
        pixa = pixaCreate(0);
        pixaAddPix(pixa, pixs, L_CLONE);
        snprintf(buf, sizeof(buf), "/tmp/seq_output_%d.pdf", L_ABS(dispsep));
        fname = genPathname(buf, NULL);
    }
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = 0;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, 0);
        op = stringRemoveChars(rawop, " \n\t");
        switch (op[0])
        {
        case 'd':
        case 'D':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixDilateGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixOpenGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixCloseGray(pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 't':
        case 'T':
            sscanf(&op[2], "%d.%d", &w, &h);
            if (op[1] == 'w' || op[1] == 'W')
                pixt2 = pixTophat(pixt1, w, h, L_TOPHAT_WHITE);
            else   /* 'b' or 'B' */
                pixt2 = pixTophat(pixt1, w, h, L_TOPHAT_BLACK);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        FREE(op);

            /* Debug output */
        if (dispsep > 0) {
            pixDisplay(pixt1, x, dispy);
            x += dispsep;
        }
        if (pdfout)
            pixaAddPix(pixa, pixt1, L_COPY);
    }

    if (pdfout) {
        pixaConvertToPdf(pixa, 0, 1.0, L_FLATE_ENCODE, 0, fname, fname);
        FREE(fname);
        pixaDestroy(&pixa);
    }

    sarrayDestroy(&sa);
    return pixt1;
}
コード例 #2
0
ファイル: rank.c プロジェクト: 0359xiaodong/tess-two
/*!
 *  pixRankFilterGray()
 *
 *      Input:  pixs (8 bpp; no colormap)
 *              wf, hf  (width and height of filter; each is >= 1)
 *              rank (in [0.0 ... 1.0])
 *      Return: pixd (of rank values), or null on error
 *
 *  Notes:
 *      (1) This defines, for each pixel in pixs, a neighborhood of
 *          pixels given by a rectangle "centered" on the pixel.
 *          This set of wf*hf pixels has a distribution of values,
 *          and if they are sorted in increasing order, we choose
 *          the pixel such that rank*(wf*hf-1) pixels have a lower
 *          or equal value and (1-rank)*(wf*hf-1) pixels have an equal
 *          or greater value.
 *      (2) By this definition, the rank = 0.0 pixel has the lowest
 *          value, and the rank = 1.0 pixel has the highest value.
 *      (3) We add mirrored boundary pixels to avoid boundary effects,
 *          and put the filter center at (0, 0).
 *      (4) This dispatches to grayscale erosion or dilation if the
 *          filter dimensions are odd and the rank is 0.0 or 1.0, rsp.
 *      (5) Returns a copy if both wf and hf are 1.
 *      (6) Uses row-major or column-major incremental updates to the
 *          histograms depending on whether hf > wf or hv <= wf, rsp.
 */
PIX  *
pixRankFilterGray(PIX       *pixs,
                  l_int32    wf,
                  l_int32    hf,
                  l_float32  rank)
{
l_int32    w, h, d, i, j, k, m, n, rankloc, wplt, wpld, val, sum;
l_int32   *histo, *histo16;
l_uint32  *datat, *linet, *datad, *lined;
PIX       *pixt, *pixd;

    PROCNAME("pixRankFilterGray");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetColormap(pixs) != NULL)
        return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 8)
        return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
    if (wf < 1 || hf < 1)
        return (PIX *)ERROR_PTR("wf < 1 || hf < 1", procName, NULL);
    if (rank < 0.0 || rank > 1.0)
        return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
    if (wf == 1 && hf == 1)   /* no-op */
        return pixCopy(NULL, pixs);

        /* For rank = 0.0, this is a grayscale erosion, and for rank = 1.0,
         * a dilation.  Grayscale morphology operations are implemented
         * for filters of odd dimension, so we dispatch to grayscale
         * morphology if both wf and hf are odd.  Otherwise, we
         * slightly adjust the rank (to get the correct behavior) and
         * use the slower rank filter here. */
    if (wf % 2 && hf % 2) {
        if (rank == 0.0)
            return pixErodeGray(pixs, wf, hf);
        else if (rank == 1.0)
            return pixDilateGray(pixs, wf, hf);
    }
    if (rank == 0.0) rank = 0.0001;
    if (rank == 1.0) rank = 0.9999;

        /* Add wf/2 to each side, and hf/2 to top and bottom of the
         * image, mirroring for accuracy and to avoid special-casing
         * the boundary. */
    if ((pixt = pixAddMirroredBorder(pixs, wf / 2, wf / 2, hf / 2, hf / 2))
        == NULL)
        return (PIX *)ERROR_PTR("pixt not made", procName, NULL);

        /* Set up the two histogram arrays. */
    histo = (l_int32 *)CALLOC(256, sizeof(l_int32));
    histo16 = (l_int32 *)CALLOC(16, sizeof(l_int32));
    rankloc = (l_int32)(rank * wf * hf);

        /* Place the filter center at (0, 0).  This is just a
         * convenient location, because it allows us to perform
         * the rank filter over x:(0 ... w - 1) and y:(0 ... h - 1). */
    pixd = pixCreateTemplate(pixs);
    datat = pixGetData(pixt);
    wplt = pixGetWpl(pixt);
    datad = pixGetData(pixd);
    wpld = pixGetWpl(pixd);

        /* If hf > wf, it's more efficient to use row-major scanning.
         * Otherwise, traverse the image in use column-major order.  */
    if (hf > wf) {
        for (j = 0; j < w; j++) {  /* row-major */
                /* Start each column with clean histogram arrays. */
            for (n = 0; n < 256; n++)
                histo[n] = 0;
            for (n = 0; n < 16; n++)
                histo16[n] = 0;

            for (i = 0; i < h; i++) {  /* fast scan on columns */
                    /* Update the histos for the new location */
                lined = datad + i * wpld;
                if (i == 0) {  /* do full histo */
                    for (k = 0; k < hf; k++) {
                        linet = datat + (i + k) * wplt; 
                        for (m = 0; m < wf; m++) {
                            val = GET_DATA_BYTE(linet, j + m);
                            histo[val]++;
                            histo16[val >> 4]++;
                        }
                    }
                } else {  /* incremental update */
                    linet = datat + (i - 1) * wplt;
                    for (m = 0; m < wf; m++) {  /* remove top line */
                        val = GET_DATA_BYTE(linet, j + m);
                        histo[val]--;
                        histo16[val >> 4]--;
                    }
                    linet = datat + (i + hf -  1) * wplt;
                    for (m = 0; m < wf; m++) {  /* add bottom line */
                        val = GET_DATA_BYTE(linet, j + m);
                        histo[val]++;
                        histo16[val >> 4]++;
                    }
                }

                    /* Find the rank value */
                sum = 0;
                for (n = 0; n < 16; n++) {  /* search over coarse histo */
                    sum += histo16[n];
                    if (sum > rankloc) {
                        sum -= histo16[n];
                        break;
                    }
                }
                k = 16 * n;  /* starting value in fine histo */
                for (m = 0; m < 16; m++) {
                    sum += histo[k];
                    if (sum > rankloc) {
                        SET_DATA_BYTE(lined, j, k); 
                        break;
                    }
                    k++;
                }
            }
        }
    } else {  /* wf >= hf */