/*!
 *  bmfGetWidth()
 *
 *      Input:  bmf
 *              chr (should be one of the 95 supported bitmaps)
 *              &w (<return> character width; -1 if not printable)
 *      Return: 0 if OK, 1 on error
 */
l_int32
bmfGetWidth(L_BMF    *bmf,
            char      chr,
            l_int32  *pw)
{
l_int32  i, index;
PIXA    *pixa;

    PROCNAME("bmfGetWidth");

    if (!pw)
        return ERROR_INT("&w not defined", procName, 1);
    *pw = -1;
    if (!bmf)
        return ERROR_INT("bmf not defined", procName, 1);
    if ((index = (l_int32)chr) == 10)  /* NL */
        return 0;

    i = bmf->fonttab[index];
    if (i == UNDEF) {
        L_ERROR("no bitmap representation for %d\n", procName, index);
        return 1;
    }

    if ((pixa = bmf->pixa) == NULL)
        return ERROR_INT("pixa not found", procName, 1);

    return pixaGetPixDimensions(pixa, i, pw, NULL, NULL);
}
예제 #2
0
/* ----------------------------------------------------- */
void PixaDisplayNumbered(PIXA        *pixa,
                         const char  *basename)
{
char     buf[64];
l_int32  fill, color, d;
L_BMF   *bmf;
PIX     *pix1;
PIXA    *pixa1, *pixa2;

    bmf = bmfCreate(NULL, 4);
    pixaGetPixDimensions(pixa, 0, NULL, NULL, &d);
    fill = (d == 8) ? 0xff : 0;
    color = (d == 8) ? 0x00000000 : 0xffffff00;
    pixa1 = pixaAddBorderGeneral(NULL, pixa, 10, 10, 0, 0, fill);
    pixa2 = pixaAddTextNumber(pixa1, bmf, NULL, color, L_ADD_BELOW);
    snprintf(buf, sizeof(buf), "%s.pa", basename);
    pixaWrite(buf, pixa2);
    pix1 = pixaDisplayTiledInColumns(pixa2, 20, 2.5, 15, 2);
    snprintf(buf, sizeof(buf), "%s.png", basename);
    pixWrite(buf, pix1, IFF_PNG);
    pixDisplay(pix1, 500, 500);
    pixDestroy(&pix1);
    pixaDestroy(&pixa1);
    pixaDestroy(&pixa2);
    bmfDestroy(&bmf);
}
/*!
 * \brief   recogRescoreDidResult()
 *
 * \param[in]    recog with LUT's pre-computed
 * \param[out]   ppixdb [optional] debug result; can be null
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This does correlation matching with all templates using the
 *          viterbi path segmentation.
 * </pre>
 */
