/*! * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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); }
/*! * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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); }
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; }
/*! * \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; }
/*! * \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; }
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; }
/*! * 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; }
/*! * 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; }
/*! * 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; }