예제 #1
0
파일: dewarp3.c 프로젝트: AAAyag/tess-two
/*!
 *  boxaApplyDisparity()
 *
 *      Input:  dew
 *              boxa
 *              direction (L_HORIZ or L_VERT)
 *              mapdir (1 if mapping forward from original to dewarped;
 *                      0 if backward)
 *      Return: boxad (modified by the disparity), or null on error
 */
static BOXA *
boxaApplyDisparity(L_DEWARP  *dew,
                   BOXA      *boxa,
                   l_int32    direction,
                   l_int32    mapdir)
{
l_int32     x, y, w, h, ib, ip, nbox, wpl;
l_float32   xn, yn;
l_float32  *data, *line;
BOX        *boxs, *boxd;
BOXA       *boxad;
FPIX       *fpix;
PTA        *ptas, *ptad;

    PROCNAME("boxaApplyDisparity");

    if (!dew)
        return (BOXA *)ERROR_PTR("dew not defined", procName, NULL);
    if (!boxa)
        return (BOXA *)ERROR_PTR("boxa not defined", procName, NULL);
    if (direction == L_VERT)
        fpix = dew->fullvdispar;
    else if (direction == L_HORIZ)
        fpix = dew->fullhdispar;
    else
        return (BOXA *)ERROR_PTR("invalid direction", procName, NULL);
    if (!fpix)
        return (BOXA *)ERROR_PTR("full disparity not defined", procName, NULL);
    fpixGetDimensions(fpix, &w, &h);

        /* Clip the output to the positive quadrant because all box
         * coordinates must be non-negative. */
    data = fpixGetData(fpix);
    wpl = fpixGetWpl(fpix);
    nbox = boxaGetCount(boxa);
    boxad = boxaCreate(nbox);
    for (ib = 0; ib < nbox; ib++) {
        boxs = boxaGetBox(boxa, ib, L_COPY);
        ptas = boxConvertToPta(boxs, 4);
        ptad = ptaCreate(4);
        for (ip = 0; ip < 4; ip++) {
            ptaGetIPt(ptas, ip, &x, &y);
            line = data + y * wpl;
            if (direction == L_VERT) {
                if (mapdir == 0)
                    yn = y - line[x];
                else
                    yn = y + line[x];
                yn = L_MAX(0, yn);
                ptaAddPt(ptad, x, yn);
            } else {  /* direction == L_HORIZ */
                if (mapdir == 0)
                    xn = x - line[x];
                else
                    xn = x + line[x];
                xn = L_MAX(0, xn);
                ptaAddPt(ptad, xn, y);
            }
        }
        boxd = ptaConvertToBox(ptad);
        boxaAddBox(boxad, boxd, L_INSERT);
        boxDestroy(&boxs);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    return boxad;
}
예제 #2
0
파일: dewarp.cpp 프로젝트: ONLYOFFICE/core
/*!
 *  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;
}
예제 #3
0
main(int    argc,
     char **argv)
{
l_int32      i, d, h;
l_float32    rat;
PIX         *pixs, *pixgb, *pixt1, *pixt2, *pixt3, *pixt4, *pixg, *pixd;
PIXA        *pixa;
PTA         *ptas, *ptad;
static char  mainName[] = "bilinear_reg";

    if (argc != 1)
	exit(ERROR_INT(" Syntax:  bilinear_reg", mainName, 1));

    pixs = pixRead("feyn.tif");
    pixg = pixScaleToGray3(pixs);

#if ALL
        /* Test non-invertability of sampling */
    pixa = pixaCreate(0);
    for (i = 1; i < 3; i++) {
        pixgb = pixAddBorder(pixg, ADDED_BORDER_PIXELS, 255);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixBilinearSampledPta(pixgb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 2, 1, 20, 8);
        pixt2 = pixBilinearSampledPta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 2, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixInvert(pixd, pixd);
        pixXor(pixd, pixd, pixg);
        pixSaveTiled(pixd, pixa, 2, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/junksamp.png", pixt1, IFF_PNG);
        pixDestroy(&pixgb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkbilin1.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 300);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
#endif

#if ALL
        /* Test non-invertability of interpolation */
    pixa = pixaCreate(0);
    for (i = 1; i < 3; i++) {
        pixgb = pixAddBorder(pixg, ADDED_BORDER_PIXELS, 255);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixBilinearPta(pixgb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 2, 1, 20, 8);
        pixt2 = pixBilinearPta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 2, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixInvert(pixd, pixd);
        pixXor(pixd, pixd, pixg);
        pixSaveTiled(pixd, pixa, 2, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/junkinterp.png", pixt1, IFF_PNG);
        pixDestroy(&pixgb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkbilin2.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 300);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
#endif

#if ALL   /* test with large distortion and inversion */
    MakePtas(0, &ptas, &ptad);
    pixa = pixaCreate(0);

    startTimer();
    pixt1 = pixBilinearSampledPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixBilinearSampled(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt1, pixa, 2, 1, 20, 8);

    startTimer();
    pixt2 = pixBilinearPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixBilinearInterpolated(): %6.2f sec\n",
           stopTimer());
    pixSaveTiled(pixt2, pixa, 2, 0, 20, 8);

    pixt3 = pixBilinearSampledPta(pixt1, ptad, ptas, L_BRING_IN_WHITE);
    pixSaveTiled(pixt3, pixa, 2, 0, 20, 8);
    pixt4 = pixBilinearPta(pixt2, ptad, ptas, L_BRING_IN_WHITE);
    pixSaveTiled(pixt4, pixa, 2, 0, 20, 8);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    pixDestroy(&pixt4);

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkbilin3.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 300);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);

    pixDestroy(&pixs);
    pixDestroy(&pixg);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

    return 0;
}
예제 #4
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");

        /* 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;
}
예제 #5
0
main(int    argc,
     char **argv)
{
l_int32       i, j, x, y, rval, gval, bval;
l_uint32      pixel;
l_float32     frval, fgval, fbval;
NUMA         *nahue, *nasat, *napk;
PIX          *pixs, *pixhsv, *pixh, *pixg, *pixf, *pixd;
PIX          *pixr, *pixt1, *pixt2, *pixt3;
PIXA         *pixa, *pixapk;
PTA          *ptapk;
L_REGPARAMS  *rp;
	l_chooseDisplayProg(L_DISPLAY_WITH_XV);

    if (regTestSetup(argc, argv, &rp))
        return 1;

        /* Make a graded frame color */
    pixs = pixCreate(650, 900, 32);
    for (i = 0; i < 900; i++) {
        rval = 40 + i / 30;
        for (j = 0; j < 650; j++) {
            gval = 255 - j / 30;
            bval = 70 + j / 30;
            composeRGBPixel(rval, gval, bval, &pixel);
            pixSetPixel(pixs, j, i, pixel);
        }
    }
            
        /* Place an image inside the frame and convert to HSV */
    pixt1 = pixRead("1555-3.jpg");
    pixt2 = pixScale(pixt1, 0.5, 0.5);
    pixRasterop(pixs, 100, 100, 2000, 2000, PIX_SRC, pixt2, 0, 0);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDisplayWithTitle(pixs, 400, 0, "Input image", rp->display);
    pixa = pixaCreate(0);
    pixhsv = pixConvertRGBToHSV(NULL, pixs);

        /* Work in the HS projection of HSV */
    pixh = pixMakeHistoHS(pixhsv, 5, &nahue, &nasat);
    pixg = pixMaxDynamicRange(pixh, L_LOG_SCALE);
    pixf = pixConvertGrayToFalseColor(pixg, 1.0);
    regTestWritePixAndCheck(rp, pixf, IFF_PNG);   /* 0 */
    pixDisplayWithTitle(pixf, 100, 0, "False color HS histo", rp->display);
    pixaAddPix(pixa, pixs, L_COPY);
    pixaAddPix(pixa, pixhsv, L_INSERT);
    pixaAddPix(pixa, pixg, L_INSERT);
    pixaAddPix(pixa, pixf, L_INSERT);
    gplotSimple1(nahue, GPLOT_PNG, "/tmp/junkhue", "Histogram of hue values");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixt3 = pixRead("/tmp/junkhue.png");
    regTestWritePixAndCheck(rp, pixt3, IFF_PNG);  /* 1 */
    pixDisplayWithTitle(pixt3, 100, 300, "Histo of hue", rp->display);
    pixaAddPix(pixa, pixt3, L_INSERT);
    gplotSimple1(nasat, GPLOT_PNG, "/tmp/junksat",
                 "Histogram of saturation values");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixt3 = pixRead("/tmp/junksat.png");
    regTestWritePixAndCheck(rp, pixt3, IFF_PNG);  /* 2 */
    pixDisplayWithTitle(pixt3, 100, 800, "Histo of saturation", rp->display);
    pixaAddPix(pixa, pixt3, L_INSERT);
    pixd = pixaDisplayTiledAndScaled(pixa, 32, 270, 7, 0, 30, 3);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pixd, 0, 400, "Hue and Saturation Mosaic", rp->display);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    numaDestroy(&nahue);
    numaDestroy(&nasat);

        /* Find all the peaks */
    pixFindHistoPeaksHSV(pixh, L_HS_HISTO, 20, 20, 6, 2.0,
                         &ptapk, &napk, &pixapk);
    numaWriteStream(stderr, napk);
    ptaWriteStream(stderr, ptapk, 1);
    pixd = pixaDisplayTiledInRows(pixapk, 32, 1400, 1.0, 0, 30, 2);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 4 */
    pixDisplayWithTitle(pixd, 0, 550, "Peaks in HS", rp->display);
    pixDestroy(&pixh);
    pixDestroy(&pixd);
    pixaDestroy(&pixapk);

        /* Make masks for each of the peaks */
    pixa = pixaCreate(0);
    pixr = pixScaleBySampling(pixs, 0.4, 0.4);
    for (i = 0; i < 6; i++) {
        ptaGetIPt(ptapk, i, &x, &y);
        pixt1 = pixMakeRangeMaskHS(pixr, y, 20, x, 20, L_INCLUDE_REGION);
        pixaAddPix(pixa, pixt1, L_INSERT);
        pixGetAverageMaskedRGB(pixr, pixt1, 0, 0, 1, L_MEAN_ABSVAL,
                               &frval, &fgval, &fbval);
        composeRGBPixel((l_int32)frval, (l_int32)fgval, (l_int32)fbval,
                        &pixel);
        pixt2 = pixCreateTemplate(pixr);
        pixSetAll(pixt2);
        pixPaintThroughMask(pixt2, pixt1, 0, 0, pixel);
        pixaAddPix(pixa, pixt2, L_INSERT);
        pixt3 = pixCreateTemplate(pixr);
        pixSetAllArbitrary(pixt3, pixel);
        pixaAddPix(pixa, pixt3, L_INSERT);
    }
    pixd = pixaDisplayTiledAndScaled(pixa, 32, 225, 3, 0, 30, 3);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 5 */
    pixDisplayWithTitle(pixd, 600, 0, "Masks over peaks", rp->display);
    pixDestroy(&pixs);
    pixDestroy(&pixr);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    ptaDestroy(&ptapk);
    numaDestroy(&napk);

    regTestCleanup(rp);
    return 0;
}
예제 #6
0
/*!
 *  wshedApply()
 *
 *      Input:  wshed (generated from wshedCreate())
 *      Return: 0 if OK, 1 on error
 *
 *  Iportant note:
 *      (1) This is buggy.  It seems to locate watersheds that are
 *          duplicates.  The watershed extraction after complete fill
 *          grabs some regions belonging to existing watersheds.
 *          See prog/watershedtest.c for testing.
 */
