Пример #1
0
/*!
 *  ptaaSortByIndex()
 *
 *      Input:  ptaas
 *              naindex (na that maps from the new ptaa to the input ptaa)
 *      Return: ptaad (sorted), or null on error
 */
PTAA *
ptaaSortByIndex(PTAA  *ptaas,
                NUMA  *naindex)
{
l_int32  i, n, index;
PTA     *pta;
PTAA    *ptaad;

    PROCNAME("ptaaSortByIndex");

    if (!ptaas)
        return (PTAA *)ERROR_PTR("ptaas not defined", procName, NULL);
    if (!naindex)
        return (PTAA *)ERROR_PTR("naindex not defined", procName, NULL);

    n = ptaaGetCount(ptaas);
    if (numaGetCount(naindex) != n)
        return (PTAA *)ERROR_PTR("numa and ptaa sizes differ", procName, NULL);
    ptaad = ptaaCreate(n);
    for (i = 0; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        pta = ptaaGetPta(ptaas, index, L_COPY);
        ptaaAddPta(ptaad, pta, L_INSERT);
    }

    return ptaad;
}
Пример #2
0
/*!
 *  ptaaRemoveShortLines()
 *
 *      Input:  pixs (1 bpp)
 *              ptaas (input lines)
 *              fract (minimum fraction of longest line to keep)
 *              debugflag
 *      Return: ptaad (containing only lines of sufficient length),
 *                     or null on error
 */
PTAA *
ptaaRemoveShortLines(PIX       *pixs,
                     PTAA      *ptaas,
                     l_float32  fract,
                     l_int32    debugflag)
{
l_int32    w, n, i, index, maxlen, len;
l_float32  minx, maxx;
NUMA      *na, *naindex;
PIX       *pixt1, *pixt2;
PTA       *pta;
PTAA      *ptaad;

    PROCNAME("ptaaRemoveShortLines");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (PTAA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (!ptaas)
        return (PTAA *)ERROR_PTR("ptaas undefined", procName, NULL);

    pixGetDimensions(pixs, &w, NULL, NULL);
    n = ptaaGetCount(ptaas);
    ptaad = ptaaCreate(n);
    na = numaCreate(n);
    for (i = 0; i < n; i++) {
        pta = ptaaGetPta(ptaas, i, L_CLONE);
        ptaGetRange(pta, &minx, &maxx, NULL, NULL);
        numaAddNumber(na, maxx - minx + 1);
        ptaDestroy(&pta);
    }

        /* Sort by length and find all that are long enough */
    naindex = numaGetSortIndex(na, L_SORT_DECREASING);
    numaGetIValue(naindex, 0, &index);
    numaGetIValue(na, index, &maxlen);
    if (maxlen < 0.5 * w)
        L_WARNING("lines are relatively short", procName);
    pta = ptaaGetPta(ptaas, index, L_CLONE);
    ptaaAddPta(ptaad, pta, L_INSERT);
    for (i = 1; i < n; i++) {
        numaGetIValue(naindex, i, &index);
        numaGetIValue(na, index, &len);
        if (len < fract * maxlen) break;
        pta = ptaaGetPta(ptaas, index, L_CLONE);
        ptaaAddPta(ptaad, pta, L_INSERT);
    }

    if (debugflag) {
        pixt1 = pixCopy(NULL, pixs);
        pixt2 = pixDisplayPtaa(pixt1, ptaad);
        pixDisplayWithTitle(pixt2, 0, 200, "pix4", 1);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }

    numaDestroy(&na);
    numaDestroy(&naindex);
    return ptaad;
}
Пример #3
0
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;
}
Пример #4
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);
}
Пример #5
0
/*!
 *  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;
}
Пример #6
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;
}
Пример #7
0
/*!
 * \brief   pixConnCompIncrAdd()
 *
 * \param[in]     pixs 32 bpp, with pixels labeled by c.c.
 * \param[in]     ptaa with each pta of pixel locations indexed by c.c.
 * \param[out]    pncc number of c.c
 * \param[in]     x,y location of added pixel
 * \param[in]     debug 0 for no output; otherwise output whenever
 *                      debug <= nvals, up to debug == 3
 * \return   -1 if nothing happens; 0 if a pixel is added; 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This adds a pixel and updates the labeled connected components.
 *          Before calling this function, initialize the process using
 *          pixConnCompIncrInit().
 *      (2) As a result of adding a pixel, one of the following can happen,
 *          depending on the number of neighbors with non-zero value:
 *          (a) nothing: the pixel is already a member of a c.c.
 *          (b) no neighbors: a new component is added, increasing the
 *              number of c.c.
 *          (c) one neighbor: the pixel is added to an existing c.c.
 *          (d) more than one neighbor: the added pixel causes joining of
 *              two or more c.c., reducing the number of c.c.  A maximum
 *              of 4 c.c. can be joined.
 *      (3) When two c.c. are joined, the pixels in the larger index are
 *          relabeled to those of the smaller in pixs, and their locations
 *          are transferred to the pta with the smaller index in the ptaa.
 *          The pta corresponding to the larger index is then deleted.
 *      (4) This is an efficient implementation of a "union-find" operation,
 *          which supports the generation and merging of disjoint sets
 *          of pixels.  This function can be called about 1.3 million times
 *          per second.
 * </pre>
 */
