Пример #1
0
/*!
 *  pixMorphCompSequenceDwa()
 *
 *      Input:  pixs
 *              sequence (string specifying sequence)
 *              dispsep (horizontal separation in pixels between
 *                       successive displays; use zero to suppress display)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This does dwa morphology on binary images, using brick Sels.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) It implements all brick Sels that have dimensions up to 63
 *          on each side, using a composite (linear + comb) when useful.
 *      (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) See pixMorphSequence() for further information about usage.
 */
PIX *
pixMorphCompSequenceDwa(PIX         *pixs,
                        const char  *sequence,
                        l_int32      dispsep)
{
char    *rawop, *op;
l_int32  nops, i, j, nred, fact, w, h, x, y, border;
l_int32  level[4];
PIX     *pixt1, *pixt2;
SARRAY  *sa;

    PROCNAME("pixMorphCompSequenceDwa");

    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);

    if (!morphSequenceVerify(sa)) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence not valid", procName, NULL);
    }

        /* Parse and operate */
    border = 0;
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = y = 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 = pixDilateCompBrickDwa(NULL, pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeCompBrickDwa(NULL, pixt1, w, h);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixOpenCompBrickDwa(pixt1, pixt1, w, h);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixCloseCompBrickDwa(pixt1, pixt1, w, h);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'r':
        case 'R':
            nred = strlen(op) - 1;
            for (j = 0; j < nred; j++)
                level[j] = op[j + 1] - '0';
            for (j = nred; j < 4; j++)
                level[j] = 0;
            pixt2 = pixReduceRankBinaryCascade(pixt1, level[0], level[1],
                                               level[2], level[3]);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'x':
        case 'X':
            sscanf(&op[1], "%d", &fact);
            pixt2 = pixExpandReplicate(pixt1, fact);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        case 'b':
        case 'B':
            sscanf(&op[1], "%d", &border);
            pixt2 = pixAddBorder(pixt1, border, 0);
            pixDestroy(&pixt1);
            pixt1 = pixClone(pixt2);
            pixDestroy(&pixt2);
            if (dispsep > 0) {
                pixDisplay(pixt1, x, y);
                x += dispsep;
            }
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        FREE(op);
    }
    if (border > 0) {
        pixt2 = pixRemoveBorder(pixt1, border);
        pixDestroy(&pixt1);
        pixt1 = pixClone(pixt2);
        pixDestroy(&pixt2);
    }

    sarrayDestroy(&sa);
    return pixt1;
}
Пример #2
0
/* dwa composite with morph non-composite */
l_int32
DoComparisonDwa5(PIX *pixs,
                 PIX *pixt1,
                 PIX *pixt2,
                 PIX *pixt3,
                 PIX *pixt4,
                 PIX *pixt5,
                 PIX *pixt6,
                 l_int32 isize) {
    l_int32 fact1, fact2, size;

    selectComposableSizes(isize, &fact1, &fact2);
    size = fact1 * fact2;

    fprintf(stderr, "..%d..", size);

    if (TIMING) startTimer();
    pixDilateCompBrickDwa(pixt1, pixs, size, 1);
    pixDilateCompBrickDwa(pixt3, pixs, 1, size);
    pixDilateCompBrickDwa(pixt5, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer());
    if (TIMING) startTimer();
    pixDilateBrick(pixt2, pixs, size, 1);
    pixDilateBrick(pixt4, pixs, 1, size);
    pixDilateBrick(pixt6, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer());
    PixCompareDwa(size, "dilate", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6);

/*    pixDisplay(pixt1, 100, 100);  */
/*    pixDisplay(pixt2, 800, 100);  */

    if (TIMING) startTimer();
    pixErodeCompBrickDwa(pixt1, pixs, size, 1);
    pixErodeCompBrickDwa(pixt3, pixs, 1, size);
    pixErodeCompBrickDwa(pixt5, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer());
    if (TIMING) startTimer();
    pixErodeBrick(pixt2, pixs, size, 1);
    pixErodeBrick(pixt4, pixs, 1, size);
    pixErodeBrick(pixt6, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer());
    PixCompareDwa(size, "erode", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6);

    if (TIMING) startTimer();
    pixOpenCompBrickDwa(pixt1, pixs, size, 1);
    pixOpenCompBrickDwa(pixt3, pixs, 1, size);
    pixOpenCompBrickDwa(pixt5, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer());
    if (TIMING) startTimer();
    pixOpenBrick(pixt2, pixs, size, 1);
    pixOpenBrick(pixt4, pixs, 1, size);
    pixOpenBrick(pixt6, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer());
    PixCompareDwa(size, "open", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6);

    if (TIMING) startTimer();
    pixCloseCompBrickDwa(pixt1, pixs, size, 1);
    pixCloseCompBrickDwa(pixt3, pixs, 1, size);
    pixCloseCompBrickDwa(pixt5, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer());
    if (TIMING) startTimer();
    pixCloseSafeBrick(pixt2, pixs, size, 1);
    pixCloseSafeBrick(pixt4, pixs, 1, size);
    pixCloseSafeBrick(pixt6, pixs, size, size);
    if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer());
    PixCompareDwa(size, "close", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6);

    return 0;
}
/*!
 * \brief   pixMorphCompSequenceDwa()
 *
 * \param[in]    pixs
 * \param[in]    sequence string specifying sequence
 * \param[in]    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
 * \return  pixd, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This does dwa morphology on binary images, using brick Sels.
 *      (2) This runs a pipeline of operations; no branching is allowed.
 *      (3) It implements all brick Sels that have dimensions up to 63
 *          on each side, using a composite (linear + comb) when useful.
 *      (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) See pixMorphSequence() for further information about usage.
 * </pre>
 */