l_int32
wshedApply(L_WSHED *wshed) {
    char two_new_watersheds[] = "Two new watersheds";
    char seed_absorbed_into_seeded_basin[] = "Seed absorbed into seeded basin";
    char one_new_watershed_label[] = "One new watershed (label)";
    char one_new_watershed_index[] = "One new watershed (index)";
    char minima_absorbed_into_seeded_basin[] =
            "Minima absorbed into seeded basin";
    char minima_absorbed_by_filler_or_another[] =
            "Minima absorbed by filler or another";
    l_int32 nseeds, nother, nboth, arraysize;
    l_int32 i, j, val, x, y, w, h, index, mindepth;
    l_int32 imin, imax, jmin, jmax, cindex, clabel, nindex;
    l_int32 hindex, hlabel, hmin, hmax, minhindex, maxhindex;
    l_int32 *lut;
    l_uint32 ulabel, uval;
    void **lines8, **linelab32;
    NUMA *nalut, *nalevels, *nash, *namh, *nasi;
    NUMA **links;
    L_HEAP *lh;
    PIX *pixmin, *pixsd;
    PIXA *pixad;
    L_STACK *rstack;
    PTA *ptas, *ptao;

    PROCNAME("wshedApply");

    if (!wshed)
        return ERROR_INT("wshed not defined", procName, 1);

    /* ------------------------------------------------------------ *
     *  Initialize priority queue and pixlab with seeds and minima  *
     * ------------------------------------------------------------ */

    lh = lheapCreate(0, L_SORT_INCREASING);  /* remove lowest values first */
    rstack = lstackCreate(0);  /* for reusing the WSPixels */
    pixGetDimensions(wshed->pixs, &w, &h, NULL);
    lines8 = wshed->lines8;  /* wshed owns this */
    linelab32 = wshed->linelab32;  /* ditto */

    /* Identify seed (marker) pixels, 1 for each c.c. in pixm */
    pixSelectMinInConnComp(wshed->pixs, wshed->pixm, &ptas, &nash);
    pixsd = pixGenerateFromPta(ptas, w, h);
    nseeds = ptaGetCount(ptas);
    for (i = 0; i < nseeds; i++) {
        ptaGetIPt(ptas, i, &x, &y);
        uval = GET_DATA_BYTE(lines8[y], x);
        pushWSPixel(lh, rstack, (l_int32) uval, x, y, i);
    }
    wshed->ptas = ptas;
    nasi = numaMakeConstant(1, nseeds);  /* indicator array */
    wshed->nasi = nasi;
    wshed->nash = nash;
    wshed->nseeds = nseeds;

    /* Identify minima that are not seeds.  Use these 4 steps:
     *  (1) Get the local minima, which can have components
     *      of arbitrary size.  This will be a clipping mask.
     *  (2) Get the image of the actual seeds (pixsd)
     *  (3) Remove all elements of the clipping mask that have a seed.
     *  (4) Shrink each of the remaining elements of the minima mask
     *      to a single pixel.  */
    pixLocalExtrema(wshed->pixs, 200, 0, &pixmin, NULL);
    pixRemoveSeededComponents(pixmin, pixsd, pixmin, 8, 2);
    pixSelectMinInConnComp(wshed->pixs, pixmin, &ptao, &namh);
    nother = ptaGetCount(ptao);
    for (i = 0; i < nother; i++) {
        ptaGetIPt(ptao, i, &x, &y);
        uval = GET_DATA_BYTE(lines8[y], x);
        pushWSPixel(lh, rstack, (l_int32) uval, x, y, nseeds + i);
    }
    wshed->namh = namh;

    /* ------------------------------------------------------------ *
     *                Initialize merging lookup tables              *
     * ------------------------------------------------------------ */

    /* nalut should always give the current after-merging index.
     * links are effectively backpointers: they are numas associated with
     * a dest index of all indices in nalut that point to that index. */
    mindepth = wshed->mindepth;
    nboth = nseeds + nother;
    arraysize = 2 * nboth;
    wshed->arraysize = arraysize;
    nalut = numaMakeSequence(0, 1, arraysize);
    lut = numaGetIArray(nalut);
    wshed->lut = lut;  /* wshed owns this */
    links = (NUMA **) CALLOC(arraysize, sizeof(NUMA * ));
    wshed->links = links;  /* wshed owns this */
    nindex = nseeds + nother;  /* the next unused index value */

    /* ------------------------------------------------------------ *
     *              Fill the basins, using the priority queue       *
     * ------------------------------------------------------------ */

    pixad = pixaCreate(nseeds);
    wshed->pixad = pixad;  /* wshed owns this */
    nalevels = numaCreate(nseeds);
    wshed->nalevels = nalevels;  /* wshed owns this */
    L_INFO("nseeds = %d, nother = %d\n", procName, nseeds, nother);
    while (lheapGetCount(lh) > 0) {
        popWSPixel(lh, rstack, &val, &x, &y, &index);
/*        fprintf(stderr, "x = %d, y = %d, index = %d\n", x, y, index); */
        ulabel = GET_DATA_FOUR_BYTES(linelab32[y], x);
        if (ulabel == MAX_LABEL_VALUE)
            clabel = ulabel;
        else
            clabel = lut[ulabel];
        cindex = lut[index];
        if (clabel == cindex) continue;  /* have already seen this one */
        if (clabel == MAX_LABEL_VALUE) {  /* new one; assign index and try to
                                           * propagate to all neighbors */
            SET_DATA_FOUR_BYTES(linelab32[y], x, cindex);
            imin = L_MAX(0, y - 1);
            imax = L_MIN(h - 1, y + 1);
            jmin = L_MAX(0, x - 1);
            jmax = L_MIN(w - 1, x + 1);
            for (i = imin; i <= imax; i++) {
                for (j = jmin; j <= jmax; j++) {
                    if (i == y && j == x) continue;
                    uval = GET_DATA_BYTE(lines8[i], j);
                    pushWSPixel(lh, rstack, (l_int32) uval, j, i, cindex);
                }
            }
        } else {  /* pixel is already labeled (differently); must resolve */

            /* If both indices are seeds, check if the min height is
             * greater than mindepth.  If so, we have two new watersheds;
             * locate them and assign to both regions a new index
             * for further waterfill.  If not, absorb the shallower
             * watershed into the deeper one and continue filling it. */
            pixGetPixel(pixsd, x, y, &uval);
            if (clabel < nseeds && cindex < nseeds) {
                wshedGetHeight(wshed, val, clabel, &hlabel);
                wshedGetHeight(wshed, val, cindex, &hindex);
                hmin = L_MIN(hlabel, hindex);
                hmax = L_MAX(hlabel, hindex);
                if (hmin == hmax) {
                    hmin = hlabel;
                    hmax = hindex;
                }
                if (wshed->debug) {
                    fprintf(stderr, "clabel,hlabel = %d,%d\n", clabel, hlabel);
                    fprintf(stderr, "hmin = %d, hmax = %d\n", hmin, hmax);
                    fprintf(stderr, "cindex,hindex = %d,%d\n", cindex, hindex);
                    if (hmin < mindepth)
                        fprintf(stderr, "Too shallow!\n");
                }

                if (hmin >= mindepth) {
                    debugWshedMerge(wshed, two_new_watersheds,
                                    x, y, clabel, cindex);
                    wshedSaveBasin(wshed, cindex, val - 1);
                    wshedSaveBasin(wshed, clabel, val - 1);
                    numaSetValue(nasi, cindex, 0);
                    numaSetValue(nasi, clabel, 0);

                    if (wshed->debug) fprintf(stderr, "nindex = %d\n", nindex);
                    debugPrintLUT(lut, nindex, wshed->debug);
                    mergeLookup(wshed, clabel, nindex);
                    debugPrintLUT(lut, nindex, wshed->debug);
                    mergeLookup(wshed, cindex, nindex);
                    debugPrintLUT(lut, nindex, wshed->debug);
                    nindex++;
                } else  /* extraneous seed within seeded basin; absorb */ {
                    debugWshedMerge(wshed, seed_absorbed_into_seeded_basin,
                                    x, y, clabel, cindex);
                }
                maxhindex = clabel;  /* TODO: is this part of above 'else'? */
                minhindex = cindex;
                if (hindex > hlabel) {
                    maxhindex = cindex;
                    minhindex = clabel;
                }
                mergeLookup(wshed, minhindex, maxhindex);
            } else if (clabel < nseeds && cindex >= nboth) {
                /* If one index is a seed and the other is a merge of
                 * 2 watersheds, generate a single watershed. */
                debugWshedMerge(wshed, one_new_watershed_label,
                                x, y, clabel, cindex);
                wshedSaveBasin(wshed, clabel, val - 1);
                numaSetValue(nasi, clabel, 0);
                mergeLookup(wshed, clabel, cindex);
            } else if (cindex < nseeds && clabel >= nboth) {
                debugWshedMerge(wshed, one_new_watershed_index,
                                x, y, clabel, cindex);
                wshedSaveBasin(wshed, cindex, val - 1);
                numaSetValue(nasi, cindex, 0);
                mergeLookup(wshed, cindex, clabel);
            } else if (clabel < nseeds) {  /* cindex from minima; absorb */
                /* If one index is a seed and the other is from a minimum,
                 * merge the minimum wshed into the seed wshed. */
                debugWshedMerge(wshed, minima_absorbed_into_seeded_basin,
                                x, y, clabel, cindex);
                mergeLookup(wshed, cindex, clabel);
            } else if (cindex < nseeds) {  /* clabel from minima; absorb */
                debugWshedMerge(wshed, minima_absorbed_into_seeded_basin,
                                x, y, clabel, cindex);
                mergeLookup(wshed, clabel, cindex);
            } else {  /* If neither index is a seed, just merge */
                debugWshedMerge(wshed, minima_absorbed_by_filler_or_another,
                                x, y, clabel, cindex);
                mergeLookup(wshed, clabel, cindex);
            }
        }
    }

#if 0
    /*  Use the indicator array to save any watersheds that fill
     *  to the maximum value.  This seems to screw things up!  */
for (i = 0; i < nseeds; i++) {
    numaGetIValue(nasi, i, &ival);
    if (ival == 1) {
        wshedSaveBasin(wshed, lut[i], val - 1);
        numaSetValue(nasi, i, 0);
    }
}
#endif

    numaDestroy(&nalut);
    pixDestroy(&pixmin);
    pixDestroy(&pixsd);
    ptaDestroy(&ptao);
    lheapDestroy(&lh, TRUE);
    lstackDestroy(&rstack, TRUE);
    return 0;
}
예제 #7
0
/*!
 *  pixProjectivePtaWithAlpha()
 *
 *      Input:  pixs (32 bpp rgb)
 *              ptad  (4 pts of final coordinate space)
 *              ptas  (4 pts of initial coordinate space)
 *              pixg (<optional> 8 bpp, for alpha channel, can be null)
 *              fract (between 0.0 and 1.0, with 0.0 fully transparent
 *                     and 1.0 fully opaque)
 *              border (of pixels added to capture transformed source pixels)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) The alpha channel is transformed separately from pixs,
 *          and aligns with it, being fully transparent outside the
 *          boundary of the transformed pixs.  For pixels that are fully
 *          transparent, a blending function like pixBlendWithGrayMask()
 *          will give zero weight to corresponding pixels in pixs.
 *      (2) If pixg is NULL, it is generated as an alpha layer that is
 *          partially opaque, using @fract.  Otherwise, it is cropped
 *          to pixs if required and @fract is ignored.  The alpha channel
 *          in pixs is never used.
 *      (3) Colormaps are removed.
 *      (4) When pixs is transformed, it doesn't matter what color is brought
 *          in because the alpha channel will be transparent (0) there.
 *      (5) To avoid losing source pixels in the destination, it may be
 *          necessary to add a border to the source pix before doing
 *          the projective transformation.  This can be any non-negative
 *          number.
 *      (6) The input @ptad and @ptas are in a coordinate space before
 *          the border is added.  Internally, we compensate for this
 *          before doing the projective transform on the image after
 *          the border is added.
 *      (7) The default setting for the border values in the alpha channel
 *          is 0 (transparent) for the outermost ring of pixels and
 *          (0.5 * fract * 255) for the second ring.  When blended over
 *          a second image, this
 *          (a) shrinks the visible image to make a clean overlap edge
 *              with an image below, and
 *          (b) softens the edges by weakening the aliasing there.
 *          Use l_setAlphaMaskBorder() to change these values.
 */
PIX *
pixProjectivePtaWithAlpha(PIX       *pixs,
                          PTA       *ptad,
                          PTA       *ptas,
                          PIX       *pixg,
                          l_float32  fract,
                          l_int32    border)
{
l_int32  ws, hs, d;
PIX     *pixd, *pixb1, *pixb2, *pixg2, *pixga;
PTA     *ptad2, *ptas2;

    PROCNAME("pixProjectivePtaWithAlpha");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &ws, &hs, &d);
    if (d != 32 && pixGetColormap(pixs) == NULL)
        return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
    if (pixg && pixGetDepth(pixg) != 8) {
        L_WARNING("pixg not 8 bpp; using @fract transparent alpha", procName);
        pixg = NULL;
    }
    if (!pixg && (fract < 0.0 || fract > 1.0)) {
        L_WARNING("invalid fract; using 1.0 (fully transparent)", procName);
        fract = 1.0;
    }
    if (!pixg && fract == 0.0)
        L_WARNING("fully opaque alpha; image will not be blended", procName);
    if (!ptad)
        return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
    if (!ptas)
        return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);

        /* Add border; the color doesn't matter */
    pixb1 = pixAddBorder(pixs, border, 0);

        /* Transform the ptr arrays to work on the bordered image */
    ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0);
    ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0);

        /* Do separate projective transform of rgb channels of pixs
         * and of pixg */
    pixd = pixProjectivePtaColor(pixb1, ptad2, ptas2, 0);
    if (!pixg) {
        pixg2 = pixCreate(ws, hs, 8);
        if (fract == 1.0)
            pixSetAll(pixg2);
        else
            pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
    }
    else
        pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
    if (ws > 10 && hs > 10) {  /* see note 7 */
        pixSetBorderRingVal(pixg2, 1,
                            (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
        pixSetBorderRingVal(pixg2, 2,
                            (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));

    }
    pixb2 = pixAddBorder(pixg2, border, 0);  /* must be black border */
    pixga = pixProjectivePtaGray(pixb2, ptad2, ptas2, 0);
    pixSetRGBComponent(pixd, pixga, L_ALPHA_CHANNEL);

    pixDestroy(&pixg2);
    pixDestroy(&pixb1);
    pixDestroy(&pixb2);
    pixDestroy(&pixga);
    ptaDestroy(&ptad2);
    ptaDestroy(&ptas2);
    return pixd;
}
예제 #8
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;
}
예제 #9
0
int main(int argc, char* argv[])
{
    PIX *pixs, *pixb, *pixt;
    int minb;

    if (argc < 2) {
USAGE:	fprintf(stderr, "Usage:  %s </path/to/text-image>\n"
		"\t\t[binarize-threshold] [minw:minh:maxw:maxh]\n",
		strrchr(argv[0], '/') + 1);
	return EINVAL;
    }

    if (2 < argc) {	errno = 0;
	minb = strtol(argv[2], NULL, 10);

	if (errno < 0) {
	    fprintf(stderr, "strtol: %s\n", strerror(errno));
	    goto USAGE;
	}
    } else minb = 180;

    if (!(pixs = pixRead(argv[1]))) ;

    if (1 && (pixt = pixBackgroundNormMorph(pixs, NULL, 4, 5, 248))) {
	pixDestroy(&pixs);	pixs = pixt;
    } else
    if (0 && (pixt = pixBackgroundNorm(pixs, NULL, NULL,
	    10, 15, 60, 40, 248, 2, 1))) {
	pixDestroy(&pixs);	pixs = pixt;
    }

    if (1 && (pixt = pixFindSkewAndDeskew(pixs, 1, NULL, NULL))) {
	pixDestroy(&pixs);	pixs = pixt;
    }	if (0 && pixDisplay(pixs, 0, 0)) ;

    if (1) {	PTA *ptas, *ptad;
	if (!(pixb = pixConvertTo1(pixs, minb))) ;

	// pixt = pixDeskewLocal(pixs, 10, 0, 0, 0.0, 0.0, 0.0))
	if (!pixGetLocalSkewTransform(pixb,
		10, 0, 0, 0.0, 0.0, 0.0, &ptas, &ptad)) {
	    if ((pixt = pixProjectiveSampledPta(pixs,
		ptad, ptas, L_BRING_IN_WHITE))) {
		pixDestroy(&pixs);	pixs = pixt;
	    }	ptaDestroy(&ptas);	ptaDestroy(&ptad);
	}	pixDestroy(&pixb);
    }

    if (0 && (pixt = pixGammaTRC(NULL, pixs, 1.0, 30, 180))) {
	pixDestroy(&pixs);	pixs = pixt;
    }

    if (!(pixb = pixConvertTo1(pixs, minb))) ;

    if (0) { pixDestroy(&pixs); pixs = pixCopy(pixs, pixb); }	// XXX:

    if (1) {
	BOX* box;
	int i, n, j, m;
	PIX *pixi, *pixl;
	BOXA *boxi, *boxl;
	int x, y, w, h, wid;
	int X = INT_MAX, Y = INT_MAX, W = 0, H;

	// XXX: do smaller(or no) pixOpenBrick
	if (pixGetRegionsBinary(pixb, &pixi, &pixl, NULL, 0)) ;

	boxl = pixConnComp(pixl, NULL, 4);
	n = boxaGetCount(boxl);

	for (i = 0; i < n; ++i) {   BOXA* boxa;
	    box = boxaGetBox(boxl, i, L_CLONE);
	    boxGetGeometry(box, &x, &y, &w, &h);

	    if (w < 30 || h < 30 || w < h || h < (w / 40)) {
		boxDestroy(&box);	continue;
		boxaRemoveBox(boxl, i);
	    }

	    if (x < X) X = x;	if (y < Y) Y = y; if (W < w) W = w;

	    pixt = pixClipRectangle(pixb, box, NULL);
	    boxDestroy(&box);

	    // XXX: for English
	    if (0) pixt = pixDilateBrick(pixt, pixt, h >> 1, h >> 1); else

	    pixt = pixDilateBrick(pixt, pixt, 16 < h ? h >> 4 : 1, h << 1);
	    if (0 && pixDisplay(pixt, 0, 0)) ;

	    boxa = pixConnComp(pixt, NULL, 8);
	    pixDestroy(&pixt);

	    wid = (h * 3) >> 2;
	    //boxaShift(boxa, x, y);
	    m = boxaGetCount(boxa);

	    for (j = 0; j < m; ++j) {
		int x0, y0, w0;

		box = boxaGetBox(boxa, j, L_CLONE);
		boxGetGeometry(box, &x0, &y0, &w0, NULL);

		// merge adjacent 2 or 3 small boxes
		if (1 && w0 < wid && (j + 1) < m) {
		    BOX* boxn;	int xn, wn;

		    boxn = boxaGetBox(boxa, j + 1, L_CLONE);
		    boxGetGeometry(boxn, &xn, NULL, &wn, NULL);

		    if ((w0 = xn + wn - x0) < h) {
			boxaSparseClearBox(boxa, ++j);

			if (w0 < wid && (j + 1) < m) {
			    boxDestroy(&boxn);
			    boxn = boxaGetBox(boxa, j + 1, L_CLONE);
			    boxGetGeometry(boxn, &xn, NULL, &wn, NULL);

			    if ((wn = xn + wn - x0) < h) {
				boxaSparseClearBox(boxa, ++j);
				w0 = wn;
			    }
			}

			boxSetGeometry(box, -1, -1, w0, -1);
		    }	boxDestroy(&boxn);
		}

		boxSetGeometry(box, x + x0, y + y0, -1, -1);
		boxDestroy(&box);
	    }	boxaSparseCompact(boxa);

	    if (1 && (pixt = pixDrawBoxa(pixs, boxa, 1, 0xff000000))) {
		pixDestroy(&pixs);	pixs = pixt;
	    }	boxaDestroy(&boxa);
	}   H = y + h;
예제 #10
0
main(int    argc,
     char **argv)
{
char         bufname[256];
l_int32      i, j, w, h, d, x, y, wpls;
l_uint32    *datas, *lines;
l_float32   *vc;
PIX         *pixs, *pixsc, *pixb, *pixg, *pixc, *pixcs, *pixd;
PIX         *pixt1, *pixt2, *pixt3;
PIXA        *pixa;
PTA         *ptas, *ptad;
static char  mainName[] = "projective_reg";

    if (argc != 1)
	exit(ERROR_INT(" Syntax:  projective_reg", mainName, 1));
    if ((pixs = pixRead("feyn.tif")) == NULL)
	exit(ERROR_INT("pixs not made", mainName, 1));
    pixsc = pixScale(pixs, 0.5, 0.5);

#if ALL
        /* Test invertability of sampling */
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixsc, ADDED_BORDER_PIXELS, 0);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixProjectiveSampledPta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1, 1, 20, 8);
        pixt2 = pixProjectiveSampledPta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixsc);
        pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/junksamp.png", pixt1, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj1.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 300);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
