Beispiel #1
0
/*!
 *  selaAddDwaCombs()
 *
 *      Input:  sela (<optional>)
 *      Return: sela with additional sels, or null on error
 *
 *  Notes:
 *      (1) Adds all comb (horizontal, vertical) Sels that are
 *          used in composite linear morphological operations
 *          up to 63 pixels in length, which are the sizes over
 *          which dwa code can be generated.
 */
SELA *
selaAddDwaCombs(SELA  *sela)
{
char     name[L_BUF_SIZE];
l_int32  i, f1, f2, prevsize, size;
SEL     *selh, *selv;

    PROCNAME("selaAddDwaCombs");

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    prevsize = 0;
    for (i = 4; i < 64; i++) {
        selectComposableSizes(i, &f1, &f2);
        size = f1 * f2;
        if (size == prevsize)
            continue;
        selectComposableSels(i, L_HORIZ, NULL, &selh);
        selectComposableSels(i, L_VERT, NULL, &selv);
        snprintf(name, L_BUF_SIZE, "sel_comb_%dh", size);
        selaAddSel(sela, selh, name, 0);
        snprintf(name, L_BUF_SIZE, "sel_comb_%dv", size);
        selaAddSel(sela, selv, name, 0);
        prevsize = size;
    }

    return sela;
}
Beispiel #2
0
main(int    argc,
     char **argv)
{
PIX         *pixd;
SEL         *sel1, *sel2, *sel3, *sel4;
SELA        *sela;
static char  mainName[] = "livre_orient";

    sel1 = selCreateFromString(textsel1, 5, 6, NULL);
    sel2 = selCreateFromString(textsel2, 5, 6, NULL);
    sel3 = selCreateFromString(textsel3, 5, 6, NULL);
    sel4 = selCreateFromString(textsel4, 5, 6, NULL);

    sela = selaCreate(4);
    selaAddSel(sela, sel1, "textsel1", L_INSERT);
    selaAddSel(sela, sel2, "textsel2", L_INSERT);
    selaAddSel(sela, sel3, "textsel3", L_INSERT);
    selaAddSel(sela, sel4, "textsel4", L_INSERT);

    pixd = selaDisplayInPix(sela, 28, 3, 30, 4);
    pixWrite("/tmp/orient.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 100);

    pixDestroy(&pixd);
    selaDestroy(&sela);
    return 0;
}
Beispiel #3
0
/*!
 *  selaAddDwaLinear()
 *
 *      Input:  sela (<optional>)
 *      Return: sela with additional sels, or null on error
 *
 *  Notes:
 *      (1) Adds all linear (horizontal, vertical) sels from
 *          2 to 63 pixels in length, which are the sizes over
 *          which dwa code can be generated.
 */
SELA *
selaAddDwaLinear(SELA  *sela)
{
char     name[L_BUF_SIZE];
l_int32  i;
SEL     *sel;

    PROCNAME("selaAddDwaLinear");

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    for (i = 2; i < 64; i++) {
        sel = selCreateBrick(1, i, 0, i / 2, 1);
        snprintf(name, L_BUF_SIZE, "sel_%dh", i);
        selaAddSel(sela, sel, name, 0);
    }
    for (i = 2; i < 64; i++) {
        sel = selCreateBrick(i, 1, i / 2, 0, 1);
        snprintf(name, L_BUF_SIZE, "sel_%dv", i);
        selaAddSel(sela, sel, name, 0);
    }
    return sela;
}
Beispiel #4
0
/*!
 * \brief   sela8ccThin()
 *
 * \param[in]    sela [optional]
 * \return  sela with additional sels, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Adds the 9 basic sels for 8-cc thinning.
 * </pre>
 */
SELA *
sela8ccThin(SELA  *sela)
{
SEL  *sel;

    if (!sela) sela = selaCreate(9);

    sel = selCreateFromString(sel_8_1, 3, 3, "sel_8_1");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_4, 3, 3, "sel_8_4");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_7, 3, 3, "sel_8_7");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_8, 3, 3, "sel_8_8");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_8_9, 3, 3, "sel_8_9");
    selaAddSel(sela, sel, NULL, 0);

    return sela;
}
Beispiel #5
0
/*!
 * \brief   sela4and8ccThin()
 *
 * \param[in]    sela [optional]
 * \return  sela with additional sels, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Adds the 2 basic sels for either 4-cc or 8-cc thinning.
 * </pre>
 */
