/*!
 *  pixcmapContrastTRC()
 *
 *      Input:  colormap
 *              factor (generally between 0.0 (no enhancement)
 *                      and 1.0, but can be larger than 1.0)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - in-place transform
 *      - see pixContrastTRC() and numaContrastTRC() in enhance.c for
 *        description and use of transform
 */
l_int32
pixcmapContrastTRC(PIXCMAP   *cmap,
                   l_float32  factor)
{
l_int32   i, ncolors, rval, gval, bval, trval, tgval, tbval;
NUMA     *nac;

    PROCNAME("pixcmapContrastTRC");

    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (factor < 0.0) {
        L_WARNING("factor must be >= 0.0; setting to 0.0", procName);
        factor = 0.0;
    }

    if ((nac = numaContrastTRC(factor)) == NULL)
        return ERROR_INT("nac not made", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        numaGetIValue(nac, rval, &trval);
        numaGetIValue(nac, gval, &tgval);
        numaGetIValue(nac, bval, &tbval);
        pixcmapResetColor(cmap, i, trval, tgval, tbval);
    }

    numaDestroy(&nac);
    return 0;
}
Exemple #2
0
/*!
 *  wshedGetHeight()
 *
 *      Input:  wshed (array of current indices)
 *              val (value of current pixel popped off queue)
 *              label (of pixel or 32 bpp label image)
 *              &height (<return> height of current value from seed
 *                       or minimum of watershed)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) It is only necessary to find the height for a watershed
 *          that is indexed by a seed or a minima.  This function should
 *          not be called on a finished watershed (that continues to fill).
 */
static l_int32
wshedGetHeight(L_WSHED *wshed,
               l_int32 val,
               l_int32 label,
               l_int32 *pheight) {
    l_int32 minval;

    PROCNAME("wshedGetHeight");

    if (!pheight)
        return ERROR_INT("&height not defined", procName, 1);
    *pheight = 0;
    if (!wshed)
        return ERROR_INT("wshed not defined", procName, 1);

    if (label < wshed->nseeds)
        numaGetIValue(wshed->nash, label, &minval);
    else if (label < wshed->nseeds + wshed->nother)
        numaGetIValue(wshed->namh, label, &minval);
    else
        return ERROR_INT("finished watershed; should not call", procName, 1);

    *pheight = val - minval;
    return 0;
}
static l_int32
testLineAlignmentX(NUMA    *na1,
                   NUMA    *na2,
                   l_int32  shiftx,
                   l_int32  delx,
                   l_int32  nperline)
{
l_int32  i, xl1, xr1, xl2, xr2, diffl, diffr;

    PROCNAME("testLineAlignmentX");

    if (!na1)
        return ERROR_INT("na1 not defined", procName, 1);
    if (!na2)
        return ERROR_INT("na2 not defined", procName, 1);

    for (i = 0; i < nperline; i++) {
        numaGetIValue(na1, i + 1, &xl1);
        numaGetIValue(na1, i + 2, &xr1);
        numaGetIValue(na2, i + 1, &xl2);
        numaGetIValue(na2, i + 2, &xr2);
        diffl = L_ABS(xl1 - xl2 - shiftx);
        diffr = L_ABS(xr1 - xr2 - shiftx);
        if (diffl > delx || diffr > delx)
            return 0;
    }

    return 1;
}
Exemple #4
0
/*!
 *  ptaaRemoveShortLines()
 *
 *      Input:  pixs (1 bpp)
 *              ptaas (input lines)
 *              fract (minimum fraction of longest line to keep)
 *              debugflag
 *      Return: ptaad (containing only lines of sufficient length),
 *                     or null on error
 */