#endif

#if ALL
        /* Test invertability of interpolation on grayscale */
    pixa = pixaCreate(0);
    pixg = pixScaleToGray3(pixs);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixg, ADDED_BORDER_PIXELS / 2, 255);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixProjectivePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1, 1, 20, 8);
        pixt2 = pixProjectivePta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS / 2);
        pixXor(pixd, pixd, pixg);
        pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/junkinterp.png", pixt1, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj2.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 500);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
    pixDestroy(&pixg);
#endif

#if ALL
        /* Test invertability of interpolation on color */
    pixa = pixaCreate(0);
    pixc = pixRead("test24.jpg");
    pixcs = pixScale(pixc, 0.3, 0.3);
    for (i = 0; i < 5; i++) {
        pixb = pixAddBorder(pixcs, ADDED_BORDER_PIXELS, 0xffffff00);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixProjectivePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1, 1, 20, 32);
        pixt2 = pixProjectivePta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixcs);
        pixSaveTiled(pixd, pixa, 1, 0, 20, 0);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj3.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 500);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
    pixDestroy(&pixc);
    pixDestroy(&pixcs);
#endif

#if ALL 
       /* Comparison between sampling and interpolated */
    MakePtas(3, &ptas, &ptad);
    pixa = pixaCreate(0);

	/* Use sampled transform */
    pixt1 = pixProjectiveSampledPta(pixs, ptas, ptad, L_BRING_IN_WHITE);
    pixSaveTiled(pixt1, pixa, 2, 1, 20, 8);

	/* Use interpolated transforms */
    pixt2 = pixProjectivePta(pixs, ptas, ptad, L_BRING_IN_WHITE);
    pixSaveTiled(pixt2, pixa, 2, 0, 20, 8);

        /* Compare the results */
    pixXor(pixt2, pixt2, pixt1);
    pixSaveTiled(pixt2, pixa, 2, 0, 20, 8);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj4.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 700);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

#if ALL
       /* Get timings */
    MakePtas(4, &ptas, &ptad);
    pixa = pixaCreate(0);
    pixg = pixScaleToGray3(pixs);

    startTimer();
    pixt1 = pixProjectiveSampledPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixProjectiveSampledPta(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt1, pixa, 1, 1, 20, 8);

    startTimer();
    pixt2 = pixProjectivePta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixProjectivePta(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt2, pixa, 1, 0, 20, 8);

    pixXor(pixt1, pixt1, pixt2);
    pixSaveTiled(pixt1, pixa, 1, 0, 20, 8);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/junkproj5.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 900);
    pixDestroy(&pixd);
    pixDestroy(&pixg);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

    pixDestroy(&pixs);
    pixDestroy(&pixsc);
    return 0;
}
예제 #11
0
void
DoWatershed(L_REGPARAMS  *rp,
            PIX          *pixs)
{
l_uint8   *data;
size_t     size;
l_int32    w, h, empty;
l_uint32   redval, greenval;
L_WSHED   *wshed;
PIX       *pixc, *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7, *pix8, *pix9;
PIXA      *pixa;
PTA       *pta;

        /* Find local extrema */
    pixa = pixaCreate(0);
    pixGetDimensions(pixs, &w, &h, NULL);
    regTestWritePixAndCheck(rp, pixs, IFF_PNG);  /* 0 */
    pixSaveTiled(pixs, pixa, 1.0, 1, 10, 32);
    startTimer();
    pixLocalExtrema(pixs, 0, 0, &pix1, &pix2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    pixSetOrClearBorder(pix1, 2, 2, 2, 2, PIX_CLR);
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixc = pixConvertTo32(pixs);
    pixPaintThroughMask(pixc, pix2, 0, 0, greenval);
    pixPaintThroughMask(pixc, pix1, 0, 0, redval);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 1 */
    pixSaveTiled(pixc, pixa, 1.0, 0, 10, 32);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 2 */
    pixSaveTiled(pix1, pixa, 1.0, 0, 10, 32);

        /* Generate seeds for watershed */
    pixSelectMinInConnComp(pixs, pix1, &pta, NULL);
    pix3 = pixGenerateFromPta(pta, w, h);
    regTestWritePixAndCheck(rp, pix3, IFF_PNG);  /* 3 */
    pixSaveTiled(pix3, pixa, 1.0, 1, 10, 32);
    pix4 = pixConvertTo32(pixs);
    pixPaintThroughMask(pix4, pix3, 0, 0, greenval);
    regTestWritePixAndCheck(rp, pix4, IFF_PNG);  /* 4 */
    pixSaveTiled(pix4, pixa, 1.0, 0, 10, 32);
    pix5 = pixRemoveSeededComponents(NULL, pix3, pix1, 8, 2);
    regTestWritePixAndCheck(rp, pix5, IFF_PNG);  /* 5 */
    pixSaveTiled(pix5, pixa, 1.0, 0, 10, 32);
    pixZero(pix5, &empty);
    regTestCompareValues(rp, 1, empty, 0.0);  /* 6 */

        /* Make and display watershed */
    wshed = wshedCreate(pixs, pix3, 10, 0);
    startTimer();
    wshedApply(wshed);
    fprintf(stderr, "Time for wshed: %7.3f\n", stopTimer());
    pix6 = pixaDisplayRandomCmap(wshed->pixad, w, h);
    regTestWritePixAndCheck(rp, pix6, IFF_PNG);  /* 7 */
    pixSaveTiled(pix6, pixa, 1.0, 1, 10, 32);
    numaWriteMem(&data, &size, wshed->nalevels);
    regTestWriteDataAndCheck(rp, data, size, "na");  /* 8 */
    pix7 = wshedRenderFill(wshed);
    regTestWritePixAndCheck(rp, pix7, IFF_PNG);  /* 9 */
    pixSaveTiled(pix7, pixa, 1.0, 0, 10, 32);
    pix8 = wshedRenderColors(wshed);
    regTestWritePixAndCheck(rp, pix8, IFF_PNG);  /* 10 */
    pixSaveTiled(pix8, pixa, 1.0, 0, 10, 32);
    wshedDestroy(&wshed);

    pix9 = pixaDisplay(pixa, 0, 0);
    regTestWritePixAndCheck(rp, pix9, IFF_PNG);  /* 11 */
    pixDisplayWithTitle(pix9, 100, 100, NULL, rp->display);

    lept_free(data);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pix6);
    pixDestroy(&pix7);
    pixDestroy(&pix8);
    pixDestroy(&pix9);
    pixDestroy(&pixc);
    pixaDestroy(&pixa);
    ptaDestroy(&pta);
}
예제 #12
0
/*!
 * \brief   pixGetSortedNeighborValues()
 *
 * \param[in]     pixs 8, 16 or 32 bpp, with pixels labeled by c.c.
 * \param[in]     x, y location of pixel
 * \param[in]     conn 4 or 8 connected neighbors
 * \param[out]    pneigh array of integers, to be filled with
 *                      the values of the neighbors, if any
 * \param[out]    pnvals the number of unique neighbor values found
 * \return   0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) The returned %neigh array is the unique set of neighboring
 *          pixel values, of size nvals, sorted from smallest to largest.
 *          The value 0, which represents background pixels that do
 *          not belong to any set of connected components, is discarded.
 *      (2) If there are no neighbors, this returns %neigh = NULL; otherwise,
 *          the caller must free the array.
 *      (3) For either 4 or 8 connectivity, the maximum number of unique
 *          neighbor values is 4.
 * </pre>
 */
l_int32
pixGetSortedNeighborValues(PIX       *pixs,
                           l_int32    x,
                           l_int32    y,
                           l_int32    conn,
                           l_int32  **pneigh,
                           l_int32   *pnvals)
{
l_int32       i, npt, index;
l_int32       neigh[4];
l_uint32      val;
l_float32     fx, fy;
L_ASET       *aset;
L_ASET_NODE  *node;
PTA          *pta;
RB_TYPE       key;

    PROCNAME("pixGetSortedNeighborValues");

    if (pneigh) *pneigh = NULL;
    if (pnvals) *pnvals = 0;
    if (!pneigh || !pnvals)
        return ERROR_INT("&neigh and &nvals not both defined", procName, 1);
    if (!pixs || pixGetDepth(pixs) < 8)
        return ERROR_INT("pixs not defined or depth < 8", procName, 1);

        /* Identify the locations of nearest neighbor pixels */
    if ((pta = ptaGetNeighborPixLocs(pixs, x, y, conn)) == NULL)
        return ERROR_INT("pta of neighbors not made", procName, 1);

        /* Find the pixel values and insert into a set as keys */
    aset = l_asetCreate(L_UINT_TYPE);
    npt = ptaGetCount(pta);
    for (i = 0; i < npt; i++) {
        ptaGetPt(pta, i, &fx, &fy);
        pixGetPixel(pixs, (l_int32)fx, (l_int32)fy, &val);
        key.utype = val;
        l_asetInsert(aset, key);
    }

        /* Extract the set keys and put them into the %neigh array.
         * Omit the value 0, which indicates the pixel doesn't
         * belong to one of the sets of connected components. */
    node = l_asetGetFirst(aset);
    index = 0;
    while (node) {
        val = node->key.utype;
        if (val > 0)
            neigh[index++] = (l_int32)val;
        node = l_asetGetNext(node);
    }
    *pnvals = index;
    if (index > 0) {
        *pneigh = (l_int32 *)LEPT_CALLOC(index, sizeof(l_int32));
        for (i = 0; i < index; i++)
            (*pneigh)[i] = neigh[i];
    }

    ptaDestroy(&pta);
    l_asetDestroy(&aset);
    return 0;
}
예제 #13
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;
}
예제 #14
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);
}
예제 #15
0
main(int    argc,
     char **argv)
{
l_int32      i;
l_float32    pi, scale, angle;
PIX         *pixc, *pixm, *pix1, *pix2, *pix3;
PIXA        *pixa;
PTA         *pta1, *pta2, *pta3, *pta4;
static char  mainName[] = "smallpix_reg";

        /* Make a small test image, the hard way! */
    pi = 3.1415926535;
    pixc = pixCreate(9, 9, 32);
    pixm = pixCreate(9, 9, 1);
    pta1 = generatePtaLineFromPt(4, 4, 3.1, 0.0);
    pta2 = generatePtaLineFromPt(4, 4, 3.1, 0.5 * pi);
    pta3 = generatePtaLineFromPt(4, 4, 3.1, pi);
    pta4 = generatePtaLineFromPt(4, 4, 3.1, 1.5 * pi);
    ptaJoin(pta1, pta2, 0, 0);
    ptaJoin(pta1, pta3, 0, 0);
    ptaJoin(pta1, pta4, 0, 0);
    pixRenderPta(pixm, pta1, L_SET_PIXELS);
    pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
    ptaDestroy(&pta1);
    ptaDestroy(&pta2);
    ptaDestroy(&pta3);
    ptaDestroy(&pta4);
    pixDestroy(&pixm);

        /* Results differ for scaleSmoothLow() w/ and w/out + 0.5.
         * Neither is properly symmetric (with symm pattern on odd-sized
         * pix, because the smoothing is destroying the symmetry. */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 2);
    for (i = 0; i < 11; i++) {
        scale = 0.30 + 0.035 * (l_float32)i;
        pix2 = pixScaleSmooth(pix1, scale, scale);
        pix3 = pixExpandReplicate(pix2, 6);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 100, NULL);

        /* Results same for pixScaleAreaMap w/ and w/out + 0.5 */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 2);
    for (i = 0; i < 11; i++) {
        scale = 0.30 + 0.035 * (l_float32)i;
        pix2 = pixScaleAreaMap(pix1, scale, scale);
        pix3 = pixExpandReplicate(pix2, 6);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 200, NULL);

        /* Results better for pixScaleBySampling with + 0.5, for small,
         * odd-dimension pix.  */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 2);
    for (i = 0; i < 11; i++) {
        scale = 0.30 + 0.035 * (l_float32)i;
        pix2 = pixScaleBySampling(pix1, scale, scale);
        pix3 = pixExpandReplicate(pix2, 6);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 300, NULL);

        /* Results same for pixRotateAM w/ and w/out + 0.5 */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 1);
    for (i = 0; i < 11; i++) {
        angle = 0.10 + 0.05 * (l_float32)i;
        pix2 = pixRotateAM(pix1, angle, L_BRING_IN_BLACK);
        pix3 = pixExpandReplicate(pix2, 8);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 400, NULL);

        /* If the size is odd, we express the center exactly, and the
         * results are better for pixRotateBySampling() w/out 0.5
         * However, if the size is even, the center value is not
         * exact, and if we choose it 0.5 smaller than the actual
         * center, we get symmetrical results with +0.5. 
         * So we choose not to include + 0.5. */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 1);
    for (i = 0; i < 11; i++) {
        angle = 0.10 + 0.05 * (l_float32)i;
        pix2 = pixRotateBySampling(pix1, 4, 4, angle, L_BRING_IN_BLACK);
        pix3 = pixExpandReplicate(pix2, 8);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 500, NULL);

        /* Results same for pixRotateAMCorner w/ and w/out + 0.5 */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 1);
    for (i = 0; i < 11; i++) {
        angle = 0.10 + 0.05 * (l_float32)i;
        pix2 = pixRotateAMCorner(pix1, angle, L_BRING_IN_BLACK);
        pix3 = pixExpandReplicate(pix2, 8);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 600, NULL);

        /* Results better for pixRotateAMColorFast without + 0.5 */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 1);
    for (i = 0; i < 11; i++) {
        angle = 0.10 + 0.05 * (l_float32)i;
        pix2 = pixRotateAMColorFast(pix1, angle, 0);
        pix3 = pixExpandReplicate(pix2, 8);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 700, NULL);

        /* Results slightly better for pixScaleColorLI() w/out + 0.5 */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 1);
    for (i = 0; i < 11; i++) {
        scale = 1.0 + 0.2 * (l_float32)i;
        pix2 = pixScaleColorLI(pix1, scale, scale);
        pix3 = pixExpandReplicate(pix2, 4);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 800, NULL);

        /* Results slightly better for pixScaleColorLI() w/out + 0.5 */
    pixa = pixaCreate(11);
    pix1 = pixExpandReplicate(pixc, 1);
    for (i = 0; i < 11; i++) {
        scale = 1.0 + 0.2 * (l_float32)i;
        pix2 = pixScaleLI(pix1, scale, scale);
        pix3 = pixExpandReplicate(pix2, 4);
        pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    pixDestroy(&pix1);
    DisplayPix(&pixa, 100, 940, NULL);

    pixDestroy(&pixc);
    return 0;
}
예제 #16
0
/*!
 * \brief   pixGenerateSelWithRuns()
 *
 * \param[in]    pixs 1 bpp, typically small, to be used as a pattern
 * \param[in]    nhlines number of hor lines along which elements are found
 * \param[in]    nvlines number of vert lines along which elements are found
 * \param[in]    distance min distance from boundary pixel; use 0 for default
 * \param[in]    minlength min runlength to set hit or miss; use 0 for default
 * \param[in]    toppix number of extra pixels of bg added above
 * \param[in]    botpix number of extra pixels of bg added below
 * \param[in]    leftpix number of extra pixels of bg added to left
 * \param[in]    rightpix number of extra pixels of bg added to right
 * \param[out]   ppixe [optional] input pix expanded by extra pixels
 * \return  sel hit-miss for input pattern, or NULL on error
 *
 * <pre>
 * Notes:
 *    (1) The horizontal and vertical lines along which elements are
 *        selected are roughly equally spaced.  The actual locations of
 *        the hits and misses are the centers of respective run-lengths.
 *    (2) No elements are selected that are less than 'distance' pixels away
 *        from a boundary pixel of the same color.  This makes the
 *        match much more robust to edge noise.  Valid inputs of
 *        'distance' are 0, 1, 2, 3 and 4.  If distance is either 0 or
 *        greater than 4, we reset it to the default value.
 *    (3) The 4 numbers for adding rectangles of pixels outside the fg
 *        can be use if the pattern is expected to be surrounded by bg
 *        (white) pixels.  On the other hand, if the pattern may be near
 *        other fg (black) components on some sides, use 0 for those sides.
 *    (4) The pixels added to a side allow you to have miss elements there.
 *        There is a constraint between distance, minlength, and
 *        the added pixels for this to work.  We illustrate using the
 *        default values.  If you add 5 pixels to the top, and use a
 *        distance of 1, then you end up with a vertical run of at least
 *        4 bg pixels along the top edge of the image.  If you use a
 *        minimum runlength of 3, each vertical line will always find
 *        a miss near the center of its run.  However, if you use a
 *        minimum runlength of 5, you will not get a miss on every vertical
 *        line.  As another example, if you have 7 added pixels and a
 *        distance of 2, you can use a runlength up to 5 to guarantee
 *        that the miss element is recorded.  We give a warning if the
 *        contraint does not guarantee a miss element outside the
 *        image proper.
 *    (5) The input pix, as extended by the extra pixels on selected sides,
 *        can optionally be returned.  For debugging, call
 *        pixDisplayHitMissSel() to visualize the hit-miss sel superimposed
 *        on the generating bitmap.
 * </pre>
 */
