Ejemplo n.º 1
0
/*
 *  fmorphautogen2()
 *
 *      Input:  sela
 *              fileindex
 *              filename (<optional>; can be null)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) This function uses morphtemplate2.txt to create a
 *          low-level file that contains the low-level functions for
 *          implementing dilation and erosion for every sel
 *          in the input sela.
 *      (2) The fileindex parameter is inserted into the output
 *          filename, as described below.
 *      (3) If filename == NULL, the output file is fmorphgenlow.<n>.c,
 *          where <n> is equal to the 'fileindex' parameter.
 *      (4) If filename != NULL, the output file is <filename>low.<n>.c.
 */
l_int32
fmorphautogen2(SELA        *sela,
               l_int32      fileindex,
               const char  *filename)
{
char    *filestr, *linestr, *fname;
char    *str_doc1, *str_doc2, *str_doc3, *str_doc4, *str_def1;
char     bigbuf[L_BUF_SIZE];
char     breakstring[] = "        break;";
char     staticstring[] = "static void";
l_int32  i, nsels, nbytes, actstart, end, newstart;
l_int32  argstart, argend, loopstart, loopend, finalstart, finalend;
size_t   size;
SARRAY  *sa1, *sa2, *sa3, *sa4, *sa5, *sa6;
SEL     *sel;

    PROCNAME("fmorphautogen2");

    if (!sela)
        return ERROR_INT("sela not defined", procName, 1);
    if (fileindex < 0)
        fileindex = 0;
    if ((nsels = selaGetCount(sela)) == 0)
        return ERROR_INT("no sels in sela", procName, 1);

        /* Make the array of textlines from morphtemplate2.txt */
    if ((filestr = (char *)l_binaryRead(TEMPLATE2, &size)) == NULL)
        return ERROR_INT("filestr not made", procName, 1);
    sa1 = sarrayCreateLinesFromString(filestr, 1);
    LEPT_FREE(filestr);
    if (!sa1)
        return ERROR_INT("sa1 not made", procName, 1);

        /* Make the array of static function names */
    if ((sa2 = sarrayCreate(2 * nsels)) == NULL) {
        sarrayDestroy(&sa1);
        return ERROR_INT("sa2 not made", procName, 1);
    }
    for (i = 0; i < nsels; i++) {
        sprintf(bigbuf, "fdilate_%d_%d", fileindex, i);
        sarrayAddString(sa2, bigbuf, L_COPY);
        sprintf(bigbuf, "ferode_%d_%d", fileindex, i);
        sarrayAddString(sa2, bigbuf, L_COPY);
    }

        /* Make the static prototype strings */
    sa3 = sarrayCreate(2 * nsels);  /* should be ok */
    for (i = 0; i < 2 * nsels; i++) {
        fname = sarrayGetString(sa2, i, L_NOCOPY);
        sprintf(bigbuf, "static void  %s%s", fname, PROTOARGS);
        sarrayAddString(sa3, bigbuf, L_COPY);
    }

        /* Make strings containing function names */
    sprintf(bigbuf, " *             l_int32    fmorphopgen_low_%d()",
            fileindex);
    str_doc1 = stringNew(bigbuf);
    sprintf(bigbuf, " *             void       fdilate_%d_*()", fileindex);
    str_doc2 = stringNew(bigbuf);
    sprintf(bigbuf, " *             void       ferode_%d_*()", fileindex);
    str_doc3 = stringNew(bigbuf);
    sprintf(bigbuf, " *  fmorphopgen_low_%d()", fileindex);
    str_doc4 = stringNew(bigbuf);
    sprintf(bigbuf, "fmorphopgen_low_%d(l_uint32  *datad,", fileindex);
    str_def1 = stringNew(bigbuf);

        /* Output to this sa */
    sa4 = sarrayCreate(0);

        /* Copyright notice and info header */
    sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);

        /* Insert function names as documentation */
    sarrayAddString(sa4, str_doc1, L_INSERT);
    sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);
    sarrayAddString(sa4, str_doc2, L_INSERT);
    sarrayAddString(sa4, str_doc3, L_INSERT);
    sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);

        /* Insert static protos */
    for (i = 0; i < 2 * nsels; i++) {
        if ((linestr = sarrayGetString(sa3, i, L_COPY)) == NULL) {
            sarrayDestroy(&sa1);
            sarrayDestroy(&sa2);
            sarrayDestroy(&sa3);
            sarrayDestroy(&sa4);
            return ERROR_INT("linestr not retrieved", procName, 1);
        }
        sarrayAddString(sa4, linestr, L_INSERT);
    }

        /* Insert function header */
    sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);
    sarrayAddString(sa4, str_doc4, L_INSERT);
    sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);
    sarrayAddString(sa4, str_def1, L_INSERT);
    sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);

        /* Generate and insert the dispatcher code */
    for (i = 0; i < 2 * nsels; i++) {
        sprintf(bigbuf, "    case %d:", i);
        sarrayAddString(sa4, bigbuf, L_COPY);
        sprintf(bigbuf, "        %s(datad, w, h, wpld, datas, wpls);",
               sarrayGetString(sa2, i, L_NOCOPY));
        sarrayAddString(sa4, bigbuf, L_COPY);
        sarrayAddString(sa4, breakstring, L_COPY);
    }

        /* Finish the dispatcher and introduce the low-level code */
    sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
    sarrayAppendRange(sa4, sa1, actstart, end);

        /* Get the range for the args common to all functions */
    sarrayParseRange(sa1, newstart, &argstart, &argend, &newstart, "--", 0);

        /* Get the range for the loop code common to all functions */
    sarrayParseRange(sa1, newstart, &loopstart, &loopend, &newstart, "--", 0);

        /* Get the range for the ending code common to all functions */
    sarrayParseRange(sa1, newstart, &finalstart, &finalend, &newstart, "--", 0);

        /* Do all the static functions */
    for (i = 0; i < 2 * nsels; i++) {
            /* Generate the function header and add the common args */
        sarrayAddString(sa4, staticstring, L_COPY);
        fname = sarrayGetString(sa2, i, L_NOCOPY);
        sprintf(bigbuf, "%s(l_uint32  *datad,", fname);
        sarrayAddString(sa4, bigbuf, L_COPY);
        sarrayAppendRange(sa4, sa1, argstart, argend);

            /* Declare and define wplsN args, as necessary */
        if ((sel = selaGetSel(sela, i/2)) == NULL) {
            sarrayDestroy(&sa1);
            sarrayDestroy(&sa2);
            sarrayDestroy(&sa3);
            sarrayDestroy(&sa4);
            return ERROR_INT("sel not returned", procName, 1);
        }
        sa5 = sarrayMakeWplsCode(sel);
        sarrayJoin(sa4, sa5);
        sarrayDestroy(&sa5);

            /* Add the function loop code */
        sarrayAppendRange(sa4, sa1, loopstart, loopend);

            /* Insert barrel-op code for *dptr */
        sa6 = sarrayMakeInnerLoopDWACode(sel, i);
        sarrayJoin(sa4, sa6);
        sarrayDestroy(&sa6);

            /* Finish the function code */
        sarrayAppendRange(sa4, sa1, finalstart, finalend);
    }

        /* Output to file */
    filestr = sarrayToString(sa4, 1);
    nbytes = strlen(filestr);
    if (filename)
        snprintf(bigbuf, L_BUF_SIZE, "%slow.%d.c", filename, fileindex);
    else
        sprintf(bigbuf, "%slow.%d.c", OUTROOT, fileindex);
    l_binaryWrite(bigbuf, "w", filestr, nbytes);
    sarrayDestroy(&sa1);
    sarrayDestroy(&sa2);
    sarrayDestroy(&sa3);
    sarrayDestroy(&sa4);
    LEPT_FREE(filestr);
    return 0;
}
Ejemplo n.º 2
0
/*!
 *  pixThinGeneral()
 *
 *      Input:  pixs (1 bpp)
 *              type (L_THIN_FG, L_THIN_BG)
 *              sela (of Sels for parallel composite HMTs)
 *              maxiters (max number of iters allowed; use 0 to iterate
 *                        until completion)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) See notes in pixThin().  That function chooses among
 *          the best of the Sels for thinning.
 *      (2) This is a general function that takes a Sela of HMTs
 *          that are used in parallel for thinning from each
 *          of four directions.  One iteration consists of four
 *          such parallel thins.
 */