PTAA *
ptaaRemoveShortLines(PIX       *pixs,
                     PTAA      *ptaas,
                     l_float32  fract,
                     l_int32    debugflag)
{
l_int32    w, n, i, index, maxlen, len;
l_float32  minx, maxx;
NUMA      *na, *naindex;
PIX       *pixt1, *pixt2;
PTA       *pta;
PTAA      *ptaad;

    PROCNAME("ptaaRemoveShortLines");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (PTAA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (!ptaas)
        return (PTAA *)ERROR_PTR("ptaas undefined", procName, NULL);

    pixGetDimensions(pixs, &w, NULL, NULL);
    n = ptaaGetCount(ptaas);
    ptaad = ptaaCreate(n);
    na = numaCreate(n);
    for (i = 0; i < n; i++) {
        pta = ptaaGetPta(ptaas, i, L_CLONE);
        ptaGetRange(pta, &minx, &maxx, NULL, NULL);
        numaAddNumber(na, maxx - minx + 1);
        ptaDestroy(&pta);
    }

        /* Sort by length and find all that are long enough */
    naindex = numaGetSortIndex(na, L_SORT_DECREASING);
    numaGetIValue(naindex, 0, &index);
    numaGetIValue(na, index, &maxlen);
    if (maxlen < 0.5 * w)
        L_WARNING("lines are relatively short", procName);
    pta = ptaaGetPta(ptaas, index, L_CLONE);
    ptaaAddPta(ptaad, pta, L_INSERT);
    for (i = 1; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        numaGetIValue(na, index, &len);
        if (len < fract * maxlen) break;
        pta = ptaaGetPta(ptaas, index, L_CLONE);
        ptaaAddPta(ptaad, pta, L_INSERT);
    }

    if (debugflag) {
        pixt1 = pixCopy(NULL, pixs);
        pixt2 = pixDisplayPtaa(pixt1, ptaad);
        pixDisplayWithTitle(pixt2, 0, 200, "pix4", 1);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }

    numaDestroy(&na);
    numaDestroy(&naindex);
    return ptaad;
}
/*!
 * \brief   recogShowPath()
 *
 * \param[in]    recog with LUT's pre-computed
 * \param[in]    select 0 for Viterbi; 1 for rescored
 * \return  pix debug output), or NULL on error
 */
static PIX *
recogShowPath(L_RECOG  *recog,
              l_int32   select)
{
char       textstr[16];
l_int32    i, n, index, xloc, dely;
l_float32  score;
L_BMF     *bmf;
NUMA      *natempl_s, *nascore_s, *naxloc_s, *nadely_s;
PIX       *pixs, *pix0, *pix1, *pix2, *pix3, *pix4, *pix5;
L_RDID    *did;

    PROCNAME("recogShowPath");

    if (!recog)
        return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
    if ((did = recogGetDid(recog)) == NULL)
        return (PIX *)ERROR_PTR("did not defined", procName, NULL);

    bmf = bmfCreate(NULL, 8);
    pixs = pixScale(did->pixs, 4.0, 4.0);
    pix0 = pixAddBorderGeneral(pixs, 0, 0, 0, 40, 0);
    pix1 = pixConvertTo32(pix0);
    if (select == 0) {  /* Viterbi */
        natempl_s = did->natempl;
        nascore_s = did->nascore;
        naxloc_s = did->naxloc;
        nadely_s = did->nadely;
    } else {  /* rescored */
        natempl_s = did->natempl_r;
        nascore_s = did->nascore_r;
        naxloc_s = did->naxloc_r;
        nadely_s = did->nadely_r;
    }

    n = numaGetCount(natempl_s);
    for (i = 0; i < n; i++) {
        numaGetIValue(natempl_s, i, &index);
        pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE);
        pix3 = pixScale(pix2, 4.0, 4.0);
        pix4 = pixErodeBrick(NULL, pix3, 5, 5);
        pixXor(pix4, pix4, pix3);
        numaGetFValue(nascore_s, i, &score);
        snprintf(textstr, sizeof(textstr), "%5.3f", score);
        pix5 = pixAddTextlines(pix4, bmf, textstr, 1, L_ADD_BELOW);
        numaGetIValue(naxloc_s, i, &xloc);
        numaGetIValue(nadely_s, i, &dely);
        pixPaintThroughMask(pix1, pix5, 4 * xloc, 4 * dely, 0xff000000);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
        pixDestroy(&pix4);
        pixDestroy(&pix5);
    }
    pixDestroy(&pixs);
    pixDestroy(&pix0);
    bmfDestroy(&bmf);
    return pix1;
}
Exemple #6
0
/*!
 *  pixGetRunCentersOnLine()
 *
 *      Input:  pixs (1 bpp)
 *              x, y (set one of these to -1; see notes)
 *              minlength (minimum length of acceptable run)
 *      Return: numa of fg runs, or null on error
 *
 *  Notes:
 *      (1) Action: this function computes the fg (black) and bg (white)
 *          pixel runlengths along the specified horizontal or vertical line,
 *          and returns a Numa of the "center" pixels of each fg run
 *          whose length equals or exceeds the minimum length.
 *      (2) This only works on horizontal and vertical lines.
 *      (3) For horizontal runs, set x = -1 and y to the value
 *          for all points along the raster line.  For vertical runs,
 *          set y = -1 and x to the value for all points along the
 *          pixel column.
 *      (4) For horizontal runs, the points in the Numa are the x
 *          values in the center of fg runs that are of length at
 *          least 'minlength'.  For vertical runs, the points in the
 *          Numa are the y values in the center of fg runs, again
 *          of length 'minlength' or greater.
 *      (5) If there are no fg runs along the line that satisfy the
 *          minlength constraint, the returned Numa is empty.  This
 *          is not an error.
 */
NUMA *
pixGetRunCentersOnLine(PIX     *pixs,
                       l_int32  x,
                       l_int32  y,
                       l_int32  minlength)
{
l_int32   w, h, i, r, nruns, len;
NUMA     *naruns, *nad;

    PROCNAME("pixGetRunCentersOnLine");

    if (!pixs)
        return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (NUMA *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (x != -1 && y != -1)
        return (NUMA *)ERROR_PTR("x or y must be -1", procName, NULL);
    if (x == -1 && y == -1)
        return (NUMA *)ERROR_PTR("x or y cannot both be -1", procName, NULL);

    if ((nad = numaCreate(0)) == NULL)
        return (NUMA *)ERROR_PTR("nad not made", procName, NULL);
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    if (x == -1) {  /* horizontal run */
        if (y < 0 || y >= h)
            return nad;
        naruns = pixGetRunsOnLine(pixs, 0, y, w - 1, y);
    }
    else {  /* vertical run */
        if (x < 0 || x >= w)
            return nad;
        naruns = pixGetRunsOnLine(pixs, x, 0, x, h - 1);
    }
    nruns = numaGetCount(naruns);

        /* extract run center values; the first run is always bg */
    r = 0;  /* cumulative distance along line */
    for (i = 0; i < nruns; i++) {
        if (i % 2 == 0) {  /* bg run */
            numaGetIValue(naruns, i, &len);
            r += len;
            continue;
        }
        else {
            numaGetIValue(naruns, i, &len);
            if (len >= minlength)
                numaAddNumber(nad, r + len / 2);
            r += len;
        }
    }

    numaDestroy(&naruns);
    return nad;
}
/*!
 * \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;
}
/*!
 * \brief   sarraySortByIndex()
 *
 * \param[in]    sain
 * \param[in]    naindex na that maps from the new sarray to the input sarray
 * \return  saout sorted, or NULL on error
 */
SARRAY *
sarraySortByIndex(SARRAY  *sain,
                  NUMA    *naindex)
{
char    *str;
l_int32  i, n, index;
SARRAY  *saout;

    PROCNAME("sarraySortByIndex");

    if (!sain)
        return (SARRAY *)ERROR_PTR("sain not defined", procName, NULL);
    if (!naindex)
        return (SARRAY *)ERROR_PTR("naindex not defined", procName, NULL);

    n = sarrayGetCount(sain);
    saout = sarrayCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        str = sarrayGetString(sain, index, L_COPY);
        sarrayAddString(saout, str, L_INSERT);
    }

    return saout;
}
/*!
 *  pixcmapGetRankIntensity()
 *
 *      Input:  cmap
 *              rankval (0.0 for darkest, 1.0 for lightest color)
 *              &index (<return> the index into the colormap that
 *                      corresponds to the rank intensity color)
 *      Return: 0 if OK, 1 on error
 */
