int main(int argc, char **argv) { l_int32 i, w, h, nbox, npta, fgcount, bgcount, count; BOXA *boxa; PIX *pixs, *pixfg, *pixbg, *pixc, *pixb, *pixd; PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixa; PTA *pta; PTAA *ptaafg, *ptaabg; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("feyn-fract.tif"); boxa = pixConnComp(pixs, NULL, 8); nbox = boxaGetCount(boxa); regTestCompareValues(rp, nbox, 464, 0); /* 0 */ /* Get fg and bg boundary pixels */ pixfg = pixMorphSequence(pixs, "e3.3", 0); pixXor(pixfg, pixfg, pixs); pixCountPixels(pixfg, &fgcount, NULL); regTestCompareValues(rp, fgcount, 58764, 0); /* 1 */ pixbg = pixMorphSequence(pixs, "d3.3", 0); pixXor(pixbg, pixbg, pixs); pixCountPixels(pixbg, &bgcount, NULL); regTestCompareValues(rp, bgcount, 60335, 0); /* 2 */ /* Get ptaa of fg pixels */ ptaafg = ptaaGetBoundaryPixels(pixs, L_BOUNDARY_FG, 8, NULL, NULL); npta = ptaaGetCount(ptaafg); regTestCompareValues(rp, npta, nbox, 0); /* 3 */ count = 0; for (i = 0; i < npta; i++) { pta = ptaaGetPta(ptaafg, i, L_CLONE); count += ptaGetCount(pta); ptaDestroy(&pta); } regTestCompareValues(rp, fgcount, count, 0); /* 4 */ /* Get ptaa of bg pixels. Note that the number of bg pts * is, in general, larger than the number of bg boundary pixels, * because bg boundary pixels are shared by two c.c. that * are 1 pixel apart. */ ptaabg = ptaaGetBoundaryPixels(pixs, L_BOUNDARY_BG, 8, NULL, NULL); npta = ptaaGetCount(ptaabg); regTestCompareValues(rp, npta, nbox, 0); /* 5 */ count = 0; for (i = 0; i < npta; i++) { pta = ptaaGetPta(ptaabg, i, L_CLONE); count += ptaGetCount(pta); ptaDestroy(&pta); } regTestCompareValues(rp, count, 60602, 0); /* 6 */ /* Render the fg boundary pixels on top of pixs. */ pixa = pixaCreate(4); pixc = pixRenderRandomCmapPtaa(pixs, ptaafg, 0, 0, 0); regTestWritePixAndCheck(rp, pixc, IFF_PNG); /* 7 */ pixSaveTiledOutline(pixc, pixa, 1.0, 1, 30, 2, 32); pixDestroy(&pixc); /* Render the bg boundary pixels on top of pixs. */ pixc = pixRenderRandomCmapPtaa(pixs, ptaabg, 0, 0, 0); regTestWritePixAndCheck(rp, pixc, IFF_PNG); /* 8 */ pixSaveTiledOutline(pixc, pixa, 1.0, 0, 30, 2, 32); pixDestroy(&pixc); pixClearAll(pixs); /* Render the fg boundary pixels alone. */ pixc = pixRenderRandomCmapPtaa(pixs, ptaafg, 0, 0, 0); regTestWritePixAndCheck(rp, pixc, IFF_PNG); /* 9 */ pixSaveTiledOutline(pixc, pixa, 1.0, 1, 30, 2, 32); /* Verify that the fg pixels are the same set as we * originally started with. */ pixb = pixConvertTo1(pixc, 255); regTestComparePix(rp, pixb, pixfg); /* 10 */ pixDestroy(&pixc); pixDestroy(&pixb); /* Render the bg boundary pixels alone. */ pixc = pixRenderRandomCmapPtaa(pixs, ptaabg, 0, 0, 0); regTestWritePixAndCheck(rp, pixc, IFF_PNG); /* 11 */ pixSaveTiledOutline(pixc, pixa, 1.0, 0, 30, 2, 32); /* Verify that the bg pixels are the same set as we * originally started with. */ pixb = pixConvertTo1(pixc, 255); regTestComparePix(rp, pixb, pixbg); /* 12 */ pixDestroy(&pixc); pixDestroy(&pixb); pixd = pixaDisplay(pixa, 0, 0); pixDisplayWithTitle(pixd, 0, 0, NULL, rp->display); ptaaDestroy(&ptaafg); ptaaDestroy(&ptaabg); pixDestroy(&pixs); pixDestroy(&pixfg); pixDestroy(&pixbg); pixDestroy(&pixd); pixaDestroy(&pixa); boxaDestroy(&boxa); /* Test rotation */ pix1 = pixRead("feyn-word.tif"); pix2 = pixAddBorderGeneral(pix1, 200, 200, 200, 200, 0); pixa = pixaCreate(0); pix3 = PtaDisplayRotate(pix2, 0, 0); pixaAddPix(pixa, pix3, L_INSERT); pix3 = PtaDisplayRotate(pix2, 500, 100); pixaAddPix(pixa, pix3, L_INSERT); pix3 = PtaDisplayRotate(pix2, 100, 410); pixaAddPix(pixa, pix3, L_INSERT); pix3 = PtaDisplayRotate(pix2, 500, 410); pixaAddPix(pixa, pix3, L_INSERT); pix4 = pixaDisplayTiledInRows(pixa, 32, 1500, 1.0, 0, 30, 2); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 13 */ pixDisplayWithTitle(pix4, 800, 0, NULL, rp->display); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix4); pixaDestroy(&pixa); return regTestCleanup(rp); }
/*! * \brief recogMakeDecodingArray() * * \param[in] recog * \param[in] index of averaged template * \param[in] debug 1 for debug output; 0 otherwise * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) Generates the bit-and sum array for a character template along pixs. * (2) The values are saved in the scoring arrays at the left edge * of the template as it is positioned on pixs. * </pre> */ static l_int32 recogMakeDecodingArray(L_RECOG *recog, l_int32 index, l_int32 debug) { l_int32 i, j, w1, h1, w2, h2, nx, ycent2, count, maxcount, maxdely; l_int32 sum, moment, dely, shifty; l_int32 *counta, *delya, *ycent1, *arraysum, *arraymoment, *sumtab; NUMA *nasum, *namoment; PIX *pix1, *pix2, *pix3; L_RDID *did; PROCNAME("recogMakeDecodingArray"); if (!recog) return ERROR_INT("recog not defined", procName, 1); if ((did = recogGetDid(recog)) == NULL) return ERROR_INT("did not defined", procName, 1); if (index < 0 || index >= did->narray) return ERROR_INT("invalid index", procName, 1); /* Check that pix1 is large enough for this template. */ pix1 = did->pixs; /* owned by did; do not destroy */ pixGetDimensions(pix1, &w1, &h1, NULL); pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE); pixGetDimensions(pix2, &w2, &h2, NULL); if (w1 < w2) { L_INFO("w1 = %d < w2 = %d for index %d\n", procName, w1, w2, index); pixDestroy(&pix2); return 0; } nasum = did->nasum; namoment = did->namoment; ptaGetIPt(recog->pta_u, index, NULL, &ycent2); sumtab = recog->sumtab; counta = did->counta[index]; delya = did->delya[index]; /* Set up the array for ycent1. This gives the y-centroid location * for a window of width w2, starting at location i. */ nx = w1 - w2 + 1; /* number of positions w2 can be placed in w1 */ ycent1 = (l_int32 *)LEPT_CALLOC(nx, sizeof(l_int32)); arraysum = numaGetIArray(nasum); arraymoment = numaGetIArray(namoment); for (i = 0, sum = 0, moment = 0; i < w2; i++) { sum += arraysum[i]; moment += arraymoment[i]; } for (i = 0; i < nx - 1; i++) { ycent1[i] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum; sum += arraysum[w2 + i] - arraysum[i]; moment += arraymoment[w2 + i] - arraymoment[i]; } ycent1[nx - 1] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum; /* Compute the bit-and sum between the template pix2 and pix1, at * locations where the left side of pix2 goes from 0 to nx - 1 * in pix1. Do this around the vertical alignment of the pix2 * centroid and the windowed pix1 centroid. * (1) Start with pix3 cleared and approximately equal in size to pix1. * (2) Blit the y-shifted pix2 onto pix3. Then all ON pixels * are within the intersection of pix1 and the shifted pix2. * (3) AND pix1 with pix3. */ pix3 = pixCreate(w2, h1, 1); for (i = 0; i < nx; i++) { shifty = (l_int32)(ycent1[i] - ycent2 + 0.5); maxcount = 0; for (j = -MaxYShift; j <= MaxYShift; j++) { pixClearAll(pix3); dely = shifty + j; /* amount pix2 is shifted relative to pix1 */ pixRasterop(pix3, 0, dely, w2, h2, PIX_SRC, pix2, 0, 0); pixRasterop(pix3, 0, 0, w2, h1, PIX_SRC & PIX_DST, pix1, i, 0); pixCountPixels(pix3, &count, sumtab); if (count > maxcount) { maxcount = count; maxdely = dely; } } counta[i] = maxcount; delya[i] = maxdely; } did->fullarrays = TRUE; pixDestroy(&pix2); pixDestroy(&pix3); LEPT_FREE(ycent1); LEPT_FREE(arraysum); LEPT_FREE(arraymoment); return 0; }
/*! * pixProjectiveSampled() * * Input: pixs (all depths) * vc (vector of 8 coefficients for projective transformation) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary. * (2) Retains colormap, which you can do for a sampled transform.. * (3) For 8 or 32 bpp, much better quality is obtained by the * somewhat slower pixProjective(). See that function * for relative timings between sampled and interpolated. */ PIX * pixProjectiveSampled(PIX *pixs, l_float32 *vc, l_int32 incolor) { l_int32 i, j, w, h, d, x, y, wpls, wpld, color, cmapindex; l_uint32 val; l_uint32 *datas, *datad, *lines, *lined; PIX *pixd; PIXCMAP *cmap; PROCNAME("pixProjectiveSampled"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32) return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8 or 16", procName, NULL); /* Init all dest pixels to color to be brought in from outside */ pixd = pixCreateTemplate(pixs); if ((cmap = pixGetColormap(pixs)) != NULL) { if (incolor == L_BRING_IN_WHITE) color = 1; else color = 0; pixcmapAddBlackOrWhite(cmap, color, &cmapindex); pixSetAllArbitrary(pixd, cmapindex); } else { if ((d == 1 && incolor == L_BRING_IN_WHITE) || (d > 1 && incolor == L_BRING_IN_BLACK)) pixClearAll(pixd); else pixSetAll(pixd); } /* Scan over the dest pixels */ datas = pixGetData(pixs); wpls = pixGetWpl(pixs); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); for (i = 0; i < h; i++) { lined = datad + i * wpld; for (j = 0; j < w; j++) { projectiveXformSampledPt(vc, j, i, &x, &y); if (x < 0 || y < 0 || x >=w || y >= h) continue; lines = datas + y * wpls; if (d == 1) { val = GET_DATA_BIT(lines, x); SET_DATA_BIT_VAL(lined, j, val); } else if (d == 8) { val = GET_DATA_BYTE(lines, x); SET_DATA_BYTE(lined, j, val); } else if (d == 32) { lined[j] = lines[x]; } else if (d == 2) { val = GET_DATA_DIBIT(lines, x); SET_DATA_DIBIT(lined, j, val); } else if (d == 4) { val = GET_DATA_QBIT(lines, x); SET_DATA_QBIT(lined, j, val); } } } return pixd; }