SELA *
sela4and8ccThin(SELA  *sela)
{
SEL  *sel;

    if (!sela) sela = selaCreate(2);

    sel = selCreateFromString(sel_48_1, 3, 3, "sel_48_1");
    selaAddSel(sela, sel, NULL, 0);
    sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2");
    selaAddSel(sela, sel, NULL, 0);

    return sela;
}
Beispiel #6
0
main(int    argc,
     char **argv)
{
PIX          *pix;
SEL          *sel;
SELA         *sela1, *sela2;
L_REGPARAMS  *rp;

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

        /* selaRead() / selaWrite()  */
    sela1 = selaAddBasic(NULL);
    selaWrite("/tmp/sel.0.sela", sela1);
    regTestCheckFile(rp, "/tmp/sel.0.sela");  /* 0 */
    sela2 = selaRead("/tmp/sel.0.sela");
    selaWrite("/tmp/sel.1.sela", sela2);
    regTestCheckFile(rp, "/tmp/sel.1.sela");  /* 1 */
    regTestCompareFiles(rp, 0, 1);  /* 2 */
    selaDestroy(&sela1);
    selaDestroy(&sela2);
    
	/* Create from file and display result */
    sela1 = selaCreateFromFile("flipsels.txt");
    pix = selaDisplayInPix(sela1, 31, 3, 15, 4);
    regTestWritePixAndCheck(rp, pix, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pix, 100, 100, NULL, rp->display);
    selaWrite("/tmp/sel.3.sela", sela1);
    regTestCheckFile(rp, "/tmp/sel.3.sela");  /* 4 */
    pixDestroy(&pix);
    selaDestroy(&sela1);

        /* Create the same set of Sels from compiled strings and compare */
    sela2 = selaCreate(4);
    sel = selCreateFromString(textsel1, 5, 6, "textsel1");
    selaAddSel(sela2, sel, NULL, 0);
    sel = selCreateFromString(textsel2, 5, 6, "textsel2");
    selaAddSel(sela2, sel, NULL, 0);
    sel = selCreateFromString(textsel3, 5, 6, "textsel3");
    selaAddSel(sela2, sel, NULL, 0);
    sel = selCreateFromString(textsel4, 5, 6, "textsel4");
    selaAddSel(sela2, sel, NULL, 0);
    selaWrite("/tmp/sel.4.sela", sela2);
    regTestCheckFile(rp, "/tmp/sel.4.sela");  /* 5 */
    regTestCompareFiles(rp, 4, 5);  /* 6 */
    selaDestroy(&sela2);

    return regTestCleanup(rp);
}
Beispiel #7
0
int main(int    argc,
         char **argv)
{
SEL         *sel1, *sel2, *sel3, *sel4;
SELA        *sela;
PIX         *pix, *pixd;
PIXA        *pixa;
static char  mainName[] = "flipselgen";

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

    sela = selaCreate(0);
    sel1 = selCreateFromString(textsel1, 5, 6, "flipsel1");
    sel2 = selCreateFromString(textsel2, 5, 6, "flipsel2");
    sel3 = selCreateFromString(textsel3, 5, 6, "flipsel3");
    sel4 = selCreateFromString(textsel4, 5, 6, "flipsel4");
    selaAddSel(sela, sel1, NULL, 0);
    selaAddSel(sela, sel2, NULL, 0);
    selaAddSel(sela, sel3, NULL, 0);
    selaAddSel(sela, sel4, NULL, 0);

    pixa = pixaCreate(4);
    pix = selDisplayInPix(sel1, 23, 2);
    pixDisplayWithTitle(pix, 100, 100, "sel1", DFLAG);
    pixaAddPix(pixa, pix, L_INSERT);
    pix = selDisplayInPix(sel2, 23, 2);
    pixDisplayWithTitle(pix, 275, 100, "sel2", DFLAG);
    pixaAddPix(pixa, pix, L_INSERT);
    pix = selDisplayInPix(sel3, 23, 2);
    pixDisplayWithTitle(pix, 450, 100, "sel3", DFLAG);
    pixaAddPix(pixa, pix, L_INSERT);
    pix = selDisplayInPix(sel4, 23, 2);
    pixDisplayWithTitle(pix, 625, 100, "sel4", DFLAG);
    pixaAddPix(pixa, pix, L_INSERT);

    pixd = pixaDisplayTiled(pixa, 800, 0, 15);
    pixDisplayWithTitle(pixd, 100, 300, "allsels", DFLAG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    if (fhmtautogen(sela, INDEX, NULL))
        return ERROR_INT(" Generation failed", mainName, 1);

    selaDestroy(&sela);
    return 0;
}
Beispiel #8
0
/*!
 *  pixThin()
 *
 *      Input:  pixs (1 bpp)
 *              type (L_THIN_FG, L_THIN_BG)
 *              connectivity (4 or 8)
 *              maxiters (max number of iters allowed; use 0 to iterate
 *                        until completion)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) See "Connectivity-preserving morphological image transformations,"
 *          Dan S. Bloomberg, in SPIE Visual Communications and Image
 *          Processing, Conference 1606, pp. 320-334, November 1991,
 *          Boston, MA.   A web version is available at
 *              http://www.leptonica.com/papers/conn.pdf
 *      (2) We implement here two of the best iterative
 *          morphological thinning algorithms, for 4 c.c and 8 c.c.
 *          Each iteration uses a mixture of parallel operations
 *          (using several different 3x3 Sels) and serial operations.
 *          Specifically, each thinning iteration consists of
 *          four sequential thinnings from each of four directions.
 *          Each of these thinnings is a parallel composite
 *          operation, where the union of a set of HMTs are set
 *          subtracted from the input.  For 4-cc thinning, we
 *          use 3 HMTs in parallel, and for 8-cc thinning we use 4 HMTs.
 *      (3) A "good" thinning algorithm is one that generates a skeleton
 *          that is near the medial axis and has neither pruned
 *          real branches nor left extra dendritic branches.
 *      (4) To thin the foreground, which is the usual situation,
 *          use type == L_THIN_FG.  Thickening the foreground is equivalent
 *          to thinning the background (type == L_THIN_BG), where the
 *          opposite connectivity gets preserved.  For example, to thicken
 *          the fg using 4-connectivity, we thin the bg using Sels that
 *          preserve 8-connectivity.
 */
PIX *
pixThin(PIX     *pixs,
        l_int32  type,
        l_int32  connectivity,
        l_int32  maxiters)
{
PIX   *pixd;
SEL   *sel;
SELA  *sela;

    PROCNAME("pixThin");

    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 (connectivity != 4 && connectivity != 8)
        return (PIX *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
    if (maxiters == 0) maxiters = 10000;

    sela = selaCreate(4);
    if (connectivity == 4) {
        sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3");
        selaAddSel(sela, sel, NULL, 0);
    } else {  /* connectivity == 8 */
        sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6");
        selaAddSel(sela, sel, NULL, 0);
    }

    pixd = pixThinGeneral(pixs, type, sela, maxiters);

    selaDestroy(&sela);
    return pixd;
}
Beispiel #9
0
/*!
 *  pixThinExamples()
 *
 *      Input:  pixs (1 bpp)
 *              type (L_THIN_FG, L_THIN_BG)
 *              index (into specific examples; valid 1-9; see notes)
 *              maxiters (max number of iters allowed; use 0 to iterate
 *                        until completion)
 *              selfile (<optional> filename for output sel display)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) See notes in pixThin().  The examples are taken from
 *          the paper referenced there.
 *      (2) Here we allow specific sets of HMTs to be used in
 *          parallel for thinning from each of four directions.
 *          One iteration consists of four such parallel thins.
 *      (3) The examples are indexed as follows:
 *          Thinning  (e.g., run to completion):
 *              index = 1     sel_4_1, sel_4_5, sel_4_6
 *              index = 2     sel_4_1, sel_4_7, sel_4_7_rot
 *              index = 3     sel_48_1, sel_48_1_rot, sel_48_2
 *              index = 4     sel_8_2, sel_8_3, sel_48_2
 *              index = 5     sel_8_1, sel_8_5, sel_8_6
 *              index = 6     sel_8_2, sel_8_3, sel_8_8, sel_8_9
 *              index = 7     sel_8_5, sel_8_6, sel_8_7, sel_8_7_rot
 *          Thickening:
 *              index = 8     sel_4_2, sel_4_3 (e.g,, do just a few iterations)
 *              index = 9     sel_8_4 (e.g., do just a few iterations)
 */
PIX *
pixThinExamples(PIX         *pixs,
                l_int32      type,
                l_int32      index,
                l_int32      maxiters,
                const char  *selfile)
{
PIX   *pixd, *pixt;
SEL   *sel;
SELA  *sela;

    PROCNAME("pixThinExamples");

    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 (index < 1 || index > 9)
        return (PIX *)ERROR_PTR("invalid index", procName, NULL);
    if (maxiters == 0) maxiters = 10000;

    switch(index)
    {
    case 1:
        sela = selaCreate(3);
        sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_4_5, 3, 3, "sel_4_5");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_4_6, 3, 3, "sel_4_6");
        selaAddSel(sela, sel, NULL, 0);
        break;
    case 2:
        sela = selaCreate(3);
        sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_4_7, 3, 3, "sel_4_7");
        selaAddSel(sela, sel, NULL, 0);
	sel = selRotateOrth(sel, 1);
        selaAddSel(sela, sel, "sel_4_7_rot", 0);
        break;
    case 3:
        sela = selaCreate(3);
        sel = selCreateFromString(sel_48_1, 3, 3, "sel_48_1");
        selaAddSel(sela, sel, NULL, 0);
	sel = selRotateOrth(sel, 1);
        selaAddSel(sela, sel, "sel_48_1_rot", 0);
        sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2");
        selaAddSel(sela, sel, NULL, 0);
        break;
    case 4:
        sela = selaCreate(3);
        sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2");
        selaAddSel(sela, sel, NULL, 0);
        break;
    case 5:
        sela = selaCreate(3);
        sel = selCreateFromString(sel_8_1, 3, 3, "sel_8_1");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6");
        selaAddSel(sela, sel, NULL, 0);
        break;
    case 6:
        sela = selaCreate(4);
        sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_8, 3, 3, "sel_8_8");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_9, 3, 3, "sel_8_9");
        selaAddSel(sela, sel, NULL, 0);
        break;
    case 7:
        sela = selaCreate(4);
        sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_8_7, 3, 3, "sel_8_7");
        selaAddSel(sela, sel, NULL, 0);
        sel = selRotateOrth(sel, 1);
        selaAddSel(sela, sel, "sel_8_7_rot", 0);
        break;
    case 8:  /* thicken for this one; just a few iterations */
        sela = selaCreate(2);
        sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2");
        selaAddSel(sela, sel, NULL, 0);
        sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3");
        selaAddSel(sela, sel, NULL, 0);
        pixt = pixThinGeneral(pixs, type, sela, maxiters);
        pixd = pixRemoveBorderConnComps(pixt, 4);
        pixDestroy(&pixt);
        break;
    case 9:  /* thicken for this one; just a few iterations */
        sela = selaCreate(1);
        sel = selCreateFromString(sel_8_4, 3, 3, "sel_8_4");
        selaAddSel(sela, sel, NULL, 0);
        pixt = pixThinGeneral(pixs, type, sela, maxiters);
        pixd = pixRemoveBorderConnComps(pixt, 4);
        pixDestroy(&pixt);
        break;
    default:
        return (PIX *)ERROR_PTR("invalid index", procName, NULL);
    }

    if (index <= 7)
        pixd = pixThinGeneral(pixs, type, sela, maxiters);

        /* Optionally display the sels */
    if (selfile) {
        pixt = selaDisplayInPix(sela, 35, 3, 15, 4);
        pixWrite(selfile, pixt, IFF_PNG);
        pixDestroy(&pixt);
    }

    selaDestroy(&sela);
    return pixd;
}
Beispiel #10
0
/*!
 *  selaAddBasic()
 *
 *      Input:  sela (<optional>)
 *      Return: sela with additional sels, or null on error
 *
 *  Notes:
 *      (1) Adds the following sels:
 *            - all linear (horiz, vert) brick sels that are
 *              necessary for decomposable sels up to size 63
 *            - square brick sels up to size 10
 *            - 4 diagonal sels
 */