l_int32
pixcmapGetRankIntensity(PIXCMAP    *cmap,
                        l_float32   rankval,
                        l_int32    *pindex)
{
l_int32  n, i, rval, gval, bval, rankindex;
NUMA    *na, *nasort;

    PROCNAME("pixcmapGetRankIntensity");

    if (!pindex)
        return ERROR_INT("&index not defined", procName, 1);
    *pindex = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (rankval < 0.0 || rankval > 1.0)
        return ERROR_INT("rankval not in [0.0 ... 1.0]", procName, 1);

    n = pixcmapGetCount(cmap);
    na = numaCreate(n);
    for (i = 0; i < n; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        numaAddNumber(na, rval + gval + bval);
    }
    nasort = numaGetSortIndex(na, L_SORT_INCREASING);
    rankindex = (l_int32)(rankval * (n - 1) + 0.5);
    numaGetIValue(nasort, rankindex, pindex);

    numaDestroy(&na);
    numaDestroy(&nasort);
    return 0;
}
/*!
 *  numa2dGetIValue()
 *
 *      Input:  na2d
 *              row of 2d array
 *              col of 2d array
 *              index (into numa)
 *              &val (<return> integer value)
 *      Return: 0 if OK, 1 on error
 */
l_int32
numa2dGetIValue(NUMA2D   *na2d,
                l_int32   row,
                l_int32   col,
                l_int32   index,
                l_int32  *pval)
{
NUMA  *na;

    PROCNAME("numa2dGetIValue");

    if (!na2d)
        return ERROR_INT("na2d not defined", procName, 1);
    if (!pval)
        return ERROR_INT("&val not defined", procName, 1);
    *pval = 0;

    if (row < 0 || row >= na2d->nrows)
        return ERROR_INT("row out of bounds", procName, 1);
    if (col < 0 || col >= na2d->ncols)
        return ERROR_INT("col out of bounds", procName, 1);
    if ((na = na2d->numa[row][col]) == NULL)
        return ERROR_INT("numa does not exist", procName, 1);

    return numaGetIValue(na, index, pval);
}
Exemple #11
0
/*!
 *  wshedRenderFill()
 *
 *      Input:  wshed
 *      Return: pixd (initial image with all basins filled), or null on error
 */
PIX *
wshedRenderFill(L_WSHED *wshed) {
    l_int32 i, n, level, bx, by;
    NUMA *na;
    PIX *pix, *pixd;
    PIXA *pixa;

    PROCNAME("wshedRenderFill");

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

    wshedBasins(wshed, &pixa, &na);
    pixd = pixCopy(NULL, wshed->pixs);
    n = pixaGetCount(pixa);
    for (i = 0; i < n; i++) {
        pix = pixaGetPix(pixa, i, L_CLONE);
        pixaGetBoxGeometry(pixa, i, &bx, &by, NULL, NULL);
        numaGetIValue(na, i, &level);
        pixPaintThroughMask(pixd, pix, bx, by, level);
        pixDestroy(&pix);
    }

    pixaDestroy(&pixa);
    numaDestroy(&na);
    return pixd;
}
Exemple #12
0
/*!
 *  ptaaSortByIndex()
 *
 *      Input:  ptaas
 *              naindex (na that maps from the new ptaa to the input ptaa)
 *      Return: ptaad (sorted), or null on error
 */
PTAA *
ptaaSortByIndex(PTAA  *ptaas,
                NUMA  *naindex)
{
l_int32  i, n, index;
PTA     *pta;
PTAA    *ptaad;

    PROCNAME("ptaaSortByIndex");

    if (!ptaas)
        return (PTAA *)ERROR_PTR("ptaas not defined", procName, NULL);
    if (!naindex)
        return (PTAA *)ERROR_PTR("naindex not defined", procName, NULL);

    n = ptaaGetCount(ptaas);
    if (numaGetCount(naindex) != n)
        return (PTAA *)ERROR_PTR("numa and ptaa sizes differ", procName, NULL);
    ptaad = ptaaCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        pta = ptaaGetPta(ptaas, index, L_COPY);
        ptaaAddPta(ptaad, pta, L_INSERT);
    }

    return ptaad;
}
Exemple #13
0
/*!
 *  pixAddWithIndicator()
 *
 *      Input:  pixs (1 bpp pix from which components are added; in-place)
 *              pixa (of connected components, some of which will be put
 *                    into pixs)
 *              na (numa indicator: add components corresponding to 1s)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This complements pixRemoveWithIndicator().   Here, the selected
 *          components are added to pixs.
 */