static l_int32
recogRescoreDidResult(L_RECOG  *recog,
                      PIX     **ppixdb)
{
l_int32    i, n, w2, h1, templ, x, xloc, dely, index;
char      *text;
l_float32  score;
BOX       *box1;
PIX       *pixs, *pix1;
L_RDID    *did;

    PROCNAME("recogRescoreDidResult");

    if (ppixdb) *ppixdb = NULL;
    if (!recog)
        return ERROR_INT("recog not defined", procName, 1);
    if ((did = recogGetDid(recog)) == NULL)
        return ERROR_INT("did not defined", procName, 1);
    if (did->fullarrays == 0)
        return ERROR_INT("did full arrays not made", procName, 1);
    if ((n = numaGetCount(did->naxloc)) == 0)
        return ERROR_INT("no elements in path", procName, 1);

    pixs = did->pixs;
    h1 = pixGetHeight(pixs);
    for (i = 0; i < n; i++) {
        numaGetIValue(did->natempl, i, &templ);
        numaGetIValue(did->naxloc, i, &xloc);
        numaGetIValue(did->nadely, i, &dely);
        pixaGetPixDimensions(recog->pixa_u, templ, &w2, NULL, NULL);
        /* TODO: try to fix xloc - 4, etc. */
        x = L_MAX(xloc, 0);
        box1 = boxCreate(x, dely, w2, h1);
        pix1 = pixClipRectangle(pixs, box1, NULL);
        recogIdentifyPix(recog, pix1, NULL);
        recogTransferRchToDid(recog, x, dely);
        if (ppixdb) {
            rchExtract(recog->rch, &index, &score, &text,
                       NULL, NULL, NULL, NULL);
            fprintf(stderr, "text = %s, index = %d, score = %5.3f\n",
                    text, index, score);
        }
        pixDestroy(&pix1);
        boxDestroy(&box1);
        LEPT_FREE(text);
    }

/*    numaWriteStream(stderr, recog->did->nadely_r);  */

    if (ppixdb)
        *ppixdb = recogShowPath(recog, 1);

    return 0;
}
예제 #4
0
/*!
 *  pixaDisplayUnsplit()
 *
 *      Input:  pixa
 *              nx   (number of mosaic cells horizontally)
 *              ny   (number of mosaic cells vertically)
 *              borderwidth  (of added border on all sides)
 *              bordercolor  (in our RGBA format: 0xrrggbbaa)
 *      Return: pix of tiled images, or null on error
 *
 *  Notes:
 *      (1) This is a logical inverse of pixaSplitPix().  It
 *          constructs a pix from a mosaic of tiles, all of equal size.
 *      (2) For added generality, a border of arbitrary color can
 *          be added to each of the tiles.
 *      (3) In use, pixa will typically have either been generated
 *          from pixaSplitPix() or will derived from a pixa that
 *          was so generated.
 *      (4) All pix in the pixa must be of equal depth, and, if
 *          colormapped, have the same colormap.
 */
PIX *
pixaDisplayUnsplit(PIXA     *pixa,
                   l_int32   nx,
                   l_int32   ny,
                   l_int32   borderwidth,
                   l_uint32  bordercolor)
{
l_int32  w, h, d, wt, ht;
l_int32  i, j, k, x, y, n;
PIX     *pixt, *pixd;

    PROCNAME("pixaDisplayUnsplit");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    if (nx <= 0 || ny <= 0)
        return (PIX *)ERROR_PTR("nx and ny must be > 0", procName, NULL);
    if ((n = pixaGetCount(pixa)) == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);
    if (n != nx * ny)
        return (PIX *)ERROR_PTR("n != nx * ny", procName, NULL);
    borderwidth = L_MAX(0, borderwidth);

    pixaGetPixDimensions(pixa, 0, &wt, &ht, &d);
    w = nx * (wt + 2 * borderwidth);
    h = ny * (ht + 2 * borderwidth);

    if ((pixd = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    pixt = pixaGetPix(pixa, 0, L_CLONE);
    pixCopyColormap(pixd, pixt);
    pixDestroy(&pixt);
    if (borderwidth > 0)
        pixSetAllArbitrary(pixd, bordercolor);

    y = borderwidth;
    for (i = 0, k = 0; i < ny; i++) {
        x = borderwidth;
        for (j = 0; j < nx; j++, k++) {
            pixt = pixaGetPix(pixa, k, L_CLONE);
            pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pixt, 0, 0);
            pixDestroy(&pixt);
            x += wt + 2 * borderwidth;
        }
        y += ht + 2 * borderwidth;
    }

    return pixd;
}
예제 #5
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;
}
예제 #6
0
/*!
 *  pixaDisplayTiledInRows()
 *
 *      Input:  pixa
 *              outdepth (output depth: 1, 8 or 32 bpp)
 *              maxwidth (of output image)
 *              scalefactor (applied to every pix; use 1.0 for no scaling)
 *              background (0 for white, 1 for black; this is the color
 *                 of the spacing between the images)
 *              spacing  (between images, and on outside)
 *              border (width of black border added to each image;
 *                      use 0 for no border)
 *      Return: pixd (of tiled images), or null on error
 *
 *  Notes:
 *      (1) This saves a pixa to a single image file of width not to
 *          exceed maxwidth, with background color either white or black,
 *          and with each row tiled such that the top of each pix is
 *          aligned and separated by 'spacing' from the next one.
 *          A black border can be added to each pix.
 *      (2) All pix are converted to outdepth; existing colormaps are removed.
 *      (3) This does a reasonably spacewise-efficient job of laying
 *          out the individual pix images into a tiled composite.
 */