SEL *
pixGenerateSelWithRuns(PIX     *pixs,
                       l_int32  nhlines,
                       l_int32  nvlines,
                       l_int32  distance,
                       l_int32  minlength,
                       l_int32  toppix,
                       l_int32  botpix,
                       l_int32  leftpix,
                       l_int32  rightpix,
                       PIX    **ppixe)
{
l_int32    ws, hs, w, h, x, y, xval, yval, i, j, nh, nm;
l_float32  delh, delw;
NUMA      *nah, *nam;
PIX       *pixt1, *pixt2, *pixfg, *pixbg;
PTA       *ptah, *ptam;
SEL       *seld, *sel;

    PROCNAME("pixGenerateSelWithRuns");

    if (ppixe) *ppixe = NULL;
    if (!pixs)
        return (SEL *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (nhlines < 1 && nvlines < 1)
        return (SEL *)ERROR_PTR("nvlines and nhlines both < 1", procName, NULL);

    if (distance <= 0)
        distance = DEFAULT_DISTANCE_TO_BOUNDARY;
    if (minlength <= 0)
        minlength = DEFAULT_MIN_RUNLENGTH;
    if (distance > MAX_DISTANCE_TO_BOUNDARY) {
        L_WARNING("distance too large; setting to max value\n", procName);
        distance = MAX_DISTANCE_TO_BOUNDARY;
    }

        /* Locate the foreground */
    pixClipToForeground(pixs, &pixt1, NULL);
    if (!pixt1)
        return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL);
    ws = pixGetWidth(pixt1);
    hs = pixGetHeight(pixt1);
    w = ws;
    h = hs;

        /* Crop out a region including the foreground, and add pixels
         * on sides depending on the side flags */
    if (toppix || botpix || leftpix || rightpix) {
        x = y = 0;
        if (toppix) {
            h += toppix;
            y = toppix;
            if (toppix < distance + minlength)
                L_WARNING("no miss elements in added top pixels\n", procName);
        }
        if (botpix) {
            h += botpix;
            if (botpix < distance + minlength)
                L_WARNING("no miss elements in added bot pixels\n", procName);
        }
        if (leftpix) {
            w += leftpix;
            x = leftpix;
            if (leftpix < distance + minlength)
                L_WARNING("no miss elements in added left pixels\n", procName);
        }
        if (rightpix) {
            w += rightpix;
            if (rightpix < distance + minlength)
                L_WARNING("no miss elements in added right pixels\n", procName);
        }
        pixt2 = pixCreate(w, h, 1);
        pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
    } else {
        pixt2 = pixClone(pixt1);
    }
    if (ppixe)
        *ppixe = pixClone(pixt2);
    pixDestroy(&pixt1);

        /* Identify fg and bg pixels that are at least 'distance' pixels
         * away from the boundary pixels in their set */
    seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
                          distance, distance, SEL_HIT);
    pixfg = pixErode(NULL, pixt2, seld);
    pixbg = pixDilate(NULL, pixt2, seld);
    pixInvert(pixbg, pixbg);
    selDestroy(&seld);
    pixDestroy(&pixt2);

        /* Accumulate hit and miss points */
    ptah = ptaCreate(0);
    ptam = ptaCreate(0);
    if (nhlines >= 1) {
        delh = (l_float32)h / (l_float32)(nhlines + 1);
        for (i = 0, y = 0; i < nhlines; i++) {
            y += (l_int32)(delh + 0.5);
            nah = pixGetRunCentersOnLine(pixfg, -1, y, minlength);
            nam = pixGetRunCentersOnLine(pixbg, -1, y, minlength);
            nh = numaGetCount(nah);
            nm = numaGetCount(nam);
            for (j = 0; j < nh; j++) {
                numaGetIValue(nah, j, &xval);
                ptaAddPt(ptah, xval, y);
            }
            for (j = 0; j < nm; j++) {
                numaGetIValue(nam, j, &xval);
                ptaAddPt(ptam, xval, y);
            }
            numaDestroy(&nah);
            numaDestroy(&nam);
        }
    }
    if (nvlines >= 1) {
        delw = (l_float32)w / (l_float32)(nvlines + 1);
        for (i = 0, x = 0; i < nvlines; i++) {
            x += (l_int32)(delw + 0.5);
            nah = pixGetRunCentersOnLine(pixfg, x, -1, minlength);
            nam = pixGetRunCentersOnLine(pixbg, x, -1, minlength);
            nh = numaGetCount(nah);
            nm = numaGetCount(nam);
            for (j = 0; j < nh; j++) {
                numaGetIValue(nah, j, &yval);
                ptaAddPt(ptah, x, yval);
            }
            for (j = 0; j < nm; j++) {
                numaGetIValue(nam, j, &yval);
                ptaAddPt(ptam, x, yval);
            }
            numaDestroy(&nah);
            numaDestroy(&nam);
        }
    }

        /* Make the Sel with those points */
    sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
    nh = ptaGetCount(ptah);
    for (i = 0; i < nh; i++) {
        ptaGetIPt(ptah, i, &x, &y);
        selSetElement(sel, y, x, SEL_HIT);
    }
    nm = ptaGetCount(ptam);
    for (i = 0; i < nm; i++) {
        ptaGetIPt(ptam, i, &x, &y);
        selSetElement(sel, y, x, SEL_MISS);
    }

    pixDestroy(&pixfg);
    pixDestroy(&pixbg);
    ptaDestroy(&ptah);
    ptaDestroy(&ptam);
    return sel;
}
예제 #17
0
int main(int    argc,
         char **argv)
{
    l_int32      i, j, w, h, empty;
    l_uint32     redval, greenval;
    l_float32    f;
    L_WSHED     *wshed;
    PIX         *pixs, *pixc, *pixd;
    PIX         *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7, *pix8;
    PIXA        *pixac;
    PTA         *pta;
    static char  mainName[] = "watershedtest";

    if (argc != 1)
        return ERROR_INT(" Syntax:  watershedtest", mainName, 1);

    pixac = pixaCreate(0);
    pixs = pixCreate(500, 500, 8);
    pixGetDimensions(pixs, &w, &h, NULL);
    for (i = 0; i < 500; i++) {
        for (j = 0; j < 500; j++) {
#if 1
            f = 128.0 + 26.3 * sin(0.0438 * (l_float32)i);
            f += 33.4 * cos(0.0712 * (l_float32)i);
            f += 18.6 * sin(0.0561 * (l_float32)j);
            f += 23.6 * cos(0.0327 * (l_float32)j);
#else
            f = 128.0 + 26.3 * sin(0.0238 * (l_float32)i);
            f += 33.4 * cos(0.0312 * (l_float32)i);
            f += 18.6 * sin(0.0261 * (l_float32)j);
            f += 23.6 * cos(0.0207 * (l_float32)j);
#endif
            pixSetPixel(pixs, j, i, (l_int32)f);
        }
    }
    pixSaveTiled(pixs, pixac, 1.0, 1, 10, 32);
    pixWrite("/tmp/pattern.png", pixs, IFF_PNG);
    startTimer();
    pixLocalExtrema(pixs, 0, 0, &pix1, &pix2);
    fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer());
    pixSetOrClearBorder(pix1, 2, 2, 2, 2, PIX_CLR);
    composeRGBPixel(255, 0, 0, &redval);
    composeRGBPixel(0, 255, 0, &greenval);
    pixc = pixConvertTo32(pixs);
    pixPaintThroughMask(pixc, pix2, 0, 0, greenval);
    pixPaintThroughMask(pixc, pix1, 0, 0, redval);
    pixSaveTiled(pixc, pixac, 1.0, 0, 10, 32);
    pixWrite("/tmp/pixc.png", pixc, IFF_PNG);
    pixSaveTiled(pix1, pixac, 1.0, 0, 10, 32);
    pixSelectMinInConnComp(pixs, pix1, &pta, NULL);
    /*    ptaWriteStream(stderr, pta, 1); */
    pix3 = pixGenerateFromPta(pta, w, h);
    pixSaveTiled(pix3, pixac, 1.0, 1, 10, 32);

    pix4 = pixConvertTo32(pixs);
    pixPaintThroughMask(pix4, pix3, 0, 0, greenval);
    pixSaveTiled(pix4, pixac, 1.0, 0, 10, 32);
    pix5 = pixRemoveSeededComponents(NULL, pix3, pix1, 8, 2);
    pixSaveTiled(pix5, pixac, 1.0, 0, 10, 32);
    pixZero(pix5, &empty);
    fprintf(stderr, "Is empty?  %d\n", empty);
    pixDestroy(&pix4);
    pixDestroy(&pix5);

    wshed = wshedCreate(pixs, pix3, 10, 0);
    startTimer();
    wshedApply(wshed);
    fprintf(stderr, "Time for wshed: %7.3f\n", stopTimer());
    pix6 = pixaDisplayRandomCmap(wshed->pixad, w, h);
    pixSaveTiled(pix6, pixac, 1.0, 1, 10, 32);
    numaWriteStream(stderr, wshed->nalevels);
    pix7 = wshedRenderFill(wshed);
    pixSaveTiled(pix7, pixac, 1.0, 0, 10, 32);
    pix8 = wshedRenderColors(wshed);
    pixSaveTiled(pix8, pixac, 1.0, 0, 10, 32);
    wshedDestroy(&wshed);

    pixd = pixaDisplay(pixac, 0, 0);
    pixDisplay(pixd, 100, 100);
    pixWrite("/tmp/wshed.png", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixaDestroy(&pixac);

    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix6);
    pixDestroy(&pix7);
    pixDestroy(&pix8);
    pixDestroy(&pixs);
    pixDestroy(&pixc);
    ptaDestroy(&pta);
    return 0;
}
예제 #18
0
/*!
 * \brief   pixGenerateSelBoundary()
 *
 * \param[in]    pixs 1 bpp, typically small, to be used as a pattern
 * \param[in]    hitdist min distance from fg boundary pixel
 * \param[in]    missdist min distance from bg boundary pixel
 * \param[in]    hitskip number of boundary pixels skipped between hits
 * \param[in]    missskip number of boundary pixels skipped between misses
 * \param[in]    topflag flag for extra pixels of bg added above
 * \param[in]    botflag flag for extra pixels of bg added below
 * \param[in]    leftflag flag for extra pixels of bg added to left
 * \param[in]    rightflag flag for extra pixels of bg added to right
 * \param[out]   ppixe [optional] input pix expanded by extra pixels
 * \return  sel hit-miss for input pattern, or NULL on error
 *
 * <pre>
 * Notes:
 *    (1) All fg elements selected are exactly hitdist pixels away from
 *        the nearest fg boundary pixel, and ditto for bg elements.
 *        Valid inputs of hitdist and missdist are 0, 1, 2, 3 and 4.
 *        For example, a hitdist of 0 puts the hits at the fg boundary.
 *        Usually, the distances should be > 0 avoid the effect of
 *        noise at the boundary.
 *    (2) Set hitskip < 0 if no hits are to be used.  Ditto for missskip.
 *        If both hitskip and missskip are < 0, the sel would be empty,
 *        and NULL is returned.
 *    (3) The 4 flags determine whether the sel is increased on that side
 *        to allow bg misses to be placed all along that boundary.
 *        The increase in sel size on that side is the minimum necessary
 *        to allow the misses to be placed at mindist.  For text characters,
 *        the topflag and botflag are typically set to 1, and the leftflag
 *        and rightflag to 0.
 *    (4) The input pix, as extended by the extra pixels on selected sides,
 *        can optionally be returned.  For debugging, call
 *        pixDisplayHitMissSel() to visualize the hit-miss sel superimposed
 *        on the generating bitmap.
 *    (5) This is probably the best of the three sel generators, in the
 *        sense that you have the most flexibility with the smallest number
 *        of hits and misses.
 * </pre>
 */
