/*! * recogCreate() * * Input: scalew (scale all widths to this; use 0 for no scaling) * scaleh (scale all heights to this; use 0 for no scaling) * templ_type (L_USE_AVERAGE or L_USE_ALL) * threshold (for binarization; typically ~128) * maxyshift (from nominal centroid alignment; typically 0 or 1) * Return: recog, or null on error * * Notes: * (1) For a set trained on one font, such as numbers in a book, * it is sensible to set scalew = scaleh = 0. * (2) For a mixed training set, scaling to a fixed height, * such as 32 pixels, but leaving the width unscaled, is effective. * (3) The storage for most of the arrays is allocated when training * is finished. */ L_RECOG * recogCreate(l_int32 scalew, l_int32 scaleh, l_int32 templ_type, l_int32 threshold, l_int32 maxyshift) { L_RECOG *recog; PIXA *pixa; PIXAA *paa; PROCNAME("recogCreate"); if (scalew < 0 || scaleh < 0) return (L_RECOG *)ERROR_PTR("invalid scalew or scaleh", procName, NULL); if (templ_type != L_USE_AVERAGE && templ_type != L_USE_ALL) return (L_RECOG *)ERROR_PTR("invalid templ_type flag", procName, NULL); if (threshold < 1 || threshold > 255) return (L_RECOG *)ERROR_PTR("invalid threshold", procName, NULL); if ((recog = (L_RECOG *)CALLOC(1, sizeof(L_RECOG))) == NULL) return (L_RECOG *)ERROR_PTR("rec not made", procName, NULL); recog->templ_type = templ_type; recog->threshold = threshold; recog->scalew = scalew; recog->scaleh = scaleh; recog->maxyshift = maxyshift; recog->asperity_fr = DEFAULT_ASPERITY_FRACT; recogSetPadParams(recog, NULL, NULL, NULL, -1, -1, -1); recog->bmf = bmfCreate(NULL, 6); recog->bmf_size = 6; recog->maxarraysize = MAX_EXAMPLES_IN_CLASS; recog->index = -1; /* Generate the LUTs */ recog->centtab = makePixelCentroidTab8(); recog->sumtab = makePixelSumTab8(); recog->sa_text = sarrayCreate(0); recog->dna_tochar = l_dnaCreate(0); /* Input default values for min component size for splitting. * These are overwritten when pixTrainingFinished() is called. */ recog->min_splitw = 6; recog->min_splith = 6; recog->max_splith = 60; /* Generate the storage for the unscaled training bitmaps */ paa = pixaaCreate(recog->maxarraysize); pixa = pixaCreate(1); pixaaInitFull(paa, pixa); pixaDestroy(&pixa); recog->pixaa_u = paa; /* Generate the storage for debugging */ recog->pixadb_boot = pixaCreate(2); recog->pixadb_split = pixaCreate(2); return recog; }
/*! * pixaaCreateFromPixa() * * Input: pixa * n (number specifying subdivision of pixa) * type (L_CHOOSE_CONSECUTIVE, L_CHOOSE_SKIP_BY) * copyflag (L_CLONE, L_COPY) * Return: pixaa, or null on error * * Notes: * (1) This subdivides a pixa into a set of smaller pixa that * are accumulated into a pixaa. * (2) If type == L_CHOOSE_CONSECUTIVE, the first 'n' pix are * put in a pixa and added to pixaa, then the next 'n', etc. * If type == L_CHOOSE_SKIP_BY, the first pixa is made by * aggregating pix[0], pix[n], pix[2*n], etc. * (3) The copyflag specifies if each new pix is a copy or a clone. */ PIXAA * pixaaCreateFromPixa(PIXA *pixa, l_int32 n, l_int32 type, l_int32 copyflag) { l_int32 count, i, j, npixa; PIX *pix; PIXA *pixat; PIXAA *pixaa; PROCNAME("pixaaCreateFromPixa"); if (!pixa) return (PIXAA *)ERROR_PTR("pixa not defined", procName, NULL); count = pixaGetCount(pixa); if (count == 0) return (PIXAA *)ERROR_PTR("no pix in pixa", procName, NULL); if (n <= 0) return (PIXAA *)ERROR_PTR("n must be > 0", procName, NULL); if (type != L_CHOOSE_CONSECUTIVE && type != L_CHOOSE_SKIP_BY) return (PIXAA *)ERROR_PTR("invalid type", procName, NULL); if (copyflag != L_CLONE && copyflag != L_COPY) return (PIXAA *)ERROR_PTR("invalid copyflag", procName, NULL); if (type == L_CHOOSE_CONSECUTIVE) npixa = (count + n - 1) / n; else /* L_CHOOSE_SKIP_BY */ npixa = L_MIN(n, count); pixaa = pixaaCreate(npixa); if (type == L_CHOOSE_CONSECUTIVE) { for (i = 0; i < count; i++) { if (i % n == 0) pixat = pixaCreate(n); pix = pixaGetPix(pixa, i, copyflag); pixaAddPix(pixat, pix, L_INSERT); if (i % n == n - 1) pixaaAddPixa(pixaa, pixat, L_INSERT); } if (i % n != 0) pixaaAddPixa(pixaa, pixat, L_INSERT); } else { /* L_CHOOSE_SKIP_BY */ for (i = 0; i < npixa; i++) { pixat = pixaCreate(count / npixa + 1); for (j = i; j < count; j += n) { pix = pixaGetPix(pixa, j, copyflag); pixaAddPix(pixat, pix, L_INSERT); } pixaaAddPixa(pixaa, pixat, L_INSERT); } } return pixaa; }
int main(int argc, char **argv) { PIX *pixs, *pixd; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("stampede2.jpg"); pixa = pixaCreate(0); pixSaveTiled(pixs, pixa, 1.0, 1, 20, 8); AddTestSet(pixa, pixs, L_SOBEL_EDGE, 18, 40, 40, 0.7, -25, 280, 128); AddTestSet(pixa, pixs, L_TWO_SIDED_EDGE, 18, 40, 40, 0.7, -25, 280, 128); AddTestSet(pixa, pixs, L_SOBEL_EDGE, 10, 40, 40, 0.7, -15, 305, 128); AddTestSet(pixa, pixs, L_TWO_SIDED_EDGE, 10, 40, 40, 0.7, -15, 305, 128); AddTestSet(pixa, pixs, L_SOBEL_EDGE, 15, 40, 40, 0.6, -45, 285, 158); AddTestSet(pixa, pixs, L_TWO_SIDED_EDGE, 15, 40, 40, 0.6, -45, 285, 158); pixDestroy(&pixs); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 0 */ pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixa); return regTestCleanup(rp); }
void AddTransformsYUV(PIXA *pixa, L_BMF *bmf, l_int32 yval) { char textbuf[256]; l_int32 i, j, wpls; l_uint32 *datas, *lines; PIX *pixs, *pixt1, *pixt2, *pixt3, *pixt4; PIXA *pixat; pixs = pixCreate(225, 225, 32); wpls = pixGetWpl(pixs); datas = pixGetData(pixs); for (i = 0; i < 225; i++) { /* v */ lines = datas + i * wpls; for (j = 0; j < 225; j++) /* u */ composeRGBPixel(yval + 16, j + 16, i + 16, lines + j); } pixat = pixaCreate(3); pixaAddPix(pixat, pixs, L_INSERT); pixt1 = pixConvertYUVToRGB(NULL, pixs); pixaAddPix(pixat, pixt1, L_INSERT); pixt2 = pixConvertRGBToYUV(NULL, pixt1); pixaAddPix(pixat, pixt2, L_INSERT); pixt3 = pixaDisplayTiledAndScaled(pixat, 32, 225, 3, 0, 20, 2); snprintf(textbuf, sizeof(textbuf), "yval = %d", yval); pixt4 = pixAddSingleTextblock(pixt3, bmf, textbuf, 0xff000000, L_ADD_BELOW, NULL); pixaAddPix(pixa, pixt4, L_INSERT); pixDestroy(&pixt3); pixaDestroy(&pixat); return; }
/*! * pixaReadFilesSA() * * Input: sarray (full pathnames for all files) * Return: pixa, or null on error */ PIXA * pixaReadFilesSA(SARRAY *sa) { char *str; l_int32 i, n; PIX *pix; PIXA *pixa; PROCNAME("pixaReadFilesSA"); if (!sa) return (PIXA *)ERROR_PTR("sa not defined", procName, NULL); n = sarrayGetCount(sa); pixa = pixaCreate(n); for (i = 0; i < n; i++) { str = sarrayGetString(sa, i, L_NOCOPY); if ((pix = pixRead(str)) == NULL) { L_WARNING("pix not read from file %s\n", procName, str); continue; } pixaAddPix(pixa, pix, L_INSERT); } return pixa; }
main(int argc, char **argv) { l_int32 i; PIX *pix; PIXA *pixa; for (i = 0; i < NTests; i++) GenerateSplitPlot(i); /* Read the results back in ... */ pixa = pixaCreate(0); for (i = 0; i < NTests; i++) { sprintf(buf, "/tmp/junkplot.%d.png", i); pix = pixRead(buf); pixSaveTiled(pix, pixa, 1, 1, 25, 32); pixDestroy(&pix); sprintf(buf, "/tmp/junkplots.%d.png", i); pix = pixRead(buf); pixSaveTiled(pix, pixa, 1, 0, 25, 32); pixDestroy(&pix); } /* ... and save into a tiled pix */ pix = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/junkotsuplot.png", pix, IFF_PNG); pixDisplay(pix, 100, 100); pixaDestroy(&pixa); pixDestroy(&pix); return 0; }
static void GetImageMask(PIX *pixs, l_int32 res, BOXA **pboxa, const char *debugfile) { PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixa; pixSetResolution(pixs, 200, 200); pix1 = pixConvertTo1(pixs, 100); pix2 = pixGenerateHalftoneMask(pix1, NULL, NULL, NULL); pix3 = pixMorphSequence(pix2, "c20.1 + c1.20", 0); *pboxa = pixConnComp(pix3, NULL, 8); if (debugfile) { pixa = pixaCreate(0); pixaAddPix(pixa, pixs, L_COPY); pixaAddPix(pixa, pix1, L_INSERT); pixaAddPix(pixa, pix2, L_INSERT); pixaAddPix(pixa, pix3, L_INSERT); pix4 = pixaDisplayTiledInRows(pixa, 32, 1800, 0.25, 0, 25, 2); pixWrite(debugfile, pix4, IFF_JFIF_JPEG); pixDisplay(pix4, 100, 100); pixDestroy(&pix4); pixaDestroy(&pixa); } else { pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } return; }
/*! * \brief pixaModifyStrokeWidth() * * \param[in] pixas of 1 bpp pix * \param[out] targetw desired width for strokes in each pix * \return pixa with modified stroke widths, or NULL on error */ PIXA * pixaModifyStrokeWidth(PIXA *pixas, l_float32 targetw) { l_int32 i, n, same, maxd; l_float32 width; NUMA *na; PIX *pix1, *pix2; PIXA *pixad; PROCNAME("pixaModifyStrokeWidth"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (targetw < 1) return (PIXA *)ERROR_PTR("target width < 1", procName, NULL); pixaVerifyDepth(pixas, &same, &maxd); if (maxd > 1) return (PIXA *)ERROR_PTR("pix not all 1 bpp", procName, NULL); na = pixaFindStrokeWidth(pixas, 0.1, NULL, 0); n = pixaGetCount(pixas); pixad = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_CLONE); numaGetFValue(na, i, &width); pix2 = pixModifyStrokeWidth(pix1, width, targetw); pixaAddPix(pixad, pix2, L_INSERT); pixDestroy(&pix1); } numaDestroy(&na); return pixad; }
/*! * 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; }
/*! * \brief pixaSetStrokeWidth() * * \param[in] pixas of 1 bpp pix * \param[in] width set stroke width to this value, in [1 ... 100]. * \param[in] thinfirst 1 to thin all pix to a skeleton first; 0 to skip * \param[in] connectivity 4 or 8, to be used if %thinfirst == 1 * \return pixa with all stroke widths being %width, or NULL on error * * <pre> * Notes: * (1) If %thinfirst == 1, thin to a skeleton using the specified * %connectivity. Use %thinfirst == 0 if all pix in pixas * have already been thinned as far as possible. * (2) The image is dilated to the required %width. This dilation * is not connectivity preserving, so this is typically * used in a situation where merging of c.c. in the individual * pix is not a problem; e.g., where each pix is a single c.c. * </pre> */ PIXA * pixaSetStrokeWidth(PIXA *pixas, l_int32 width, l_int32 thinfirst, l_int32 connectivity) { l_int32 i, n, maxd, same; PIX *pix1, *pix2; PIXA *pixad; PROCNAME("pixaSetStrokeWidth"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (width < 1 || width > 100) return (PIXA *)ERROR_PTR("width not in [1 ... 100]", procName, NULL); if (connectivity != 4 && connectivity != 8) return (PIXA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL); pixaVerifyDepth(pixas, &same, &maxd); if (maxd > 1) return (PIXA *)ERROR_PTR("pix are not all 1 bpp", procName, NULL); n = pixaGetCount(pixas); pixad = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_CLONE); pix2 = pixSetStrokeWidth(pix1, width, thinfirst, connectivity); pixaAddPix(pixad, pix2, L_INSERT); pixDestroy(&pix1); } return pixad; }
/* Reconstruction without compaction */ static PIXA * ReconstructPixa1(L_PTRA *papix, L_PTRA *pabox) { l_int32 i, imax, nactual; BOX *box; PIX *pix; PIXA *pixat; ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "Before removal: imax = %4d, actual = %4d\n", imax, nactual); pixat = pixaCreate(imax + 1); for (i = 0; i <= imax; i++) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); if (pix) pixaAddPix(pixat, pix, L_INSERT); if (box) pixaAddBox(pixat, box, L_INSERT); } ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "After removal: imax = %4d, actual = %4d\n\n", imax, nactual); return pixat; }
static PIXA * PixSavePlots1(void) { PIX *pixt; PIXA *pixa; pixa = pixaCreate(8); pixt = pixRead("/tmp/rtnan.png"); pixSaveTiled(pixt, pixa, 1, 1, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnar.png"); pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnai.png"); pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnarbin.png"); pixSaveTiled(pixt, pixa, 1, 1, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnabb.png"); pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnared.png"); pixSaveTiled(pixt, pixa, 1, 1, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnagreen.png"); pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); pixt = pixRead("/tmp/rtnablue.png"); pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); return pixa; }
void CopyStoreClean(PIXA *pixas, l_int32 nlevels, l_int32 ncopies) { l_int32 i, j; PIX *pix, *pixt; PIXA *pixa; PIXAA *paa; paa = pixaaCreate(0); for (i = 0; i < nlevels ; i++) { pixa = pixaCreate(0); pixaaAddPixa(paa, pixa, L_INSERT); pix = pixaGetPix(pixas, i, L_CLONE); for (j = 0; j < ncopies; j++) { pixt = pixCopy(NULL, pix); pixaAddPix(pixa, pixt, L_INSERT); } pixDestroy(&pix); } pixaaDestroy(&paa); return; }
/*! * pixaClipToPix() * * Input: pixas * pixs * Return: pixad, or null on error * * Notes: * (1) This is intended for use in situations where pixas * was originally generated from the input pixs. * (2) Returns a pixad where each pix in pixas is ANDed * with its associated region of the input pixs. This * region is specified by the the box that is associated * with the pix. * (3) In a typical application of this function, pixas has * a set of region masks, so this generates a pixa of * the parts of pixs that correspond to each region * mask component, along with the bounding box for * the region. */ PIXA * pixaClipToPix(PIXA *pixas, PIX *pixs) { l_int32 i, n; BOX *box; PIX *pix, *pixc; PIXA *pixad; PROCNAME("pixaClipToPix"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); n = pixaGetCount(pixas); if ((pixad = pixaCreate(n)) == NULL) return (PIXA *)ERROR_PTR("pixad not made", procName, NULL); for (i = 0; i < n; i++) { pix = pixaGetPix(pixas, i, L_CLONE); box = pixaGetBox(pixas, i, L_COPY); pixc = pixClipRectangle(pixs, box, NULL); pixAnd(pixc, pixc, pix); pixaAddPix(pixad, pixc, L_INSERT); pixaAddBox(pixad, box, L_INSERT); pixDestroy(&pix); } return pixad; }
main(int argc, char **argv) { l_int32 w; PIX *pixs, *pixt, *pixd; PIXA *pixa; static char mainName[] = "smoothedge_reg"; pixs = pixRead("raggededge.png"); w = pixGetWidth(pixs); pixa = pixaCreate(0); PixAddEdgeData(pixa, pixs, L_FROM_RIGHT, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixs, L_FROM_LEFT, MIN_JUMP, MIN_REVERSAL); pixt = pixRotateOrth(pixs, 1); PixAddEdgeData(pixa, pixt, L_FROM_BOTTOM, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixt, L_FROM_TOP, MIN_JUMP, MIN_REVERSAL); pixDestroy(&pixt); pixt = pixRotateOrth(pixs, 2); PixAddEdgeData(pixa, pixt, L_FROM_LEFT, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixt, L_FROM_RIGHT, MIN_JUMP, MIN_REVERSAL); pixDestroy(&pixt); pixt = pixRotateOrth(pixs, 3); PixAddEdgeData(pixa, pixt, L_FROM_TOP, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixt, L_FROM_BOTTOM, MIN_JUMP, MIN_REVERSAL); pixDestroy(&pixt); pixDestroy(&pixs); /* Display at 2x scaling */ pixd = pixaDisplayTiledAndScaled(pixa, 32, 2 * (w + 10), 2, 0, 25, 2); pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG); pixDestroy(&pixd); pixaDestroy(&pixa); return 0; }
int main(int argc, char **argv) { l_float32 fcolor; PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixadb; static char mainName[] = "find_colorregions"; lept_mkdir("lept/color"); pix1 = pixRead("colorpage.030.jpg"); /* pix1 = pixRead("map.057.jpg"); */ /* More general method */ pixadb = pixaCreate(0); pixFindColorRegions(pix1, NULL, 4, 200, 60, 10, 90, 0.05, &fcolor, &pix3, &pix4, pixadb); fprintf(stderr, "ncolor = %f\n", fcolor); if (pix3) pixDisplay(pix3, 0, 800); if (pix4) pixDisplay(pix4, 600, 800); pix2 = pixaDisplayTiledInColumns(pixadb, 5, 0.3, 20, 2); pixDisplay(pix2, 0, 0); pixWrite("/tmp/lept/color/result1.png", pix2, IFF_PNG); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixaDestroy(&pixadb); /* Method for pages with very light background */ pixadb = pixaCreate(0); pixFindColorRegionsLight(pix1, NULL, 4, 60, 230, 40, 20, &fcolor, &pix3, &pix4, pixadb); fprintf(stderr, "ncolor = %f\n", fcolor); if (pix3) pixDisplay(pix3, 1100, 800); if (pix4) pixDisplay(pix4, 1700, 800); pix2 = pixaDisplayTiledInColumns(pixadb, 5, 0.3, 20, 2); pixDisplay(pix2, 1100, 0); pixWrite("/tmp/lept/color/result2.png", pix2, IFF_PNG); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixaDestroy(&pixadb); pixDestroy(&pix1); return 0; }
/* Reconstruction with compaction */ static PIXA * ReconstructPixa2(L_PTRA *papix, L_PTRA *pabox) { l_int32 i, imax, nactual; BOX *box; PIX *pix; PIXA *pixat; ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "Before removal: imax = %4d, actual = %4d\n", imax, nactual); /* Remove half */ pixat = pixaCreate(imax + 1); for (i = 0; i <= imax; i++) { if (i % 2 == 0) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); if (pix) pixaAddPix(pixat, pix, L_INSERT); if (box) pixaAddBox(pixat, box, L_INSERT); } } /* Compact */ ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "Before compaction: imax = %4d, actual = %4d\n", imax, nactual); ptraCompactArray(papix); ptraCompactArray(pabox); ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "After compaction: imax = %4d, actual = %4d\n", imax, nactual); /* Remove the rest (and test compaction with removal) */ while (1) { ptraGetActualCount(papix, &nactual); if (nactual == 0) break; pix = (PIX *)ptraRemove(papix, 0, L_COMPACTION); box = (BOX *)ptraRemove(pabox, 0, L_COMPACTION); pixaAddPix(pixat, pix, L_INSERT); pixaAddBox(pixat, box, L_INSERT); } ptraGetMaxIndex(papix, &imax); ptraGetActualCount(papix, &nactual); fprintf(stderr, "After removal: imax = %4d, actual = %4d\n\n", imax, nactual); return pixat; }
/*! * pixaAddBorderGeneral() * * Input: pixad (can be null or equal to pixas) * pixas (containing pix of all depths; colormap ok) * left, right, top, bot (number of pixels added) * val (value of added border pixels) * Return: pixad (with border added to each pix), including on error * * Notes: * (1) For binary images: * white: val = 0 * black: val = 1 * For grayscale images: * white: val = 2 ** d - 1 * black: val = 0 * For rgb color images: * white: val = 0xffffff00 * black: val = 0 * For colormapped images, use 'index' found this way: * white: pixcmapGetRankIntensity(cmap, 1.0, &index); * black: pixcmapGetRankIntensity(cmap, 0.0, &index); * (2) For in-place replacement of each pix with a bordered version, * use @pixad = @pixas. To make a new pixa, use @pixad = NULL. * (3) In both cases, the boxa has sides adjusted as if it were * expanded by the border. */ PIXA * pixaAddBorderGeneral(PIXA *pixad, PIXA *pixas, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val) { l_int32 i, n, nbox; BOX *box; BOXA *boxad; PIX *pixs, *pixd; PROCNAME("pixaAddBorderGeneral"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, pixad); if (left < 0 || right < 0 || top < 0 || bot < 0) return (PIXA *)ERROR_PTR("negative border added!", procName, pixad); if (pixad && (pixad != pixas)) return (PIXA *)ERROR_PTR("pixad defined but != pixas", procName, pixad); n = pixaGetCount(pixas); if (!pixad) pixad = pixaCreate(n); for (i = 0; i < n; i++) { pixs = pixaGetPix(pixas, i, L_CLONE); pixd = pixAddBorderGeneral(pixs, left, right, top, bot, val); if (pixad == pixas) /* replace */ pixaReplacePix(pixad, i, pixd, NULL); else pixaAddPix(pixad, pixd, L_INSERT); pixDestroy(&pixs); } nbox = pixaGetBoxaCount(pixas); boxad = pixaGetBoxa(pixad, L_CLONE); for (i = 0; i < nbox; i++) { if ((box = pixaGetBox(pixas, i, L_COPY)) == NULL) { L_WARNING_INT("box %d not found", procName, i); break; } boxAdjustSides(box, box, -left, right, -top, bot); if (pixad == pixas) /* replace */ boxaReplaceBox(boxad, i, box); else boxaAddBox(boxad, box, L_INSERT); } boxaDestroy(&boxad); return pixad; }
void static PlotBoxa(L_REGPARAMS *rp, l_int32 index) { BOXA *boxa1, *boxa2; PIX *pix1, *pix2, *pix3; PIXA *pixa; boxa1 = boxaRead(boxafiles[index]); /* Read and display initial boxa */ boxaPlotSizes(boxa1, NULL, NULL, NULL, &pix1); boxaPlotSides(boxa1, NULL, NULL, NULL, NULL, NULL, &pix2); pixa = pixaCreate(2); pixaAddPix(pixa, pix1, L_INSERT); pixaAddPix(pixa, pix2, L_INSERT); pix3 = pixaDisplayTiledInColumns(pixa, 2, 1.0, 20, 2); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 39, 41, 43 */ pixDisplayWithTitle(pix3, 0 + 800 * index, 500, NULL, rp->display); pixDestroy(&pix3); pixaDestroy(&pixa); /* Read and display reconciled boxa */ boxa2 = boxaReconcileSizeByMedian(boxa1, L_CHECK_BOTH, 0.05, 0.04, 1.03, NULL, NULL, NULL); boxaPlotSizes(boxa2, NULL, NULL, NULL, &pix1); boxaPlotSides(boxa2, NULL, NULL, NULL, NULL, NULL, &pix2); pixa = pixaCreate(2); pixaAddPix(pixa, pix1, L_INSERT); pixaAddPix(pixa, pix2, L_INSERT); pix3 = pixaDisplayTiledInColumns(pixa, 2, 1.0, 20, 2); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 40, 42, 44 */ pixDisplayWithTitle(pix3, 0 + 800 * index, 920, NULL, rp->display); pixDestroy(&pix3); pixaDestroy(&pixa); boxaDestroy(&boxa1); boxaDestroy(&boxa2); }
main(int argc, char **argv) { l_int32 i, k, x, y, w, h; BOX *box; BOXA *boxa1, *boxa2; PIX *pix1, *pix2, *pixd; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; for (k = 0; k < 7; k++) { srand(45617); pixa = pixaCreate(2); boxa1 = boxaCreate(0); for (i = 0; i < 500; i++) { x = (l_int32)(600.0 * (l_float64)rand() / (l_float64)RAND_MAX); y = (l_int32)(600.0 * (l_float64)rand() / (l_float64)RAND_MAX); w = (l_int32) (1.0 + maxsize[k] * (l_float64)rand() / (l_float64)RAND_MAX); h = (l_int32) (1.0 + maxsize[k] * (l_float64)rand() / (l_float64)RAND_MAX); box = boxCreate(x, y, w, h); boxaAddBox(boxa1, box, L_INSERT); } pix1 = pixCreate(660, 660, 1); pixRenderBoxa(pix1, boxa1, 1, L_SET_PIXELS); pixaAddPix(pixa, pix1, L_INSERT); boxa2 = boxaCombineOverlaps(boxa1); pix2 = pixCreate(660, 660, 1); pixRenderBoxa(pix2, boxa2, 1, L_SET_PIXELS); pixaAddPix(pixa, pix2, L_INSERT); pixd = pixaDisplayTiledInRows(pixa, 1, 1500, 1.0, 0, 50, 2); pixDisplayWithTitle(pixd, 100, 100 + 100 * k, NULL, rp->display); regTestWritePixAndCheck(rp, pixd, IFF_PNG); fprintf(stderr, "%d: n_init = %d, n_final = %d\n", k, boxaGetCount(boxa1), boxaGetCount(boxa2)); pixDestroy(&pixd); boxaDestroy(&boxa1); boxaDestroy(&boxa2); pixaDestroy(&pixa); } regTestCleanup(rp); return 0; }
/*! * pixaCreateFromBoxa() * * Input: pixs * boxa * &cropwarn (<optional return> TRUE if the boxa extent * is larger than pixs. * Return: pixad, or null on error * * Notes: * (1) This simply extracts from pixs the region corresponding to each * box in the boxa. * (2) The 3rd arg is optional. If the extent of the boxa exceeds the * size of the pixa, so that some boxes are either clipped * or entirely outside the pix, a warning is returned as TRUE. * (3) pixad will have only the properly clipped elements, and * the internal boxa will be correct. */ PIXA * pixaCreateFromBoxa(PIX *pixs, BOXA *boxa, l_int32 *pcropwarn) { l_int32 i, n, w, h, wbox, hbox, cropwarn; BOX *box, *boxc; PIX *pixd; PIXA *pixad; PROCNAME("pixaCreateFromBoxa"); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); if (!boxa) return (PIXA *)ERROR_PTR("boxa not defined", procName, NULL); n = boxaGetCount(boxa); if ((pixad = pixaCreate(n)) == NULL) return (PIXA *)ERROR_PTR("pixad not made", procName, NULL); boxaGetExtent(boxa, &wbox, &hbox, NULL); pixGetDimensions(pixs, &w, &h, NULL); cropwarn = FALSE; if (wbox > w || hbox > h) cropwarn = TRUE; if (pcropwarn) *pcropwarn = cropwarn; for (i = 0; i < n; i++) { box = boxaGetBox(boxa, i, L_COPY); if (cropwarn) { /* if box is outside pixs, pixd is NULL */ pixd = pixClipRectangle(pixs, box, &boxc); /* may be NULL */ if (pixd) { pixaAddPix(pixad, pixd, L_INSERT); pixaAddBox(pixad, boxc, L_INSERT); } boxDestroy(&box); } else { pixd = pixClipRectangle(pixs, box, NULL); pixaAddPix(pixad, pixd, L_INSERT); pixaAddBox(pixad, box, L_INSERT); } } return pixad; }
main(int argc, char **argv) { char buf[256]; l_int32 i, j, k, index, conn, depth, bc; BOX *box; PIX *pix, *pixs, *pixd; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pix = pixRead("feyn.tif"); box = boxCreate(383, 338, 1480, 1050); pixs = pixClipRectangle(pix, box, NULL); regTestWritePixAndCheck(rp, pixs, IFF_PNG); /* 0 */ for (i = 0; i < 2; i++) { conn = 4 + 4 * i; for (j = 0; j < 2; j++) { depth = 8 + 8 * j; for (k = 0; k < 2; k++) { bc = k + 1; index = 4 * i + 2 * j + k; fprintf(stderr, "Set %d\n", index); if (DEBUG) { fprintf(stderr, "%d: conn = %d, depth = %d, bc = %d\n", rp->index + 1, conn, depth, bc); } pixa = pixaCreate(0); pixSaveTiled(pixs, pixa, 1, 1, 20, 8); TestDistance(pixa, pixs, conn, depth, bc, rp); pixd = pixaDisplay(pixa, 0, 0); pixDisplayWithTitle(pixd, 0, 0, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pixd); } } } boxDestroy(&box); pixDestroy(&pix); pixDestroy(&pixs); regTestCleanup(rp); return 0; }
/*! * pixaSplitPix() * * Input: pixs (with individual components on a lattice) * nx (number of mosaic cells horizontally) * ny (number of mosaic cells vertically) * borderwidth (of added border on all sides) * bordercolor (in our RGBA format: 0xrrggbbaa) * Return: pixa, or null on error * * Notes: * (1) This is a variant on pixaCreateFromPix(), where we * simply divide the image up into (approximately) equal * subunits. If you want the subimages to have essentially * the same aspect ratio as the input pix, use nx = ny. * (2) If borderwidth is 0, we ignore the input bordercolor and * redefine it to white. * (3) The bordercolor is always used to initialize each tiled pix, * so that if the src is clipped, the unblitted part will * be this color. This avoids 1 pixel wide black stripes at the * left and lower edges. */ PIXA * pixaSplitPix(PIX *pixs, l_int32 nx, l_int32 ny, l_int32 borderwidth, l_uint32 bordercolor) { l_int32 w, h, d, cellw, cellh, i, j; PIX *pixt; PIXA *pixa; PROCNAME("pixaSplitPix"); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); if (nx <= 0 || ny <= 0) return (PIXA *)ERROR_PTR("nx and ny must be > 0", procName, NULL); borderwidth = L_MAX(0, borderwidth); if ((pixa = pixaCreate(nx * ny)) == NULL) return (PIXA *)ERROR_PTR("pixa not made", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); cellw = (w + nx - 1) / nx; /* round up */ cellh = (h + ny - 1) / ny; for (i = 0; i < ny; i++) { for (j = 0; j < nx; j++) { if ((pixt = pixCreate(cellw + 2 * borderwidth, cellh + 2 * borderwidth, d)) == NULL) return (PIXA *)ERROR_PTR("pixt not made", procName, NULL); pixCopyColormap(pixt, pixs); if (borderwidth == 0) { /* initialize full image to white */ if (d == 1) pixClearAll(pixt); else pixSetAll(pixt); } else pixSetAllArbitrary(pixt, bordercolor); pixRasterop(pixt, borderwidth, borderwidth, cellw, cellh, PIX_SRC, pixs, j * cellw, i * cellh); pixaAddPix(pixa, pixt, L_INSERT); } } return pixa; }
/*! * pixaReadStream() * * Input: stream * Return: pixa, or null on error */ PIXA * pixaReadStream(FILE *fp) { l_int32 n, i, xres, yres, version; l_int32 ignore; BOXA *boxa; PIX *pix; PIXA *pixa; PROCNAME("pixaReadStream"); #if !HAVE_LIBPNG /* defined in environ.h */ return (PIXA *)ERROR_PTR("no libpng: can't read data", procName, NULL); #else if (!fp) return (PIXA *)ERROR_PTR("stream not defined", procName, NULL); if (fscanf(fp, "\nPixa Version %d\n", &version) != 1) return (PIXA *)ERROR_PTR("not a pixa file", procName, NULL); if (version != PIXA_VERSION_NUMBER) return (PIXA *)ERROR_PTR("invalid pixa version", procName, NULL); if (fscanf(fp, "Number of pix = %d\n", &n) != 1) return (PIXA *)ERROR_PTR("not a pixa file", procName, NULL); if ((pixa = pixaCreate(n)) == NULL) return (PIXA *)ERROR_PTR("pixa not made", procName, NULL); if ((boxa = boxaReadStream(fp)) == NULL) return (PIXA *)ERROR_PTR("boxa not made", procName, NULL); boxaDestroy(&pixa->boxa); pixa->boxa = boxa; for (i = 0; i < n; i++) { if ((fscanf(fp, " pix[%d]: xres = %d, yres = %d\n", &ignore, &xres, &yres)) != 3) return (PIXA *)ERROR_PTR("res reading", procName, NULL); if ((pix = pixReadStreamPng(fp)) == NULL) return (PIXA *)ERROR_PTR("pix not read", procName, NULL); pixSetXRes(pix, xres); pixSetYRes(pix, yres); pixaAddPix(pixa, pix, L_INSERT); } return pixa; #endif /* !HAVE_LIBPNG */ }
int main(int argc, char **argv) { SEL *sel1, *sel2, *sel3, *sel4; SELA *sela; PIX *pix, *pixd; PIXA *pixa; static char mainName[] = "flipselgen"; if (argc != 1) return ERROR_INT(" Syntax: flipselgen", mainName, 1); sela = selaCreate(0); sel1 = selCreateFromString(textsel1, 5, 6, "flipsel1"); sel2 = selCreateFromString(textsel2, 5, 6, "flipsel2"); sel3 = selCreateFromString(textsel3, 5, 6, "flipsel3"); sel4 = selCreateFromString(textsel4, 5, 6, "flipsel4"); selaAddSel(sela, sel1, NULL, 0); selaAddSel(sela, sel2, NULL, 0); selaAddSel(sela, sel3, NULL, 0); selaAddSel(sela, sel4, NULL, 0); pixa = pixaCreate(4); pix = selDisplayInPix(sel1, 23, 2); pixDisplayWithTitle(pix, 100, 100, "sel1", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pix = selDisplayInPix(sel2, 23, 2); pixDisplayWithTitle(pix, 275, 100, "sel2", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pix = selDisplayInPix(sel3, 23, 2); pixDisplayWithTitle(pix, 450, 100, "sel3", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pix = selDisplayInPix(sel4, 23, 2); pixDisplayWithTitle(pix, 625, 100, "sel4", DFLAG); pixaAddPix(pixa, pix, L_INSERT); pixd = pixaDisplayTiled(pixa, 800, 0, 15); pixDisplayWithTitle(pixd, 100, 300, "allsels", DFLAG); pixDestroy(&pixd); pixaDestroy(&pixa); if (fhmtautogen(sela, INDEX, NULL)) return ERROR_INT(" Generation failed", mainName, 1); selaDestroy(&sela); return 0; }
/*! * \brief fpixaDisplayQuadtree() * * \param[in] fpixa mean, variance or root variance * \param[in] factor replication factor at lowest level * \param[in] fontsize 4, ... 20 * \return pixd 8 bpp, mosaic of quadtree images, or NULL on error * * <pre> * Notes: * (1) The mean and root variance fall naturally in the 8 bpp range, * but the variance is typically outside the range. This * function displays 8 bpp pix clipped to 255, so the image * pixels will mostly be 255 (white). * </pre> */ PIX * fpixaDisplayQuadtree(FPIXA *fpixa, l_int32 factor, l_int32 fontsize) { char buf[256]; l_int32 nlevels, i, mag, w; L_BMF *bmf; FPIX *fpix; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixd; PIXA *pixat; PROCNAME("fpixaDisplayQuadtree"); if (!fpixa) return (PIX *)ERROR_PTR("fpixa not defined", procName, NULL); if ((nlevels = fpixaGetCount(fpixa)) == 0) return (PIX *)ERROR_PTR("pixas empty", procName, NULL); if ((bmf = bmfCreate(NULL, fontsize)) == NULL) L_ERROR("bmf not made; text will not be added", procName); pixat = pixaCreate(nlevels); for (i = 0; i < nlevels; i++) { fpix = fpixaGetFPix(fpixa, i, L_CLONE); pixt1 = fpixConvertToPix(fpix, 8, L_CLIP_TO_ZERO, 0); mag = factor * (1 << (nlevels - i - 1)); pixt2 = pixExpandReplicate(pixt1, mag); pixt3 = pixConvertTo32(pixt2); snprintf(buf, sizeof(buf), "Level %d\n", i); pixt4 = pixAddSingleTextblock(pixt3, bmf, buf, 0xff000000, L_ADD_BELOW, NULL); pixaAddPix(pixat, pixt4, L_INSERT); fpixDestroy(&fpix); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); } w = pixGetWidth(pixt4); pixd = pixaDisplayTiledInRows(pixat, 32, nlevels * (w + 80), 1.0, 0, 30, 2); pixaDestroy(&pixat); bmfDestroy(&bmf); return pixd; }
/*! * 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; }
/*! * \brief recogAddAllSamples() * * \param[in] precog addr of recog * \param[in] paa pixaa from previously trained recog * \param[in] debug * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) On error, the input recog is destroyed. * (2) This is used with the serialization routine recogRead(), * where each pixa in the pixaa represents a set of characters * in a different class. Before calling this function, we have * verified that the number of character classes, given by the * setsize field in %recog, equals the number of pixa in the paa. * The character labels for each set are in the sa_text field. * </pre> */ static l_int32 recogAddAllSamples(L_RECOG **precog, PIXAA *paa, l_int32 debug) { char *text; l_int32 i, j, nc, ns; PIX *pix; PIXA *pixa, *pixa1; L_RECOG *recog; PROCNAME("recogAddAllSamples"); if (!precog) return ERROR_INT("&recog not defined", procName, 1); if ((recog = *precog) == NULL) return ERROR_INT("recog not defined", procName, 1); if (!paa) { recogDestroy(&recog); return ERROR_INT("paa not defined", procName, 1); } nc = pixaaGetCount(paa, NULL); for (i = 0; i < nc; i++) { pixa = pixaaGetPixa(paa, i, L_CLONE); ns = pixaGetCount(pixa); text = sarrayGetString(recog->sa_text, i, L_NOCOPY); pixa1 = pixaCreate(ns); pixaaAddPixa(recog->pixaa_u, pixa1, L_INSERT); for (j = 0; j < ns; j++) { pix = pixaGetPix(pixa, j, L_CLONE); if (debug) fprintf(stderr, "pix[%d,%d]: text = %s\n", i, j, text); pixaaAddPix(recog->pixaa_u, i, pix, NULL, L_INSERT); } pixaDestroy(&pixa); } recogTrainingFinished(&recog, 0, -1, -1.0); /* For second parameter, see comment in recogRead() */ if (!recog) return ERROR_INT("bad templates; recog destroyed", procName, 1); return 0; }
/*! * pixaaFlattenToPixa() * * Input: pixaa * &naindex (<optional return> the pixa index in the pixaa) * copyflag (L_COPY or L_CLONE) * Return: pixa, or null on error * * Notes: * (1) This 'flattens' the pixaa to a pixa, taking the pix in * order in the first pixa, then the second, etc. * (2) If &naindex is defined, we generate a Numa that gives, for * each pix in the pixaa, the index of the pixa to which it belongs. */ PIXA * pixaaFlattenToPixa(PIXAA *pixaa, NUMA **pnaindex, l_int32 copyflag) { l_int32 i, j, m, n; BOX *box; NUMA *naindex; PIX *pix; PIXA *pixa, *pixat; PROCNAME("pixaaFlattenToPixa"); if (pnaindex) *pnaindex = NULL; if (!pixaa) return (PIXA *)ERROR_PTR("pixaa not defined", procName, NULL); if (copyflag != L_COPY && copyflag != L_CLONE) return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL); if (pnaindex) { naindex = numaCreate(0); *pnaindex = naindex; } n = pixaaGetCount(pixaa); pixa = pixaCreate(n); for (i = 0; i < n; i++) { pixat = pixaaGetPixa(pixaa, i, L_CLONE); m = pixaGetCount(pixat); for (j = 0; j < m; j++) { pix = pixaGetPix(pixat, j, copyflag); box = pixaGetBox(pixat, j, copyflag); pixaAddPix(pixa, pix, L_INSERT); pixaAddBox(pixa, box, L_INSERT); if (pnaindex) numaAddNumber(naindex, i); /* save 'row' number */ } pixaDestroy(&pixat); } return pixa; }
/*! * \brief recogDecode() * * \param[in] recog with LUT's pre-computed * \param[in] pixs typically of multiple touching characters, 1 bpp * \param[in] nlevels of templates; 2 for now * \param[out] ppixdb [optional] debug result; can be null * \return 0 if OK, 1 on error */ l_int32 recogDecode(L_RECOG *recog, PIX *pixs, l_int32 nlevels, PIX **ppixdb) { l_int32 debug; PIX *pixt; PIXA *pixa; PROCNAME("recogDecode"); if (ppixdb) *ppixdb = NULL; if (!recog) return ERROR_INT("recog not defined", procName, 1); if (!pixs || pixGetDepth(pixs) != 1) return ERROR_INT("pixs not defined or not 1 bpp", procName, 1); if (!recog->train_done) return ERROR_INT("training not finished", procName, 1); if (nlevels != 2) return ERROR_INT("nlevels != 2 (for now)", procName, 1); pixa = (ppixdb) ? pixaCreate(2) : NULL; debug = (ppixdb) ? 1 : 0; if (recogMakeDecodingArrays(recog, pixs, debug)) return ERROR_INT("error making arrays", procName, 1); recogSetChannelParams(recog, nlevels); if (recogRunViterbi(recog, &pixt)) return ERROR_INT("error in viterbi", procName, 1); if (ppixdb) pixaAddPix(pixa, pixt, L_INSERT); if (recogRescoreDidResult(recog, &pixt)) return ERROR_INT("error in rescoring", procName, 1); if (ppixdb) pixaAddPix(pixa, pixt, L_INSERT); *ppixdb = pixaDisplayTiledInRows(pixa, 32, 2 * pixGetWidth(pixt) + 100, 1.0, 0, 30, 2); pixaDestroy(&pixa); return 0; }