SELA *
selaAddBasic(SELA  *sela)
{
char     name[L_BUF_SIZE];
l_int32  i, size;
SEL     *sel;

    PROCNAME("selaAddBasic");

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    /*--------------------------------------------------------------*
     *             Linear horizontal and vertical sels              *
     *--------------------------------------------------------------*/
    for (i = 0; i < num_linear; i++) {
        size = basic_linear[i];
        sel = selCreateBrick(1, size, 0, size / 2, 1);
        snprintf(name, L_BUF_SIZE, "sel_%dh", size);
        selaAddSel(sela, sel, name, 0);
    }
    for (i = 0; i < num_linear; i++) {
        size = basic_linear[i];
        sel = selCreateBrick(size, 1, size / 2, 0, 1);
        snprintf(name, L_BUF_SIZE, "sel_%dv", size);
        selaAddSel(sela, sel, name, 0);
    }

    /*-----------------------------------------------------------*
     *                      2-d Bricks                           *
     *-----------------------------------------------------------*/
    for (i = 2; i <= 5; i++) {
        sel = selCreateBrick(i, i, i / 2, i / 2, 1);
        snprintf(name, L_BUF_SIZE, "sel_%d", i);
        selaAddSel(sela, sel, name, 0);
    }

    /*-----------------------------------------------------------*
     *                        Diagonals                          *
     *-----------------------------------------------------------*/
        /*  0c  1
            1   0  */
    sel = selCreateBrick(2, 2, 0, 0, 1);
    selSetElement(sel, 0, 0, 0);
    selSetElement(sel, 1, 1, 0);
    selaAddSel(sela, sel, "sel_2dp", 0);

        /*  1c  0
            0   1   */
    sel = selCreateBrick(2, 2, 0, 0, 1);
    selSetElement(sel, 0, 1, 0);
    selSetElement(sel, 1, 0, 0);
    selaAddSel(sela, sel, "sel_2dm", 0);

        /*  Diagonal, slope +, size 5 */
    sel = selCreate(5, 5, "sel_5dp");
    sel->cy = 2;
    sel->cx = 2;
    selSetElement(sel, 0, 4, 1);
    selSetElement(sel, 1, 3, 1);
    selSetElement(sel, 2, 2, 1);
    selSetElement(sel, 3, 1, 1);
    selSetElement(sel, 4, 0, 1);
    selaAddSel(sela, sel, "sel_5dp", 0);

        /*  Diagonal, slope -, size 5 */
    sel = selCreate(5, 5, "sel_5dm");
    sel->cy = 2;
    sel->cx = 2;
    selSetElement(sel, 0, 0, 1);
    selSetElement(sel, 1, 1, 1);
    selSetElement(sel, 2, 2, 1);
    selSetElement(sel, 3, 3, 1);
    selSetElement(sel, 4, 4, 1);
    selaAddSel(sela, sel, "sel_5dm", 0);

    return sela;
}
Beispiel #11
0
/*!
 *  selaAddTJunctions()
 *
 *      Input:  sela (<optional>)
 *              hlsize (length of each line of hits from origin)
 *              mdist (distance of misses from the origin)
 *              norient (number of orientations; max of 8)
 *              debugflag (1 for debug output)
 *      Return: sela with additional sels, or null on error
 *
 *  Notes:
 *      (1) Adds hitmiss Sels for the T-junction of two lines.
 *          If the lines are very thin, they must be nearly orthogonal
 *          to register.
 *      (2) The number of Sels generated is 4 * @norient.
 *      (3) It is suggested that @hlsize be chosen at least 1 greater
 *          than @mdist.  Try values of (@hlsize, @mdist) such as
 *          (6,5), (7,6), (8,7), (9,7), etc.
 */