SEL *
pixGenerateSelBoundary(PIX     *pixs,
                       l_int32  hitdist,
                       l_int32  missdist,
                       l_int32  hitskip,
                       l_int32  missskip,
                       l_int32  topflag,
                       l_int32  botflag,
                       l_int32  leftflag,
                       l_int32  rightflag,
                       PIX      **ppixe)
{
l_int32  ws, hs, w, h, x, y, ix, iy, i, npt;
PIX     *pixt1, *pixt2, *pixt3, *pixfg, *pixbg;
SEL     *selh, *selm, *sel_3, *sel;
PTA     *ptah, *ptam;

    PROCNAME("pixGenerateSelBoundary");

    if (ppixe) *ppixe = NULL;
    if (!pixs)
        return (SEL *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (SEL *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4)
        return (SEL *)ERROR_PTR("dist not in {0 .. 4}", procName, NULL);
    if (hitskip < 0 && missskip < 0)
        return (SEL *)ERROR_PTR("no hits or misses", procName, NULL);

        /* Locate the foreground */
    pixClipToForeground(pixs, &pixt1, NULL);
    if (!pixt1)
        return (SEL *)ERROR_PTR("pixt1 not made", procName, NULL);
    ws = pixGetWidth(pixt1);
    hs = pixGetHeight(pixt1);
    w = ws;
    h = hs;

        /* Crop out a region including the foreground, and add pixels
         * on sides depending on the side flags */
    if (topflag || botflag || leftflag || rightflag) {
        x = y = 0;
        if (topflag) {
            h += missdist + 1;
            y = missdist + 1;
        }
        if (botflag)
            h += missdist + 1;
        if (leftflag) {
            w += missdist + 1;
            x = missdist + 1;
        }
        if (rightflag)
            w += missdist + 1;
        pixt2 = pixCreate(w, h, 1);
        pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
    } else {
        pixt2 = pixClone(pixt1);
    }
    if (ppixe)
        *ppixe = pixClone(pixt2);
    pixDestroy(&pixt1);

        /* Identify fg and bg pixels that are exactly hitdist and
         * missdist (rsp) away from the boundary pixels in their set.
         * Then get a subsampled set of these points. */
    sel_3 = selCreateBrick(3, 3, 1, 1, SEL_HIT);
    if (hitskip >= 0) {
        selh = selCreateBrick(2 * hitdist + 1, 2 * hitdist + 1,
                              hitdist, hitdist, SEL_HIT);
        pixt3 = pixErode(NULL, pixt2, selh);
        pixfg = pixErode(NULL, pixt3, sel_3);
        pixXor(pixfg, pixfg, pixt3);
        ptah = pixSubsampleBoundaryPixels(pixfg, hitskip);
        pixDestroy(&pixt3);
        pixDestroy(&pixfg);
        selDestroy(&selh);
    }
    if (missskip >= 0) {
        selm = selCreateBrick(2 * missdist + 1, 2 * missdist + 1,
                              missdist, missdist, SEL_HIT);
        pixt3 = pixDilate(NULL, pixt2, selm);
        pixbg = pixDilate(NULL, pixt3, sel_3);
        pixXor(pixbg, pixbg, pixt3);
        ptam = pixSubsampleBoundaryPixels(pixbg, missskip);
        pixDestroy(&pixt3);
        pixDestroy(&pixbg);
        selDestroy(&selm);
    }
    selDestroy(&sel_3);
    pixDestroy(&pixt2);

        /* Generate the hit-miss sel from these point */
    sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
    if (hitskip >= 0) {
        npt = ptaGetCount(ptah);
        for (i = 0; i < npt; i++) {
            ptaGetIPt(ptah, i, &ix, &iy);
            selSetElement(sel, iy, ix, SEL_HIT);
        }
    }
    if (missskip >= 0) {
        npt = ptaGetCount(ptam);
        for (i = 0; i < npt; i++) {
            ptaGetIPt(ptam, i, &ix, &iy);
            selSetElement(sel, iy, ix, SEL_MISS);
        }
    }

    ptaDestroy(&ptah);
    ptaDestroy(&ptam);
    return sel;
}
예제 #19
0
int main(int    argc,
         char **argv)
{
PIX          *pixs2, *pixs3, *pixb1, *pixb2, *pixb3;
PIX          *pixr2, *pixr3;
PIX          *pixc1, *pixc2, *pixc3, *pixcs1, *pixcs2, *pixcs3;
PIX          *pixd, *pixt1, *pixt2, *pixt3;
PTA          *ptas1, *ptas2, *ptas3, *ptad1, *ptad2, *ptad3;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    pixc1 = pixRead("test24.jpg");
    pixc2 = pixRead("wyom.jpg");
    pixc3 = pixRead("marge.jpg");

        /* Test alpha blend scaling */
    pixd = pixCreate(900, 400, 32);
    pixSetAll(pixd);
    pixs2 = pixScaleWithAlpha(pixc2, 0.5, 0.5, NULL, 0.3);
    pixs3 = pixScaleWithAlpha(pixc3, 0.4, 0.4, NULL, 0.7);
    pixb1 = pixBlendWithGrayMask(pixd, pixs3, NULL, 100, 100);
    pixb2 = pixBlendWithGrayMask(pixb1, pixs2, NULL, 300, 130);
    pixb3 = pixBlendWithGrayMask(pixb2, pixs3, NULL, 600, 160);
    regTestWritePixAndCheck(rp, pixb3, IFF_PNG);  /* 0 */
    pixDisplayWithTitle(pixb3, 900, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixs2);
    pixDestroy(&pixs3);
    pixDestroy(&pixb1);
    pixDestroy(&pixb2);
    pixDestroy(&pixb3);

        /* Test alpha blend rotation */
    pixd = pixCreate(1200, 800, 32);
    pixSetAll(pixd);
    pixr3 = pixRotateWithAlpha(pixc3, -0.3, NULL, 1.0);
    pixr2 = pixRotateWithAlpha(pixc2, +0.3, NULL, 1.0);
    pixb3 = pixBlendWithGrayMask(pixd, pixr3, NULL, 100, 100);
    pixb2 = pixBlendWithGrayMask(pixb3, pixr2, NULL, 400, 100);
    regTestWritePixAndCheck(rp, pixb2, IFF_PNG);  /* 1 */
    pixDisplayWithTitle(pixb2, 500, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixr3);
    pixDestroy(&pixr2);
    pixDestroy(&pixb3);
    pixDestroy(&pixb2);

    pixcs1 = pixScale(pixc1, 0.35, 0.35);
    pixcs2 = pixScale(pixc2, 0.55, 0.55);
    pixcs3 = pixScale(pixc3, 0.65, 0.65);

        /* Test alpha blend affine */
    pixd = pixCreate(800, 900, 32);
    pixSetAll(pixd);
    MakePtas(2, 3, &ptas1, &ptad1);
    MakePtas(4, 3, &ptas2, &ptad2);
    MakePtas(3, 3, &ptas3, &ptad3);
    pixt1 = pixAffinePtaWithAlpha(pixcs1, ptad1, ptas1, NULL, 1.0, 300);
    pixt2 = pixAffinePtaWithAlpha(pixcs2, ptad2, ptas2, NULL, 0.8, 400);
    pixt3 = pixAffinePtaWithAlpha(pixcs3, ptad3, ptas3, NULL, 0.7, 300);
    pixb1 = pixBlendWithGrayMask(pixd, pixt1, NULL, -250, 20);
    pixb2 = pixBlendWithGrayMask(pixb1, pixt2, NULL, -150, -250);
    pixb3 = pixBlendWithGrayMask(pixb2, pixt3, NULL, -100, 220);
    regTestWritePixAndCheck(rp, pixb3, IFF_PNG);  /* 2 */
    pixDisplayWithTitle(pixb3, 100, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixb1);
    pixDestroy(&pixb2);
    pixDestroy(&pixb3);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    ptaDestroy(&ptas1);
    ptaDestroy(&ptas2);
    ptaDestroy(&ptas3);
    ptaDestroy(&ptad1);
    ptaDestroy(&ptad2);
    ptaDestroy(&ptad3);

        /* Test alpha blend projective */
    pixd = pixCreate(900, 900, 32);
    pixSetAll(pixd);
    MakePtas(2, 4, &ptas1, &ptad1);
    MakePtas(4, 4, &ptas2, &ptad2);
    MakePtas(3, 4, &ptas3, &ptad3);
    pixt1 = pixProjectivePtaWithAlpha(pixcs1, ptad1, ptas1, NULL, 1.0, 300);
    pixt2 = pixProjectivePtaWithAlpha(pixcs2, ptad2, ptas2, NULL, 0.8, 400);
    pixt3 = pixProjectivePtaWithAlpha(pixcs3, ptad3, ptas3, NULL, 0.7, 400);
    pixb1 = pixBlendWithGrayMask(pixd, pixt1, NULL, -150, 20);
    pixb2 = pixBlendWithGrayMask(pixb1, pixt2, NULL, -50, -250);
    pixb3 = pixBlendWithGrayMask(pixb2, pixt3, NULL, -100, 220);
    regTestWritePixAndCheck(rp, pixb3, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pixb3, 300, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixb1);
    pixDestroy(&pixb2);
    pixDestroy(&pixb3);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    ptaDestroy(&ptas1);
    ptaDestroy(&ptas2);
    ptaDestroy(&ptas3);
    ptaDestroy(&ptad1);
    ptaDestroy(&ptad2);
    ptaDestroy(&ptad3);

        /* Test alpha blend bilinear */
    pixd = pixCreate(900, 900, 32);
    pixSetAll(pixd);
    MakePtas(2, 4, &ptas1, &ptad1);
    MakePtas(4, 4, &ptas2, &ptad2);
    MakePtas(3, 4, &ptas3, &ptad3);
    pixt1 = pixBilinearPtaWithAlpha(pixcs1, ptad1, ptas1, NULL, 1.0, 300);
    pixt2 = pixBilinearPtaWithAlpha(pixcs2, ptad2, ptas2, NULL, 0.8, 400);
    pixt3 = pixBilinearPtaWithAlpha(pixcs3, ptad3, ptas3, NULL, 0.7, 400);
    pixb1 = pixBlendWithGrayMask(pixd, pixt1, NULL, -150, 20);
    pixb2 = pixBlendWithGrayMask(pixb1, pixt2, NULL, -50, -250);
    pixb3 = pixBlendWithGrayMask(pixb2, pixt3, NULL, -100, 220);
    regTestWritePixAndCheck(rp, pixb3, IFF_PNG);  /* 4 */
    pixDisplayWithTitle(pixb3, 500, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixDestroy(&pixb1);
    pixDestroy(&pixb2);
    pixDestroy(&pixb3);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);
    ptaDestroy(&ptas1);
    ptaDestroy(&ptas2);
    ptaDestroy(&ptas3);
    ptaDestroy(&ptad1);
    ptaDestroy(&ptad2);
    ptaDestroy(&ptad3);

    pixDestroy(&pixc1);
    pixDestroy(&pixc2);
    pixDestroy(&pixc3);
    pixDestroy(&pixcs1);
    pixDestroy(&pixcs2);
    pixDestroy(&pixcs3);
    return regTestCleanup(rp);
}
예제 #20
0
/*!
 * \brief   pixGetRunsOnLine()
 *
 * \param[in]    pixs 1 bpp
 * \param[in]    x1, y1, x2, y2
 * \return  numa, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Action: this function uses the bresenham algorithm to compute
 *          the pixels along the specified line.  It returns a Numa of the
 *          runlengths of the fg (black) and bg (white) runs, always
 *          starting with a white run.
 *      (2) If the first pixel on the line is black, the length of the
 *          first returned run (which is white) is 0.
 * </pre>
 */
NUMA *
pixGetRunsOnLine(PIX     *pixs,
                 l_int32  x1,
                 l_int32  y1,
                 l_int32  x2,
                 l_int32  y2)
{
l_int32   w, h, x, y, npts;
l_int32   i, runlen, preval;
l_uint32  val;
NUMA     *numa;
PTA      *pta;

    PROCNAME("pixGetRunsOnLine");

    if (!pixs)
        return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (NUMA *)ERROR_PTR("pixs not 1 bpp", procName, NULL);

    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    if (x1 < 0 || x1 >= w)
        return (NUMA *)ERROR_PTR("x1 not valid", procName, NULL);
    if (x2 < 0 || x2 >= w)
        return (NUMA *)ERROR_PTR("x2 not valid", procName, NULL);
    if (y1 < 0 || y1 >= h)
        return (NUMA *)ERROR_PTR("y1 not valid", procName, NULL);
    if (y2 < 0 || y2 >= h)
        return (NUMA *)ERROR_PTR("y2 not valid", procName, NULL);

    if ((pta = generatePtaLine(x1, y1, x2, y2)) == NULL)
        return (NUMA *)ERROR_PTR("pta not made", procName, NULL);
    if ((npts = ptaGetCount(pta)) == 0) {
        ptaDestroy(&pta);
        return (NUMA *)ERROR_PTR("pta has no pts", procName, NULL);
    }
    if ((numa = numaCreate(0)) == NULL) {
        ptaDestroy(&pta);
        return (NUMA *)ERROR_PTR("numa not made", procName, NULL);
    }

    for (i = 0; i < npts; i++) {
        ptaGetIPt(pta, i, &x, &y);
        pixGetPixel(pixs, x, y, &val);
        if (i == 0) {
            if (val == 1) {  /* black pixel; append white run of size 0 */
                numaAddNumber(numa, 0);
            }
            preval = val;
            runlen = 1;
            continue;
        }
        if (val == preval) {  /* extend current run */
            preval = val;
            runlen++;
        } else {  /* end previous run */
            numaAddNumber(numa, runlen);
            preval = val;
            runlen = 1;
        }
    }
    numaAddNumber(numa, runlen);  /* append last run */

    ptaDestroy(&pta);
    return numa;
}
예제 #21
0
/*!
 *  selaAddTJunctions()
 *
 *      Input:  sela (<optional>)
 *              hlsize (length of each line of hits from origin)
 *              mdist (distance of misses from the origin)
 *              norient (number of orientations; max of 8)
 *              debugflag (1 for debug output)
 *      Return: sela with additional sels, or null on error
 *
 *  Notes:
 *      (1) Adds hitmiss Sels for the T-junction of two lines.
 *          If the lines are very thin, they must be nearly orthogonal
 *          to register.
 *      (2) The number of Sels generated is 4 * @norient.
 *      (3) It is suggested that @hlsize be chosen at least 1 greater
 *          than @mdist.  Try values of (@hlsize, @mdist) such as
 *          (6,5), (7,6), (8,7), (9,7), etc.
 */
SELA *
selaAddTJunctions(SELA *sela,
                  l_float32 hlsize,
                  l_float32 mdist,
                  l_int32 norient,
                  l_int32 debugflag) {
    char name[L_BUF_SIZE];
    l_int32 i, j, k, w, xc, yc;
    l_float64 pi, halfpi, radincr, jang, radang;
    l_float64 angle[3], dist[3];
    PIX *pixc, *pixm, *pixt;
    PIXA *pixa;
    PTA *pta1, *pta2, *pta3;
    SEL *sel;

    PROCNAME("selaAddTJunctions");

    if (hlsize <= 2)
        return (SELA *) ERROR_PTR("hlsizel not > 1", procName, NULL);
    if (norient < 1 || norient > 8)
        return (SELA *) ERROR_PTR("norient not in [1, ... 8]", procName, NULL);

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *) ERROR_PTR("sela not made", procName, NULL);
    }

    pi = 3.1415926535;
    halfpi = 3.1415926535 / 2.0;
    radincr = halfpi / (l_float32) norient;
    w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5));
    if (w % 2 == 0)
        w++;
    xc = w / 2;
    yc = w / 2;

    pixa = pixaCreate(4 * norient);
    for (i = 0; i < norient; i++) {
        for (j = 0; j < 4; j++) {  /* 4 orthogonal orientations */
            jang = (l_float32) j * halfpi;

            /* Set the don't cares */
            pixc = pixCreate(w, w, 32);
            pixSetAll(pixc);

            /* Add the green lines of hits */
            pixm = pixCreate(w, w, 1);
            radang = (l_float32) i * radincr;
            pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang);
            pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1,
                                         jang + radang + halfpi);
            pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1,
                                         jang + radang + pi);
            ptaJoin(pta1, pta2, 0, -1);
            ptaJoin(pta1, pta3, 0, -1);
            pixRenderPta(pixm, pta1, L_SET_PIXELS);
            pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
            ptaDestroy(&pta1);
            ptaDestroy(&pta2);
            ptaDestroy(&pta3);

            /* Add red misses between the lines */
            angle[0] = radang + jang - halfpi;
            angle[1] = radang + jang + 0.5 * halfpi;
            angle[2] = radang + jang + 1.5 * halfpi;
            dist[0] = 0.8 * mdist;
            dist[1] = dist[2] = mdist;
            for (k = 0; k < 3; k++) {
                pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])),
                            yc + (l_int32)(dist[k] * sin(angle[k])),
                            0xff000000);
            }

            /* Add dark green for origin */
            pixSetPixel(pixc, xc, yc, 0x00550000);

            /* Generate the sel */
            sel = selCreateFromColorPix(pixc, NULL);
            sprintf(name, "sel_cross_%d", 4 * i + j);
            selaAddSel(sela, sel, name, 0);

            if (debugflag) {
                pixt = pixScaleBySampling(pixc, 10.0, 10.0);
                pixaAddPix(pixa, pixt, L_INSERT);
            }
            pixDestroy(&pixm);
            pixDestroy(&pixc);
        }
    }

    if (debugflag) {
        l_int32 w;
        pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
        pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2);
        pixWriteTempfile("/tmp", "tsel1.png", pixt, IFF_PNG, 0);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 4);
        pixWriteTempfile("/tmp", "tsel2.png", pixt, IFF_PNG, 0);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}
예제 #22
0
/*!
 *  boxIntersectByLine()
 *
 *      Input:  box
 *              x, y (point that line goes through)
 *              slope (of line)
 *              (&x1, &y1) (<return> 1st point of intersection with box)
 *              (&x2, &y2) (<return> 2nd point of intersection with box)
 *              &n (<return> number of points of intersection)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) If the intersection is at only one point (a corner), the
 *          coordinates are returned in (x1, y1).
 *      (2) Represent a vertical line by one with a large but finite slope.
 */