l_int32
pixAddWithIndicator(PIX   *pixs,
                    PIXA  *pixa,
                    NUMA  *na)
{
l_int32  i, n, ival, x, y, w, h;
BOX     *box;
PIX     *pix;

    PROCNAME("pixAddWithIndicator");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (!pixa)
        return ERROR_INT("pixa not defined", procName, 1);
    if (!na)
        return ERROR_INT("na not defined", procName, 1);
    n = pixaGetCount(pixa);
    if (n != numaGetCount(na))
        return ERROR_INT("pixa and na sizes not equal", procName, 1);

    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &ival);
        if (ival == 1) {
            pix = pixaGetPix(pixa, i, L_CLONE);
            box = pixaGetBox(pixa, i, L_CLONE);
            boxGetGeometry(box, &x, &y, &w, &h);
            pixRasterop(pixs, x, y, w, h, PIX_SRC | PIX_DST, pix, 0, 0);
            boxDestroy(&box);
            pixDestroy(&pix);
        }
    }

    return 0;
}
Exemple #14
0
/*!
 *  ptaSortByIndex()
 *
 *      Input:  ptas
 *              naindex (na that maps from the new pta to the input pta)
 *      Return: ptad (sorted), or null on  error
 */
PTA *
ptaSortByIndex(PTA   *ptas,
               NUMA  *naindex)
{
l_int32    i, index, n;
l_float32  x, y;
PTA       *ptad;

    PROCNAME("ptaSortByIndex");

    if (!ptas)
        return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
    if (!naindex)
        return (PTA *)ERROR_PTR("naindex not defined", procName, NULL);

        /* Build up sorted pta using sort index */
    n = numaGetCount(naindex);
    if ((ptad = ptaCreate(n)) == NULL)
        return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        ptaGetPt(ptas, index, &x, &y);
        ptaAddPt(ptad, x, y);
    }

    return ptad;
}
Exemple #15
0
/*!
 *  pixaSortByIndex()
 * 
 *      Input:  pixas
 *              naindex (na that maps from the new pixa to the input pixa)
 *              copyflag (L_COPY, L_CLONE)
 *      Return: pixad (sorted), or null on error
 */
PIXA *
pixaSortByIndex(PIXA    *pixas,
                NUMA    *naindex,
                l_int32  copyflag)
{
l_int32  i, n, index;
BOX     *box;
PIX     *pix;
PIXA    *pixad;

    PROCNAME("pixaSortByIndex");

    if (!pixas)
        return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
    if (!naindex)
        return (PIXA *)ERROR_PTR("naindex not defined", procName, NULL);
    if (copyflag != L_CLONE && copyflag != L_COPY)
        return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL);

    n = pixaGetCount(pixas);
    pixad = pixaCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        pix = pixaGetPix(pixas, index, copyflag);
        box = pixaGetBox(pixas, index, copyflag);
        pixaAddPix(pixad, pix, L_INSERT);
        pixaAddBox(pixad, box, L_INSERT);
    }

    return pixad;
}
Exemple #16
0
/*!
 *  boxaSortByIndex()
 *
 *      Input:  boxas
 *              naindex (na that maps from the new boxa to the input boxa)
 *      Return: boxad (sorted), or null on error
 */
BOXA *
boxaSortByIndex(BOXA  *boxas,
                NUMA  *naindex)
{
l_int32  i, n, index;
BOX     *box;
BOXA    *boxad;

    PROCNAME("boxaSortByIndex");

    if (!boxas)
        return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
    if (!naindex)
        return (BOXA *)ERROR_PTR("naindex not defined", procName, NULL);

    n = boxaGetCount(boxas);
    boxad = boxaCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        box = boxaGetBox(boxas, index, L_COPY);
        boxaAddBox(boxad, box, L_INSERT);
    }

    return boxad;
}
/*!
 *  dewarpaInfo()
 *
 *      Input:  fp
 *              dewa
 *      Return: 0 if OK, 1 on error
 */