l_int32
pixConnCompIncrAdd(PIX       *pixs,
                   PTAA      *ptaa,
                   l_int32   *pncc,
                   l_float32  x,
                   l_float32  y,
                   l_int32    debug)
{
l_int32   conn, i, j, w, h, count, nvals, ns, firstindex;
l_uint32  val;
l_int32  *neigh;
PTA      *ptas, *ptad;

    PROCNAME("pixConnCompIncrAdd");

    if (!pixs || pixGetDepth(pixs) != 32)
        return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);
    if (!pncc)
        return ERROR_INT("&ncc not defined", procName, 1);
    conn = pixs->special;
    if (conn != 4 && conn != 8)
        return ERROR_INT("connectivity must be 4 or 8", procName, 1);
    pixGetDimensions(pixs, &w, &h, NULL);
    if (x < 0 || x >= w)
        return ERROR_INT("invalid x pixel location", procName, 1);
    if (y < 0 || y >= h)
        return ERROR_INT("invalid y pixel location", procName, 1);

    pixGetPixel(pixs, x, y, &val);
    if (val > 0)  /* already belongs to a set */
        return -1;

        /* Find unique neighbor pixel values in increasing order of value.
         * If %nvals > 0, these are returned in the %neigh array, which
         * is of size %nvals.  Note that the pixel values in each
         * connected component are used as the index into the pta
         * array of the ptaa, giving the pixel locations. */
    pixGetSortedNeighborValues(pixs, x, y, conn, &neigh, &nvals);

        /* If there are no neighbors, just add a new component */
    if (nvals == 0) {
        count = ptaaGetCount(ptaa);
        pixSetPixel(pixs, x, y, count);
        ptas = ptaCreate(1);
        ptaAddPt(ptas, x, y);
        ptaaAddPta(ptaa, ptas, L_INSERT);
        *pncc += 1;
        LEPT_FREE(neigh);
        return 0;
    }

        /* Otherwise, there is at least one neighbor.  Add the pixel
         * to the first neighbor c.c. */
    firstindex = neigh[0];
    pixSetPixel(pixs, x, y, firstindex);
    ptaaAddPt(ptaa, neigh[0], x, y);
    if (nvals == 1) {
        if (debug == 1)
            fprintf(stderr, "nvals = %d: neigh = (%d)\n", nvals, neigh[0]);
        LEPT_FREE(neigh);
        return 0;
    }

        /* If nvals > 1, there are at least 2 neighbors, so this pixel
         * joins at least one pair of existing c.c.  Join each component
         * to the first component in the list, which is the one with
         * the smallest integer label.  This is done in two steps:
         *  (a) re-label the pixels in the component to the label of the
         *      first component, and
         *  (b) save the pixel locations in the pta for the first component. */
    if (nvals == 2) {
        if (debug >= 1 && debug <= 2) {
            fprintf(stderr, "nvals = %d: neigh = (%d,%d)\n", nvals,
                    neigh[0], neigh[1]);
        }
    } else if (nvals == 3) {
        if (debug >= 1 && debug <= 3) {
            fprintf(stderr, "nvals = %d: neigh = (%d,%d,%d)\n", nvals,
                    neigh[0], neigh[1], neigh[2]);
        }
    } else {  /* nvals == 4 */
        if (debug >= 1 && debug <= 4) {
            fprintf(stderr, "nvals = %d: neigh = (%d,%d,%d,%d)\n", nvals,
                    neigh[0], neigh[1], neigh[2], neigh[3]);
        }
    }
    ptad = ptaaGetPta(ptaa, firstindex, L_CLONE);
    for (i = 1; i < nvals; i++) {
        ptas = ptaaGetPta(ptaa, neigh[i], L_CLONE);
        ns = ptaGetCount(ptas);
        for (j = 0; j < ns; j++) {  /* relabel pixels */
            ptaGetPt(ptas, j, &x, &y);
            pixSetPixel(pixs, x, y, firstindex);
        }
        ptaJoin(ptad, ptas, 0, -1);  /* add relabeled pixel locations */
        *pncc -= 1;
        ptaDestroy(&ptaa->pta[neigh[i]]);
        ptaDestroy(&ptas);  /* the clone */
    }
    ptaDestroy(&ptad);  /* the clone */
    LEPT_FREE(neigh);
    return 0;
}
Пример #8
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;
}