/*! * numaaTruncate() * * Input: naa * Return: 0 if OK, 1 on error * * Notes: * (1) This identifies the largest index containing a numa that * has any numbers within it, destroys all numa beyond that * index, and resets the count. */ l_int32 numaaTruncate(NUMAA *naa) { l_int32 i, n, nn; NUMA *na; PROCNAME("numaaTruncate"); if (!naa) return ERROR_INT("naa not defined", procName, 1); n = numaaGetCount(naa); for (i = n - 1; i >= 0; i--) { na = numaaGetNuma(naa, i, L_CLONE); if (!na) continue; nn = numaGetCount(na); numaDestroy(&na); if (nn == 0) numaDestroy(&naa->numa[i]); else break; } naa->n = i + 1; return 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; }
/*! * 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; }
/*! * numaWriteStream() * * Input: stream, na * Return: 0 if OK, 1 on error */ l_int32 numaWriteStream(FILE *fp, NUMA *na) { l_int32 i, n; l_float32 startx, delx; PROCNAME("numaWriteStream"); if (!fp) return ERROR_INT("stream not defined", procName, 1); if (!na) return ERROR_INT("na not defined", procName, 1); n = numaGetCount(na); fprintf(fp, "\nNuma Version %d\n", NUMA_VERSION_NUMBER); fprintf(fp, "Number of numbers = %d\n", n); for (i = 0; i < n; i++) fprintf(fp, " [%d] = %f\n", i, na->array[i]); fprintf(fp, "\n"); /* Optional data */ numaGetParameters(na, &startx, &delx); if (startx != 0.0 || delx != 1.0) fprintf(fp, "startx = %f, delx = %f\n", startx, delx); return 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; }
jfloatArray Java_com_googlecode_eyesfree_textdetect_HydrogenTextDetector_nativeGetTextConfs( JNIEnv *env, jclass clazz, jlong nativePtr) { if (DEBUG_MODE) LOGV(__FUNCTION__); HydrogenTextDetector *ptr = (HydrogenTextDetector *) nativePtr; NUMA *confs = ptr->GetTextConfs(); l_int32 count = numaGetCount(confs); jfloatArray ret = env->NewFloatArray(count); l_float32 nval; jfloat jval; if (ret != NULL) { for (int i = 0; i < count; i++) { numaGetFValue(confs, i, &nval); jval = (jfloat) nval; env->SetFloatArrayRegion(ret, i, 1, &jval); } } numaDestroy(&confs); return ret; }
/*! * \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; }
/*! * 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; }
/*! * 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; }
/* * Use these variable abbreviations: * * pap1: distance from left edge to the page * txt1: distance from left edge to the text * Identify pap1 by (a) 1st downward transition in intensity (nait). * (b) start of 1st lowpass interval (nail) * Identify txt1 by (a) end of 1st lowpass interval (nail) * (b) first upward transition in reversals (nart) * * pap2: distance from right edge to beginning of last upward transition, * plus some extra for safety. * txt1: distance from right edge to the text * Identify pap2 by 1st downward transition in intensity. * Identify txt2 by (a) beginning of 1st lowpass interval from bottom * (b) last downward transition in reversals from bottom */ l_int32 GetLeftCut(NUMA *narl, NUMA *nart, NUMA *nait, l_int32 w, l_int32 *pleft) { l_int32 nrl, nrt, nit, start, end, sign, pap1, txt1, del; nrl = numaGetCount(narl); nrt = numaGetCount(nart); nit = numaGetCount(nait); /* Check for small max number of reversals or no edge */ numaGetSpanValues(narl, 0, NULL, &end); if (end < 20 || nrl <= 1) { *pleft = 0; return 0; } /* Where is text and page, scanning from the left? */ pap1 = 0; txt1 = 0; if (nrt >= 4) { /* beginning of first upward transition */ numaGetEdgeValues(nart, 0, &start, NULL, NULL); txt1 = start; } if (nit >= 4) { /* end of first downward trans in (inverse) intensity */ numaGetEdgeValues(nait, 0, NULL, &end, &sign); if (end < txt1 && sign == -1) pap1 = end; else pap1 = 0.5 * txt1; } del = txt1 - pap1; if (del > 20) { txt1 -= L_MIN(20, 0.5 * del); pap1 += L_MIN(20, 0.5 * del); } fprintf(stderr, "txt1 = %d, pap1 = %d\n", txt1, pap1); *pleft = pap1; return 0; }
/*! * \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; }
/*! * numaaGetNumaCount() * * Input: naa * index (of numa in naa) * Return: count of numbers in the referenced numa, or 0 on error. */ l_int32 numaaGetNumaCount(NUMAA *naa, l_int32 index) { PROCNAME("numaaGetNumaCount"); if (!naa) return ERROR_INT("naa not defined", procName, 0); if (index < 0 || index >= naa->n) return ERROR_INT("invalid index into naa", procName, 0); return numaGetCount(naa->numa[index]); }
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; }
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); }
/*! * 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 GetRightCut(NUMA *narl, NUMA *nart, NUMA *nait, l_int32 w, l_int32 *pright) { l_int32 nrt, ntrans, start, end, sign, txt2, pap2, found, trans; nrt = numaGetCount(nart); /* Check for small max number of reversals or no edge */ /* Where is text and page, scanning from the right? */ ntrans = nrt / 3; if (ntrans > 1) { found = FALSE; for (trans = ntrans - 1; trans > 0; --trans) { numaGetEdgeValues(nart, trans, &start, &end, &sign); if (sign == -1) { /* end of textblock */ txt2 = end; found = TRUE; } } if (!found) { txt2 = w - 1; /* take the whole thing! */ pap2 = w - 1; } else { /* found textblock; now find right side of page */ found = FALSE; for (trans = ntrans - 1; trans > 0; --trans) { numaGetEdgeValues(nart, trans, &start, &end, &sign); if (sign == 1 && start > txt2) { pap2 = start; /* start of textblock on other page */ found = TRUE; } } if (!found) { /* no text from other page */ pap2 = w - 1; /* refine later */ } } } else { txt2 = w - 1; pap2 = w - 1; } fprintf(stderr, "txt2 = %d, pap2 = %d\n", txt2, pap2); *pright = pap2; 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; }
/*! * kernelCreateFromString() * * Input: height, width * cy, cx (origin) * kdata * Return: kernel of the given size, or null on error * * Notes: * (1) The data is an array of chars, in row-major order, giving * space separated integers in the range [-255 ... 255]. * (2) The only other formatting limitation is that you must * leave space between the last number in each row and * the double-quote. If possible, it's also nice to have each * line in the string represent a line in the kernel; e.g., * static const char *kdata = * " 20 50 20 " * " 70 140 70 " * " 20 50 20 "; */ L_KERNEL * kernelCreateFromString(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, const char *kdata) { l_int32 n, i, j, index; l_float32 val; L_KERNEL *kel; NUMA *na; PROCNAME("kernelCreateFromString"); if (h < 1) return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL); if (w < 1) return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL); if (cy < 0 || cy >= h) return (L_KERNEL *)ERROR_PTR("cy invalid", procName, NULL); if (cx < 0 || cx >= w) return (L_KERNEL *)ERROR_PTR("cx invalid", procName, NULL); kel = kernelCreate(h, w); kernelSetOrigin(kel, cy, cx); na = parseStringForNumbers(kdata, " \t\n"); n = numaGetCount(na); if (n != w * h) { numaDestroy(&na); fprintf(stderr, "w = %d, h = %d, num ints = %d\n", w, h, n); return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL); } index = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { numaGetFValue(na, index, &val); kernelSetElement(kel, i, j, val); index++; } } numaDestroy(&na); return kel; }
/*! * \brief pixFindDifferentialSquareSum() * * \param[in] pixs * \param[out] psum result * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) At the top and bottom, we skip: * ~ at least one scanline * ~ not more than 10% of the image height * ~ not more than 5% of the image width * </pre> */ l_int32 pixFindDifferentialSquareSum(PIX *pixs, l_float32 *psum) { l_int32 i, n; l_int32 w, h, skiph, skip, nskip; l_float32 val1, val2, diff, sum; NUMA *na; PROCNAME("pixFindDifferentialSquareSum"); if (!psum) return ERROR_INT("&sum not defined", procName, 1); *psum = 0.0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); /* Generate a number array consisting of the sum * of pixels in each row of pixs */ if ((na = pixCountPixelsByRow(pixs, NULL)) == NULL) return ERROR_INT("na not made", procName, 1); /* Compute the number of rows at top and bottom to omit. * We omit these to avoid getting a spurious signal from * the top and bottom of a (nearly) all black image. */ w = pixGetWidth(pixs); h = pixGetHeight(pixs); skiph = (l_int32)(0.05 * w); /* skip for max shear of 0.025 radians */ skip = L_MIN(h / 10, skiph); /* don't remove more than 10% of image */ nskip = L_MAX(skip / 2, 1); /* at top & bot; skip at least one line */ /* Sum the squares of differential row sums, on the * allowed rows. Note that nskip must be >= 1. */ n = numaGetCount(na); sum = 0.0; for (i = nskip; i < n - nskip; i++) { numaGetFValue(na, i - 1, &val1); numaGetFValue(na, i, &val2); diff = val2 - val1; sum += diff * diff; } numaDestroy(&na); *psum = sum; return 0; }
/*! * numaAddNumber() * * Input: na * val (float or int to be added; stored as a float) * Return: 0 if OK, 1 on error */ l_int32 numaAddNumber(NUMA *na, l_float32 val) { l_int32 n; PROCNAME("numaAddNumber"); if (!na) return ERROR_INT("na not defined", procName, 1); n = numaGetCount(na); if (n >= na->nalloc) numaExtendArray(na); na->array[n] = val; na->n++; return 0; }
/*! * numaReplaceNumber() * * Input: na * index (element to be replaced) * val (new value to replace old one) * Return: 0 if OK, 1 on error */ l_int32 numaReplaceNumber(NUMA *na, l_int32 index, l_float32 val) { l_int32 n; PROCNAME("numaReplaceNumber"); if (!na) return ERROR_INT("na not defined", procName, 1); n = numaGetCount(na); if (index < 0 || index >= n) return ERROR_INT("index not in {0...n - 1}", procName, 1); na->array[index] = val; 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; }
/*! * numaRemoveNumber() * * Input: na * index (element to be removed) * Return: 0 if OK, 1 on error * * Notes: * (1) This shifts na[i] --> na[i - 1] for all i > index. * (2) It should not be used repeatedly on large arrays, * because the function is O(n). */ l_int32 numaRemoveNumber(NUMA *na, l_int32 index) { l_int32 i, n; PROCNAME("numaRemoveNumber"); if (!na) return ERROR_INT("na not defined", procName, 1); n = numaGetCount(na); if (index < 0 || index >= n) return ERROR_INT("index not in {0...n - 1}", procName, 1); for (i = index + 1; i < n; i++) na->array[i - 1] = na->array[i]; na->n--; return 0; }
int register_mappings (const JBDATA * data, struct mapping **in_maps) { int i; /* Register mappings for each component */ l_int32 ncomp = numaGetCount (data->naclass); *in_maps = malloc_guarded (ncomp * sizeof (struct mapping)); struct mapping *maps = *in_maps; for (i = 0; i < ncomp; i++) { maps[i].used = 0; } unsigned char code_point = first_code_point (); int font_num = 0; for (i = 0; i < data->nclass; i++) { l_int32 iclass = i; if (maps[iclass].used) continue; maps[iclass].iclass = iclass; maps[iclass].font_num = font_num; maps[iclass].code_point = code_point; maps[iclass].used = 1; if (code_point == max_code_point ()) { code_point = first_code_point (); font_num++; } else { code_point = next_code_point (code_point); } } printf ("%d fonts\n", font_num + 1); return font_num + 1; }
/*! * numaConvertToDna * * Input: na * Return: da, or null on error */ L_DNA * numaConvertToDna(NUMA *na) { l_int32 i, n; l_float32 val; L_DNA *da; PROCNAME("numaConvertToDna"); if (!na) return (L_DNA *)ERROR_PTR("na not defined", procName, NULL); n = numaGetCount(na); da = l_dnaCreate(n); for (i = 0; i < n; i++) { numaGetFValue(na, i, &val); l_dnaAddNumber(da, val); } return da; }
/*! * numaaGetNumberCount() * * Input: naa * Return: count (total number of numbers in the numaa), * or 0 if no numbers or on error */ l_int32 numaaGetNumberCount(NUMAA *naa) { NUMA *na; l_int32 n, sum, i; PROCNAME("numaaGetNumberCount"); if (!naa) return ERROR_INT("naa not defined", procName, 0); n = numaaGetCount(naa); for (sum = 0, i = 0; i < n; i++) { na = numaaGetNuma(naa, i, L_CLONE); sum += numaGetCount(na); numaDestroy(&na); } return sum; }
/*! * 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; }