SELA *
selaAddTJunctions(SELA      *sela,
                  l_float32  hlsize,
                  l_float32  mdist,
                  l_int32    norient,
                  l_int32    debugflag)
{
char       name[L_BUF_SIZE];
l_int32    i, j, k, w, xc, yc;
l_float64  pi, halfpi, radincr, jang, radang;
l_float64  angle[3], dist[3];
PIX       *pixc, *pixm, *pixt;
PIXA      *pixa;
PTA       *pta1, *pta2, *pta3;
SEL       *sel;

    PROCNAME("selaAddTJunctions");

    if (hlsize <= 2)
        return (SELA *)ERROR_PTR("hlsizel not > 1", procName, NULL);
    if (norient < 1 || norient > 8)
        return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    pi = 3.1415926535;
    halfpi = 3.1415926535 / 2.0;
    radincr = halfpi / (l_float32)norient;
    w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5));
    if (w % 2 == 0)
        w++;
    xc = w / 2;
    yc = w / 2;

    pixa = pixaCreate(4 * norient);
    for (i = 0; i < norient; i++) {
        for (j = 0; j < 4; j++) {  /* 4 orthogonal orientations */
            jang = (l_float32)j * halfpi;

                /* Set the don't cares */
            pixc = pixCreate(w, w, 32);
            pixSetAll(pixc);

                /* Add the green lines of hits */
            pixm = pixCreate(w, w, 1);
            radang = (l_float32)i * radincr;
            pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang);
            pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1,
                                         jang + radang + halfpi);
            pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1,
                                         jang + radang + pi);
            ptaJoin(pta1, pta2, 0, -1);
            ptaJoin(pta1, pta3, 0, -1);
            pixRenderPta(pixm, pta1, L_SET_PIXELS);
            pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
            ptaDestroy(&pta1);
            ptaDestroy(&pta2);
            ptaDestroy(&pta3);

                /* Add red misses between the lines */
            angle[0] = radang + jang - halfpi;
            angle[1] = radang + jang + 0.5 * halfpi;
            angle[2] = radang + jang + 1.5 * halfpi;
            dist[0] = 0.8 * mdist;
            dist[1] = dist[2] = mdist;
            for (k = 0; k < 3; k++) {
                pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])),
                            yc + (l_int32)(dist[k] * sin(angle[k])),
                            0xff000000);
            }

                /* Add dark green for origin */
            pixSetPixel(pixc, xc, yc, 0x00550000);

                /* Generate the sel */
            sel = selCreateFromColorPix(pixc, NULL);
            sprintf(name, "sel_cross_%d", 4 * i + j);
            selaAddSel(sela, sel, name, 0);

            if (debugflag) {
                pixt = pixScaleBySampling(pixc, 10.0, 10.0);
                pixaAddPix(pixa, pixt, L_INSERT);
            }
            pixDestroy(&pixm);
            pixDestroy(&pixc);
        }
    }

    if (debugflag) {
        l_int32  w;
        pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
        pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2);
        pixWriteTempfile("/tmp", "tsel1.png", pixt, IFF_PNG, 0);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 4);
        pixWriteTempfile("/tmp", "tsel2.png", pixt, IFF_PNG, 0);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}