PIX *
pixaDisplayTiledInRows(PIXA      *pixa,
                       l_int32    outdepth,
                       l_int32    maxwidth,
                       l_float32  scalefactor,
                       l_int32    background,
                       l_int32    spacing,
                       l_int32    border)
{
l_int32  h;  /* cumulative height over all the rows */
l_int32  w;  /* cumulative height in the current row */
l_int32  bordval, wtry, wt, ht;
l_int32  irow;  /* index of current pix in current row */
l_int32  wmaxrow;  /* width of the largest row */
l_int32  maxh;  /* max height in row */
l_int32  i, j, index, n, x, y, nrows, ninrow;
NUMA    *nainrow;  /* number of pix in the row */
NUMA    *namaxh;  /* height of max pix in the row */
PIX     *pix, *pixn, *pixt, *pixd;
PIXA    *pixan;

    PROCNAME("pixaDisplayTiledInRows");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    if (outdepth != 1 && outdepth != 8 && outdepth != 32)
        return (PIX *)ERROR_PTR("outdepth not in {1, 8, 32}", procName, NULL);
    if (border < 0)
        border = 0;
    if (scalefactor <= 0.0) scalefactor = 1.0;
    
    if ((n = pixaGetCount(pixa)) == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);

        /* Normalize depths, scale, remove colormaps; optionally add border */
    pixan = pixaCreate(n);
    bordval = (outdepth == 1) ? 1 : 0;
    for (i = 0; i < n; i++) {
        if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
            continue;

        if (outdepth == 1)
            pixn = pixConvertTo1(pix, 128);
        else if (outdepth == 8)
            pixn = pixConvertTo8(pix, FALSE);
        else  /* outdepth == 32 */
            pixn = pixConvertTo32(pix);
        pixDestroy(&pix);

        if (scalefactor != 1.0)
            pixt = pixScale(pixn, scalefactor, scalefactor);
        else
            pixt = pixClone(pixn);
        if (border)
            pixd = pixAddBorder(pixt, border, bordval);
        else
            pixd = pixClone(pixt);
        pixDestroy(&pixn);
        pixDestroy(&pixt);

        pixaAddPix(pixan, pixd, L_INSERT);
    }
    if (pixaGetCount(pixan) != n) {
        n = pixaGetCount(pixan);
        L_WARNING_INT("only got %d components", procName, n);
        if (n == 0) {
            pixaDestroy(&pixan);
            return (PIX *)ERROR_PTR("no components", procName, NULL);
        }
    }

        /* Compute parameters for layout */
    nainrow = numaCreate(0);
    namaxh = numaCreate(0);
    wmaxrow = 0;
    w = h = spacing;
    maxh = 0;  /* max height in row */
    for (i = 0, irow = 0; i < n; i++, irow++) {
        pixaGetPixDimensions(pixan, i, &wt, &ht, NULL);
        wtry = w + wt + spacing;
        if (wtry > maxwidth) {  /* end the current row and start next one */
            numaAddNumber(nainrow, irow); 
            numaAddNumber(namaxh, maxh); 
            wmaxrow = L_MAX(wmaxrow, w);
            h += maxh + spacing;
            irow = 0;
            w = wt + 2 * spacing;
            maxh = ht;
        } else {
            w = wtry;
            maxh = L_MAX(maxh, ht);
        }
    }

        /* Enter the parameters for the last row */
    numaAddNumber(nainrow, irow); 
    numaAddNumber(namaxh, maxh); 
    wmaxrow = L_MAX(wmaxrow, w);
    h += maxh + spacing;
            
    if ((pixd = pixCreate(wmaxrow, h, outdepth)) == NULL) {
        numaDestroy(&nainrow);
        numaDestroy(&namaxh);
        pixaDestroy(&pixan);
	return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

        /* Reset the background color if necessary */
    if ((background == 1 && outdepth == 1) ||
        (background == 0 && outdepth != 1))
        pixSetAll(pixd);

        /* Blit the images to the dest */
    nrows = numaGetCount(nainrow);
    y = spacing;
    for (i = 0, index = 0; i < nrows; i++) {  /* over rows */
        numaGetIValue(nainrow, i, &ninrow);
        numaGetIValue(namaxh, i, &maxh);
        x = spacing;
        for (j = 0; j < ninrow; j++, index++) {   /* over pix in row */
            pix = pixaGetPix(pixan, index, L_CLONE);
            pixGetDimensions(pix, &wt, &ht, NULL);
            pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pix, 0, 0);
            pixDestroy(&pix);
            x += wt + spacing;
        }
        y += maxh + spacing;
    }

    numaDestroy(&nainrow);
    numaDestroy(&namaxh);
    pixaDestroy(&pixan);
    return pixd;
}
예제 #7
0
/*!
 *  pixaDisplayOnLattice()
 *
 *      Input:  pixa
 *              xspace
 *              yspace
 *      Return: pix of composite images, or null on error
 *
 *  Notes:
 *      (1) This places each pix on sequentially on a regular lattice
 *          in the rendered composite.  If a pix is too large to fit in the
 *          allocated lattice space, it is not rendered.
 *      (2) If any pix has a colormap, all pix are rendered in rgb.
 *      (3) This is useful when putting bitmaps of components,
 *          such as characters, into a single image.
 */
