/*! * recogDestroy() * * Input: &recog (<will be set to null before returning>) * Return: void * * Notes: * (1) If a recog has a parent, the parent owns it. A recogDestroy() * will fail if there is a parent. */ void recogDestroy(L_RECOG **precog) { L_RECOG *recog; PROCNAME("recogDestroy"); if (!precog) { L_WARNING("ptr address is null\n", procName); return; } if ((recog = *precog) == NULL) return; if (recogGetParent(recog) != NULL) { L_ERROR("recog has parent; can't be destroyed\n", procName); return; } FREE(recog->bootdir); FREE(recog->bootpattern); FREE(recog->bootpath); FREE(recog->centtab); FREE(recog->sumtab); FREE(recog->fname); sarrayDestroy(&recog->sa_text); l_dnaDestroy(&recog->dna_tochar); pixaaDestroy(&recog->pixaa_u); pixaDestroy(&recog->pixa_u); ptaaDestroy(&recog->ptaa_u); ptaDestroy(&recog->pta_u); numaDestroy(&recog->nasum_u); numaaDestroy(&recog->naasum_u); pixaaDestroy(&recog->pixaa); pixaDestroy(&recog->pixa); ptaaDestroy(&recog->ptaa); ptaDestroy(&recog->pta); numaDestroy(&recog->nasum); numaaDestroy(&recog->naasum); pixaDestroy(&recog->pixa_tr); pixaDestroy(&recog->pixadb_ave); pixaDestroy(&recog->pixa_id); pixDestroy(&recog->pixdb_ave); pixDestroy(&recog->pixdb_range); pixaDestroy(&recog->pixadb_boot); pixaDestroy(&recog->pixadb_split); FREE(recog->fontdir); bmfDestroy(&recog->bmf); rchDestroy(&recog->rch); rchaDestroy(&recog->rcha); recogDestroyDid(recog); FREE(recog); *precog = NULL; return; }
static PIX * PtaDisplayRotate(PIX *pixs, l_float32 xc, l_float32 yc) { l_int32 i, w, h; PIX *pix1, *pix2; PTA *pta1, *pta2, *pta3, *pta4; PTAA *ptaa; /* Save rotated sets of pixels */ pta1 = ptaGetPixelsFromPix(pixs, NULL); ptaa = ptaaCreate(0); for (i = 0; i < 9; i++) { pta2 = ptaRotate(pta1, xc, yc, -0.8 + 0.2 * i); ptaaAddPta(ptaa, pta2, L_INSERT); } ptaDestroy(&pta1); /* Render them */ pixGetDimensions(pixs, &w, &h, NULL); pix1 = pixCreate(w, h, 32); pixSetAll(pix1); pta3 = generatePtaFilledCircle(4); pta4 = ptaTranslate(pta3, xc, yc); pixRenderPtaArb(pix1, pta4, 255, 0, 0); /* circle at rotation center */ pix2 = pixDisplayPtaa(pix1, ptaa); /* rotated sets */ pixDestroy(&pix1); ptaDestroy(&pta3); ptaDestroy(&pta4); ptaaDestroy(&ptaa); return pix2; }
/*! * \brief recogDestroy() * * \param[in,out] precog will be set to null before returning * \return void */ void recogDestroy(L_RECOG **precog) { L_RECOG *recog; PROCNAME("recogDestroy"); if (!precog) { L_WARNING("ptr address is null\n", procName); return; } if ((recog = *precog) == NULL) return; LEPT_FREE(recog->centtab); LEPT_FREE(recog->sumtab); sarrayDestroy(&recog->sa_text); l_dnaDestroy(&recog->dna_tochar); pixaaDestroy(&recog->pixaa_u); pixaDestroy(&recog->pixa_u); ptaaDestroy(&recog->ptaa_u); ptaDestroy(&recog->pta_u); numaDestroy(&recog->nasum_u); numaaDestroy(&recog->naasum_u); pixaaDestroy(&recog->pixaa); pixaDestroy(&recog->pixa); ptaaDestroy(&recog->ptaa); ptaDestroy(&recog->pta); numaDestroy(&recog->nasum); numaaDestroy(&recog->naasum); pixaDestroy(&recog->pixa_tr); pixaDestroy(&recog->pixadb_ave); pixaDestroy(&recog->pixa_id); pixDestroy(&recog->pixdb_ave); pixDestroy(&recog->pixdb_range); pixaDestroy(&recog->pixadb_boot); pixaDestroy(&recog->pixadb_split); bmfDestroy(&recog->bmf); rchDestroy(&recog->rch); rchaDestroy(&recog->rcha); recogDestroyDid(recog); LEPT_FREE(recog); *precog = NULL; return; }
l_int32 main(int argc, char **argv) { l_int32 i, n; l_float32 a, b, c, d, e; NUMA *nax, *nafit; PIX *pixs, *pixn, *pixg, *pixb, *pixt1, *pixt2; PIXA *pixa; PTA *pta, *ptad; PTAA *ptaa1, *ptaa2; pixs = pixRead("cat-35.jpg"); /* pixs = pixRead("zanotti-78.jpg"); */ /* Normalize for varying background and binarize */ pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); pixDestroy(&pixn); pixDestroy(&pixg); /* Get the textline centers */ pixa = pixaCreate(6); ptaa1 = dewarpGetTextlineCenters(pixb, 0); pixt1 = pixCreateTemplate(pixs); pixSetAll(pixt1); pixt2 = pixDisplayPtaa(pixt1, ptaa1); pixWrite("/tmp/textline1.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 0, 100, "textline centers 1", 1); pixaAddPix(pixa, pixt2, L_INSERT); pixDestroy(&pixt1); /* Remove short lines */ fprintf(stderr, "Num all lines = %d\n", ptaaGetCount(ptaa1)); ptaa2 = dewarpRemoveShortLines(pixb, ptaa1, 0.8, 0); pixt1 = pixCreateTemplate(pixs); pixSetAll(pixt1); pixt2 = pixDisplayPtaa(pixt1, ptaa2); pixWrite("/tmp/textline2.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 300, 100, "textline centers 2", 1); pixaAddPix(pixa, pixt2, L_INSERT); pixDestroy(&pixt1); n = ptaaGetCount(ptaa2); fprintf(stderr, "Num long lines = %d\n", n); ptaaDestroy(&ptaa1); pixDestroy(&pixb); /* Long lines over input image */ pixt1 = pixCopy(NULL, pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa2); pixWrite("/tmp/textline3.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 600, 100, "textline centers 3", 1); pixaAddPix(pixa, pixt2, L_INSERT); pixDestroy(&pixt1); /* Quadratic fit to curve */ pixt1 = pixCopy(NULL, pixs); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetQuadraticLSF(pta, &a, &b, &c, &nafit); fprintf(stderr, "Quadratic: a = %10.6f, b = %7.3f, c = %7.3f\n", a, b, c); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt1, pixt1, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixWrite("/tmp/textline4.png", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 900, 100, "textline centers 4", 1); pixaAddPix(pixa, pixt1, L_INSERT); /* Cubic fit to curve */ pixt1 = pixCopy(NULL, pixs); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetCubicLSF(pta, &a, &b, &c, &d, &nafit); fprintf(stderr, "Cubic: a = %10.6f, b = %10.6f, c = %7.3f, d = %7.3f\n", a, b, c, d); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt1, pixt1, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixWrite("/tmp/textline5.png", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 1200, 100, "textline centers 5", 1); pixaAddPix(pixa, pixt1, L_INSERT); /* Quartic fit to curve */ pixt1 = pixCopy(NULL, pixs); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetQuarticLSF(pta, &a, &b, &c, &d, &e, &nafit); fprintf(stderr, "Quartic: a = %7.3f, b = %7.3f, c = %9.5f, d = %7.3f, e = %7.3f\n", a, b, c, d, e); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt1, pixt1, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixWrite("/tmp/textline6.png", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 1500, 100, "textline centers 6", 1); pixaAddPix(pixa, pixt1, L_INSERT); pixaConvertToPdf(pixa, 300, 0.5, L_JPEG_ENCODE, 75, "LS fittings to textlines", "/tmp/dewarp_fittings.pdf"); pixaDestroy(&pixa); pixDestroy(&pixs); ptaaDestroy(&ptaa2); return 0; }
int main(int argc, char **argv) { char *filein, *fileout; l_int32 x, y, n, i; PIX *pixs; PTA *pta; PTAA *ptaa, *ptaa2, *ptaa3; static char mainName[] = "cornertest"; if (argc != 3) return ERROR_INT(" Syntax: cornertest filein fileout", mainName, 1); filein = argv[1]; fileout = argv[2]; if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); /* Clean noise in LR corner of witten.tif */ pixSetPixel(pixs, 2252, 3051, 0); pixSetPixel(pixs, 2252, 3050, 0); pixSetPixel(pixs, 2251, 3050, 0); pta = pixFindCornerPixels(pixs); ptaWriteStream(stderr, pta, 1); /* Test pta and ptaa I/O */ #if 1 ptaa = ptaaCreate(3); ptaaAddPta(ptaa, pta, L_COPY); ptaaAddPta(ptaa, pta, L_COPY); ptaaAddPta(ptaa, pta, L_COPY); ptaaWriteStream(stderr, ptaa, 1); ptaaWrite("/tmp/junkptaa", ptaa, 1); ptaa2 = ptaaRead("/tmp/junkptaa"); ptaaWrite("/tmp/junkptaa2", ptaa2, 1); ptaaWrite("/tmp/junkptaa3", ptaa, 0); ptaa3 = ptaaRead("/tmp/junkptaa3"); ptaaWrite("/tmp/junkptaa4", ptaa3, 0); ptaaDestroy(&ptaa); ptaaDestroy(&ptaa2); ptaaDestroy(&ptaa3); #endif /* mark corner pixels */ n = ptaGetCount(pta); for (i = 0; i < n; i++) { ptaGetIPt(pta, i, &x, &y); pixRenderLine(pixs, x - LINE_SIZE, y, x + LINE_SIZE, y, 5, L_FLIP_PIXELS); pixRenderLine(pixs, x, y - LINE_SIZE, x, y + LINE_SIZE, 5, L_FLIP_PIXELS); } pixWrite(fileout, pixs, IFF_PNG); pixDestroy(&pixs); ptaDestroy(&pta); ptaDestroy(&pta); return 0; }
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); }
/*! * dewarpBuildModel() * * Input: dew * debugflag (1 for debugging output) * Return: 0 if OK, 1 on error * * Notes: * (1) This is the basic function that builds the vertical * disparity array, which allows determination of the * src pixel in the input image corresponding to each * dest pixel in the dewarped image. * (2) The method is as follows: * * Estimate the centers of all the long textlines and * fit a LS quadratic to each one. This smooths the curves. * * Sample each curve at a regular interval, find the y-value * of the flat point on each curve, and subtract the sampled * curve value from this value. This is the vertical * disparity. * * Fit a LS quadratic to each set of vertically aligned * disparity samples. This smooths the disparity values * in the vertical direction. Then resample at the same * regular interval, We now have a regular grid of smoothed * vertical disparity valuels. * * Interpolate this grid to get a full resolution disparity * map. This can be applied directly to the src image * pixels to dewarp the image in the vertical direction, * making all textlines horizontal. */ l_int32 dewarpBuildModel(L_DEWARP *dew, l_int32 debugflag) { char *tempname; l_int32 i, j, nlines, nx, ny, sampling; l_float32 c0, c1, c2, x, y, flaty, val; l_float32 *faflats; NUMA *nax, *nafit, *nacurve, *nacurves, *naflat, *naflats, *naflatsi; PIX *pixs, *pixt1, *pixt2; PTA *pta, *ptad; PTAA *ptaa1, *ptaa2, *ptaa3, *ptaa4, *ptaa5, *ptaa6, *ptaa7; FPIX *fpix1, *fpix2, *fpix3; PROCNAME("dewarpBuildModel"); if (!dew) return ERROR_INT("dew not defined", procName, 1); pixs = dew->pixs; if (debugflag) { pixDisplayWithTitle(pixs, 0, 0, "pixs", 1); pixWriteTempfile("/tmp", "pixs.png", pixs, IFF_PNG, NULL); } /* Make initial estimate of centers of textlines */ ptaa1 = pixGetTextlineCenters(pixs, DEBUG_TEXTLINE_CENTERS); if (debugflag) { pixt1 = pixConvertTo32(pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa1); pixWriteTempfile("/tmp", "lines1.png", pixt2, IFF_PNG, NULL); pixDestroy(&pixt1); pixDestroy(&pixt2); } /* Remove all lines that are not near the length * of the longest line. */ ptaa2 = ptaaRemoveShortLines(pixs, ptaa1, 0.8, DEBUG_SHORT_LINES); if (debugflag) { pixt1 = pixConvertTo32(pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa2); pixWriteTempfile("/tmp", "lines2.png", pixt2, IFF_PNG, NULL); pixDestroy(&pixt1); pixDestroy(&pixt2); } nlines = ptaaGetCount(ptaa2); if (nlines < dew->minlines) return ERROR_INT("insufficient lines to build model", procName, 1); /* Do quadratic fit to smooth each line. A single quadratic * over the entire width of the line appears to be sufficient. * Quartics tend to overfit to noise. Each line is thus * represented by three coefficients: c2 * x^2 + c1 * x + c0. * Using the coefficients, sample each fitted curve uniformly * across the full width of the image. */ sampling = dew->sampling; nx = dew->nx; ny = dew->ny; ptaa3 = ptaaCreate(nlines); nacurve = numaCreate(nlines); /* stores curvature coeff c2 */ for (i = 0; i < nlines; i++) { /* for each line */ pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetQuadraticLSF(pta, &c2, &c1, &c0, NULL); numaAddNumber(nacurve, c2); ptad = ptaCreate(nx); for (j = 0; j < nx; j++) { /* uniformly sampled in x */ x = j * sampling; applyQuadraticFit(c2, c1, c0, x, &y); ptaAddPt(ptad, x, y); } ptaaAddPta(ptaa3, ptad, L_INSERT); ptaDestroy(&pta); } if (debugflag) { ptaa4 = ptaaCreate(nlines); for (i = 0; i < nlines; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetQuadraticLSF(pta, NULL, NULL, NULL, &nafit); ptad = ptaCreateFromNuma(nax, nafit); ptaaAddPta(ptaa4, ptad, L_INSERT); ptaDestroy(&pta); numaDestroy(&nax); numaDestroy(&nafit); } pixt1 = pixConvertTo32(pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa4); pixWriteTempfile("/tmp", "lines3.png", pixt2, IFF_PNG, NULL); pixDestroy(&pixt1); pixDestroy(&pixt2); ptaaDestroy(&ptaa4); } /* Find and save the flat points in each curve. */ naflat = numaCreate(nlines); for (i = 0; i < nlines; i++) { pta = ptaaGetPta(ptaa3, i, L_CLONE); numaGetFValue(nacurve, i, &c2); if (c2 <= 0) /* flat point at bottom; max value of y in curve */ ptaGetRange(pta, NULL, NULL, NULL, &flaty); else /* flat point at top; min value of y in curve */ ptaGetRange(pta, NULL, NULL, &flaty, NULL); numaAddNumber(naflat, flaty); ptaDestroy(&pta); } /* Sort the lines in ptaa3 by their position */ naflatsi = numaGetSortIndex(naflat, L_SORT_INCREASING); naflats = numaSortByIndex(naflat, naflatsi); nacurves = numaSortByIndex(nacurve, naflatsi); dew->naflats = naflats; dew->nacurves = nacurves; ptaa4 = ptaaSortByIndex(ptaa3, naflatsi); numaDestroy(&naflat); numaDestroy(&nacurve); numaDestroy(&naflatsi); if (debugflag) { tempname = genTempFilename("/tmp", "naflats.na", 0); numaWrite(tempname, naflats); FREE(tempname); } /* Convert the sampled points in ptaa3 to a sampled disparity with * with respect to the flat point in the curve. */ ptaa5 = ptaaCreate(nlines); for (i = 0; i < nlines; i++) { pta = ptaaGetPta(ptaa4, i, L_CLONE); numaGetFValue(naflats, i, &flaty); ptad = ptaCreate(nx); for (j = 0; j < nx; j++) { ptaGetPt(pta, j, &x, &y); ptaAddPt(ptad, x, flaty - y); } ptaaAddPta(ptaa5, ptad, L_INSERT); ptaDestroy(&pta); } if (debugflag) { tempname = genTempFilename("/tmp", "ptaa5.ptaa", 0); ptaaWrite(tempname, ptaa5, 0); FREE(tempname); } /* Generate a ptaa taking vertical 'columns' from ptaa5. * We want to fit the vertical disparity on the column to the * vertical position of the line, which we call 'y' here and * obtain from naflats. */ ptaa6 = ptaaCreate(nx); faflats = numaGetFArray(naflats, L_NOCOPY); for (j = 0; j < nx; j++) { pta = ptaCreate(nlines); for (i = 0; i < nlines; i++) { y = faflats[i]; ptaaGetPt(ptaa5, i, j, NULL, &val); /* disparity value */ ptaAddPt(pta, y, val); } ptaaAddPta(ptaa6, pta, L_INSERT); } if (debugflag) { tempname = genTempFilename("/tmp", "ptaa6.ptaa", 0); ptaaWrite(tempname, ptaa6, 0); FREE(tempname); } /* Do quadratic fit vertically on a subset of pixel columns * for the vertical displacement, which identifies the * src pixel(s) for each dest pixel. Sample the displacement * on a regular grid in the vertical direction. */ ptaa7 = ptaaCreate(nx); /* uniformly sampled across full height of image */ for (j = 0; j < nx; j++) { /* for each column */ pta = ptaaGetPta(ptaa6, j, L_CLONE); ptaGetQuadraticLSF(pta, &c2, &c1, &c0, NULL); ptad = ptaCreate(ny); for (i = 0; i < ny; i++) { /* uniformly sampled in y */ y = i * sampling; applyQuadraticFit(c2, c1, c0, y, &val); ptaAddPt(ptad, y, val); } ptaaAddPta(ptaa7, ptad, L_INSERT); ptaDestroy(&pta); } if (debugflag) { tempname = genTempFilename("/tmp", "ptaa7.ptaa", 0); ptaaWrite(tempname, ptaa7, 0); FREE(tempname); } /* Save the result in a fpix at the specified subsampling */ fpix1 = fpixCreate(nx, ny); for (i = 0; i < ny; i++) { for (j = 0; j < nx; j++) { ptaaGetPt(ptaa7, j, i, NULL, &val); fpixSetPixel(fpix1, j, i, val); } } dew->sampvdispar = fpix1; /* Generate a full res fpix for vertical dewarping. We require that * the size of this fpix is at least as big as the input image. */ fpix2 = fpixScaleByInteger(fpix1, sampling); dew->fullvdispar = fpix2; if (debugflag) { pixt1 = fpixRenderContours(fpix2, -2., 2.0, 0.2); pixWriteTempfile("/tmp", "vert-contours.png", pixt1, IFF_PNG, NULL); pixDisplay(pixt1, 1000, 0); pixDestroy(&pixt1); } /* Generate full res and sampled fpix for horizontal dewarping. This * works to the extent that the line curvature is due to bending * out of the plane normal to the camera, and not wide-angle * "fishbowl" distortion. Also generate the sampled horizontal * disparity array. */ if (dew->applyhoriz) { fpix3 = fpixBuildHorizontalDisparity(fpix2, 0, &dew->extraw); dew->fullhdispar = fpix3; dew->samphdispar = fpixSampledDisparity(fpix3, dew->sampling); if (debugflag) { pixt1 = fpixRenderContours(fpix3, -2., 2.0, 0.2); pixWriteTempfile("/tmp", "horiz-contours.png", pixt1, IFF_PNG, NULL); pixDisplay(pixt1, 1000, 0); pixDestroy(&pixt1); } } dew->success = 1; ptaaDestroy(&ptaa1); ptaaDestroy(&ptaa2); ptaaDestroy(&ptaa3); ptaaDestroy(&ptaa4); ptaaDestroy(&ptaa5); ptaaDestroy(&ptaa6); ptaaDestroy(&ptaa7); return 0; }
l_int32 DoPageSegmentation(PIX *pixs, /* should be at least 300 ppi */ l_int32 which) /* 1, 2, 3, 4 */ { char buf[256]; l_int32 zero; BOXA *boxatm, *boxahm; PIX *pixr; /* image reduced to 150 ppi */ PIX *pixhs; /* image of halftone seed, 150 ppi */ PIX *pixm; /* image of mask of components, 150 ppi */ PIX *pixhm1; /* image of halftone mask, 150 ppi */ PIX *pixhm2; /* image of halftone mask, 300 ppi */ PIX *pixht; /* image of halftone components, 150 ppi */ PIX *pixnht; /* image without halftone components, 150 ppi */ PIX *pixi; /* inverted image, 150 ppi */ PIX *pixvws; /* image of vertical whitespace, 150 ppi */ PIX *pixm1; /* image of closed textlines, 150 ppi */ PIX *pixm2; /* image of refined text line mask, 150 ppi */ PIX *pixm3; /* image of refined text line mask, 300 ppi */ PIX *pixb1; /* image of text block mask, 150 ppi */ PIX *pixb2; /* image of text block mask, 300 ppi */ PIX *pixnon; /* image of non-text or halftone, 150 ppi */ PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixa; PIXCMAP *cmap; PTAA *ptaa; l_int32 ht_flag = 0; l_int32 ws_flag = 0; l_int32 text_flag = 0; l_int32 block_flag = 0; PROCNAME("DoPageSegmentation"); if (which == 1) ht_flag = 1; else if (which == 2) ws_flag = 1; else if (which == 3) text_flag = 1; else if (which == 4) block_flag = 1; else return ERROR_INT("invalid parameter: not in [1...4]", procName, 1); pixa = pixaCreate(0); lept_mkdir("lept/livre"); /* Reduce to 150 ppi */ pix1 = pixScaleToGray2(pixs); if (ws_flag || ht_flag || block_flag) pixaAddPix(pixa, pix1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/orig.gray.150.png", pix1, IFF_PNG); pixDestroy(&pix1); pixr = pixReduceRankBinaryCascade(pixs, 1, 0, 0, 0); /* Get seed for halftone parts */ pix1 = pixReduceRankBinaryCascade(pixr, 4, 4, 3, 0); pix2 = pixOpenBrick(NULL, pix1, 5, 5); pixhs = pixExpandBinaryPower2(pix2, 8); if (ht_flag) pixaAddPix(pixa, pixhs, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/htseed.150.png", pixhs, IFF_PNG); pixDestroy(&pix1); pixDestroy(&pix2); /* Get mask for connected regions */ pixm = pixCloseSafeBrick(NULL, pixr, 4, 4); if (ht_flag) pixaAddPix(pixa, pixm, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/ccmask.150.png", pixm, IFF_PNG); /* Fill seed into mask to get halftone mask */ pixhm1 = pixSeedfillBinary(NULL, pixhs, pixm, 4); if (ht_flag) pixaAddPix(pixa, pixhm1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/htmask.150.png", pixhm1, IFF_PNG); pixhm2 = pixExpandBinaryPower2(pixhm1, 2); /* Extract halftone stuff */ pixht = pixAnd(NULL, pixhm1, pixr); if (which == 1) pixWrite("/tmp/lept/livre/ht.150.png", pixht, IFF_PNG); /* Extract non-halftone stuff */ pixnht = pixXor(NULL, pixht, pixr); if (text_flag) pixaAddPix(pixa, pixnht, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/text.150.png", pixnht, IFF_PNG); pixZero(pixht, &zero); if (zero) fprintf(stderr, "No halftone parts found\n"); else fprintf(stderr, "Halftone parts found\n"); /* Get bit-inverted image */ pixi = pixInvert(NULL, pixnht); if (ws_flag) pixaAddPix(pixa, pixi, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/invert.150.png", pixi, IFF_PNG); /* The whitespace mask will break textlines where there * is a large amount of white space below or above. * We can prevent this by identifying regions of the * inverted image that have large horizontal (bigger than * the separation between columns) and significant * vertical extent (bigger than the separation between * textlines), and subtracting this from the whitespace mask. */ pix1 = pixMorphCompSequence(pixi, "o80.60", 0); pix2 = pixSubtract(NULL, pixi, pix1); if (ws_flag) pixaAddPix(pixa, pix2, L_COPY); pixDestroy(&pix1); /* Identify vertical whitespace by opening inverted image */ pix3 = pixOpenBrick(NULL, pix2, 5, 1); /* removes thin vertical lines */ pixvws = pixOpenBrick(NULL, pix3, 1, 200); /* gets long vertical lines */ if (text_flag || ws_flag) pixaAddPix(pixa, pixvws, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/vertws.150.png", pixvws, IFF_PNG); pixDestroy(&pix2); pixDestroy(&pix3); /* Get proto (early processed) text line mask. */ /* First close the characters and words in the textlines */ pixm1 = pixCloseSafeBrick(NULL, pixnht, 30, 1); if (text_flag) pixaAddPix(pixa, pixm1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textmask1.150.png", pixm1, IFF_PNG); /* Next open back up the vertical whitespace corridors */ pixm2 = pixSubtract(NULL, pixm1, pixvws); if (which == 1) pixWrite("/tmp/lept/livre/textmask2.150.png", pixm2, IFF_PNG); /* Do a small opening to remove noise */ pixOpenBrick(pixm2, pixm2, 3, 3); if (text_flag) pixaAddPix(pixa, pixm2, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textmask3.150.png", pixm2, IFF_PNG); pixm3 = pixExpandBinaryPower2(pixm2, 2); /* Join pixels vertically to make text block mask */ pixb1 = pixMorphSequence(pixm2, "c1.10 + o4.1", 0); if (block_flag) pixaAddPix(pixa, pixb1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textblock1.150.png", pixb1, IFF_PNG); /* Solidify the textblock mask and remove noise: * (1) For each c.c., close the blocks and dilate slightly * to form a solid mask. * (2) Small horizontal closing between components * (3) Open the white space between columns, again * (4) Remove small components */ pix1 = pixMorphSequenceByComponent(pixb1, "c30.30 + d3.3", 8, 0, 0, NULL); pixCloseSafeBrick(pix1, pix1, 10, 1); if (block_flag) pixaAddPix(pixa, pix1, L_COPY); pix2 = pixSubtract(NULL, pix1, pixvws); pix3 = pixSelectBySize(pix2, 25, 5, 8, L_SELECT_IF_BOTH, L_SELECT_IF_GTE, NULL); if (block_flag) pixaAddPix(pixa, pix3, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textblock2.150.png", pix3, IFF_PNG); pixb2 = pixExpandBinaryPower2(pix3, 2); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Identify the outlines of each textblock */ ptaa = pixGetOuterBordersPtaa(pixb2); pix1 = pixRenderRandomCmapPtaa(pixb2, ptaa, 1, 8, 1); cmap = pixGetColormap(pix1); pixcmapResetColor(cmap, 0, 130, 130, 130); /* set interior to gray */ if (which == 1) pixWrite("/tmp/lept/livre/textblock3.300.png", pix1, IFF_PNG); pixDisplayWithTitle(pix1, 480, 360, "textblock mask with outlines", DFLAG); ptaaDestroy(&ptaa); pixDestroy(&pix1); /* Fill line mask (as seed) into the original */ pix1 = pixSeedfillBinary(NULL, pixm3, pixs, 8); pixOr(pixm3, pixm3, pix1); pixDestroy(&pix1); if (which == 1) pixWrite("/tmp/lept/livre/textmask.300.png", pixm3, IFF_PNG); pixDisplayWithTitle(pixm3, 480, 360, "textline mask 4", DFLAG); /* Fill halftone mask (as seed) into the original */ pix1 = pixSeedfillBinary(NULL, pixhm2, pixs, 8); pixOr(pixhm2, pixhm2, pix1); pixDestroy(&pix1); if (which == 1) pixWrite("/tmp/lept/livre/htmask.300.png", pixhm2, IFF_PNG); pixDisplayWithTitle(pixhm2, 520, 390, "halftonemask 2", DFLAG); /* Find objects that are neither text nor halftones */ pix1 = pixSubtract(NULL, pixs, pixm3); /* remove text pixels */ pixnon = pixSubtract(NULL, pix1, pixhm2); /* remove halftone pixels */ pixDestroy(&pix1); if (which == 1) pixWrite("/tmp/lept/livre/other.300.png", pixnon, IFF_PNG); pixDisplayWithTitle(pixnon, 540, 420, "other stuff", DFLAG); /* Write out b.b. for text line mask and halftone mask components */ boxatm = pixConnComp(pixm3, NULL, 4); boxahm = pixConnComp(pixhm2, NULL, 8); if (which == 1) { boxaWrite("/tmp/lept/livre/textmask.boxa", boxatm); boxaWrite("/tmp/lept/livre/htmask.boxa", boxahm); } pix1 = pixaDisplayTiledAndScaled(pixa, 8, 250, 4, 0, 25, 2); pixDisplay(pix1, 0, 375 * (which - 1)); snprintf(buf, sizeof(buf), "/tmp/lept/livre/segout.%d.png", which); pixWrite(buf, pix1, IFF_PNG); pixDestroy(&pix1); pixaDestroy(&pixa); /* clean up to test with valgrind */ pixDestroy(&pixr); pixDestroy(&pixhs); pixDestroy(&pixm); pixDestroy(&pixhm1); pixDestroy(&pixhm2); pixDestroy(&pixht); pixDestroy(&pixi); pixDestroy(&pixnht); pixDestroy(&pixvws); pixDestroy(&pixm1); pixDestroy(&pixm2); pixDestroy(&pixm3); pixDestroy(&pixb1); pixDestroy(&pixb2); pixDestroy(&pixnon); boxaDestroy(&boxatm); boxaDestroy(&boxahm); return 0; }
/*! * pixGetRegionsBinary() * * Input: pixs (1 bpp, assumed to be 300 to 400 ppi) * &pixhm (<optional return> halftone mask) * &pixtm (<optional return> textline mask) * &pixtb (<optional return> textblock mask) * debug (flag: set to 1 for debug output) * Return: 0 if OK, 1 on error * * Notes: * (1) It is best to deskew the image before segmenting. * (2) The debug flag enables a number of outputs. These * are included to show how to generate and save/display * these results. */ l_int32 pixGetRegionsBinary(PIX *pixs, PIX **ppixhm, PIX **ppixtm, PIX **ppixtb, l_int32 debug) { char *tempname; l_int32 htfound, tlfound; PIX *pixr, *pixt1, *pixt2; PIX *pixtext; /* text pixels only */ PIX *pixhm2; /* halftone mask; 2x reduction */ PIX *pixhm; /* halftone mask; */ PIX *pixtm2; /* textline mask; 2x reduction */ PIX *pixtm; /* textline mask */ PIX *pixvws; /* vertical white space mask */ PIX *pixtb2; /* textblock mask; 2x reduction */ PIX *pixtbf2; /* textblock mask; 2x reduction; small comps filtered */ PIX *pixtb; /* textblock mask */ PROCNAME("pixGetRegionsBinary"); if (ppixhm) *ppixhm = NULL; if (ppixtm) *ppixtm = NULL; if (ppixtb) *ppixtb = NULL; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (pixGetDepth(pixs) != 1) return ERROR_INT("pixs not 1 bpp", procName, 1); /* 2x reduce, to 150 -200 ppi */ pixr = pixReduceRankBinaryCascade(pixs, 1, 0, 0, 0); pixDisplayWrite(pixr, debug); /* Get the halftone mask */ pixhm2 = pixGenHalftoneMask(pixr, &pixtext, &htfound, debug); /* Get the textline mask from the text pixels */ pixtm2 = pixGenTextlineMask(pixtext, &pixvws, &tlfound, debug); /* Get the textblock mask from the textline mask */ pixtb2 = pixGenTextblockMask(pixtm2, pixvws, debug); pixDestroy(&pixr); pixDestroy(&pixtext); pixDestroy(&pixvws); /* Remove small components from the mask, where a small * component is defined as one with both width and height < 60 */ pixtbf2 = pixSelectBySize(pixtb2, 60, 60, 4, L_SELECT_IF_EITHER, L_SELECT_IF_GTE, NULL); pixDestroy(&pixtb2); pixDisplayWriteFormat(pixtbf2, debug, IFF_PNG); /* Expand all masks to full resolution, and do filling or * small dilations for better coverage. */ pixhm = pixExpandReplicate(pixhm2, 2); pixt1 = pixSeedfillBinary(NULL, pixhm, pixs, 8); pixOr(pixhm, pixhm, pixt1); pixDestroy(&pixt1); pixDisplayWriteFormat(pixhm, debug, IFF_PNG); pixt1 = pixExpandReplicate(pixtm2, 2); pixtm = pixDilateBrick(NULL, pixt1, 3, 3); pixDestroy(&pixt1); pixDisplayWriteFormat(pixtm, debug, IFF_PNG); pixt1 = pixExpandReplicate(pixtbf2, 2); pixtb = pixDilateBrick(NULL, pixt1, 3, 3); pixDestroy(&pixt1); pixDisplayWriteFormat(pixtb, debug, IFF_PNG); pixDestroy(&pixhm2); pixDestroy(&pixtm2); pixDestroy(&pixtbf2); /* Debug: identify objects that are neither text nor halftone image */ if (debug) { pixt1 = pixSubtract(NULL, pixs, pixtm); /* remove text pixels */ pixt2 = pixSubtract(NULL, pixt1, pixhm); /* remove halftone pixels */ pixDisplayWriteFormat(pixt2, 1, IFF_PNG); pixDestroy(&pixt1); pixDestroy(&pixt2); } /* Debug: display textline components with random colors */ if (debug) { l_int32 w, h; BOXA *boxa; PIXA *pixa; boxa = pixConnComp(pixtm, &pixa, 8); pixGetDimensions(pixtm, &w, &h, NULL); pixt1 = pixaDisplayRandomCmap(pixa, w, h); pixcmapResetColor(pixGetColormap(pixt1), 0, 255, 255, 255); pixDisplay(pixt1, 100, 100); pixDisplayWriteFormat(pixt1, 1, IFF_PNG); pixaDestroy(&pixa); boxaDestroy(&boxa); pixDestroy(&pixt1); } /* Debug: identify the outlines of each textblock */ if (debug) { PIXCMAP *cmap; PTAA *ptaa; ptaa = pixGetOuterBordersPtaa(pixtb); tempname = genTempFilename("/tmp", "tb_outlines.ptaa", 0, 0); ptaaWrite(tempname, ptaa, 1); FREE(tempname); pixt1 = pixRenderRandomCmapPtaa(pixtb, ptaa, 1, 16, 1); cmap = pixGetColormap(pixt1); pixcmapResetColor(cmap, 0, 130, 130, 130); pixDisplay(pixt1, 500, 100); pixDisplayWriteFormat(pixt1, 1, IFF_PNG); pixDestroy(&pixt1); ptaaDestroy(&ptaa); } /* Debug: get b.b. for all mask components */ if (debug) { BOXA *bahm, *batm, *batb; bahm = pixConnComp(pixhm, NULL, 4); batm = pixConnComp(pixtm, NULL, 4); batb = pixConnComp(pixtb, NULL, 4); tempname = genTempFilename("/tmp", "htmask.boxa", 0, 0); boxaWrite(tempname, bahm); FREE(tempname); tempname = genTempFilename("/tmp", "textmask.boxa", 0, 0); boxaWrite(tempname, batm); FREE(tempname); tempname = genTempFilename("/tmp", "textblock.boxa", 0, 0); boxaWrite(tempname, batb); FREE(tempname); boxaDestroy(&bahm); boxaDestroy(&batm); boxaDestroy(&batb); } if (ppixhm) *ppixhm = pixhm; else pixDestroy(&pixhm); if (ppixtm) *ppixtm = pixtm; else pixDestroy(&pixtm); if (ppixtb) *ppixtb = pixtb; else pixDestroy(&pixtb); return 0; }
l_int32 main(int argc, char **argv) { l_int32 i, n, ignore; l_float32 a, b, c, d, e; L_DEWARP *dew; FILE *fp; FPIX *fpix; NUMA *nax, *nay, *nafit; PIX *pixs, *pixn, *pixg, *pixb, *pixt1, *pixt2, *pixt3; PIX *pixs2, *pixn2, *pixg2, *pixb2, *pixv, *pixd; PTA *pta, *ptad; PTAA *ptaa1, *ptaa2; pixs = pixRead("1555-7.jpg"); /* Normalize for varying background and binarize */ pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); /* Run the basic functions */ dew = dewarpCreate(pixb, 7, 30, 15, 1); dewarpBuildModel(dew, 1); dewarpApplyDisparity(dew, pixg, 1); /* Save the intermediate dewarped images */ pixv = pixRead("/tmp/pixv.png"); pixd = pixRead("/tmp/pixd.png"); /* Normalize another image, that doesn't have enough textlines * to build an accurate model */ pixs2 = pixRead("1555-3.jpg"); pixn2 = pixBackgroundNormSimple(pixs2, NULL, NULL); pixg2 = pixConvertRGBToGray(pixn2, 0.5, 0.3, 0.2); pixb2 = pixThresholdToBinary(pixg2, 130); /* Apply the previous disparity model to this image */ dewarpApplyDisparity(dew, pixg2, 1); dewarpDestroy(&dew); /* Get the textline centers */ const char* const morph2 = "c15.1 + o15.1 + c50.1"; ptaa1 = pixGetTextlineCenters(pixb,morph2, 0); pixt1 = pixCreateTemplate(pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa1); pixWrite("/tmp/textline1.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 500, 100, "textline centers", 1); pixDestroy(&pixt1); /* Remove short lines */ fprintf(stderr, "Num all lines = %d\n", ptaaGetCount(ptaa1)); ptaa2 = ptaaRemoveShortLines(pixb, ptaa1, 0.8, 0); /* Fit to curve */ n = ptaaGetCount(ptaa2); fprintf(stderr, "Num long lines = %d\n", n); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); #if DO_QUAD ptaGetQuadraticLSF(pta, &a, &b, &c, &nafit); /* fprintf(stderr, "a = %7.3f, b = %7.3f, c = %7.3f\n", a, b, c); */ #elif DO_CUBIC ptaGetCubicLSF(pta, &a, &b, &c, &d, &nafit); /* fprintf(stderr, "a = %7.3f, b = %7.3f, c = %7.3f, d = %7.3f\n", a, b, c, d); */ #elif DO_QUARTIC ptaGetQuarticLSF(pta, &a, &b, &c, &d, &e, &nafit); /* fprintf(stderr, "a = %7.3f, b = %7.3f, c = %7.3f, d = %7.3f, e = %7.3f\n", a, b, c, d, e); */ #endif ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt2, pixt2, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixDisplayWithTitle(pixt2, 700, 100, "fitted lines superimposed", 1); pixWrite("/tmp/textline2.png", pixt2, IFF_PNG); ptaaDestroy(&ptaa1); ptaaDestroy(&ptaa2); pixDestroy(&pixt2); /* Write out the files to be imaged */ lept_mkdir("junkdir"); pixWrite("/tmp/junkdir/001.jpg", pixs, IFF_JFIF_JPEG); pixWrite("/tmp/junkdir/002.jpg", pixn, IFF_JFIF_JPEG); pixWrite("/tmp/junkdir/003.jpg", pixg, IFF_JFIF_JPEG); pixWrite("/tmp/junkdir/004.png", pixb, IFF_TIFF_G4); pixt1 = pixRead("/tmp/textline1.png"); pixWrite("/tmp/junkdir/005.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixt1 = pixRead("/tmp/textline2.png"); pixWrite("/tmp/junkdir/006.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixt1 = pixRead("/tmp/lines1.png"); pixWrite("/tmp/junkdir/007.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixt1 = pixRead("/tmp/lines2.png"); pixWrite("/tmp/junkdir/008.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixt1 = pixRead("/tmp/vert-contours.png"); pixWrite("/tmp/junkdir/009.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixWrite("/tmp/junkdir/010.png", pixv, IFF_PNG); pixt1 = pixThresholdToBinary(pixv, 130); pixWrite("/tmp/junkdir/011.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixt1 = pixRead("/tmp/horiz-contours.png"); pixWrite("/tmp/junkdir/012.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixWrite("/tmp/junkdir/013.png", pixd, IFF_PNG); pixt1 = pixThresholdToBinary(pixd, 130); pixWrite("/tmp/junkdir/014.png", pixt1, IFF_PNG); pixDestroy(&pixt1); pixWrite("/tmp/junkdir/015.png", pixb, IFF_TIFF_G4); /* (these are for the second image) */ pixWrite("/tmp/junkdir/016.jpg", pixs2, IFF_JFIF_JPEG); pixWrite("/tmp/junkdir/017.png", pixb2, IFF_TIFF_G4); pixt1 = pixRead("/tmp/pixv.png"); pixt2 = pixThresholdToBinary(pixt1, 130); pixWrite("/tmp/junkdir/018.png", pixt2, IFF_PNG); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixRead("/tmp/pixd.png"); pixt2 = pixThresholdToBinary(pixt1, 130); pixWrite("/tmp/junkdir/019.png", pixt2, IFF_PNG); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Generate the 19 page ps and pdf files */ convertFilesToPS("/tmp/junkdir", NULL, 135, "/tmp/dewarp.ps"); fprintf(stderr, "ps file made: /tmp/dewarp.ps\n"); ignore = system("ps2pdf /tmp/dewarp.ps /tmp/dewarp.pdf"); fprintf(stderr, "pdf file made: /tmp/dewarp.pdf\n"); pixDestroy(&pixs); pixDestroy(&pixn); pixDestroy(&pixg); pixDestroy(&pixb); pixDestroy(&pixs2); pixDestroy(&pixn2); pixDestroy(&pixg2); pixDestroy(&pixb2); pixDestroy(&pixv); pixDestroy(&pixd); return 0; }
main(int argc, char **argv) { l_int32 i, w, h, bx, by, bw, bh, index, rval, gval, bval; BOX *box; BOXA *boxa; PIX *pixm, *pixs, *pixg, *pixt, *pixd; PIXA *pixa; PIXCMAP *cmap; PTA *pta; PTAA *ptaa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixa = pixaCreate(0); /* ---------------- Shortest path in binary maze ---------------- */ /* Generate the maze */ pixm = generateBinaryMaze(200, 200, 20, 20, 0.65, 0.25); pixd = pixExpandBinaryReplicate(pixm, 3); pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32); pixDestroy(&pixd); /* Find the shortest path between two points */ pta = pixSearchBinaryMaze(pixm, 20, 20, 170, 170, NULL); pixt = pixDisplayPta(NULL, pixm, pta); pixd = pixScaleBySampling(pixt, 3., 3.); pixSaveTiledOutline(pixd, pixa, 1, 0, 20, 2, 32); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 0 */ ptaDestroy(&pta); pixDestroy(&pixt); pixDestroy(&pixd); pixDestroy(&pixm); /* ---------------- Shortest path in gray maze ---------------- */ pixg = pixRead("test8.jpg"); pixGetDimensions(pixg, &w, &h, NULL); ptaa = ptaaCreate(NPATHS); for (i = 0; i < NPATHS; i++) { if (x0[i] >= w || x1[i] >= w || y0[i] >= h || y1[i] >= h) { fprintf(stderr, "path %d extends beyond image; skipping\n", i); continue; } pta = pixSearchGrayMaze(pixg, x0[i], y0[i], x1[i], y1[i], NULL); ptaaAddPta(ptaa, pta, L_INSERT); } pixt = pixDisplayPtaa(pixg, ptaa); pixd = pixScaleBySampling(pixt, 2., 2.); pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 1 */ ptaaDestroy(&ptaa); pixDestroy(&pixg); pixDestroy(&pixt); pixDestroy(&pixd); /* ---------------- Largest rectangles in image ---------------- */ pixs = pixRead("test1.png"); pixd = pixConvertTo8(pixs, FALSE); cmap = pixcmapCreateRandom(8, 1, 1); pixSetColormap(pixd, cmap); boxa = boxaCreate(0); for (i = 0; i < NBOXES; i++) { pixFindLargestRectangle(pixs, POLARITY, &box, NULL); boxGetGeometry(box, &bx, &by, &bw, &bh); pixSetInRect(pixs, box); fprintf(stderr, "bx = %5d, by = %5d, bw = %5d, bh = %5d, area = %d\n", bx, by, bw, bh, bw * bh); boxaAddBox(boxa, box, L_INSERT); } for (i = 0; i < NBOXES; i++) { index = 32 + (i & 254); pixcmapGetColor(cmap, index, &rval, &gval, &bval); box = boxaGetBox(boxa, i, L_CLONE); pixRenderHashBoxArb(pixd, box, 6, 2, L_NEG_SLOPE_LINE, 1, rval, gval, bval); boxDestroy(&box); } pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 2 */ pixDestroy(&pixs); pixDestroy(&pixd); boxaDestroy(&boxa); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 3 */ pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixa); return regTestCleanup(rp); }
l_int32 main(int argc, char **argv) { l_int32 i, n; l_float32 a, b, c; L_DEWARP *dew, *dew2; DPIX *dpix1, *dpix2, *dpix3; FPIX *fpix1, *fpix2, *fpix3; NUMA *nax, *nafit; PIX *pixs, *pixn, *pixg, *pixb, *pixt1, *pixt2; PIX *pixs2, *pixn2, *pixg2, *pixb2; PTA *pta, *ptad; PTAA *ptaa1, *ptaa2; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("1555-7.jpg"); /* Normalize for varying background and binarize */ pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); pixDestroy(&pixn); pixDestroy(&pixg); regTestWritePixAndCheck(rp, pixb, IFF_PNG); /* 0 */ pixDisplayWithTitle(pixb, 0, 0, "binarized input", rp->display); /* Get the textline centers */ ptaa1 = pixGetTextlineCenters(pixb, 0); pixt1 = pixCreateTemplate(pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa1); regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 1 */ pixDisplayWithTitle(pixt2, 0, 500, "textline centers", rp->display); pixDestroy(&pixt1); /* Remove short lines */ ptaa2 = ptaaRemoveShortLines(pixb, ptaa1, 0.8, 0); /* Fit to quadratic */ n = ptaaGetCount(ptaa2); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetQuadraticLSF(pta, &a, &b, &c, &nafit); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt2, pixt2, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 2 */ pixDisplayWithTitle(pixt2, 300, 500, "fitted lines superimposed", rp->display); ptaaDestroy(&ptaa1); ptaaDestroy(&ptaa2); pixDestroy(&pixt2); /* Run with only vertical disparity correction */ if ((dew = dewarpCreate(pixb, 7, 30, 15, 0)) == NULL) return ERROR_INT("\n\n\n FAILURE !!! \n\n\n", rp->testname, 1); dewarpBuildModel(dew, 0); dewarpApplyDisparity(dew, pixb, 0); regTestWritePixAndCheck(rp, dew->pixd, IFF_PNG); /* 3 */ pixDisplayWithTitle(dew->pixd, 400, 0, "fixed for vert disparity", rp->display); dewarpDestroy(&dew); /* Run with both vertical and horizontal disparity correction */ if ((dew = dewarpCreate(pixb, 7, 30, 15, 1)) == NULL) return ERROR_INT("\n\n\n FAILURE !!! \n\n\n", rp->testname, 1); dewarpBuildModel(dew, 0); dewarpApplyDisparity(dew, pixb, 0); regTestWritePixAndCheck(rp, dew->pixd, IFF_PNG); /* 4 */ pixDisplayWithTitle(dew->pixd, 800, 0, "fixed for both disparities", rp->display); /* Read another image, normalize background and binarize */ pixs2 = pixRead("1555-3.jpg"); pixn2 = pixBackgroundNormSimple(pixs2, NULL, NULL); pixg2 = pixConvertRGBToGray(pixn2, 0.5, 0.3, 0.2); pixb2 = pixThresholdToBinary(pixg2, 130); pixDestroy(&pixn2); pixDestroy(&pixg2); regTestWritePixAndCheck(rp, pixb, IFF_PNG); /* 5 */ pixDisplayWithTitle(pixb, 0, 400, "binarized input (2)", rp->display); /* Minimize and re-apply previous disparity to this image */ dewarpMinimize(dew); dewarpApplyDisparity(dew, pixb2, 0); regTestWritePixAndCheck(rp, dew->pixd, IFF_PNG); /* 6 */ pixDisplayWithTitle(dew->pixd, 400, 400, "fixed (2) for both disparities", rp->display); /* Write and read back minimized dewarp struct */ dewarpWrite("/tmp/dewarp.7.dew", dew); regTestCheckFile(rp, "/tmp/dewarp.7.dew"); /* 7 */ dew2 = dewarpRead("/tmp/dewarp.7.dew"); dewarpWrite("/tmp/dewarp.8.dew", dew2); regTestCheckFile(rp, "/tmp/dewarp.8.dew"); /* 8 */ regTestCompareFiles(rp, 7, 8); /* 9 */ /* Apply dew2 to pixb2 */ dewarpApplyDisparity(dew2, pixb2, 0); regTestWritePixAndCheck(rp, dew2->pixd, IFF_PNG); /* 10 */ pixDisplayWithTitle(dew->pixd, 800, 400, "fixed (3) for both disparities", rp->display); /* Minimize, repopulate disparity arrays, and apply again */ dewarpMinimize(dew2); dewarpApplyDisparity(dew2, pixb2, 0); regTestWritePixAndCheck(rp, dew2->pixd, IFF_PNG); /* 11 */ regTestCompareFiles(rp, 10, 11); /* 12 */ pixDisplayWithTitle(dew->pixd, 900, 400, "fixed (4) for both disparities", rp->display); /* Test a few of the fpix functions */ fpix1 = fpixClone(dew->sampvdispar); fpixWrite("/tmp/sampv.13.fpix", fpix1); regTestCheckFile(rp, "/tmp/sampv.13.fpix"); /* 13 */ fpix2 = fpixRead("/tmp/sampv.13.fpix"); fpixWrite("/tmp/sampv.14.fpix", fpix2); regTestCheckFile(rp, "/tmp/sampv.14.fpix"); /* 14 */ regTestCompareFiles(rp, 13, 14); /* 15 */ fpix3 = fpixScaleByInteger(fpix2, 30); pixt1 = fpixRenderContours(fpix3, -2., 2.0, 0.2); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 16 */ pixDisplayWithTitle(pixt1, 0, 800, "v. disparity contours", rp->display); fpixDestroy(&fpix1); fpixDestroy(&fpix2); fpixDestroy(&fpix3); pixDestroy(&pixt1); /* Test a few of the dpix functions */ dpix1 = fpixConvertToDPix(dew->sampvdispar); dpixWrite("/tmp/sampv.17.dpix", dpix1); regTestCheckFile(rp, "/tmp/sampv.17.dpix"); /* 17 */ dpix2 = dpixRead("/tmp/sampv.17.dpix"); dpixWrite("/tmp/sampv.18.dpix", dpix2); regTestCheckFile(rp, "/tmp/sampv.18.dpix"); /* 18 */ regTestCompareFiles(rp, 17, 18); /* 19 */ dpix3 = dpixScaleByInteger(dpix2, 30); fpix3 = dpixConvertToFPix(dpix3); pixt1 = fpixRenderContours(fpix3, -2., 2.0, 0.2); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 20 */ pixDisplayWithTitle(pixt1, 400, 800, "v. disparity contours", rp->display); regTestCompareFiles(rp, 16, 20); /* 21 */ dpixDestroy(&dpix1); dpixDestroy(&dpix2); dpixDestroy(&dpix3); fpixDestroy(&fpix3); pixDestroy(&pixt1); dewarpDestroy(&dew); dewarpDestroy(&dew2); pixDestroy(&pixs); pixDestroy(&pixb); pixDestroy(&pixs2); pixDestroy(&pixb2); regTestCleanup(rp); return 0; }