Beispiel #12
0
/*!
 *  selaAddHitMiss()
 *
 *      Input:  sela  (<optional>)
 *      Return: sela with additional sels, or null on error
 */
SELA *
selaAddHitMiss(SELA  *sela)
{
SEL  *sel;

    PROCNAME("selaAddHitMiss");

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

#if 0   /*  use just for testing */
    sel = selCreateBrick(3, 3, 1, 1, 2);
    selaAddSel(sela, sel, "sel_bad", 0);
#endif


    /*--------------------------------------------------------------*
     *                   Isolated foreground pixel                  *
     *--------------------------------------------------------------*/
    sel = selCreateBrick(3, 3, 1, 1, SEL_MISS);
    selSetElement(sel, 1, 1, SEL_HIT);
    selaAddSel(sela, sel, "sel_3hm", 0);

    /*--------------------------------------------------------------*
     *                Horizontal and vertical edges                 *
     *--------------------------------------------------------------*/
    sel = selCreateBrick(2, 3, 0, 1, SEL_HIT);
    selSetElement(sel, 1, 0, SEL_MISS);
    selSetElement(sel, 1, 1, SEL_MISS);
    selSetElement(sel, 1, 2, SEL_MISS);
    selaAddSel(sela, sel, "sel_3de", 0);

    sel = selCreateBrick(2, 3, 1, 1, SEL_HIT);
    selSetElement(sel, 0, 0, SEL_MISS);
    selSetElement(sel, 0, 1, SEL_MISS);
    selSetElement(sel, 0, 2, SEL_MISS);
    selaAddSel(sela, sel, "sel_3ue", 0);

    sel = selCreateBrick(3, 2, 1, 0, SEL_HIT);
    selSetElement(sel, 0, 1, SEL_MISS);
    selSetElement(sel, 1, 1, SEL_MISS);
    selSetElement(sel, 2, 1, SEL_MISS);
    selaAddSel(sela, sel, "sel_3re", 0);

    sel = selCreateBrick(3, 2, 1, 1, SEL_HIT);
    selSetElement(sel, 0, 0, SEL_MISS);
    selSetElement(sel, 1, 0, SEL_MISS);
    selSetElement(sel, 2, 0, SEL_MISS);
    selaAddSel(sela, sel, "sel_3le", 0);

    /*--------------------------------------------------------------*
     *                        Slanted edge                          *
     *--------------------------------------------------------------*/
    sel = selCreateBrick(13, 6, 6, 2, SEL_DONT_CARE);
    selSetElement(sel, 0, 3, SEL_MISS);
    selSetElement(sel, 0, 5, SEL_HIT);
    selSetElement(sel, 4, 2, SEL_MISS);
    selSetElement(sel, 4, 4, SEL_HIT);
    selSetElement(sel, 8, 1, SEL_MISS);
    selSetElement(sel, 8, 3, SEL_HIT);
    selSetElement(sel, 12, 0, SEL_MISS);
    selSetElement(sel, 12, 2, SEL_HIT);
    selaAddSel(sela, sel, "sel_sl1", 0);

    /*--------------------------------------------------------------*
     *                           Corners                            *
     *  This allows for up to 3 missing edge pixels at the corner   *
     *--------------------------------------------------------------*/
    sel = selCreateBrick(4, 4, 1, 1, SEL_MISS);
    selSetElement(sel, 1, 1, SEL_DONT_CARE);
    selSetElement(sel, 1, 2, SEL_DONT_CARE);
    selSetElement(sel, 2, 1, SEL_DONT_CARE);
    selSetElement(sel, 1, 3, SEL_HIT);
    selSetElement(sel, 2, 2, SEL_HIT);
    selSetElement(sel, 2, 3, SEL_HIT);
    selSetElement(sel, 3, 1, SEL_HIT);
    selSetElement(sel, 3, 2, SEL_HIT);
    selSetElement(sel, 3, 3, SEL_HIT);
    selaAddSel(sela, sel, "sel_ulc", 0);

    sel = selCreateBrick(4, 4, 1, 2, SEL_MISS);
    selSetElement(sel, 1, 1, SEL_DONT_CARE);
    selSetElement(sel, 1, 2, SEL_DONT_CARE);
    selSetElement(sel, 2, 2, SEL_DONT_CARE);
    selSetElement(sel, 1, 0, SEL_HIT);
    selSetElement(sel, 2, 0, SEL_HIT);
    selSetElement(sel, 2, 1, SEL_HIT);
    selSetElement(sel, 3, 0, SEL_HIT);
    selSetElement(sel, 3, 1, SEL_HIT);
    selSetElement(sel, 3, 2, SEL_HIT);
    selaAddSel(sela, sel, "sel_urc", 0);

    sel = selCreateBrick(4, 4, 2, 1, SEL_MISS);
    selSetElement(sel, 1, 1, SEL_DONT_CARE);
    selSetElement(sel, 2, 1, SEL_DONT_CARE);
    selSetElement(sel, 2, 2, SEL_DONT_CARE);
    selSetElement(sel, 0, 1, SEL_HIT);
    selSetElement(sel, 0, 2, SEL_HIT);
    selSetElement(sel, 0, 3, SEL_HIT);
    selSetElement(sel, 1, 2, SEL_HIT);
    selSetElement(sel, 1, 3, SEL_HIT);
    selSetElement(sel, 2, 3, SEL_HIT);
    selaAddSel(sela, sel, "sel_llc", 0);

    sel = selCreateBrick(4, 4, 2, 2, SEL_MISS);
    selSetElement(sel, 1, 2, SEL_DONT_CARE);
    selSetElement(sel, 2, 1, SEL_DONT_CARE);
    selSetElement(sel, 2, 2, SEL_DONT_CARE);
    selSetElement(sel, 0, 0, SEL_HIT);
    selSetElement(sel, 0, 1, SEL_HIT);
    selSetElement(sel, 0, 2, SEL_HIT);
    selSetElement(sel, 1, 0, SEL_HIT);
    selSetElement(sel, 1, 1, SEL_HIT);
    selSetElement(sel, 2, 0, SEL_HIT);
    selaAddSel(sela, sel, "sel_lrc", 0);

    return sela;
}
Beispiel #13
0
int main(int    argc,
         char **argv)
{
BOX         *box;
PIX         *pix, *pixs, *pixd, *pixt;
PIXA        *pixa;
SEL         *sel, *sel1, *sel2, *sel3;
SELA        *sela4, *sela8, *sela48;
static char  mainName[] = "ccthin1_reg";

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

        /* Generate and display all of the 4-cc sels */
    sela4 = selaCreate(9);
    sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_4, 3, 3, "sel_4_4");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_5, 3, 3, "sel_4_5");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_6, 3, 3, "sel_4_6");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_7, 3, 3, "sel_4_7");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_8, 3, 3, "sel_4_8");
    selaAddSel(sela4, sel, NULL, 0);
    sel = selCreateFromString(sel_4_9, 3, 3, "sel_4_9");
    selaAddSel(sela4, sel, NULL, 0);
    pixt = selaDisplayInPix(sela4, 35, 3, 15, 3);
    pixWrite("/tmp/junkallsel4.png", pixt, IFF_PNG);
    pixDestroy(&pixt);
    selaDestroy(&sela4);

        /* Generate and display all of the 8-cc sels */
    sela8 = selaCreate(9);
    sel = selCreateFromString(sel_8_1, 3, 3, "sel_8_1");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_4, 3, 3, "sel_8_4");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_7, 3, 3, "sel_8_7");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_8, 3, 3, "sel_8_8");
    selaAddSel(sela8, sel, NULL, 0);
    sel = selCreateFromString(sel_8_9, 3, 3, "sel_8_9");
    selaAddSel(sela8, sel, NULL, 0);
    pixt = selaDisplayInPix(sela8, 35, 3, 15, 3);
    pixWrite("/tmp/junkallsel8.png", pixt, IFF_PNG);
    pixDestroy(&pixt);
    selaDestroy(&sela8);

        /* Generate and display all of the 4 and 8-cc preserving sels */
    sela48 = selaCreate(3);
    sel = selCreateFromString(sel_48_1, 3, 3, "sel_48_1");
    selaAddSel(sela48, sel, NULL, 0);
    sel = selCreateFromString(sel_48_2, 3, 3, "sel_48_2");
    selaAddSel(sela48, sel, NULL, 0);
    pixt = selaDisplayInPix(sela48, 35, 3, 15, 4);
    pixWrite("/tmp/junkallsel48.png", pixt, IFF_PNG);
    pixDestroy(&pixt);
    selaDestroy(&sela48);

        /* Generate and display three of the 4-cc sels and their rotations */
    sela4 = selaCreate(3);
    sel = selCreateFromString(sel_4_1, 3, 3, "sel_4_1");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela4, sel, NULL, 0);
    selaAddSel(sela4, sel1, "sel_4_1_90", 0);
    selaAddSel(sela4, sel2, "sel_4_1_180", 0);
    selaAddSel(sela4, sel3, "sel_4_1_270", 0);
    sel = selCreateFromString(sel_4_2, 3, 3, "sel_4_2");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela4, sel, NULL, 0);
    selaAddSel(sela4, sel1, "sel_4_2_90", 0);
    selaAddSel(sela4, sel2, "sel_4_2_180", 0);
    selaAddSel(sela4, sel3, "sel_4_2_270", 0);
    sel = selCreateFromString(sel_4_3, 3, 3, "sel_4_3");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela4, sel, NULL, 0);
    selaAddSel(sela4, sel1, "sel_4_3_90", 0);
    selaAddSel(sela4, sel2, "sel_4_3_180", 0);
    selaAddSel(sela4, sel3, "sel_4_3_270", 0);
    pixt = selaDisplayInPix(sela4, 35, 3, 15, 4);
    pixWrite("/tmp/junksel4.png", pixt, IFF_PNG);
    pixDestroy(&pixt);
    selaDestroy(&sela4);

        /* Generate and display four of the 8-cc sels and their rotations */
    sela8 = selaCreate(4);
    sel = selCreateFromString(sel_8_2, 3, 3, "sel_8_2");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela8, sel, NULL, 0);
    selaAddSel(sela8, sel1, "sel_8_2_90", 0);
    selaAddSel(sela8, sel2, "sel_8_2_180", 0);
    selaAddSel(sela8, sel3, "sel_8_2_270", 0);
    sel = selCreateFromString(sel_8_3, 3, 3, "sel_8_3");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela8, sel, NULL, 0);
    selaAddSel(sela8, sel1, "sel_8_3_90", 0);
    selaAddSel(sela8, sel2, "sel_8_3_180", 0);
    selaAddSel(sela8, sel3, "sel_8_3_270", 0);
    sel = selCreateFromString(sel_8_5, 3, 3, "sel_8_5");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela8, sel, NULL, 0);
    selaAddSel(sela8, sel1, "sel_8_5_90", 0);
    selaAddSel(sela8, sel2, "sel_8_5_180", 0);
    selaAddSel(sela8, sel3, "sel_8_5_270", 0);
    sel = selCreateFromString(sel_8_6, 3, 3, "sel_8_6");
    sel1 = selRotateOrth(sel, 1);
    sel2 = selRotateOrth(sel, 2);
    sel3 = selRotateOrth(sel, 3);
    selaAddSel(sela8, sel, NULL, 0);
    selaAddSel(sela8, sel1, "sel_8_6_90", 0);
    selaAddSel(sela8, sel2, "sel_8_6_180", 0);
    selaAddSel(sela8, sel3, "sel_8_6_270", 0);
    pixt = selaDisplayInPix(sela8, 35, 3, 15, 4);
    pixWrite("/tmp/junksel8.png", pixt, IFF_PNG);
    pixDestroy(&pixt);
    selaDestroy(&sela8);

        /* Test the best 4 and 8 cc thinning */
    pixDisplayWrite(NULL, 0);
    pix = pixRead("feyn.tif");
    box = boxCreate(683, 799, 970, 479);
    pixs = pixClipRectangle(pix, box, NULL);
    pixDisplayWrite(pixs, 1);

    pixt = pixThin(pixs, L_THIN_FG, 4, 0);
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThin(pixs, L_THIN_BG, 4, 0);
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);

    pixt = pixThin(pixs, L_THIN_FG, 8, 0);
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixThin(pixs, L_THIN_BG, 8, 0);
    pixDisplayWrite(pixt, 1);
    pixDestroy(&pixt);

        /* Display tiled */
    pixa = pixaReadFiles("/tmp/display", "file");
    pixd = pixaDisplayTiledAndScaled(pixa, 8, 500, 1, 0, 25, 2);
    pixWrite("/tmp/junktiles.jpg", pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    pixDestroy(&pix);
    pixDestroy(&pixs);
    boxDestroy(&box);

    pixDisplayMultiple("/tmp/display/file*");
    return 0;
}
Beispiel #14
0
/*!
 * \brief   selaAddCrossJunctions()
 *
 * \param[in]    sela [optional]
 * \param[in]    hlsize length of each line of hits from origin
 * \param[in]    mdist distance of misses from the origin
 * \param[in]    norient number of orientations; max of 8
 * \param[in]    debugflag 1 for debug output
 * \return  sela with additional sels, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Adds hitmiss Sels for the intersection of two lines.
 *          If the lines are very thin, they must be nearly orthogonal
 *          to register.
 *      (2) The number of Sels generated is equal to %norient.
 *      (3) If %norient == 2, this generates 2 Sels of crosses, each with
 *          two perpendicular lines of hits.  One Sel has horizontal and
 *          vertical hits; the other has hits along lines at +-45 degrees.
 *          Likewise, if %norient == 3, this generates 3 Sels of crosses
 *          oriented at 30 degrees with each other.
 *      (4) It is suggested that %hlsize be chosen at least 1 greater
 *          than %mdist.  Try values of (%hlsize, %mdist) such as
 *          (6,5), (7,6), (8,7), (9,7), etc.
 * </pre>
 */
