/*! * dewarpDebug() * * Input: dew * subdir (a subdirectory of /tmp; e.g., "dew1") * index (to help label output images; e.g., the page number) * Return: 0 if OK, 1 on error * * Notes: * (1) Prints dewarp fields and generates disparity array contour images. * The contour images are written to file: * /tmp/[subdir]/pixv_[index].png */ l_int32 dewarpDebug(L_DEWARP *dew, const char *subdir, l_int32 index) { char outdir[256], fname[64]; char *pathname; l_int32 svd, shd; PIX *pixv, *pixh; PROCNAME("dewarpDebug"); if (!dew) return ERROR_INT("dew not defined", procName, 1); if (!subdir) return ERROR_INT("subdir not defined", procName, 1); fprintf(stderr, "pageno = %d, hasref = %d, refpage = %d\n", dew->pageno, dew->hasref, dew->refpage); fprintf(stderr, "sampling = %d, redfactor = %d, minlines = %d\n", dew->sampling, dew->redfactor, dew->minlines); svd = shd = 0; if (!dew->hasref) { if (dew->sampvdispar) svd = 1; if (dew->samphdispar) shd = 1; fprintf(stderr, "sampv = %d, samph = %d\n", svd, shd); fprintf(stderr, "w = %d, h = %d\n", dew->w, dew->h); fprintf(stderr, "nx = %d, ny = %d\n", dew->nx, dew->ny); fprintf(stderr, "nlines = %d\n", dew->nlines); if (svd) { fprintf(stderr, "(min,max,abs-diff) line curvature = (%d,%d,%d)\n", dew->mincurv, dew->maxcurv, dew->maxcurv - dew->mincurv); } if (shd) { fprintf(stderr, "(left edge slope = %d, right edge slope = %d\n", dew->leftslope, dew->rightslope); fprintf(stderr, "(left,right,abs-diff) edge curvature = " "(%d,%d,%d)\n", dew->leftcurv, dew->rightcurv, L_ABS(dew->leftcurv - dew->rightcurv)); } } if (!svd && !shd) { fprintf(stderr, "No disparity arrays\n"); return 0; } dewarpPopulateFullRes(dew, NULL, 0, 0); lept_mkdir(subdir); snprintf(outdir, sizeof(outdir), "/tmp/%s", subdir); if (svd) { pixv = fpixRenderContours(dew->fullvdispar, 3.0, 0.15); snprintf(fname, sizeof(fname), "pixv_%d.png", index); pathname = genPathname(outdir, fname); pixWrite(pathname, pixv, IFF_PNG); pixDestroy(&pixv); FREE(pathname); } if (shd) { pixh = fpixRenderContours(dew->fullhdispar, 3.0, 0.15); snprintf(fname, sizeof(fname), "pixh_%d.png", index); pathname = genPathname(outdir, fname); pixWrite(pathname, pixh, IFF_PNG); pixDestroy(&pixh); FREE(pathname); } return 0; }
/*! * dewarpaShowArrays() * * Input: dewa * scalefact (on contour images; typ. 0.5) * first (first page model to render) * last (last page model to render; use 0 to go to end) * fontdir (for text bitmap fonts) * Return: 0 if OK, 1 on error * * Notes: * (1) Generates a pdf of contour plots of the disparity arrays. * (2) This only shows actual models; not ref models */ l_int32 dewarpaShowArrays(L_DEWARPA *dewa, l_float32 scalefact, l_int32 first, l_int32 last, const char *fontdir) { char buf[256]; char *pathname; l_int32 i, svd, shd; L_BMF *bmf; L_DEWARP *dew; PIX *pixv, *pixvs, *pixh, *pixhs, *pixt, *pixd; PIXA *pixa; PROCNAME("dewarpaShowArrays"); if (!dewa) return ERROR_INT("dew not defined", procName, 1); if (first < 0 || first > dewa->maxpage) return ERROR_INT("first out of bounds", procName, 1); if (last <= 0 || last > dewa->maxpage) last = dewa->maxpage; if (last < first) return ERROR_INT("last < first", procName, 1); lept_rmdir("lept"); lept_mkdir("lept"); if ((bmf = bmfCreate(fontdir, 8)) == NULL) L_ERROR("bmf not made; page info not displayed", procName); fprintf(stderr, "Generating contour plots\n"); for (i = first; i <= last; i++) { if (i && ((i % 10) == 0)) fprintf(stderr, " .. %d", i); dew = dewarpaGetDewarp(dewa, i); if (!dew) continue; if (dew->hasref == 1) continue; svd = shd = 0; if (dew->sampvdispar) svd = 1; if (dew->samphdispar) shd = 1; if (!svd) { L_ERROR("sampvdispar not made for page %d!\n", procName, i); continue; } /* Generate contour plots at reduced resolution */ dewarpPopulateFullRes(dew, NULL, 0, 0); pixv = fpixRenderContours(dew->fullvdispar, 3.0, 0.15); pixvs = pixScaleBySampling(pixv, scalefact, scalefact); pixDestroy(&pixv); if (shd) { pixh = fpixRenderContours(dew->fullhdispar, 3.0, 0.15); pixhs = pixScaleBySampling(pixh, scalefact, scalefact); pixDestroy(&pixh); } dewarpMinimize(dew); /* Save side-by-side */ pixa = pixaCreate(2); pixaAddPix(pixa, pixvs, L_INSERT); if (shd) pixaAddPix(pixa, pixhs, L_INSERT); pixt = pixaDisplayTiledInRows(pixa, 32, 1500, 1.0, 0, 30, 2); snprintf(buf, sizeof(buf), "Page %d", i); pixd = pixAddSingleTextblock(pixt, bmf, buf, 0x0000ff00, L_ADD_BELOW, NULL); snprintf(buf, sizeof(buf), "arrays_%04d.png", i); pathname = genPathname("/tmp/lept", buf); pixWrite(pathname, pixd, IFF_PNG); pixaDestroy(&pixa); pixDestroy(&pixt); pixDestroy(&pixd); FREE(pathname); } bmfDestroy(&bmf); fprintf(stderr, "\n"); fprintf(stderr, "Generating pdf of contour plots\n"); convertFilesToPdf("/tmp/lept", "arrays_", 90, 1.0, L_FLATE_ENCODE, 0, "Disparity arrays", "/tmp/lept/disparity_arrays.pdf"); fprintf(stderr, "Output written to: /tmp/lept/disparity_arrays.pdf\n"); return 0; }
main(int argc, char **argv) { l_float32 sum, sumx, sumy, diff; L_DEWARP *dew; L_DEWARPA *dewa; FPIX *fpixs, *fpixs2, *fpixs3, *fpixs4, *fpixg, *fpixd; FPIX *fpix1, *fpix2, *fpixt1, *fpixt2; DPIX *dpix, *dpix2; L_KERNEL *kel, *kelx, *kely; PIX *pixs, *pixs2, *pixs3, *pixt, *pixd, *pixg, *pixb, *pixn; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIXA *pixa; PTA *ptas, *ptad; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixa = pixaCreate(0); /* Gaussian kernel */ kel = makeGaussianKernel(5, 5, 3.0, 4.0); kernelGetSum(kel, &sum); if (rp->display) fprintf(stderr, "Sum for 2d gaussian kernel = %f\n", sum); pixt = kernelDisplayInPix(kel, 41, 2); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 0 */ pixSaveTiled(pixt, pixa, 1, 1, 20, 8); pixDestroy(&pixt); /* Separable gaussian kernel */ makeGaussianKernelSep(5, 5, 3.0, 4.0, &kelx, &kely); kernelGetSum(kelx, &sumx); if (rp->display) fprintf(stderr, "Sum for x gaussian kernel = %f\n", sumx); kernelGetSum(kely, &sumy); if (rp->display) fprintf(stderr, "Sum for y gaussian kernel = %f\n", sumy); if (rp->display) fprintf(stderr, "Sum for x * y gaussian kernel = %f\n", sumx * sumy); pixt = kernelDisplayInPix(kelx, 41, 2); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 1 */ pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); pixt = kernelDisplayInPix(kely, 41, 2); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 2 */ pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); /* Use pixRasterop() to generate source image */ pixs = pixRead("test8.jpg"); pixs2 = pixRead("karen8.jpg"); pixRasterop(pixs, 150, 125, 150, 100, PIX_SRC, pixs2, 75, 100); regTestWritePixAndCheck(rp, pixs, IFF_JFIF_JPEG); /* 3 */ /* Convolution directly with pix */ pixt1 = pixConvolve(pixs, kel, 8, 1); regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 4 */ pixSaveTiled(pixt1, pixa, 1, 1, 20, 8); pixt2 = pixConvolveSep(pixs, kelx, kely, 8, 1); regTestWritePixAndCheck(rp, pixt2, IFF_JFIF_JPEG); /* 5 */ pixSaveTiled(pixt2, pixa, 1, 0, 20, 8); /* Convolution indirectly with fpix, using fpixRasterop() * to generate the source image. */ fpixs = pixConvertToFPix(pixs, 3); fpixs2 = pixConvertToFPix(pixs2, 3); fpixRasterop(fpixs, 150, 125, 150, 100, fpixs2, 75, 100); fpixt1 = fpixConvolve(fpixs, kel, 1); pixt3 = fpixConvertToPix(fpixt1, 8, L_CLIP_TO_ZERO, 1); regTestWritePixAndCheck(rp, pixt3, IFF_JFIF_JPEG); /* 6 */ pixSaveTiled(pixt3, pixa, 1, 1, 20, 8); fpixt2 = fpixConvolveSep(fpixs, kelx, kely, 1); pixt4 = fpixConvertToPix(fpixt2, 8, L_CLIP_TO_ZERO, 1); regTestWritePixAndCheck(rp, pixt4, IFF_JFIF_JPEG); /* 7 */ pixSaveTiled(pixt4, pixa, 1, 0, 20, 8); pixDestroy(&pixs2); fpixDestroy(&fpixs2); fpixDestroy(&fpixt1); fpixDestroy(&fpixt2); /* Comparison of results */ pixCompareGray(pixt1, pixt2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of pixConvolve and pixConvolveSep: %f\n", diff); pixCompareGray(pixt3, pixt4, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of fpixConvolve and fpixConvolveSep: %f\n", diff); pixCompareGray(pixt1, pixt3, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of pixConvolve and fpixConvolve: %f\n", diff); pixCompareGray(pixt2, pixt4, L_COMPARE_ABS_DIFF, GPLOT_PNG, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of pixConvolveSep and fpixConvolveSep: %f\n", diff); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Test arithmetic operations; add in a fraction rotated by 180 */ pixs3 = pixRotate180(NULL, pixs); regTestWritePixAndCheck(rp, pixs3, IFF_JFIF_JPEG); /* 8 */ pixSaveTiled(pixs3, pixa, 1, 1, 20, 8); fpixs3 = pixConvertToFPix(pixs3, 3); fpixd = fpixLinearCombination(NULL, fpixs, fpixs3, 20.0, 5.0); fpixAddMultConstant(fpixd, 0.0, 23.174); /* multiply up in magnitude */ pixd = fpixDisplayMaxDynamicRange(fpixd); /* bring back to 8 bpp */ regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 9 */ pixSaveTiled(pixd, pixa, 1, 0, 20, 8); pixDestroy(&pixs3); fpixDestroy(&fpixs3); fpixDestroy(&fpixd); pixDestroy(&pixd); pixDestroy(&pixs); fpixDestroy(&fpixs); /* Save the comparison graph; gnuplot should have made it by now! */ #ifndef _WIN32 sleep(2); #else Sleep(2000); #endif /* _WIN32 */ pixt5 = pixRead("/tmp/grayroot.png"); regTestWritePixAndCheck(rp, pixt5, IFF_PNG); /* 10 */ pixSaveTiled(pixt5, pixa, 1, 1, 20, 8); pixDestroy(&pixt5); /* Display results */ pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 11 */ pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixa); /* Test some more convolutions, with sampled output. First on pix */ pixa = pixaCreate(0); pixs = pixRead("1555-7.jpg"); pixg = pixConvertTo8(pixs, 0); l_setConvolveSampling(5, 5); pixt1 = pixConvolve(pixg, kel, 8, 1); regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 12 */ pixSaveTiled(pixt1, pixa, 1, 1, 20, 32); pixt2 = pixConvolveSep(pixg, kelx, kely, 8, 1); regTestWritePixAndCheck(rp, pixt2, IFF_JFIF_JPEG); /* 13 */ pixSaveTiled(pixt2, pixa, 1, 0, 20, 32); pixt3 = pixConvolveRGB(pixs, kel); regTestWritePixAndCheck(rp, pixt3, IFF_JFIF_JPEG); /* 14 */ pixSaveTiled(pixt3, pixa, 1, 0, 20, 32); pixt4 = pixConvolveRGBSep(pixs, kelx, kely); regTestWritePixAndCheck(rp, pixt4, IFF_JFIF_JPEG); /* 15 */ pixSaveTiled(pixt4, pixa, 1, 0, 20, 32); /* Then on fpix */ fpixg = pixConvertToFPix(pixg, 1); fpixt1 = fpixConvolve(fpixg, kel, 1); pixt5 = fpixConvertToPix(fpixt1, 8, L_CLIP_TO_ZERO, 0); regTestWritePixAndCheck(rp, pixt5, IFF_JFIF_JPEG); /* 16 */ pixSaveTiled(pixt5, pixa, 1, 1, 20, 32); fpixt2 = fpixConvolveSep(fpixg, kelx, kely, 1); pixt6 = fpixConvertToPix(fpixt2, 8, L_CLIP_TO_ZERO, 0); regTestWritePixAndCheck(rp, pixt6, IFF_JFIF_JPEG); /* 17 */ pixSaveTiled(pixt2, pixa, 1, 0, 20, 32); regTestCompareSimilarPix(rp, pixt1, pixt5, 2, 0.00, 0); /* 18 */ regTestCompareSimilarPix(rp, pixt2, pixt6, 2, 0.00, 0); /* 19 */ pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); fpixDestroy(&fpixg); fpixDestroy(&fpixt1); fpixDestroy(&fpixt2); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 20 */ pixDisplayWithTitle(pixd, 600, 100, NULL, rp->display); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixd); pixaDestroy(&pixa); /* Test extension (continued and slope). * First, build a smooth vertical disparity array; * then extend and show the contours. */ pixs = pixRead("cat-35.jpg"); pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); dewa = dewarpaCreate(1, 30, 1, 15, 0); dew = dewarpCreate(pixb, 35); dewarpaInsertDewarp(dewa, dew); dewarpBuildModel(dew, NULL); dewarpPopulateFullRes(dew, NULL); fpixs = dew->fullvdispar; fpixs2 = fpixAddContinuedBorder(fpixs, 200, 200, 100, 300); fpixs3 = fpixAddSlopeBorder(fpixs, 200, 200, 100, 300); dpix = fpixConvertToDPix(fpixs3); fpixs4 = dpixConvertToFPix(dpix); pixt1 = fpixRenderContours(fpixs, 2.0, 0.2); pixt2 = fpixRenderContours(fpixs2, 2.0, 0.2); pixt3 = fpixRenderContours(fpixs3, 2.0, 0.2); pixt4 = fpixRenderContours(fpixs4, 2.0, 0.2); pixt5 = pixRead("karen8.jpg"); dpix2 = pixConvertToDPix(pixt5, 1); pixt6 = dpixConvertToPix(dpix2, 8, L_CLIP_TO_ZERO, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 21 */ pixDisplayWithTitle(pixt1, 0, 100, NULL, rp->display); regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 22 */ pixDisplayWithTitle(pixt2, 470, 100, NULL, rp->display); regTestWritePixAndCheck(rp, pixt3, IFF_PNG); /* 23 */ pixDisplayWithTitle(pixt3, 1035, 100, NULL, rp->display); regTestComparePix(rp, pixt3, pixt4); /* 24 */ regTestComparePix(rp, pixt5, pixt6); /* 25 */ pixDestroy(&pixs); pixDestroy(&pixn); pixDestroy(&pixg); pixDestroy(&pixb); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); fpixDestroy(&fpixs2); fpixDestroy(&fpixs3); fpixDestroy(&fpixs4); dpixDestroy(&dpix); dpixDestroy(&dpix2); /* Test affine and projective transforms on fpix */ fpixWrite("/tmp/fpix1.fp", dew->fullvdispar); fpix1 = fpixRead("/tmp/fpix1.fp"); pixt1 = fpixAutoRenderContours(fpix1, 40); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 26 */ pixDisplayWithTitle(pixt1, 0, 500, NULL, rp->display); pixDestroy(&pixt1); MakePtasAffine(1, &ptas, &ptad); fpix2 = fpixAffinePta(fpix1, ptad, ptas, 200, 0.0); pixt2 = fpixAutoRenderContours(fpix2, 40); regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 27 */ pixDisplayWithTitle(pixt2, 400, 500, NULL, rp->display); fpixDestroy(&fpix2); pixDestroy(&pixt2); ptaDestroy(&ptas); ptaDestroy(&ptad); MakePtas(1, &ptas, &ptad); fpix2 = fpixProjectivePta(fpix1, ptad, ptas, 200, 0.0); pixt3 = fpixAutoRenderContours(fpix2, 40); regTestWritePixAndCheck(rp, pixt3, IFF_PNG); /* 28 */ pixDisplayWithTitle(pixt3, 400, 500, NULL, rp->display); fpixDestroy(&fpix2); pixDestroy(&pixt3); ptaDestroy(&ptas); ptaDestroy(&ptad); fpixDestroy(&fpix1); dewarpaDestroy(&dewa); kernelDestroy(&kel); kernelDestroy(&kelx); kernelDestroy(&kely); 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 main(int argc, char **argv) { L_DEWARP *dew1, *dew2, *dew3; L_DEWARPA *dewa1, *dewa2, *dewa3; PIX *pixs, *pixn, *pixg, *pixb, *pixd; PIX *pixs2, *pixn2, *pixg2, *pixb2, *pixd2; PIX *pixd3, *pixc1, *pixc2; /* pixs = pixRead("1555-7.jpg"); */ pixs = pixRead("cat-35.jpg"); dewa1 = dewarpaCreate(40, 30, 1, 15, 10); dewarpaUseBothArrays(dewa1, 1); /* 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 */ dew1 = dewarpCreate(pixb, 35); dewarpaInsertDewarp(dewa1, dew1); dewarpBuildPageModel(dew1, "/tmp/dewarp_junk35.pdf"); /* debug output */ dewarpPopulateFullRes(dew1, pixg, 0, 0); dewarpaApplyDisparity(dewa1, 35, pixg, 200, 0, 0, &pixd, "/tmp/dewarp_debug_35.pdf"); /* Normalize another image. */ /* pixs2 = pixRead("1555-3.jpg"); */ pixs2 = pixRead("cat-7.jpg"); pixn2 = pixBackgroundNormSimple(pixs2, NULL, NULL); pixg2 = pixConvertRGBToGray(pixn2, 0.5, 0.3, 0.2); pixb2 = pixThresholdToBinary(pixg2, 130); /* Run the basic functions */ dew2 = dewarpCreate(pixb2, 7); dewarpaInsertDewarp(dewa1, dew2); dewarpBuildPageModel(dew2, "/tmp/dewarp_junk7.pdf"); dewarpaApplyDisparity(dewa1, 7, pixg, 200, 0, 0, &pixd2, "/tmp/dewarp_debug_7.pdf"); /* Serialize and deserialize dewarpa */ dewarpaWrite("/tmp/dewarpa1.dewa", dewa1); dewa2 = dewarpaRead("/tmp/dewarpa1.dewa"); dewarpaWrite("/tmp/dewarpa2.dewa", dewa2); dewa3 = dewarpaRead("/tmp/dewarpa2.dewa"); dewarpDebug(dewa3->dewarp[7], "dew1", 7); dewarpaWrite("/tmp/dewarpa3.dewa", dewa3); /* Repopulate and show the vertical disparity arrays */ dewarpPopulateFullRes(dew1, NULL, 0, 0); pixc1 = fpixRenderContours(dew1->fullvdispar, 2.0, 0.2); pixDisplay(pixc1, 1400, 900); dew3 = dewarpaGetDewarp(dewa2, 35); dewarpPopulateFullRes(dew3, pixs, 0, 0); pixc2 = fpixRenderContours(dew3->fullvdispar, 2.0, 0.2); pixDisplay(pixc2, 1400, 900); dewarpaApplyDisparity(dewa2, 35, pixb, 200, 0, 0, &pixd3, "/tmp/dewarp_debug_35b.pdf"); pixDisplay(pixd, 0, 1000); pixDisplay(pixd2, 600, 1000); pixDisplay(pixd3, 1200, 1000); pixDestroy(&pixd3); dewarpaDestroy(&dewa1); dewarpaDestroy(&dewa2); dewarpaDestroy(&dewa3); pixDestroy(&pixs); pixDestroy(&pixn); pixDestroy(&pixg); pixDestroy(&pixb); pixDestroy(&pixd); pixDestroy(&pixs2); pixDestroy(&pixn2); pixDestroy(&pixg2); pixDestroy(&pixb2); pixDestroy(&pixd2); pixDestroy(&pixc1); pixDestroy(&pixc2); return 0; }
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; }