l_int32
boxIntersectByLine(BOX       *box,
                   l_int32    x,
                   l_int32    y,
                   l_float32  slope,
                   l_int32   *px1,
                   l_int32   *py1,
                   l_int32   *px2,
                   l_int32   *py2,
                   l_int32   *pn)
{
l_int32    bx, by, bw, bh, xp, yp, xt, yt, i, n;
l_float32  invslope;
PTA       *pta;

    PROCNAME("boxIntersectByLine");

    if (!px1 || !py1 || !px2 || !py2)
        return ERROR_INT("&x1, &y1, &x2, &y2 not all defined", procName, 1);
    *px1 = *py1 = *px2 = *py2 = 0;
    if (!pn)
        return ERROR_INT("&n not defined", procName, 1);
    *pn = 0;
    if (!box)
        return ERROR_INT("box not defined", procName, 1);
    boxGetGeometry(box, &bx, &by, &bw, &bh);

    if (slope == 0.0) {
        if (y >= by && y < by + bh) {
            *py1 = *py2 = y; 
            *px1 = bx;
            *px2 = bx + bw - 1;
        }
        return 0;
    }

    if (slope > 1000000.0) {
        if (x >= bx && x < bx + bw) {
            *px1 = *px2 = x; 
            *py1 = by;
            *py2 = by + bh - 1;
        }
        return 0;
    }

        /* Intersection with top and bottom lines of box */
    pta = ptaCreate(2);
    invslope = 1.0 / slope;
    xp = (l_int32)(x + invslope * (y - by));
    if (xp >= bx && xp < bx + bw)
        ptaAddPt(pta, xp, by); 
    xp = (l_int32)(x + invslope * (y - by - bh + 1));
    if (xp >= bx && xp < bx + bw)
        ptaAddPt(pta, xp, by + bh - 1); 

        /* Intersection with left and right lines of box */
    yp = (l_int32)(y + slope * (x - bx));
    if (yp >= by && yp < by + bh)
        ptaAddPt(pta, bx, yp); 
    yp = (l_int32)(y + slope * (x - bx - bw + 1));
    if (yp >= by && yp < by + bh)
        ptaAddPt(pta, bx + bw - 1, yp); 

        /* There is a maximum of 2 unique points; remove duplicates.  */
    n = ptaGetCount(pta);
    if (n > 0) {
        ptaGetIPt(pta, 0, px1, py1);  /* accept the first one */
	*pn = 1;
    }
    for (i = 1; i < n; i++) {
        ptaGetIPt(pta, i, &xt, &yt);
        if ((*px1 != xt) || (*py1 != yt)) {
            *px2 = xt;
            *py2 = yt;
            *pn = 2;
            break;
        }
    }

    ptaDestroy(&pta);
    return 0;
}
예제 #23
0
/*!
 *  pixGetLocalSkewAngles()
 *
 *      Input:  pixs
 *              nslices  (the number of horizontal overlapping slices; must
 *                  be larger than 1 and not exceed 20; use 0 for default)
 *              redsweep (sweep reduction factor: 1, 2, 4 or 8;
 *                        use 0 for default value)
 *              redsearch (search reduction factor: 1, 2, 4 or 8, and
 *                         not larger than redsweep; use 0 for default value)
 *              sweeprange (half the full range, assumed about 0; in degrees;
 *                          use 0.0 for default value)
 *              sweepdelta (angle increment of sweep; in degrees;
 *                          use 0.0 for default value)
 *              minbsdelta (min binary search increment angle; in degrees;
 *                          use 0.0 for default value)
 *              &a (<optional return> slope of skew as fctn of y)
 *              &b (<optional return> intercept at y=0 of skew as fctn of y)
 *      Return: naskew, or null on error
 *
 *  Notes:
 *      (1) The local skew is measured in a set of overlapping strips.
 *          We then do a least square linear fit parameters to get
 *          the slope and intercept parameters a and b in
 *              skew-angle = a * y + b  (degrees)
 *          for the local skew as a function of raster line y.
 *          This is then used to make naskew, which can be interpreted
 *          as the computed skew angle (in degrees) at the left edge
 *          of each raster line.
 *      (2) naskew can then be used to find the baselines of text, because
 *          each text line has a baseline that should intersect
 *          the left edge of the image with the angle given by this
 *          array, evaluated at the raster line of intersection.
 */
NUMA *
pixGetLocalSkewAngles(PIX        *pixs,
                      l_int32     nslices,
                      l_int32     redsweep,
                      l_int32     redsearch,
                      l_float32   sweeprange,
                      l_float32   sweepdelta,
                      l_float32   minbsdelta,
                      l_float32  *pa,
                      l_float32  *pb)
{
l_int32    w, h, hs, i, ystart, yend, ovlap, npts;
l_float32  angle, conf, ycenter, a, b;
BOX       *box;
NUMA      *naskew;
PIX       *pix;
PTA       *pta;

    PROCNAME("pixGetLocalSkewAngles");

    if (!pixs)
        return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
    if (nslices < 2 || nslices > 20)
        nslices = DEFAULT_SLICES;
    if (redsweep < 1 || redsweep > 8)
        redsweep = DEFAULT_SWEEP_REDUCTION;
    if (redsearch < 1 || redsearch > redsweep)
        redsearch = DEFAULT_BS_REDUCTION;
    if (sweeprange == 0.0)
        sweeprange = DEFAULT_SWEEP_RANGE;
    if (sweepdelta == 0.0)
        sweepdelta = DEFAULT_SWEEP_DELTA;
    if (minbsdelta == 0.0)
        minbsdelta = DEFAULT_MINBS_DELTA;

    h = pixGetHeight(pixs);
    w = pixGetWidth(pixs);
    hs = h / nslices;
    ovlap = (l_int32)(OVERLAP_FRACTION * hs);
    pta = ptaCreate(nslices);
    for (i = 0; i < nslices; i++) {
        ystart = L_MAX(0, hs * i - ovlap);
        yend = L_MIN(h - 1, hs * (i + 1) + ovlap);
        ycenter = (ystart + yend) / 2;
        box = boxCreate(0, ystart, w, yend - ystart + 1);
        pix = pixClipRectangle(pixs, box, NULL);
        pixFindSkewSweepAndSearch(pix, &angle, &conf, redsweep, redsearch,
                                  sweeprange, sweepdelta, minbsdelta);
        if (conf > MIN_ALLOWED_CONFIDENCE)
            ptaAddPt(pta, ycenter, angle);
        pixDestroy(&pix);
        boxDestroy(&box);
    }
/*    ptaWriteStream(stderr, pta, 0); */

        /* Do linear least squares fit */
    if ((npts = ptaGetCount(pta)) < 2) {
        ptaDestroy(&pta);
        return (NUMA *)ERROR_PTR("can't fit skew", procName, NULL);
    }
    ptaGetLinearLSF(pta, &a, &b, NULL);
    if (pa) *pa = a;
    if (pb) *pb = b;

        /* Make skew angle array as function of raster line */
    naskew = numaCreate(h);
    for (i = 0; i < h; i++) {
        angle = a * i + b;
        numaAddNumber(naskew, angle);
    }

#if  DEBUG_PLOT
{ NUMA   *nax, *nay;
  GPLOT  *gplot;
    ptaGetArrays(pta, &nax, &nay);
    gplot = gplotCreate("/tmp/lept/baseline/kew", GPLOT_PNG,
                        "skew as fctn of y", "y (in raster lines from top)",
                        "angle (in degrees)");
    gplotAddPlot(gplot, NULL, naskew, GPLOT_POINTS, "linear lsf");
    gplotAddPlot(gplot, nax, nay, GPLOT_POINTS, "actual data pts");
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    numaDestroy(&nax);
    numaDestroy(&nay);
}
#endif  /* DEBUG_PLOT */

    ptaDestroy(&pta);
    return naskew;
}
예제 #24
0
int main(int    argc,
         char **argv)
{
l_int32      i, j, n;
l_int32      w, h, bw, bh, wpls, rval, gval, bval, same;
l_uint32     pixel;
l_uint32    *lines, *datas;
l_float32    sum1, sum2, sum3, ave1, ave2, ave3, ave4, diff1, diff2;
l_float32    var1, var2, var3;
BOX         *box1, *box2;
NUMA        *na, *na1, *na2, *na3, *na4;
PIX         *pix, *pixs, *pix1, *pix2, *pix3, *pix4, *pix5, *pixg, *pixd;
PIXA        *pixa;
PTA         *pta;
static char  mainName[] = "numa2_reg";

    if (argc != 1)
        return ERROR_INT(" Syntax:  numa2_reg", mainName, 1);

    /* -------------------------------------------------------------------*
     *                         Numa-windowed stats                        *
     * -------------------------------------------------------------------*/
#if  DO_ALL
    na = numaRead("lyra-5.numa");
    numaWindowedStats(na, 5, &na1, &na2, &na3, &na4);
    gplotSimple1(na, GPLOT_PNG, "/tmp/lyraroot6", "Original");
    gplotSimple1(na1, GPLOT_PNG, "/tmp/lyraroot7", "Mean");
    gplotSimple1(na2, GPLOT_PNG, "/tmp/lyraroot8", "Mean Square");
    gplotSimple1(na3, GPLOT_PNG, "/tmp/lyraroot9", "Variance");
    gplotSimple1(na4, GPLOT_PNG, "/tmp/lyraroot10", "RMS Difference");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixa = pixaCreate(5);
    pix1 = pixRead("/tmp/lyraroot6.png");
    pix2 = pixRead("/tmp/lyraroot7.png");
    pix3 = pixRead("/tmp/lyraroot8.png");
    pix4 = pixRead("/tmp/lyraroot9.png");
    pix5 = pixRead("/tmp/lyraroot10.png");
    pixSaveTiled(pix1, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix2, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix3, pixa, 1.0, 0, 25, 32);
    pixSaveTiled(pix4, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix5, pixa, 1.0, 0, 25, 32);
    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplay(pixd, 100, 100);
    pixWrite("/tmp/numawindow.png", pixd, IFF_PNG);
    numaDestroy(&na);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    numaDestroy(&na4);
    pixaDestroy(&pixa);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pixd);
#endif

    /* -------------------------------------------------------------------*
     *                        Extraction on a line                        *
     * -------------------------------------------------------------------*/
#if  DO_ALL
        /* First, make a pretty image */
    w = h = 200;
    pixs = pixCreate(w, h, 32);
    wpls = pixGetWpl(pixs);
    datas = pixGetData(pixs);
    for (i = 0; i < 200; i++) {
        lines = datas + i * wpls;
        for (j = 0; j < 200; j++) {
            rval = (l_int32)((255. * j) / w + (255. * i) / h);
            gval = (l_int32)((255. * 2 * j) / w + (255. * 2 * i) / h) % 255;
            bval = (l_int32)((255. * 4 * j) / w + (255. * 4 * i) / h) % 255;
            composeRGBPixel(rval, gval, bval, &pixel);
            lines[j] = pixel;
        }
    }
    pixg = pixConvertTo8(pixs, 0);  /* and a grayscale version */
    pixWrite("/tmp/junkpixg", pixg, IFF_PNG);
    pixDisplay(pixg, 450, 100);

    na1 = pixExtractOnLine(pixg, 20, 20, 180, 20, 1);
    na2 = pixExtractOnLine(pixg, 40, 30, 40, 170, 1);
    na3 = pixExtractOnLine(pixg, 20, 170, 180, 30, 1);
    na4 = pixExtractOnLine(pixg, 20, 190, 180, 10, 1);
    gplotSimple1(na1, GPLOT_PNG, "/tmp/extroot1", "Horizontal");
    gplotSimple1(na2, GPLOT_PNG, "/tmp/extroot2", "Vertical");
    gplotSimple1(na3, GPLOT_PNG, "/tmp/extroot3",
                "Slightly more horizontal than vertical");
    gplotSimple1(na4, GPLOT_PNG, "/tmp/extroot4",
                "Slightly more vertical than horizontal");
#ifndef  _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif  /* _WIN32 */
    pixa = pixaCreate(4);
    pix1 = pixRead("/tmp/extroot1.png");
    pix2 = pixRead("/tmp/extroot2.png");
    pix3 = pixRead("/tmp/extroot3.png");
    pix4 = pixRead("/tmp/extroot4.png");
    pixSaveTiled(pix1, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix2, pixa, 1.0, 0, 25, 32);
    pixSaveTiled(pix3, pixa, 1.0, 1, 25, 32);
    pixSaveTiled(pix4, pixa, 1.0, 0, 25, 32);
    pixd = pixaDisplay(pixa, 0, 0);
    pixDisplay(pixd, 100, 500);
    pixWrite("/tmp/numaextract.png", pixd, IFF_PNG);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    numaDestroy(&na4);
    pixaDestroy(&pixa);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pixs);
    pixDestroy(&pixg);
    pixDestroy(&pixd);
#endif

    /* -------------------------------------------------------------------*
     *                     Row and column pixel sums                      *
     * -------------------------------------------------------------------*/
#if  DO_ALL
        /* Sum by columns in two halves (left and right) */
    pixs = pixRead("test8.jpg");
    pixGetDimensions(pixs, &w, &h, NULL);
    box1 = boxCreate(0, 0, w / 2, h);
    box2 = boxCreate(w / 2, 0, w - 2 / 2, h);
    na1 = pixAverageByColumn(pixs, box1, L_BLACK_IS_MAX);
    na2 = pixAverageByColumn(pixs, box2, L_BLACK_IS_MAX);
    numaJoin(na1, na2, 0, -1);
    na3 = pixAverageByColumn(pixs, NULL, L_BLACK_IS_MAX);
    numaSimilar(na1, na3, 0.0, &same);
    if (same)
        fprintf(stderr, "Same for columns\n");
    else
        fprintf(stderr, "Error for columns\n");
    pta = generatePlotPtaFromNuma(na3, L_HORIZONTAL_LINE, 3, h / 2, 80, 1);
    pix = pixConvertTo32(pixs);
    pixRenderPtaArb(pix, pta, 255, 0, 0);
    boxDestroy(&box1);
    boxDestroy(&box2);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    ptaDestroy(&pta);

        /* Sum by rows in two halves (top and bottom) */
    box1 = boxCreate(0, 0, w, h / 2);
    box2 = boxCreate(0, h / 2, w, h - h / 2);
    na1 = pixAverageByRow(pixs, box1, L_WHITE_IS_MAX);
    na2 = pixAverageByRow(pixs, box2, L_WHITE_IS_MAX);
    numaJoin(na1, na2, 0, -1);
    na3 = pixAverageByRow(pixs, NULL, L_WHITE_IS_MAX);
    numaSimilar(na1, na3, 0.0, &same);
    if (same)
        fprintf(stderr, "Same for rows\n");
    else
        fprintf(stderr, "Error for rows\n");
    pta = generatePlotPtaFromNuma(na3, L_VERTICAL_LINE, 3, w / 2, 80, 1);
    pixRenderPtaArb(pix, pta, 0, 255, 0);
    pixDisplay(pix, 500, 200);
    boxDestroy(&box1);
    boxDestroy(&box2);
    numaDestroy(&na1);
    numaDestroy(&na2);
    numaDestroy(&na3);
    pixDestroy(&pix);
    ptaDestroy(&pta);

        /* Average left by rows; right by columns; compare totals */
    box1 = boxCreate(0, 0, w / 2, h);
    box2 = boxCreate(w / 2, 0, w - 2 / 2, h);
    na1 = pixAverageByRow(pixs, box1, L_WHITE_IS_MAX);
    na2 = pixAverageByColumn(pixs, box2, L_WHITE_IS_MAX);
    numaGetSum(na1, &sum1);  /* sum of averages of left box */
    numaGetSum(na2, &sum2);  /* sum of averages of right box */
    ave1 = sum1 / h;
    ave2 = 2.0 * sum2 / w;
    ave3 = 0.5 * (ave1 + ave2);  /* average over both halves */
    fprintf(stderr, "ave1 = %8.4f\n", sum1 / h);
    fprintf(stderr, "ave2 = %8.4f\n", 2.0 * sum2 / w);
    pixAverageInRect(pixs, NULL, &ave4);  /* entire image */
    diff1 = ave4 - ave3;
    diff2 = w * h * ave4 - (0.5 * w * sum1 + h * sum2);
    if (diff1 < 0.001)
        fprintf(stderr, "Average diffs are correct\n");
    else
        fprintf(stderr, "Average diffs are wrong: diff1 = %7.5f\n", diff1);
    if (diff2 < 20)  /* float-to-integer roundoff */
        fprintf(stderr, "Pixel sums are correct\n");
    else
        fprintf(stderr, "Pixel sums are in error: diff = %7.0f\n", diff2);

        /* Variance left and right halves.  Variance doesn't average
         * in a simple way, unlike pixel sums. */
    pixVarianceInRect(pixs, box1, &var1);  /* entire image */
    pixVarianceInRect(pixs, box2, &var2);  /* entire image */
    pixVarianceInRect(pixs, NULL, &var3);  /* entire image */
    fprintf(stderr, "0.5 * (var1 + var2) = %7.3f, var3 = %7.3f\n",
            0.5 * (var1 + var2), var3);
    boxDestroy(&box1);
    boxDestroy(&box2);
    numaDestroy(&na1);
    numaDestroy(&na2);