PIX *
pixaDisplayOnLattice(PIXA    *pixa,
                     l_int32  xspace,
                     l_int32  yspace)
{
l_int32  n, nw, nh, w, h, d, wt, ht;
l_int32  index, i, j, hascmap;
PIX     *pix, *pixt, *pixd;
PIXA    *pixat;

    PROCNAME("pixaDisplayOnLattice");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    
        /* If any pix have colormaps, generate rgb */
    if ((n = pixaGetCount(pixa)) == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);
    pixaAnyColormaps(pixa, &hascmap);
    if (hascmap) {
        pixat = pixaCreate(n);
        for (i = 0; i < n; i++) {
            pixt = pixaGetPix(pixa, i, L_CLONE);
            pix = pixConvertTo32(pixt);
            pixaAddPix(pixat, pix, L_INSERT);
            pixDestroy(&pixt);
        }
    }
    else
        pixat = pixaCopy(pixa, L_CLONE);

    nw = (l_int32)sqrt((l_float64)n);
    nh = (n + nw - 1) / nw;
    w = xspace * nw;
    h = yspace * nh;

        /* Use the first pix in pixa to determine the depth.  */
    pixaGetPixDimensions(pixat, 0, NULL, NULL, &d);

    if ((pixd = pixCreate(w, h, d)) == NULL) {
        pixaDestroy(&pixat);
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }
    
    index = 0;
    for (i = 0; i < nh; i++) {
        for (j = 0; j < nw && index < n; j++, index++) {
            pixt = pixaGetPix(pixat, index, L_CLONE);
            pixGetDimensions(pixt, &wt, &ht, NULL);
            if (wt > xspace || ht > yspace) {
                fprintf(stderr, "pix(%d) omitted; size %dx%d\n", index, wt, ht);
                pixDestroy(&pixt);
                continue;
            }
            pixRasterop(pixd, j * xspace, i * yspace, wt, ht, 
                        PIX_PAINT, pixt, 0, 0);
            pixDestroy(&pixt);
        }
    }

    pixaDestroy(&pixat);
    return pixd;
}
예제 #8
0
파일: sel2.c 프로젝트: pnordhus/leptonica
/*!
 * \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;
}