l_int32
dewarpaInfo(FILE       *fp,
            L_DEWARPA  *dewa)
{
l_int32    i, n, pageno, nnone, nvsuccess, nvvalid, nhsuccess, nhvalid, nref;
L_DEWARP  *dew;

    PROCNAME("dewarpaInfo");

    if (!fp)
        return ERROR_INT("dewa not defined", procName, 1);
    if (!dewa)
        return ERROR_INT("dewa not defined", procName, 1);

    fprintf(fp, "\nDewarpaInfo: %p\n", dewa);
    fprintf(fp, "nalloc = %d, maxpage = %d\n", dewa->nalloc, dewa->maxpage);
    fprintf(fp, "sampling = %d, redfactor = %d, minlines = %d\n",
            dewa->sampling, dewa->redfactor, dewa->minlines);
    fprintf(fp, "maxdist = %d, useboth = %d\n",
            dewa->maxdist, dewa->useboth);

    dewarpaModelStats(dewa, &nnone, &nvsuccess, &nvvalid,
                      &nhsuccess, &nhvalid, &nref);
    n = numaGetCount(dewa->napages);
    fprintf(stderr, "Total number of pages with a dew = %d\n", n);
    fprintf(stderr, "Number of pages without any models = %d\n", nnone);
    fprintf(stderr, "Number of pages with a vert model = %d\n", nvsuccess);
    fprintf(stderr, "Number of pages with a valid vert model = %d\n", nvvalid);
    fprintf(stderr, "Number of pages with both models = %d\n", nhsuccess);
    fprintf(stderr, "Number of pages with both models valid = %d\n", nhvalid);
    fprintf(stderr, "Number of pages with a ref model = %d\n", nref);

    for (i = 0; i < n; i++) {
        numaGetIValue(dewa->napages, i, &pageno);
        if ((dew = dewarpaGetDewarp(dewa, pageno)) == NULL)
            continue;
        fprintf(stderr, "Page: %d\n", dew->pageno);
        fprintf(stderr, "  hasref = %d, refpage = %d\n",
                dew->hasref, dew->refpage);
        fprintf(stderr, "  nlines = %d\n", dew->nlines);
        fprintf(stderr, "  w = %d, h = %d, nx = %d, ny = %d\n",
                dew->w, dew->h, dew->nx, dew->ny);
        if (dew->sampvdispar)
            fprintf(stderr, "  Vertical disparity builds:\n"
                    "    (min,max,abs-diff) line curvature = (%d,%d,%d)\n",
                    dew->mincurv, dew->maxcurv, dew->maxcurv - dew->mincurv);
        if (dew->samphdispar)
            fprintf(stderr, "  Horizontal disparity builds:\n"
                    "    left edge slope = %d, right edge slope = %d\n"
                    "    (left,right,abs-diff) edge curvature = (%d,%d,%d)\n",
                    dew->leftslope, dew->rightslope, dew->leftcurv,
                    dew->rightcurv, L_ABS(dew->leftcurv - dew->rightcurv));
    }
    return 0;
}
Exemple #18
0
/*!
 *  pixaSelectWithIndicator()
 *
 *      Input:  pixas
 *              na (indicator numa)
 *              &changed (<optional return> 1 if changed; 0 if clone returned)
 *      Return: pixad, or null on error
 *
 *  Notes:
 *      (1) Returns a pixa clone if no components are removed.
 *      (2) Uses pix and box clones in the new pixa.
 *      (3) The indicator numa has values 0 (ignore) and 1 (accept).
 */
PIXA *
pixaSelectWithIndicator(PIXA     *pixas,
                        NUMA     *na,
                        l_int32  *pchanged)
{
l_int32  i, n, ival, nsave;
BOX     *box;
PIX     *pixt;
PIXA    *pixad;

    PROCNAME("pixaSelectWithIndicator");

    if (!pixas)
        return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
    if (!na)
        return (PIXA *)ERROR_PTR("na not defined", procName, NULL);

    nsave = 0;
    n = numaGetCount(na);
    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &ival);
        if (ival == 1) nsave++;
    }

    if (nsave == n) {
        if (pchanged) *pchanged = FALSE;
        return pixaCopy(pixas, L_CLONE);
    }
    if (pchanged) *pchanged = TRUE;
    pixad = pixaCreate(nsave);
    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &ival);
        if (ival == 0) continue;
        pixt = pixaGetPix(pixas, i, L_CLONE);
        box = pixaGetBox(pixas, i, L_CLONE);
        pixaAddPix(pixad, pixt, L_INSERT);
        pixaAddBox(pixad, box, L_INSERT);
    }

    return pixad;
}
/*!
 *  pixGetTextBaseline()
 *
 *      Input:  pixs (1 bpp, one textline character set)
 *              tab8 (<optional> pixel sum table)
 *              &y   (<return> baseline value)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Method: find the largest difference in pixel sums from one
 *          raster line to the next one below it.  The baseline is the
 *          upper raster line for the pair of raster lines that
 *          maximizes this function.
 */
static l_int32
pixGetTextBaseline(PIX      *pixs,
                   l_int32  *tab8,
                   l_int32  *py)
{
l_int32   i, h, val1, val2, diff, diffmax, ymax;
l_int32  *tab;
NUMA     *na;

    PROCNAME("pixGetTextBaseline");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (!py)
        return ERROR_INT("&y not defined", procName, 1);
    *py = 0;
    if (!tab8)
        tab = makePixelSumTab8();
    else
        tab = tab8;

    na = pixCountPixelsByRow(pixs, tab);
    h = numaGetCount(na);
    diffmax = 0;
    ymax = 0;
    for (i = 1; i < h; i++) {
        numaGetIValue(na, i - 1, &val1);
        numaGetIValue(na, i, &val2);
        diff = L_MAX(0, val1 - val2);
        if (diff > diffmax) {
            diffmax = diff;
            ymax = i - 1;  /* upper raster line */
        }
    }
    *py = ymax;

    if (!tab8)
        FREE(tab);
    numaDestroy(&na);
    return 0;
}
void PixelHistogram::ConstructHorizontalCountHist(Pix* pix) {
  Clear();
  Numa* counts = pixCountPixelsByRow(pix, NULL);
  length_ = numaGetCount(counts);
  hist_ = new int[length_];
  for (int i = 0; i < length_; ++i) {
    l_int32 val = 0;
    numaGetIValue(counts, i, &val);
    hist_[i] = val;
  }
  numaDestroy(&counts);
}
Exemple #21
0
Numa* numaMakeYNuma(Numa* nax, Numa* nay) {
    l_int32 n = numaGetCount(nax);
    Numa* numaYValues = numaCreate(0);
    for (int i = 0; i < n; i++) {
        l_int32 index;
        l_float32 number;
        numaGetIValue(nax, i, &index);
        
        numaGetFValue(nay, index/nay->delx, &number);
        numaAddNumber(numaYValues, number);
    }
    return numaYValues;
}
Exemple #22
0
/*!
 * \brief   boxaSelectWithIndicator()
 *
 * \param[in]    boxas
 * \param[in]    na         indicator numa
 * \param[out]   pchanged   [optional] 1 if changed; 0 if clone returned
 * \return  boxad, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Returns a copy of the boxa if no components are removed.
 *      (2) Uses box copies in the new boxa.
 *      (3) The indicator numa has values 0 (ignore) and 1 (accept).
 *      (4) If all indicator values are 0, the returned boxa is empty.
 * </pre>
 */