#endif

    /* -------------------------------------------------------------------*
     *                     Row and column variances                       *
     * -------------------------------------------------------------------*/
#if  DO_ALL
        /* Display variance by rows and columns */
    box1 = boxCreate(415, 0, 130, 425);
    boxGetGeometry(box1, NULL, NULL, &bw, &bh);
    na1 = pixVarianceByRow(pixs, box1);
    na2 = pixVarianceByColumn(pixs, box1);
    pix = pixConvertTo32(pixs);
    pta = generatePlotPtaFromNuma(na1, L_VERTICAL_LINE, 3, 415, 100, 1);
    pixRenderPtaArb(pix, pta, 255, 0, 0);
    ptaDestroy(&pta);
    pta = generatePlotPtaFromNuma(na2, L_HORIZONTAL_LINE, 3, bh / 2, 100, 1);
    pixRenderPtaArb(pix, pta, 0, 255, 0);
    pixDisplay(pix, 500, 900);
    boxDestroy(&box1);
    numaDestroy(&na1);
    numaDestroy(&na2);
    ptaDestroy(&pta);
    pixDestroy(&pix);
    pixDestroy(&pixs);

        /* Again on a different image */
    pix1 = pixRead("boxedpage.jpg");
    pix2 = pixConvertTo8(pix1, 0);
    pixGetDimensions(pix2, &w, &h, NULL);
    na1 = pixVarianceByRow(pix2, NULL);
    pta = generatePlotPtaFromNuma(na1, L_VERTICAL_LINE, 3, 0, 70, 1);
    pix3 = pixConvertTo32(pix1);
    pixRenderPtaArb(pix3, pta, 255, 0, 0);
    ptaDestroy(&pta);
    na2 = pixVarianceByColumn(pix2, NULL);
    pta = generatePlotPtaFromNuma(na2, L_HORIZONTAL_LINE, 3, bh - 1, 70, 1);
    pixRenderPtaArb(pix3, pta, 0, 255, 0);
    pixDisplay(pix3, 1000, 0);
    numaDestroy(&na1);
    numaDestroy(&na2);
    ptaDestroy(&pta);
    pixDestroy(&pix3);

        /* Again, with an erosion */
    pix3 = pixErodeGray(pix2, 3, 21);
    pixDisplay(pix3, 1400, 0);
    na1 = pixVarianceByRow(pix3, NULL);
    pta = generatePlotPtaFromNuma(na1, L_VERTICAL_LINE, 3, 30, 70, 1);
    pix4 = pixConvertTo32(pix1);
    pixRenderPtaArb(pix4, pta, 255, 0, 0);
    ptaDestroy(&pta);
    na2 = pixVarianceByColumn(pix3, NULL);
    pta = generatePlotPtaFromNuma(na2, L_HORIZONTAL_LINE, 3, bh - 1, 70, 1);
    pixRenderPtaArb(pix4, pta, 0, 255, 0);
    pixDisplay(pix4, 1000, 550);
    numaDestroy(&na1);
    numaDestroy(&na2);
    ptaDestroy(&pta);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
#endif

    /* -------------------------------------------------------------------*
     *                    Windowed variance along a line                  *
     * -------------------------------------------------------------------*/
#if  DO_ALL
    pix1 = pixRead("boxedpage.jpg");
    pix2 = pixConvertTo8(pix1, 0);
    pixGetDimensions(pix2, &w, &h, NULL);

        /* Plot along horizontal line */
    pixWindowedVarianceOnLine(pix2, L_HORIZONTAL_LINE, h / 2 - 30, 0,
                              w, 5, &na1);
    pta = generatePlotPtaFromNuma(na1, L_HORIZONTAL_LINE, 3,
                                   h / 2 - 30, 80, 1);
    pixRenderPtaArb(pix1, pta, 255, 0, 0);
    numaDestroy(&na1);
    ptaDestroy(&pta);

        /* Plot along vertical line */
    pixWindowedVarianceOnLine(pix2, L_VERTICAL_LINE, 0.78 * w, 0,
                              h, 5, &na1);
    pta = generatePlotPtaFromNuma(na1, L_VERTICAL_LINE, 3,
                                   0.78 * w, 60, 1);
    pixRenderPtaArb(pix1, pta, 0, 255, 0);
    pixDisplay(pix1, 100, 100);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    numaDestroy(&na1);
    ptaDestroy(&pta);
#endif
    return 0;
}
예제 #25
0
int main(int    argc,
         char **argv)
{
char          bufname[256];
l_int32       i, w, h;
l_float32    *mat1, *mat2, *mat3, *mat1i, *mat2i, *mat3i, *matdinv;
l_float32     matd[9], matdi[9];
BOXA         *boxa, *boxa2;
PIX          *pix, *pixs, *pixb, *pixg, *pixc, *pixcs;
PIX          *pixd, *pix1, *pix2, *pix3;
PIXA         *pixa;
PTA          *ptas, *ptad;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    pix = pixRead("feyn.tif");
    pixs = pixScale(pix, 0.22, 0.22);
    pixDestroy(&pix);

#if ALL
        /* Test invertability of sequential. */
    fprintf(stderr, "Test invertability of sequential\n");
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixs, ADDED_BORDER_PIXELS, 0);
        MakePtas(i, &ptas, &ptad);
        pix1 = pixAffineSequential(pixb, ptad, ptas, 0, 0);
        regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 0,3,6 */
        pixaAddPix(pixa, pix1, L_INSERT);
        pix2 = pixAffineSequential(pix1, ptas, ptad, 0, 0);
        regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 1,4,7 */
        pixaAddPix(pixa, pix2, L_INSERT);
        pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixs);
        regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 2,5,8 */
        pixaAddPix(pixa, pixd, L_INSERT);
        pixDestroy(&pixb);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
    pix2 = pixScaleToGray(pix1, 0.2);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 9 */
    pixDisplayWithTitle(pix2, 0, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixaDestroy(&pixa);
#endif

#if ALL
        /* Test invertability of sampling */
    fprintf(stderr, "Test invertability of sampling\n");
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixs, ADDED_BORDER_PIXELS, 0);
        MakePtas(i, &ptas, &ptad);
        pix1 = pixAffineSampledPta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 10,13,16 */
        pixaAddPix(pixa, pix1, L_INSERT);
        pix2 = pixAffineSampledPta(pix1, ptas, ptad, L_BRING_IN_WHITE);
        regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 11,14,17 */
        pixaAddPix(pixa, pix2, L_INSERT);
        pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixs);
        regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 12,15,18 */
        pixaAddPix(pixa, pixd, L_INSERT);
        pixDestroy(&pixb);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
    pix2 = pixScaleToGray(pix1, 0.2);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 19 */
    pixDisplayWithTitle(pix2, 200, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixs);
    pixaDestroy(&pixa);
#endif

#if ALL
        /* Test invertability of interpolation on grayscale */
    fprintf(stderr, "Test invertability of grayscale interpolation\n");
    pix = pixRead("feyn.tif");
    pixg = pixScaleToGray3(pix);
    pixDestroy(&pix);
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixg, ADDED_BORDER_PIXELS / 3, 255);
        MakePtas(i, &ptas, &ptad);
        pix1 = pixAffinePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG);  /* 20,23,26 */
        pixaAddPix(pixa, pix1, L_INSERT);
        pix2 = pixAffinePta(pix1, ptas, ptad, L_BRING_IN_WHITE);
        regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 21,24,27 */
        pixaAddPix(pixa, pix2, L_INSERT);
        pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS / 3);
        pixXor(pixd, pixd, pixg);
        pixInvert(pixd, pixd);
        regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG);  /* 22,25,28 */
        pixaAddPix(pixa, pixd, L_INSERT);
        pixDestroy(&pixb);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
    pix2 = pixScale(pix1, 0.2, 0.2);
    regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 29 */
    pixDisplayWithTitle(pix2, 400, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixg);
    pixaDestroy(&pixa);
#endif

#if ALL
        /* Test invertability of interpolation on color */
    fprintf(stderr, "Test invertability of color interpolation\n");
    pixa = pixaCreate(0);
    pixc = pixRead("test24.jpg");
    pixcs = pixScale(pixc, 0.3, 0.3);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixcs, ADDED_BORDER_PIXELS / 4, 0xffffff00);
        MakePtas(i, &ptas, &ptad);
        pix1 = pixAffinePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG);  /* 30,33,36 */
        pixaAddPix(pixa, pix1, L_INSERT);
        pix2 = pixAffinePta(pix1, ptas, ptad, L_BRING_IN_WHITE);
        regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 31,34,37 */
        pixaAddPix(pixa, pix2, L_INSERT);
        pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS / 4);
        pixXor(pixd, pixd, pixcs);
        pixInvert(pixd, pixd);
        regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG);  /* 32,35,38 */
        pixaAddPix(pixa, pixd, L_INSERT);
        pixDestroy(&pixb);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
    pix2 = pixScale(pix1, 0.25, 0.25);
    regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 39 */
    pixDisplayWithTitle(pix2, 600, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixc);
    pixaDestroy(&pixa);
#endif

#if ALL
       /* Comparison between sequential and sampling */
    fprintf(stderr, "Compare sequential with sampling\n");
    pix = pixRead("feyn.tif");
    pixs = pixScale(pix, 0.22, 0.22);
    pixDestroy(&pix);

    MakePtas(3, &ptas, &ptad);
    pixa = pixaCreate(0);

        /* Use sequential transforms */
    pix1 = pixAffineSequential(pixs, ptas, ptad,
                     ADDED_BORDER_PIXELS, ADDED_BORDER_PIXELS);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 40 */
    pixaAddPix(pixa, pix1, L_INSERT);

        /* Use sampled transform */
    pix2 = pixAffineSampledPta(pixs, ptas, ptad, L_BRING_IN_WHITE);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 41 */
    pixaAddPix(pixa, pix2, L_COPY);

        /* Compare the results */
    pixXor(pix2, pix2, pix1);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 42 */
    pixaAddPix(pixa, pix2, L_INSERT);

    pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
    pix2 = pixScale(pix1, 0.5, 0.5);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 43 */
    pixDisplayWithTitle(pix2, 800, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixs);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif


#if ALL
       /* Test with large distortion */
    fprintf(stderr, "Test with large distortion\n");
    MakePtas(4, &ptas, &ptad);
    pixa = pixaCreate(0);
    pix = pixRead("feyn.tif");
    pixg = pixScaleToGray6(pix);
    pixDestroy(&pix);

    pix1 = pixAffineSequential(pixg, ptas, ptad, 0, 0);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 44 */
    pixaAddPix(pixa, pix1, L_COPY);

    pix2 = pixAffineSampledPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 45 */
    pixaAddPix(pixa, pix2, L_COPY);

    pix3 = pixAffinePta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    regTestWritePixAndCheck(rp, pix3, IFF_PNG);  /* 46 */
    pixaAddPix(pixa, pix3, L_INSERT);

    pixXor(pix1, pix1, pix2);
    pixInvert(pix1, pix1);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 47 */
    pixaAddPix(pixa, pix1, L_INSERT);
    pixXor(pix2, pix2, pix3);
    pixInvert(pix2, pix2);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 48 */
    pixaAddPix(pixa, pix2, L_INSERT);

    pix1 = pixaDisplayTiledInColumns(pixa, 5, 1.0, 20, 3);
    pix2 = pixScale(pix1, 0.8, 0.8);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 49 */
    pixDisplayWithTitle(pix2, 1000, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pixg);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

#if ALL 
        /* Set up pix and boxa */
    fprintf(stderr, "Test affine transforms and inverses on pix and boxa\n");
    pixa = pixaCreate(0);
    pix = pixRead("lucasta.1.300.tif");
    pixTranslate(pix, pix, 70, 0, L_BRING_IN_WHITE);
    pix1 = pixCloseBrick(NULL, pix, 14, 5);
    pixOpenBrick(pix1, pix1, 1, 2);
    boxa = pixConnComp(pix1, NULL, 8);
    pixs = pixConvertTo32(pix);
    pixGetDimensions(pixs, &w, &h, NULL);
    pixc = pixCopy(NULL, pixs);
    RenderHashedBoxa(pixc, boxa, 113);
    regTestWritePixAndCheck(rp, pixc, IFF_PNG);  /* 50 */
    pixaAddPix(pixa, pixc, L_INSERT);
    pixDestroy(&pix);
    pixDestroy(&pix1);

        /* Set up an affine transform in matd, and apply it to boxa */
    mat1 = createMatrix2dTranslate(SHIFTX, SHIFTY);
    mat2 = createMatrix2dScale(SCALEX, SCALEY);
    mat3 = createMatrix2dRotate(w / 2, h / 2, ROTATION);
    l_productMat3(mat3, mat2, mat1, matd, 3);
    boxa2 = boxaAffineTransform(boxa, matd);

        /* Set up the inverse transform --> matdi */
    mat1i = createMatrix2dTranslate(-SHIFTX, -SHIFTY);
    mat2i = createMatrix2dScale(1.0/ SCALEX, 1.0 / SCALEY);
    mat3i = createMatrix2dRotate(w / 2, h / 2, -ROTATION);
    l_productMat3(mat1i, mat2i, mat3i, matdi, 3);

        /* Invert the original affine transform --> matdinv */
    affineInvertXform(matd, &matdinv);
    if (rp->display) { 
        fprintf(stderr, "  Affine transform, applied to boxa\n");
        for (i = 0; i < 9; i++) {
            if (i && (i % 3 == 0))  fprintf(stderr, "\n");
            fprintf(stderr, "   %7.3f ", matd[i]);
        }
        fprintf(stderr, "\n  Inverse transform, by composing inverse parts");
        for (i = 0; i < 9; i++) {
            if (i % 3 == 0)  fprintf(stderr, "\n");
            fprintf(stderr, "   %7.3f ", matdi[i]);
        }
        fprintf(stderr, "\n  Inverse transform, by inverting affine xform");
        for (i = 0; i < 6; i++) {
            if (i % 3 == 0)  fprintf(stderr, "\n");
            fprintf(stderr, "   %7.3f ", matdinv[i]);
        }
        fprintf(stderr, "\n");
    }

        /* Apply the inverted affine transform --> pixs */
    pixd = pixAffine(pixs, matdinv, L_BRING_IN_WHITE);
    RenderHashedBoxa(pixd, boxa2, 513);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 51 */
    pixaAddPix(pixa, pixd, L_INSERT);

    pix1 = pixaDisplayTiledInColumns(pixa, 2, 1.0, 30, 2);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 52 */
    pixDisplayWithTitle(pix1, 1200, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixaDestroy(&pixa);

    pixDestroy(&pixs);
    boxaDestroy(&boxa);
    boxaDestroy(&boxa2);
    lept_free(mat1);
    lept_free(mat2);
    lept_free(mat3);
    lept_free(mat1i);
    lept_free(mat2i);
    lept_free(mat3i);
    lept_free(matdinv);
#endif

    return regTestCleanup(rp);
}
예제 #26
0
int main(int argc,
         char **argv) {
    char bufname[256];
    l_int32 i, w, h;
    l_float32 *mat1, *mat2, *mat3, *mat1i, *mat2i, *mat3i, *matdinv;
    l_float32 matd[9], matdi[9];
    BOXA *boxa, *boxa2;
    PIX *pix, *pixs, *pixb, *pixg, *pixc, *pixcs;
    PIX *pixd, *pixt1, *pixt2, *pixt3;
    PIXA *pixa;
    PTA *ptas, *ptad;
    static char mainName[] = "affine_reg";

    if (argc != 1)
        return ERROR_INT(" Syntax:  affine_reg", mainName, 1);

    if ((pixs = pixRead("feyn.tif")) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);

#if 1
    /* Test invertability of sequential. */
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixs, ADDED_BORDER_PIXELS, 0);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixAffineSequential(pixb, ptad, ptas, 0, 0);
        pixSaveTiled(pixt1, pixa, 0.3333, 1, 20, 8);
        pixt2 = pixAffineSequential(pixt1, ptas, ptad, 0, 0);
        pixSaveTiled(pixt2, pixa, 0.3333, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixs);
        pixSaveTiled(pixd, pixa, 0.3333, 0, 20, 0);
        sprintf(bufname, "/tmp/seq%d.png", i);
        pixWrite(bufname, pixd, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine1.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 100);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