PIX *
pixMorphCompSequenceDwa(PIX         *pixs,
                        const char  *sequence,
                        l_int32      dispsep)
{
char    *rawop, *op, *fname;
char     buf[256];
l_int32  nops, i, j, nred, fact, w, h, x, y, border, pdfout;
l_int32  level[4];
PIX     *pixt1, *pixt2;
PIXA    *pixa;
SARRAY  *sa;

    PROCNAME("pixMorphCompSequenceDwa");

    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;

    if (!morphSequenceVerify(sa)) {
        sarrayDestroy(&sa);
        return (PIX *)ERROR_PTR("sequence not valid", 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);
    }
    border = 0;
    pixt1 = pixCopy(NULL, pixs);
    pixt2 = NULL;
    x = y = 0;
    for (i = 0; i < nops; i++) {
        rawop = sarrayGetString(sa, i, L_NOCOPY);
        op = stringRemoveChars(rawop, " \n\t");
        switch (op[0])
        {
        case 'd':
        case 'D':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixDilateCompBrickDwa(NULL, pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'e':
        case 'E':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixt2 = pixErodeCompBrickDwa(NULL, pixt1, w, h);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'o':
        case 'O':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixOpenCompBrickDwa(pixt1, pixt1, w, h);
            break;
        case 'c':
        case 'C':
            sscanf(&op[1], "%d.%d", &w, &h);
            pixCloseCompBrickDwa(pixt1, pixt1, w, h);
            break;
        case 'r':
        case 'R':
            nred = strlen(op) - 1;
            for (j = 0; j < nred; j++)
                level[j] = op[j + 1] - '0';
            for (j = nred; j < 4; j++)
                level[j] = 0;
            pixt2 = pixReduceRankBinaryCascade(pixt1, level[0], level[1],
                                               level[2], level[3]);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'x':
        case 'X':
            sscanf(&op[1], "%d", &fact);
            pixt2 = pixExpandReplicate(pixt1, fact);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        case 'b':
        case 'B':
            sscanf(&op[1], "%d", &border);
            pixt2 = pixAddBorder(pixt1, border, 0);
            pixSwapAndDestroy(&pixt1, &pixt2);
            break;
        default:
            /* All invalid ops are caught in the first pass */
            break;
        }
        LEPT_FREE(op);

            /* Debug output */
        if (dispsep > 0) {
            pixDisplay(pixt1, x, y);
            x += dispsep;
        }
        if (pdfout)
            pixaAddPix(pixa, pixt1, L_COPY);
    }
    if (border > 0) {
        pixt2 = pixRemoveBorder(pixt1, border);
        pixSwapAndDestroy(&pixt1, &pixt2);
    }

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

    sarrayDestroy(&sa);
    return pixt1;
}
Пример #4
0
int main(int    argc,
         char **argv)
{
char        *selname;
l_int32      i, j, nsels, sx, sy;
l_float32    fact, time;
GPLOT       *gplot;
NUMA        *na1, *na2, *na3, *na4, *nac1, *nac2, *nac3, *nac4, *nax;
PIX         *pixs, *pixt;
PIXA        *pixa;
SEL         *sel;
SELA        *selalinear;
static char  mainName[] = "dwamorph2_reg";

    if (argc != 1)
        return ERROR_INT(" Syntax: dwamorph2_reg", mainName, 1);

    pixs = pixRead("feyn-fract.tif");
    pixt = pixCreateTemplate(pixs);
    selalinear = selaAddDwaLinear(NULL);
    nsels = selaGetCount(selalinear);

    fact = 1000. / (l_float32)NTIMES;  /* converts to time in msec */
    na1 = numaCreate(64);
    na2 = numaCreate(64);
    na3 = numaCreate(64);
    na4 = numaCreate(64);

    lept_mkdir("lept/morph");

        /*  ---------  dilation  ----------*/

    for (i = 0; i < nsels / 2; i++)
    {
        sel = selaGetSel(selalinear, i);
        selGetParameters(sel, &sy, &sx, NULL, NULL);
        selname = selGetName(sel);
        fprintf(stderr, " %d .", i);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixDilate(pixt, pixs, sel);
        time = fact * stopTimer();
        numaAddNumber(na1, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixDilateCompBrick(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na2, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixMorphDwa_3(pixt, pixs, L_MORPH_DILATE, selname);
        time = fact * stopTimer();
        numaAddNumber(na3, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixDilateCompBrickDwa(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na4, time);
    }

    nax = numaMakeSequence(2, 1, nsels / 2);
    nac1 = numaWindowedMean(na1, HALFWIDTH);
    nac2 = numaWindowedMean(na2, HALFWIDTH);
    nac3 = numaWindowedMean(na3, HALFWIDTH);
    nac4 = numaWindowedMean(na4, HALFWIDTH);
    gplot = gplotCreate("/tmp/lept/morph/dilate", GPLOT_PNG,
                        "Dilation time vs sel size", "size", "time (ms)");
    gplotAddPlot(gplot, nax, nac1, GPLOT_LINES, "linear rasterop");
    gplotAddPlot(gplot, nax, nac2, GPLOT_LINES, "composite rasterop");
    gplotAddPlot(gplot, nax, nac3, GPLOT_LINES, "linear dwa");
    gplotAddPlot(gplot, nax, nac4, GPLOT_LINES, "composite dwa");
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    numaDestroy(&nac1);
    numaDestroy(&nac2);
    numaDestroy(&nac3);
    numaDestroy(&nac4);

        /*  ---------  erosion  ----------*/

    numaEmpty(na1);
    numaEmpty(na2);
    numaEmpty(na3);
    numaEmpty(na4);
    for (i = 0; i < nsels / 2; i++)
    {
        sel = selaGetSel(selalinear, i);
        selGetParameters(sel, &sy, &sx, NULL, NULL);
        selname = selGetName(sel);
        fprintf(stderr, " %d .", i);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixErode(pixt, pixs, sel);
        time = fact * stopTimer();
        numaAddNumber(na1, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixErodeCompBrick(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na2, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixMorphDwa_3(pixt, pixs, L_MORPH_ERODE, selname);
        time = fact * stopTimer();
        numaAddNumber(na3, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixErodeCompBrickDwa(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na4, time);
    }

    nac1 = numaWindowedMean(na1, HALFWIDTH);
    nac2 = numaWindowedMean(na2, HALFWIDTH);
    nac3 = numaWindowedMean(na3, HALFWIDTH);
    nac4 = numaWindowedMean(na4, HALFWIDTH);
    gplot = gplotCreate("/tmp/lept/morph/erode", GPLOT_PNG,
                        "Erosion time vs sel size", "size", "time (ms)");
    gplotAddPlot(gplot, nax, nac1, GPLOT_LINES, "linear rasterop");
    gplotAddPlot(gplot, nax, nac2, GPLOT_LINES, "composite rasterop");
    gplotAddPlot(gplot, nax, nac3, GPLOT_LINES, "linear dwa");
    gplotAddPlot(gplot, nax, nac4, GPLOT_LINES, "composite dwa");
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    numaDestroy(&nac1);
    numaDestroy(&nac2);
    numaDestroy(&nac3);
    numaDestroy(&nac4);

        /*  ---------  opening  ----------*/

    numaEmpty(na1);
    numaEmpty(na2);
    numaEmpty(na3);
    numaEmpty(na4);
    for (i = 0; i < nsels / 2; i++)
    {
        sel = selaGetSel(selalinear, i);
        selGetParameters(sel, &sy, &sx, NULL, NULL);
        selname = selGetName(sel);
        fprintf(stderr, " %d .", i);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixOpen(pixt, pixs, sel);
        time = fact * stopTimer();
        numaAddNumber(na1, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixOpenCompBrick(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na2, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixMorphDwa_3(pixt, pixs, L_MORPH_OPEN, selname);
        time = fact * stopTimer();
        numaAddNumber(na3, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixOpenCompBrickDwa(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na4, time);
    }

    nac1 = numaWindowedMean(na1, HALFWIDTH);
    nac2 = numaWindowedMean(na2, HALFWIDTH);
    nac3 = numaWindowedMean(na3, HALFWIDTH);
    nac4 = numaWindowedMean(na4, HALFWIDTH);
    gplot = gplotCreate("/tmp/lept/morph/open", GPLOT_PNG,
                        "Opening time vs sel size", "size", "time (ms)");
    gplotAddPlot(gplot, nax, nac1, GPLOT_LINES, "linear rasterop");
    gplotAddPlot(gplot, nax, nac2, GPLOT_LINES, "composite rasterop");
    gplotAddPlot(gplot, nax, nac3, GPLOT_LINES, "linear dwa");
    gplotAddPlot(gplot, nax, nac4, GPLOT_LINES, "composite dwa");
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    numaDestroy(&nac1);
    numaDestroy(&nac2);
    numaDestroy(&nac3);
    numaDestroy(&nac4);

        /*  ---------  closing  ----------*/

    numaEmpty(na1);
    numaEmpty(na2);
    numaEmpty(na3);
    numaEmpty(na4);
    for (i = 0; i < nsels / 2; i++)
    {
        sel = selaGetSel(selalinear, i);
        selGetParameters(sel, &sy, &sx, NULL, NULL);
        selname = selGetName(sel);
        fprintf(stderr, " %d .", i);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixClose(pixt, pixs, sel);
        time = fact * stopTimer();
        numaAddNumber(na1, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixCloseCompBrick(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na2, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixMorphDwa_3(pixt, pixs, L_MORPH_CLOSE, selname);
        time = fact * stopTimer();
        numaAddNumber(na3, time);

        startTimer();
        for (j = 0; j < NTIMES; j++)
            pixCloseCompBrickDwa(pixt, pixs, sx, sy);
        time = fact * stopTimer();
        numaAddNumber(na4, time);
    }

    nac1 = numaWindowedMean(na1, HALFWIDTH);
    nac2 = numaWindowedMean(na2, HALFWIDTH);
    nac3 = numaWindowedMean(na3, HALFWIDTH);
    nac4 = numaWindowedMean(na4, HALFWIDTH);
    gplot = gplotCreate("/tmp/lept/morph/close", GPLOT_PNG,
                        "Closing time vs sel size", "size", "time (ms)");
    gplotAddPlot(gplot, nax, nac1, GPLOT_LINES, "linear rasterop");
    gplotAddPlot(gplot, nax, nac2, GPLOT_LINES, "composite rasterop");
    gplotAddPlot(gplot, nax, nac3, GPLOT_LINES, "linear dwa");
    gplotAddPlot(gplot, nax, nac4, GPLOT_LINES, "composite dwa");
    gplotMakeOutput(gplot);
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */

    gplotDestroy(&gplot);
    numaDestroy(&nac1);
    numaDestroy(&nac2);
    numaDestroy(&nac3);
    numaDestroy(&nac4);


    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    numaDestroy(&na4);
    numaDestroy(&nax);
    selaDestroy(&selalinear);
    pixDestroy(&pixt);
    pixDestroy(&pixs);

        /* Display the results together */
    pixa = pixaCreate(0);
    pixs = pixRead("/tmp/lept/morph/dilate.png");
    pixaAddPix(pixa, pixs, L_INSERT);
    pixs = pixRead("/tmp/lept/morph/erode.png");
    pixaAddPix(pixa, pixs, L_INSERT);
    pixs = pixRead("/tmp/lept/morph/open.png");
    pixaAddPix(pixa, pixs, L_INSERT);
    pixs = pixRead("/tmp/lept/morph/close.png");
    pixaAddPix(pixa, pixs, L_INSERT);
    pixt = pixaDisplayTiledInRows(pixa, 32, 1500, 1.0, 0, 40, 3);
    pixWrite("/tmp/lept/morph/timings.png", pixt, IFF_PNG);
    pixDisplay(pixt, 100, 100);
    pixDestroy(&pixt);
    pixaDestroy(&pixa);
    return 0;
}
main(int    argc,
     char **argv)
{
l_int32      i, ok, same;
char         sequence[512];
PIX         *pixs, *pixref;
PIX         *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6;
PIX         *pixt7, *pixt8, *pixt9, *pixt10, *pixt11;
PIX         *pixt12, *pixt13, *pixt14;
SEL         *sel;
static char  mainName[] = "binmorph1_reg";

    if (argc != 1)
	exit(ERROR_INT(" Syntax: binmorph1_reg", mainName, 1));

    if ((pixs = pixRead("feyn.tif")) == NULL)
	exit(ERROR_INT("pix not made", mainName, 1));

#if TEST_SYMMETRIC
        /* This works properly if there is an added border */
    resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC);
#if 1
    pixt1 = pixAddBorder(pixs, 32, 0);
    pixTransferAllData(pixs, &pixt1, 0, 0);
#endif
#endif  /* TEST_SYMMETRIC */

        /* This is our test sel */
    sel = selCreateBrick(HEIGHT, WIDTH, HEIGHT / 2, WIDTH / 2, SEL_HIT);

        /* Dilation */
    fprintf(stderr, "Testing dilation\n");
    ok = TRUE;
    pixref = pixDilate(NULL, pixs, sel);   /* new one */
    pixt1 = pixCreateTemplate(pixs);
    pixDilate(pixt1, pixs, sel);           /* existing one */
    pixEqual(pixref, pixt1, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE;
    }
    pixt2 = pixCopy(NULL, pixs);
    pixDilate(pixt2, pixt2, sel);          /* in-place */
    pixEqual(pixref, pixt2, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE;
    }
    sprintf(sequence, "d%d.%d", WIDTH, HEIGHT);
    pixt3 = pixMorphSequence(pixs, sequence, 0);    /* sequence, atomic */
    pixEqual(pixref, pixt3, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE;
    }
    sprintf(sequence, "d%d.1 + d1.%d", WIDTH, HEIGHT);
    pixt4 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable */
    pixEqual(pixref, pixt4, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE;
    }
    pixt5 = pixDilateBrick(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt5, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE;
    }
    pixt6 = pixCreateTemplate(pixs);
    pixDilateBrick(pixt6, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt6, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE;
    }
    pixt7 = pixCopy(NULL, pixs);
    pixDilateBrick(pixt7, pixt7, WIDTH, HEIGHT);  /* in-place */
    pixEqual(pixref, pixt7, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE;
    }
    pixt8 = pixDilateBrickDwa(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt8, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE;
    }
    pixt9 = pixCreateTemplate(pixs);
    pixDilateBrickDwa(pixt9, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt9, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE;
    }
    pixt10 = pixCopy(NULL, pixs);
    pixDilateBrickDwa(pixt10, pixt10, WIDTH, HEIGHT);  /* in-place */
    pixEqual(pixref, pixt10, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE;
    }
    pixt11 = pixCreateTemplate(pixs);
    pixDilateCompBrickDwa(pixt11, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt11, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE;
    }
    sprintf(sequence, "d%d.%d", WIDTH, HEIGHT);
    pixt12 = pixMorphCompSequence(pixs, sequence, 0);    /* comp sequence */
    pixEqual(pixref, pixt12, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE;
    }
    pixt13 = pixMorphSequenceDwa(pixs, sequence, 0);    /* dwa sequence */
    pixEqual(pixref, pixt13, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE;
    }
    pixDestroy(&pixref);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);
    pixDestroy(&pixt7);
    pixDestroy(&pixt8);
    pixDestroy(&pixt9);
    pixDestroy(&pixt10);
    pixDestroy(&pixt11);
    pixDestroy(&pixt12);
    pixDestroy(&pixt13);

        /* Erosion */
    fprintf(stderr, "Testing erosion\n");
    pixref = pixErode(NULL, pixs, sel);   /* new one */
    pixt1 = pixCreateTemplate(pixs);
    pixErode(pixt1, pixs, sel);           /* existing one */
    pixEqual(pixref, pixt1, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE;
    }
    pixt2 = pixCopy(NULL, pixs);
    pixErode(pixt2, pixt2, sel);          /* in-place */
    pixEqual(pixref, pixt2, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE;
    }
    sprintf(sequence, "e%d.%d", WIDTH, HEIGHT);
    pixt3 = pixMorphSequence(pixs, sequence, 0);    /* sequence, atomic */
    pixEqual(pixref, pixt3, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE;
    }
    sprintf(sequence, "e%d.1 + e1.%d", WIDTH, HEIGHT);
    pixt4 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable */
    pixEqual(pixref, pixt4, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE;
    }
    pixt5 = pixErodeBrick(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt5, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE;
    }
    pixt6 = pixCreateTemplate(pixs);
    pixErodeBrick(pixt6, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt6, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE;
    }
    pixt7 = pixCopy(NULL, pixs);
    pixErodeBrick(pixt7, pixt7, WIDTH, HEIGHT);  /* in-place */
    pixEqual(pixref, pixt7, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE;
    }
    pixt8 = pixErodeBrickDwa(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt8, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE;
    }
    pixt9 = pixCreateTemplate(pixs);
    pixErodeBrickDwa(pixt9, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt9, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE;
    }
    pixt10 = pixCopy(NULL, pixs);
    pixErodeBrickDwa(pixt10, pixt10, WIDTH, HEIGHT);  /* in-place */
    pixEqual(pixref, pixt10, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE;
    }
    pixt11 = pixCreateTemplate(pixs);
    pixErodeCompBrickDwa(pixt11, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt11, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE;
    }
    
    sprintf(sequence, "e%d.%d", WIDTH, HEIGHT);
    pixt12 = pixMorphCompSequence(pixs, sequence, 0);    /* comp sequence */
    pixEqual(pixref, pixt12, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE;
    }
    pixt13 = pixMorphSequenceDwa(pixs, sequence, 0);    /* dwa sequence */
    pixEqual(pixref, pixt13, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE;
    }
    pixDestroy(&pixref);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);
    pixDestroy(&pixt7);
    pixDestroy(&pixt8);
    pixDestroy(&pixt9);
    pixDestroy(&pixt10);
    pixDestroy(&pixt11);
    pixDestroy(&pixt12);
    pixDestroy(&pixt13);

        /* Opening */
    fprintf(stderr, "Testing opening\n");
    pixref = pixOpen(NULL, pixs, sel);   /* new one */
    pixt1 = pixCreateTemplate(pixs);
    pixOpen(pixt1, pixs, sel);           /* existing one */
    pixEqual(pixref, pixt1, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE;
    }
    pixt2 = pixCopy(NULL, pixs);
    pixOpen(pixt2, pixt2, sel);          /* in-place */
    pixEqual(pixref, pixt2, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE;
    }
    sprintf(sequence, "o%d.%d", WIDTH, HEIGHT);
    pixt3 = pixMorphSequence(pixs, sequence, 0);    /* sequence, atomic */
    pixEqual(pixref, pixt3, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE;
    }
    sprintf(sequence, "e%d.%d + d%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT);
    pixt4 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable */
    pixEqual(pixref, pixt4, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE;
    }
    sprintf(sequence, "e%d.1 + e1.%d + d%d.1 + d1.%d", WIDTH, HEIGHT,
            WIDTH, HEIGHT);
    pixt5 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable^2 */
    pixEqual(pixref, pixt5, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE;
    }
    pixt6 = pixOpenBrick(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt6, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE;
    }
    pixt7 = pixCreateTemplate(pixs);
    pixOpenBrick(pixt7, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt7, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE;
    }
    pixt8 = pixCopy(NULL, pixs);  /* in-place */
    pixOpenBrick(pixt8, pixt8, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt8, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE;
    }
    pixt9 = pixOpenBrickDwa(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt9, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE;
    }
    pixt10 = pixCreateTemplate(pixs);
    pixOpenBrickDwa(pixt10, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt10, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE;
    }
    pixt11 = pixCopy(NULL, pixs);
    pixOpenBrickDwa(pixt11, pixt11, WIDTH, HEIGHT);  /* in-place */
    pixEqual(pixref, pixt11, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE;
    }
    sprintf(sequence, "o%d.%d", WIDTH, HEIGHT);
    pixt12 = pixMorphCompSequence(pixs, sequence, 0);    /* comp sequence */
    pixEqual(pixref, pixt12, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE;
    }

#if 0
    pixWrite("/tmp/junkref.png", pixref, IFF_PNG);
    pixWrite("/tmp/junk12.png", pixt12, IFF_PNG);
    pixt13 = pixXor(NULL, pixref, pixt12);
    pixWrite("/tmp/junk12a.png", pixt13, IFF_PNG);
    pixDestroy(&pixt13);
#endif

    pixt13 = pixMorphSequenceDwa(pixs, sequence, 0);    /* dwa sequence */
    pixEqual(pixref, pixt13, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE;
    }
    pixt14 = pixCreateTemplate(pixs);
    pixOpenCompBrickDwa(pixt14, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt14, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt14 !\n"); ok = FALSE;
    }

    pixDestroy(&pixref);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);
    pixDestroy(&pixt7);
    pixDestroy(&pixt8);
    pixDestroy(&pixt9);
    pixDestroy(&pixt10);
    pixDestroy(&pixt11);
    pixDestroy(&pixt12);
    pixDestroy(&pixt13);
    pixDestroy(&pixt14);

        /* Closing */
    fprintf(stderr, "Testing closing\n");
    pixref = pixClose(NULL, pixs, sel);   /* new one */
    pixt1 = pixCreateTemplate(pixs);
    pixClose(pixt1, pixs, sel);           /* existing one */
    pixEqual(pixref, pixt1, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE;
    }
    pixt2 = pixCopy(NULL, pixs);
    pixClose(pixt2, pixt2, sel);          /* in-place */
    pixEqual(pixref, pixt2, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE;
    }
    sprintf(sequence, "d%d.%d + e%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT);
    pixt3 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable */
    pixEqual(pixref, pixt3, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE;
    }
    sprintf(sequence, "d%d.1 + d1.%d + e%d.1 + e1.%d", WIDTH, HEIGHT,
            WIDTH, HEIGHT);
    pixt4 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable^2 */
    pixEqual(pixref, pixt4, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE;
    }
    pixt5 = pixCloseBrick(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt5, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE;
    }
    pixt6 = pixCreateTemplate(pixs);
    pixCloseBrick(pixt6, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt6, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE;
    }
    pixt7 = pixCopy(NULL, pixs);  /* in-place */
    pixCloseBrick(pixt7, pixt7, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt7, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE;
    }
    pixDestroy(&pixref);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);
    pixDestroy(&pixt7);

        /* Safe closing (using pix, not pixs) */
    fprintf(stderr, "Testing safe closing\n");
    pixref = pixCloseSafe(NULL, pixs, sel);   /* new one */
    pixt1 = pixCreateTemplate(pixs);
    pixCloseSafe(pixt1, pixs, sel);           /* existing one */
    pixEqual(pixref, pixt1, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE;
    }
    pixt2 = pixCopy(NULL, pixs);
    pixCloseSafe(pixt2, pixt2, sel);          /* in-place */
    pixEqual(pixref, pixt2, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE;
    }
    sprintf(sequence, "c%d.%d", WIDTH, HEIGHT);
    pixt3 = pixMorphSequence(pixs, sequence, 0);    /* sequence, atomic */
    pixEqual(pixref, pixt3, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE;
    }
    sprintf(sequence, "b32 + d%d.%d + e%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT);
    pixt4 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable */
    pixEqual(pixref, pixt4, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE;
    }
    sprintf(sequence, "b32 + d%d.1 + d1.%d + e%d.1 + e1.%d", WIDTH, HEIGHT,
            WIDTH, HEIGHT);
    pixt5 = pixMorphSequence(pixs, sequence, 0);    /* sequence, separable^2 */
    pixEqual(pixref, pixt5, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE;
    }
    pixt6 = pixCloseSafeBrick(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt6, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE;
    }
    pixt7 = pixCreateTemplate(pixs);
    pixCloseSafeBrick(pixt7, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt7, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE;
    }
    pixt8 = pixCopy(NULL, pixs);  /* in-place */
    pixCloseSafeBrick(pixt8, pixt8, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt8, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE;
    }
    pixt9 = pixCloseBrickDwa(NULL, pixs, WIDTH, HEIGHT);  /* new one */
    pixEqual(pixref, pixt9, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE;
    }
    pixt10 = pixCreateTemplate(pixs);
    pixCloseBrickDwa(pixt10, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt10, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE;
    }
    pixt11 = pixCopy(NULL, pixs);
    pixCloseBrickDwa(pixt11, pixt11, WIDTH, HEIGHT);  /* in-place */
    pixEqual(pixref, pixt11, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE;
    }
    sprintf(sequence, "c%d.%d", WIDTH, HEIGHT);
    pixt12 = pixMorphCompSequence(pixs, sequence, 0);    /* comp sequence */
    pixEqual(pixref, pixt12, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE;
    }
    pixt13 = pixMorphSequenceDwa(pixs, sequence, 0);    /* dwa sequence */
    pixEqual(pixref, pixt13, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE;
    }
    pixt14 = pixCreateTemplate(pixs);
    pixCloseCompBrickDwa(pixt14, pixs, WIDTH, HEIGHT);  /* existing one */
    pixEqual(pixref, pixt14, &same);
    if (!same) {
        fprintf(stderr, "pixref != pixt14 !\n"); ok = FALSE;
    }

#if 0
    pixWrite("/tmp/junkref.png", pixref, IFF_PNG);
    pixWrite("/tmp/junk12.png", pixt12, IFF_PNG);
    pixt13 = pixXor(NULL, pixref, pixt12);
    pixWrite("/tmp/junk12a.png", pixt13, IFF_PNG);
    pixDestroy(&pixt13);
#endif

    pixDestroy(&pixref);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);
    pixDestroy(&pixt5);
    pixDestroy(&pixt6);
    pixDestroy(&pixt7);
    pixDestroy(&pixt8);
    pixDestroy(&pixt9);
    pixDestroy(&pixt10);
    pixDestroy(&pixt11);
    pixDestroy(&pixt12);
    pixDestroy(&pixt13);
    pixDestroy(&pixt14);

    if (ok)
        fprintf(stderr, "All morph tests OK!\n");

    pixDestroy(&pixs);
    selDestroy(&sel);
    exit(0);
}