BOXA *
boxaSelectWithIndicator(BOXA     *boxas,
                        NUMA     *na,
                        l_int32  *pchanged)
{
l_int32  i, n, ival, nsave;
BOX     *box;
BOXA    *boxad;

    PROCNAME("boxaSelectWithIndicator");

    if (pchanged) *pchanged = FALSE;
    if (!boxas)
        return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
    if (!na)
        return (BOXA *)ERROR_PTR("na not defined", procName, NULL);

    nsave = 0;
    n = numaGetCount(na);
    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &ival);
        if (ival == 1) nsave++;
    }

    if (nsave == n) {
        if (pchanged) *pchanged = FALSE;
        return boxaCopy(boxas, L_COPY);
    }
    if (pchanged) *pchanged = TRUE;
    boxad = boxaCreate(nsave);
    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &ival);
        if (ival == 0) continue;
        box = boxaGetBox(boxas, i, L_COPY);
        boxaAddBox(boxad, box, L_INSERT);
    }

    return boxad;
}
Exemple #23
0
/*!
 * \brief   pixColorSegmentClean()
 *
 * \param[in]    pixs  8 bpp, colormapped
 * \param[in]    selsize for closing
 * \param[in]    countarray ptr to array containing the number of pixels
 *                          found in each color in the colormap
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This operation is in-place.
 *      (2) This is phase 3 of color segmentation.  It is the first
 *          part of a two-step noise removal process.  Colors with a
 *          large population are closed first; this operation absorbs
 *          small sets of intercolated pixels of a different color.
 * </pre>
 */
l_ok
pixColorSegmentClean(PIX      *pixs,
                     l_int32   selsize,
                     l_int32  *countarray)
{
l_int32    i, ncolors, val;
l_uint32   val32;
NUMA      *na, *nasi;
PIX       *pixt1, *pixt2;
PIXCMAP   *cmap;

    PROCNAME("pixColorSegmentClean");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (pixGetDepth(pixs) != 8)
        return ERROR_INT("pixs not 8 bpp", procName, 1);
    if ((cmap = pixGetColormap(pixs)) == NULL)
        return ERROR_INT("cmap not found", procName, 1);
    if (!countarray)
        return ERROR_INT("countarray not defined", procName, 1);
    if (selsize <= 1)
        return 0;  /* nothing to do */

        /* Sort colormap indices in decreasing order of pixel population */
    ncolors = pixcmapGetCount(cmap);
    na = numaCreate(ncolors);
    for (i = 0; i < ncolors; i++)
        numaAddNumber(na, countarray[i]);
    nasi = numaGetSortIndex(na, L_SORT_DECREASING);
    numaDestroy(&na);
    if (!nasi)
        return ERROR_INT("nasi not made", procName, 1);

        /* For each color, in order of decreasing population,
         * do a closing and absorb the added pixels.  Note that
         * if the closing removes pixels at the border, they'll
         * still appear in the xor and will be properly (re)set. */
    for (i = 0; i < ncolors; i++) {
        numaGetIValue(nasi, i, &val);
        pixt1 = pixGenerateMaskByValue(pixs, val, 1);
        pixt2 = pixCloseSafeCompBrick(NULL, pixt1, selsize, selsize);
        pixXor(pixt2, pixt2, pixt1);  /* pixels to be added to type 'val' */
        pixcmapGetColor32(cmap, val, &val32);
        pixSetMasked(pixs, pixt2, val32);  /* add them */
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }
    numaDestroy(&nasi);
    return 0;
}
Exemple #24
0
main(int    argc,
char **argv)
{
l_int32       i, ival, n;
l_float32     f, val;
GPLOT        *gplot;
NUMA         *na1, *na2, *na3;
PIX          *pixt;
L_REGPARAMS  *rp;

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

        /* Generate a 1D signal and plot it */
    na1 = numaCreate(500);
    for (i = 0; i < 500; i++) {
        f = 48.3 * sin(0.13 * (l_float32)i);
	f += 63.4 * cos(0.21 * (l_float32)i);
	numaAddNumber(na1, f);
    }
    gplot = gplotCreate("/tmp/extrema", GPLOT_PNG, "Extrema test", "x", "y");
    gplotAddPlot(gplot, NULL, na1, GPLOT_LINES, "plot 1");

        /* Find the local min and max and plot them */
    na2 = numaFindExtrema(na1, 38.3);
    n = numaGetCount(na2);
    na3 = numaCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(na2, i, &ival);
        numaGetFValue(na1, ival, &val);
	numaAddNumber(na3, val);
    }
    gplotAddPlot(gplot, na2, na3, GPLOT_POINTS, "plot 2");
    gplotMakeOutput(gplot);
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */

    regTestCheckFile(rp, "/tmp/extrema.png");  /* 0 */
    pixt = pixRead("/tmp/extrema.png");
    pixDisplayWithTitle(pixt, 100, 100, "Extrema test", rp->display);
    pixDestroy(&pixt);

    gplotDestroy(&gplot);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    return regTestCleanup(rp);
}
/*!
 *  pixcmapGammaTRC()
 *
 *      Input:  colormap
 *              gamma (gamma correction; must be > 0.0)
 *              minval  (input value that gives 0 for output; can be < 0)
 *              maxval  (input value that gives 255 for output; can be > 255)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - in-place transform
 *      - see pixGammaTRC() and numaGammaTRC() in enhance.c for
 *        description and use of transform
 */