#endif

#if ALL
    /* Test invertability of sampling */
    pixa = pixaCreate(0);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixs, ADDED_BORDER_PIXELS, 0);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixAffineSampledPta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 0.3333, 1, 20, 8);
        pixt2 = pixAffineSampledPta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 0.3333, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS);
        pixXor(pixd, pixd, pixs);
        pixSaveTiled(pixd, pixa, 0.3333, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/samp.png", pixt1, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine2.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 300);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
#endif

#if ALL
    /* Test invertability of interpolation on grayscale */
    pixa = pixaCreate(0);
    pixg = pixScaleToGray3(pixs);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixg, ADDED_BORDER_PIXELS / 3, 255);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixAffinePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1.0, 1, 20, 8);
        pixt2 = pixAffinePta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1.0, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS / 3);
        pixXor(pixd, pixd, pixg);
        pixSaveTiled(pixd, pixa, 1.0, 0, 20, 0);
        if (i == 0) pixWrite("/tmp/interp.png", pixt1, IFF_PNG);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine3.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 500);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
    pixDestroy(&pixg);
#endif

#if ALL
    /* Test invertability of interpolation on color */
    pixa = pixaCreate(0);
    pixc = pixRead("test24.jpg");
    pixcs = pixScale(pixc, 0.3, 0.3);
    for (i = 0; i < 3; i++) {
        pixb = pixAddBorder(pixcs, ADDED_BORDER_PIXELS / 4, 0xffffff00);
        MakePtas(i, &ptas, &ptad);
        pixt1 = pixAffinePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
        pixSaveTiled(pixt1, pixa, 1.0, 1, 20, 32);
        pixt2 = pixAffinePta(pixt1, ptas, ptad, L_BRING_IN_WHITE);
        pixSaveTiled(pixt2, pixa, 1.0, 0, 20, 0);
        pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS / 4);
        pixXor(pixd, pixd, pixcs);
        pixSaveTiled(pixd, pixa, 1.0, 0, 20, 0);
        pixDestroy(&pixb);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixd);
        ptaDestroy(&ptas);
        ptaDestroy(&ptad);
    }

    pixt1 = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine4.png", pixt1, IFF_PNG);
    pixDisplay(pixt1, 100, 500);
    pixDestroy(&pixt1);
    pixaDestroy(&pixa);
    pixDestroy(&pixc);
    pixDestroy(&pixcs);
#endif

#if ALL
    /* Comparison between sequential and sampling */
    MakePtas(3, &ptas, &ptad);
    pixa = pixaCreate(0);

    /* Use sequential transforms */
    pixt1 = pixAffineSequential(pixs, ptas, ptad,
                                ADDED_BORDER_PIXELS, ADDED_BORDER_PIXELS);
    pixSaveTiled(pixt1, pixa, 0.5, 0, 20, 8);

    /* Use sampled transform */
    pixt2 = pixAffineSampledPta(pixs, ptas, ptad, L_BRING_IN_WHITE);
    pixSaveTiled(pixt2, pixa, 0.5, 0, 20, 8);

    /* Compare the results */
    pixXor(pixt2, pixt2, pixt1);
    pixSaveTiled(pixt2, pixa, 0.5, 0, 20, 8);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine5.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 700);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

#if ALL
    /* Get timings and test with large distortion */
    MakePtas(4, &ptas, &ptad);
    pixa = pixaCreate(0);
    pixg = pixScaleToGray3(pixs);

    startTimer();
    pixt1 = pixAffineSequential(pixg, ptas, ptad, 0, 0);
    fprintf(stderr, " Time for pixAffineSequentialPta(): %6.2f sec\n",
            stopTimer());
    pixSaveTiled(pixt1, pixa, 1.0, 1, 20, 8);

    startTimer();
    pixt2 = pixAffineSampledPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixAffineSampledPta(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt2, pixa, 1.0, 0, 20, 8);

    startTimer();
    pixt3 = pixAffinePta(pixg, ptas, ptad, L_BRING_IN_WHITE);
    fprintf(stderr, " Time for pixAffinePta(): %6.2f sec\n", stopTimer());
    pixSaveTiled(pixt3, pixa, 1.0, 0, 20, 8);

    pixXor(pixt1, pixt1, pixt2);
    pixSaveTiled(pixt1, pixa, 1.0, 1, 20, 8);
    pixXor(pixt2, pixt2, pixt3);
    pixSaveTiled(pixt2, pixa, 1.0, 0, 20, 8);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixt3);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine6.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 900);
    pixDestroy(&pixd);
    pixDestroy(&pixg);
    pixaDestroy(&pixa);
    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
#endif

    pixDestroy(&pixs);

#if ALL
    /* Set up pix and boxa */
    pixa = pixaCreate(0);
    pix = pixRead("lucasta.1.300.tif");
    pixTranslate(pix, pix, 70, 0, L_BRING_IN_WHITE);
    pixt1 = pixCloseBrick(NULL, pix, 14, 5);
    pixOpenBrick(pixt1, pixt1, 1, 2);
    boxa = pixConnComp(pixt1, NULL, 8);
    pixs = pixConvertTo32(pix);
    pixGetDimensions(pixs, &w, &h, NULL);
    pixc = pixCopy(NULL, pixs);
    RenderHashedBoxa(pixc, boxa, 113);
    pixSaveTiled(pixc, pixa, 0.5, 1, 30, 32);
    pixDestroy(&pix);
    pixDestroy(&pixc);
    pixDestroy(&pixt1);

    /* Set up an affine transform in matd, and apply it to boxa */
    mat1 = createMatrix2dTranslate(SHIFTX, SHIFTY);
    mat2 = createMatrix2dScale(SCALEX, SCALEY);
    mat3 = createMatrix2dRotate(w / 2, h / 2, ROTATION);
    l_productMat3(mat3, mat2, mat1, matd, 3);
    boxa2 = boxaAffineTransform(boxa, matd);

    /* Set up the inverse transform in matdi */
    mat1i = createMatrix2dTranslate(-SHIFTX, -SHIFTY);
    mat2i = createMatrix2dScale(1.0 / SCALEX, 1.0 / SCALEY);
    mat3i = createMatrix2dRotate(w / 2, h / 2, -ROTATION);
    l_productMat3(mat1i, mat2i, mat3i, matdi, 3);

    /* Invert the original affine transform in matdinv */
    affineInvertXform(matd, &matdinv);
    fprintf(stderr, "Affine transform, applied to boxa\n");
    for (i = 0; i < 9; i++) {
        if (i && (i % 3 == 0)) fprintf(stderr, "\n");
        fprintf(stderr, " %7.3f ", matd[i]);
    }
    fprintf(stderr, "\nInverse transform, made by composing inverse parts");
    for (i = 0; i < 9; i++) {
        if (i % 3 == 0) fprintf(stderr, "\n");
        fprintf(stderr, " %7.3f ", matdi[i]);
    }
    fprintf(stderr, "\nInverse transform, made by inverting the affine xform");
    for (i = 0; i < 6; i++) {
        if (i % 3 == 0) fprintf(stderr, "\n");
        fprintf(stderr, " %7.3f ", matdinv[i]);
    }
    fprintf(stderr, "\n");

    /* Apply the inverted affine transform pixs */
    pixd = pixAffine(pixs, matdinv, L_BRING_IN_WHITE);
    RenderHashedBoxa(pixd, boxa2, 513);
    pixSaveTiled(pixd, pixa, 0.5, 0, 30, 32);
    pixDestroy(&pixd);

    pixd = pixaDisplay(pixa, 0, 0);
    pixWrite("/tmp/affine7.png", pixd, IFF_PNG);
    pixDisplay(pixd, 100, 900);
    pixDestroy(&pixd);
    pixDestroy(&pixs);
    pixaDestroy(&pixa);
    boxaDestroy(&boxa);
    boxaDestroy(&boxa2);
    lept_free(mat1);
    lept_free(mat2);
    lept_free(mat3);
    lept_free(mat1i);
    lept_free(mat2i);
    lept_free(mat3i);
#endif

    return 0;
}
예제 #27
0
int 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.0, 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, 0, 20, 8);
    pixDestroy(&pixt);
    pixt = kernelDisplayInPix(kely, 41, 2);
    regTestWritePixAndCheck(rp, pixt, IFF_PNG);  /* 2 */
    pixSaveTiled(pixt, pixa, 1.0, 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.0, 1, 20, 8);
    pixt2 = pixConvolveSep(pixs, kelx, kely, 8, 1);
    regTestWritePixAndCheck(rp, pixt2, IFF_JFIF_JPEG);  /* 5 */
    pixSaveTiled(pixt2, pixa, 1.0, 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.0, 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, 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.0, 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, 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/lept/compare_gray0.png");
    regTestWritePixAndCheck(rp, pixt5, IFF_PNG);  /* 10 */
    pixSaveTiled(pixt5, pixa, 1.0, 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.0, 1, 20, 32);
    pixt2 = pixConvolveSep(pixg, kelx, kely, 8, 1);
    regTestWritePixAndCheck(rp, pixt2, IFF_JFIF_JPEG);  /* 13 */
    pixSaveTiled(pixt2, pixa, 1.0, 0, 20, 32);
    pixt3 = pixConvolveRGB(pixs, kel);
    regTestWritePixAndCheck(rp, pixt3, IFF_JFIF_JPEG);  /* 14 */
    pixSaveTiled(pixt3, pixa, 1.0, 0, 20, 32);
    pixt4 = pixConvolveRGBSep(pixs, kelx, kely);
    regTestWritePixAndCheck(rp, pixt4, IFF_JFIF_JPEG);  /* 15 */
    pixSaveTiled(pixt4, pixa, 1.0, 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.0, 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, 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);
    if ((dew = dewarpCreate(pixb, 35)) == NULL) {
        rp->success = FALSE;
        L_ERROR("dew not made; tests 21-28 skipped (failed)\n", "fpix1_reg");
        return regTestCleanup(rp);
    }
    dewarpaInsertDewarp(dewa, dew);
    dewarpBuildPageModel(dew, NULL);
    dewarpPopulateFullRes(dew, NULL, 0, 0);
    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/regout/fpix1.fp", dew->fullvdispar);
    fpix1 = fpixRead("/tmp/regout/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);
}
예제 #28
0
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)
	exit(ERROR_INT(" Syntax:  cornertest filein fileout", mainName, 1));

    filein = argv[1];
    fileout = argv[2];

    if ((pixs = pixRead(filein)) == NULL)
	exit(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, 3,
	              L_FLIP_PIXELS);
	pixRenderLine(pixs, x, y - LINE_SIZE, x, y + LINE_SIZE, 3,
	              L_FLIP_PIXELS);
    }

    pixWrite(fileout, pixs, IFF_PNG);

    pixDestroy(&pixs);
    ptaDestroy(&pta);
    ptaDestroy(&pta);
    return 0;
}
예제 #29
0
파일: pta_reg.c 프로젝트: vkbrad/AndroidOCR
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);
}
예제 #30
0
파일: sel2.c 프로젝트: pnordhus/leptonica
/*!
 * \brief   selaAddCrossJunctions()
 *
 * \param[in]    sela [optional]
 * \param[in]    hlsize length of each line of hits from origin
 * \param[in]    mdist distance of misses from the origin
 * \param[in]    norient number of orientations; max of 8
 * \param[in]    debugflag 1 for debug output
 * \return  sela with additional sels, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) Adds hitmiss Sels for the intersection of two lines.
 *          If the lines are very thin, they must be nearly orthogonal
 *          to register.
 *      (2) The number of Sels generated is equal to %norient.
 *      (3) If %norient == 2, this generates 2 Sels of crosses, each with
 *          two perpendicular lines of hits.  One Sel has horizontal and
 *          vertical hits; the other has hits along lines at +-45 degrees.
 *          Likewise, if %norient == 3, this generates 3 Sels of crosses
 *          oriented at 30 degrees with each other.
 *      (4) It is suggested that %hlsize be chosen at least 1 greater
 *          than %mdist.  Try values of (%hlsize, %mdist) such as
 *          (6,5), (7,6), (8,7), (9,7), etc.
 * </pre>
 */
SELA *
selaAddCrossJunctions(SELA      *sela,
                      l_float32  hlsize,
                      l_float32  mdist,
                      l_int32    norient,
                      l_int32    debugflag)
{
char       name[L_BUF_SIZE];
l_int32    i, j, w, xc, yc;
l_float64  pi, halfpi, radincr, radang;
l_float64  angle;
PIX       *pixc, *pixm, *pixt;
PIXA      *pixa;
PTA       *pta1, *pta2, *pta3, *pta4;
SEL       *sel;

    PROCNAME("selaAddCrossJunctions");

    if (hlsize <= 0)
        return (SELA *)ERROR_PTR("hlsize not > 0", procName, NULL);
    if (norient < 1 || norient > 8)
        return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL);

    if (!sela) {
        if ((sela = selaCreate(0)) == NULL)
            return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    }

    pi = 3.1415926535;
    halfpi = 3.1415926535 / 2.0;
    radincr = halfpi / (l_float64)norient;
    w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5));
    if (w % 2 == 0)
        w++;
    xc = w / 2;
    yc = w / 2;

    pixa = pixaCreate(norient);
    for (i = 0; i < norient; i++) {

            /* Set the don't cares */
        pixc = pixCreate(w, w, 32);
        pixSetAll(pixc);

            /* Add the green lines of hits */
        pixm = pixCreate(w, w, 1);
        radang = (l_float32)i * radincr;
        pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang);
        pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi);
        pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi);
        pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi);
        ptaJoin(pta1, pta2, 0, -1);
        ptaJoin(pta1, pta3, 0, -1);
        ptaJoin(pta1, pta4, 0, -1);
        pixRenderPta(pixm, pta1, L_SET_PIXELS);
        pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000);
        ptaDestroy(&pta1);
        ptaDestroy(&pta2);
        ptaDestroy(&pta3);
        ptaDestroy(&pta4);

            /* Add red misses between the lines */
        for (j = 0; j < 4; j++) {
            angle = radang + (j - 0.5) * halfpi;
            pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)),
                        yc + (l_int32)(mdist * sin(angle)), 0xff000000);
        }

            /* Add dark green for origin */
        pixSetPixel(pixc, xc, yc, 0x00550000);

            /* Generate the sel */
        sel = selCreateFromColorPix(pixc, NULL);
        sprintf(name, "sel_cross_%d", i);
        selaAddSel(sela, sel, name, 0);

        if (debugflag) {
            pixt = pixScaleBySampling(pixc, 10.0, 10.0);
            pixaAddPix(pixa, pixt, L_INSERT);
        }
        pixDestroy(&pixm);
        pixDestroy(&pixc);
    }

    if (debugflag) {
        l_int32  w;
        lept_mkdir("lept/sel");
        pixaGetPixDimensions(pixa, 0, &w, NULL, NULL);
        pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 1, 0, 10, 2);
        pixWrite("/tmp/lept/sel/xsel1.png", pixt, IFF_PNG);
        pixDisplay(pixt, 0, 100);
        pixDestroy(&pixt);
        pixt = selaDisplayInPix(sela, 15, 2, 20, 1);
        pixWrite("/tmp/lept/sel/xsel2.png", pixt, IFF_PNG);
        pixDisplay(pixt, 500, 100);
        pixDestroy(&pixt);
        selaWriteStream(stderr, sela);
    }
    pixaDestroy(&pixa);

    return sela;
}