SELA *
selaAddCrossJunctions(SELA      *sela,
                      l_float32  hlsize,
                      l_float32  mdist,
                      l_int32    norient,
                      l_int32    debugflag)
{
char       name[L_BUF_SIZE];
l_int32    i, j, w, xc, yc;
l_float64  pi, halfpi, radincr, radang;
l_float64  angle;
PIX       *pixc, *pixm, *pixt;
PIXA      *pixa;
PTA       *pta1, *pta2, *pta3, *pta4;
SEL       *sel;

    PROCNAME("selaAddCrossJunctions");

    if (hlsize <= 0)
        return (SELA *)ERROR_PTR("hlsize not > 0", procName, NULL);
    if (norient < 1 || norient > 8)
        return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    pi = 3.1415926535;
    halfpi = 3.1415926535 / 2.0;
    radincr = halfpi / (l_float64)norient;
    w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5));
    if (w % 2 == 0)
        w++;
    xc = w / 2;
    yc = w / 2;

    pixa = pixaCreate(norient);
    for (i = 0; i < norient; i++) {

            /* Set the don't cares */
        pixc = pixCreate(w, w, 32);
        pixSetAll(pixc);

            /* Add the green lines of hits */
        pixm = pixCreate(w, w, 1);
        radang = (l_float32)i * radincr;
        pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang);
        pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi);
        pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi);
        pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi);
        ptaJoin(pta1, pta2, 0, -1);
        ptaJoin(pta1, pta3, 0, -1);
        ptaJoin(pta1, pta4, 0, -1);
        pixRenderPta(pixm, pta1, L_SET_PIXELS);
        pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
        ptaDestroy(&pta1);
        ptaDestroy(&pta2);
        ptaDestroy(&pta3);
        ptaDestroy(&pta4);

            /* Add red misses between the lines */
        for (j = 0; j < 4; j++) {
            angle = radang + (j - 0.5) * halfpi;
            pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)),
                        yc + (l_int32)(mdist * sin(angle)), 0xff000000);
        }

            /* Add dark green for origin */
        pixSetPixel(pixc, xc, yc, 0x00550000);

            /* Generate the sel */
        sel = selCreateFromColorPix(pixc, NULL);
        sprintf(name, "sel_cross_%d", i);
        selaAddSel(sela, sel, name, 0);

        if (debugflag) {
            pixt = pixScaleBySampling(pixc, 10.0, 10.0);
            pixaAddPix(pixa, pixt, L_INSERT);
        }
        pixDestroy(&pixm);
        pixDestroy(&pixc);
    }

    if (debugflag) {
        l_int32  w;
        lept_mkdir("lept/sel");
        pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
        pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 1, 0, 10, 2);
        pixWrite("/tmp/lept/sel/xsel1.png", pixt, IFF_PNG);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 1);
        pixWrite("/tmp/lept/sel/xsel2.png", pixt, IFF_PNG);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}