l_int32
pixcmapGammaTRC(PIXCMAP   *cmap,
                l_float32  gamma,
                l_int32    minval,
                l_int32    maxval)
{
l_int32   rval, gval, bval, trval, tgval, tbval, i, ncolors;
NUMA     *nag;

    PROCNAME("pixcmapGammaTRC");

    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (gamma <= 0.0) {
        L_WARNING("gamma must be > 0.0; setting to 1.0", procName);
        gamma = 1.0;
    }
    if (minval >= maxval)
        return ERROR_INT("minval not < maxval", procName, 1);

    if (gamma == 1.0 && minval == 0 && maxval == 255)  /* no-op */
        return 0;

    if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
        return ERROR_INT("nag not made", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        numaGetIValue(nag, rval, &trval);
        numaGetIValue(nag, gval, &tgval);
        numaGetIValue(nag, bval, &tbval);
        pixcmapResetColor(cmap, i, trval, tgval, tbval);
    }

    numaDestroy(&nag);
    return 0;
}
/*!
 *  dewarpaModelStats()
 *
 *      Input:  dewa
 *              &nnone (<optional return> number without any model)
 *              &nvsuccess (<optional return> number with a vert model)
 *              &nvvalid (<optional return> number with a valid vert model)
 *              &nhsuccess (<optional return> number with both models)
 *              &nhvalid (<optional return> number with both models valid)
 *              &nref (<optional return> number with a reference model)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) A page without a model has no dew.  It most likely failed to
 *          generate a vertical model, and has not been assigned a ref
 *          model from a neighboring page with a valid vertical model.
 *      (2) A page has vsuccess == 1 if there is at least a model of the
 *          vertical disparity.  The model may be invalid, in which case
 *          dewarpaInsertRefModels() will stash it in the cache and
 *          attempt to replace it by a valid ref model.
 *      (3) A vvvalid model is a vertical disparity model whose parameters
 *          satisfy the constraints given in dewarpaSetValidModels().
 *      (4) A page has hsuccess == 1 if both the vertical and horizontal
 *          disparity arrays have been constructed.
 *      (5) An  hvalid model has vertical and horizontal disparity
 *          models whose parameters satisfy the constraints given
 *          in dewarpaSetValidModels().
 *      (6) A page has a ref model if it failed to generate a valid
 *          model but was assigned a vvalid or hvalid model on another
 *          page (within maxdist) by dewarpaInsertRefModel().
 *      (7) This calls dewarpaTestForValidModel(); it ignores the vvalid
 *          and hvalid fields.
 */
l_int32
dewarpaModelStats(L_DEWARPA  *dewa,
                  l_int32    *pnnone,
                  l_int32    *pnvsuccess,
                  l_int32    *pnvvalid,
                  l_int32    *pnhsuccess,
                  l_int32    *pnhvalid,
                  l_int32    *pnref)
{
l_int32    i, n, pageno, nnone, nvsuccess, nvvalid, nhsuccess, nhvalid, nref;
L_DEWARP  *dew;

    PROCNAME("dewarpaModelStats");

    if (!dewa)
        return ERROR_INT("dewa not defined", procName, 1);

    dewarpaListPages(dewa);
    n = numaGetCount(dewa->napages);
    nnone = nref = nvsuccess = nvvalid = nhsuccess = nhvalid = 0;
    for (i = 0; i < n; i++) {
        numaGetIValue(dewa->napages, i, &pageno);
        dew = dewarpaGetDewarp(dewa, pageno);
        if (!dew) {
            nnone++;
            continue;
        }
        if (dew->hasref == 1)
            nref++;
        if (dew->vsuccess == 1)
            nvsuccess++;
        if (dew->hsuccess == 1)
            nhsuccess++;
        dewarpaTestForValidModel(dewa, dew, 0);
        if (dew->vvalid == 1)
            nvvalid++;
        if (dew->hvalid == 1)
            nhvalid++;
    }

    if (pnnone) *pnnone = nnone;
    if (pnref) *pnref = nref;
    if (pnvsuccess) *pnvsuccess = nvsuccess;
    if (pnvvalid) *pnvvalid = nvvalid;
    if (pnhsuccess) *pnhsuccess = nhsuccess;
    if (pnhvalid) *pnhvalid = nhvalid;
    return 0;
}
l_int32 count_ones(NUMA  *na, l_int32 nexp, l_int32 index, const char *name)
{
l_int32  i, n, val, sum;

    n = numaGetCount(na);
    sum = 0;
    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &val);
        if (val == 1) sum++;
    }
    if (!name) return sum;
    if (nexp == sum)
        fprintf(stderr, "Correct: %s[%d]: num. ones: %d\n", name, index, sum);
    else
        fprintf(stderr, "WRONG!: %s[%d]: num. ones: %d\n", name, index, sum);
    return 0;
}
Exemple #28
0
/*!
 *  numaConvertToSarray()
 *
 *      Input:  na
 *              size1 (size of conversion field)
 *              size2 (for float conversion: size of field to the right
 *                     of the decimal point)
 *              addzeros (for integer conversion: to add lead zeros)
 *              type (L_INTEGER_VALUE, L_FLOAT_VALUE)
 *      Return: a sarray of the float values converted to strings
 *              representing either integer or float values; or null on error.
 *
 *  Notes:
 *      (1) For integer conversion, size2 is ignored.
 *          For float conversion, addzeroes is ignored.
 */