PIX *
pixThinGeneral(PIX     *pixs,
               l_int32  type,
               SELA    *sela,
               l_int32  maxiters)
{
    l_int32  i, j, r, nsels, same;
    PIXA    *pixahmt;
    PIX    **pixhmt;  /* array owned by pixahmt; do not destroy! */
    PIX     *pixd, *pixt;
    SEL     *sel, *selr;

    PROCNAME("pixThinGeneral");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (type != L_THIN_FG && type != L_THIN_BG)
        return (PIX *)ERROR_PTR("invalid fg/bg type", procName, NULL);
    if (!sela)
        return (PIX *)ERROR_PTR("sela not defined", procName, NULL);
    if (maxiters == 0) maxiters = 10000;

    /* Set up array of temp pix to hold hmts */
    nsels = selaGetCount(sela);
    pixahmt = pixaCreate(nsels);
    for (i = 0; i < nsels; i++) {
        pixt = pixCreateTemplate(pixs);
        pixaAddPix(pixahmt, pixt, L_INSERT);
    }
    pixhmt = pixaGetPixArray(pixahmt);
    if (!pixhmt)
        return (PIX *)ERROR_PTR("pixhmt array not made", procName, NULL);

#if  DEBUG_SELS
    pixt = selaDisplayInPix(sela, 35, 3, 15, 4);
    pixDisplayWithTitle(pixt, 100, 100, "allsels", 1);
    pixDestroy(&pixt);
#endif  /* DEBUG_SELS */

    /* Set up initial image for fg thinning */
    if (type == L_THIN_FG)
        pixd = pixCopy(NULL, pixs);
    else  /* bg thinning */
        pixd = pixInvert(NULL, pixs);

    /* Thin the fg, with up to maxiters iterations */
    for (i = 0; i < maxiters; i++) {
        pixt = pixCopy(NULL, pixd);  /* test for completion */
        for (r = 0; r < 4; r++) {  /* over 90 degree rotations of Sels */
            for (j = 0; j < nsels; j++) {  /* over individual sels in sela */
                sel = selaGetSel(sela, j);  /* not a copy */
                selr = selRotateOrth(sel, r);
                pixHMT(pixhmt[j], pixd, selr);
                selDestroy(&selr);
                if (j > 0)
                    pixOr(pixhmt[0], pixhmt[0], pixhmt[j]);  /* accum result */
            }
            pixSubtract(pixd, pixd, pixhmt[0]);  /* remove result */
        }
        pixEqual(pixd, pixt, &same);
        pixDestroy(&pixt);
        if (same) {
            L_INFO_INT("%d iterations to completion", procName, i);
            break;
        }
    }

    if (type == L_THIN_BG)
        pixInvert(pixd, pixd);

    pixaDestroy(&pixahmt);
    return pixd;
}
Ejemplo n.º 3
0
                       int main(int argc,
                                char **argv)
{
    l_int32 i, nsels, same, xorcount;
    char *selname;
    PIX *pixs, *pixt1, *pixt2, *pixt3;
    SEL *sel;
    SELA *sela;
    L_REGPARAMS *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    if ((pixs = pixRead("feyn-fract.tif")) == NULL) {
        rp->success = FALSE;
        return regTestCleanup(rp);
    }
    sela = selaAddDwaLinear(NULL);
    nsels = selaGetCount(sela);

    for (i = 0; i < nsels; i++) {
        sel = selaGetSel(sela, i);
        selname = selGetName(sel);

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

        pixt1 = pixDilate(NULL, pixs, sel);
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_DILATE, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "dilations are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "dilations differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);

        /*  ---------  erosion with asymmetric b.c  ----------*/

        resetMorphBoundaryCondition(ASYMMETRIC_MORPH_BC);
        fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC);

        pixt1 = pixErode(NULL, pixs, sel);
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_ERODE, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "erosions are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "erosions differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);

        /*  ---------  erosion with symmetric b.c  ----------*/

        resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC);
        fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC);

        pixt1 = pixErode(NULL, pixs, sel);
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_ERODE, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "erosions are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "erosions differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);

        /*  ---------  opening with asymmetric b.c  ----------*/

        resetMorphBoundaryCondition(ASYMMETRIC_MORPH_BC);
        fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC);

        pixt1 = pixOpen(NULL, pixs, sel);
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_OPEN, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "openings are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "openings differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);

        /*  ---------  opening with symmetric b.c  ----------*/

        resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC);
        fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC);

        pixt1 = pixOpen(NULL, pixs, sel);
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_OPEN, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "openings are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "openings differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);

        /*  ---------  safe closing with asymmetric b.c  ----------*/

        resetMorphBoundaryCondition(ASYMMETRIC_MORPH_BC);
        fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC);

        pixt1 = pixCloseSafe(NULL, pixs, sel);  /* must use safe version */
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_CLOSE, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "closings are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "closings differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);

        /*  ---------  safe closing with symmetric b.c  ----------*/

        resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC);
        fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC);

        pixt1 = pixClose(NULL, pixs, sel);  /* safe version not required */
        pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_CLOSE, selname);
        pixEqual(pixt1, pixt2, &same);

        if (same == 1) {
            fprintf(stderr, "closings are identical for sel %d (%s)\n",
                    i, selname);
        }
        else {
            rp->success = FALSE;
            fprintf(rp->fp, "closings differ for sel %d (%s)\n", i, selname);
            pixt3 = pixXor(NULL, pixt1, pixt2);
            pixCountPixels(pixt3, &xorcount, NULL);
            fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount);
            pixDestroy(&pixt3);
        }
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }

    selaDestroy(&sela);
    pixDestroy(&pixs);
    return regTestCleanup(rp);
}
Ejemplo n.º 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;
}