SARRAY *
numaConvertToSarray(NUMA    *na,
                    l_int32  size1,
                    l_int32  size2,
                    l_int32  addzeros,
                    l_int32  type)
{
char       fmt[32], strbuf[64];
l_int32    i, n, ival;
l_float32  fval;
SARRAY    *sa;

    PROCNAME("numaConvertToSarray");

    if (!na)
        return (SARRAY *)ERROR_PTR("na not defined", procName, NULL);
    if (type != L_INTEGER_VALUE && type != L_FLOAT_VALUE)
        return (SARRAY *)ERROR_PTR("invalid type", procName, NULL);

    if (type == L_INTEGER_VALUE) {
        if (addzeros)
            snprintf(fmt, sizeof(fmt), "%%0%dd", size1);
        else
            snprintf(fmt, sizeof(fmt), "%%%dd", size1);
    } else {  /* L_FLOAT_VALUE */
        snprintf(fmt, sizeof(fmt), "%%%d.%df", size1, size2);
    }

    n = numaGetCount(na);
    if ((sa = sarrayCreate(n)) == NULL)
        return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);

    for (i = 0; i < n; i++) {
        if (type == L_INTEGER_VALUE) {
            numaGetIValue(na, i, &ival);
            snprintf(strbuf, sizeof(strbuf), fmt, ival);
        } else {  /* L_FLOAT_VALUE */
            numaGetFValue(na, i, &fval);
            snprintf(strbuf, sizeof(strbuf), fmt, fval);
        }
        sarrayAddString(sa, strbuf, L_COPY);
    }

    return sa;
}
Exemple #29
0
/*!
 *  mergeLookup()
 *
 *      Input:  wshed
 *              sindex (primary index being changed in the merge)
 *              dindex (index that @sindex will point to after the merge)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) The links are a sparse array of Numas showing current back-links.
 *          The lut gives the current index (of the seed or the minima
 *          for the wshed  in which it is located.
 *      (2) Think of each entry in the lut.  There are two types:
 *             owner:     lut[index] = index
 *             redirect:  lut[index] != index
 *      (3) This is called each time a merge occurs.  It puts the lut
 *          and backlinks in a canonical form after the merge, where
 *          all entries in the lut point to the current "owner", which
 *          has all backlinks.  That is, every "redirect" in the lut
 *          points to an "owner".  The lut always gives the index of
 *          the current owner.
 */
static l_int32
mergeLookup(L_WSHED  *wshed,
            l_int32   sindex,
            l_int32   dindex)
{
l_int32   i, n, size, index;
l_int32  *lut;
NUMA     *na;
NUMA    **links;

    PROCNAME("mergeLookup");

    if (!wshed)
        return ERROR_INT("wshed not defined", procName, 1);
    size = wshed->arraysize;
    if (sindex < 0 || sindex >= size)
        return ERROR_INT("invalid sindex", procName, 1);
    if (dindex < 0 || dindex >= size)
        return ERROR_INT("invalid dindex", procName, 1);

        /* Redirect links in the lut */
    n = 0;
    links = wshed->links;
    lut = wshed->lut;
    if ((na = links[sindex]) != NULL) {
        n = numaGetCount(na);
        for (i = 0; i < n; i++) {
            numaGetIValue(na, i, &index);
            lut[index] = dindex;
        }
    }
    lut[sindex] = dindex;

        /* Shift the backlink arrays from sindex to dindex.
         * sindex should have no backlinks because all entries in the
         * lut that were previously pointing to it have been redirected
         * to dindex. */
    if (!links[dindex])
        links[dindex] = numaCreate(n);
    numaJoin(links[dindex], links[sindex], 0, -1);
    numaAddNumber(links[dindex], sindex);
    numaDestroy(&links[sindex]);

    return 0;
}
Exemple #30
0
/*!
 *  pixaSort2dByIndex()
 * 
 *      Input:  pixas
 *              naa (numaa that maps from the new pixaa to the input pixas)
 *              copyflag (L_CLONE or L_COPY)
 *      Return: pixaa (sorted), or null on error
 */
PIXAA *
pixaSort2dByIndex(PIXA    *pixas,
                  NUMAA   *naa,
                  l_int32  copyflag)
{
l_int32  pixtot, ntot, i, j, n, nn, index;
BOX     *box;
NUMA    *na;
PIX     *pix;
PIXA    *pixa;
PIXAA   *pixaa;

    PROCNAME("pixaSort2dByIndex");

    if (!pixas)
        return (PIXAA *)ERROR_PTR("pixas not defined", procName, NULL);
    if (!naa)
        return (PIXAA *)ERROR_PTR("naindex not defined", procName, NULL);

        /* Check counts */
    ntot = numaaGetNumberCount(naa);
    pixtot = pixaGetCount(pixas);
    if (ntot != pixtot)
        return (PIXAA *)ERROR_PTR("element count mismatch", procName, NULL);

    n = numaaGetCount(naa);
    pixaa = pixaaCreate(n);
    for (i = 0; i < n; i++) {
        na = numaaGetNuma(naa, i, L_CLONE);
        nn = numaGetCount(na);
        pixa = pixaCreate(nn);
        for (j = 0; j < nn; j++) {
            numaGetIValue(na, j, &index);
            pix = pixaGetPix(pixas, index, copyflag);
            box = pixaGetBox(pixas, index, copyflag);
            pixaAddPix(pixa, pix, L_INSERT);
            pixaAddBox(pixa, box, L_INSERT);
        }
        pixaaAddPixa(pixaa, pixa, L_INSERT);
        numaDestroy(&na);
    }

    return pixaa;
}