/*! * ptaaSortByIndex() * * Input: ptaas * naindex (na that maps from the new ptaa to the input ptaa) * Return: ptaad (sorted), or null on error */ PTAA * ptaaSortByIndex(PTAA *ptaas, NUMA *naindex) { l_int32 i, n, index; PTA *pta; PTAA *ptaad; PROCNAME("ptaaSortByIndex"); if (!ptaas) return (PTAA *)ERROR_PTR("ptaas not defined", procName, NULL); if (!naindex) return (PTAA *)ERROR_PTR("naindex not defined", procName, NULL); n = ptaaGetCount(ptaas); if (numaGetCount(naindex) != n) return (PTAA *)ERROR_PTR("numa and ptaa sizes differ", procName, NULL); ptaad = ptaaCreate(n); for (i = 0; i < n; i++) { numaGetIValue(naindex, i, &index); pta = ptaaGetPta(ptaas, index, L_COPY); ptaaAddPta(ptaad, pta, L_INSERT); } return ptaad; }
static PIX * PtaDisplayRotate(PIX *pixs, l_float32 xc, l_float32 yc) { l_int32 i, w, h; PIX *pix1, *pix2; PTA *pta1, *pta2, *pta3, *pta4; PTAA *ptaa; /* Save rotated sets of pixels */ pta1 = ptaGetPixelsFromPix(pixs, NULL); ptaa = ptaaCreate(0); for (i = 0; i < 9; i++) { pta2 = ptaRotate(pta1, xc, yc, -0.8 + 0.2 * i); ptaaAddPta(ptaa, pta2, L_INSERT); } ptaDestroy(&pta1); /* Render them */ pixGetDimensions(pixs, &w, &h, NULL); pix1 = pixCreate(w, h, 32); pixSetAll(pix1); pta3 = generatePtaFilledCircle(4); pta4 = ptaTranslate(pta3, xc, yc); pixRenderPtaArb(pix1, pta4, 255, 0, 0); /* circle at rotation center */ pix2 = pixDisplayPtaa(pix1, ptaa); /* rotated sets */ pixDestroy(&pix1); ptaDestroy(&pta3); ptaDestroy(&pta4); ptaaDestroy(&ptaa); return pix2; }
/*! * \brief pixConnCompIncrInit() * * \param[in] pixs 1 bpp * \param[in] conn connectivity: 4 or 8 * \param[out] ppixd 32 bpp, with c.c. labelled * \param[out] pptaa with pixel locations indexed by c.c. * \param[out] pncc initial number of c.c. * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This labels the connected components in a 1 bpp pix, and * additionally sets up a ptaa that lists the locations of pixels * in each of the components. * (2) It can be used to initialize the output image and arrays for * an application that maintains information about connected * components incrementally as pixels are added. * (3) pixs can be empty or have some foreground pixels. * (4) The connectivity is stored in pixd->special. * (5) Always initialize with the first pta in ptaa being empty * and representing the background value (index 0) in the pix. * </pre> */ l_int32 pixConnCompIncrInit(PIX *pixs, l_int32 conn, PIX **ppixd, PTAA **pptaa, l_int32 *pncc) { l_int32 empty, w, h, ncc; PIX *pixd; PTA *pta; PTAA *ptaa; PROCNAME("pixConnCompIncrInit"); if (ppixd) *ppixd = NULL; if (pptaa) *pptaa = NULL; if (pncc) *pncc = 0; if (!ppixd || !pptaa || !pncc) return ERROR_INT("&pixd, &ptaa, &ncc not all defined", procName, 1); if (!pixs || pixGetDepth(pixs) != 1) return ERROR_INT("pixs undefined or not 1 bpp", procName, 1); if (conn != 4 && conn != 8) return ERROR_INT("connectivity must be 4 or 8", procName, 1); pixGetDimensions(pixs, &w, &h, NULL); pixZero(pixs, &empty); if (empty) { *ppixd = pixCreate(w, h, 32); pixSetSpp(*ppixd, 1); pixSetSpecial(*ppixd, conn); *pptaa = ptaaCreate(0); pta = ptaCreate(1); ptaaAddPta(*pptaa, pta, L_INSERT); /* reserve index 0 for background */ return 0; } /* Set up the initial labeled image and indexed pixel arrays */ if ((pixd = pixConnCompTransform(pixs, conn, 32)) == NULL) return ERROR_INT("pixd not made", procName, 1); pixSetSpecial(pixd, conn); *ppixd = pixd; if ((ptaa = ptaaIndexLabeledPixels(pixd, &ncc)) == NULL) return ERROR_INT("ptaa not made", procName, 1); *pptaa = ptaa; *pncc = ncc; return 0; }
int main(int argc, char **argv) { char *filein, *fileout; l_int32 x, y, n, i; PIX *pixs; PTA *pta; PTAA *ptaa, *ptaa2, *ptaa3; static char mainName[] = "cornertest"; if (argc != 3) return ERROR_INT(" Syntax: cornertest filein fileout", mainName, 1); filein = argv[1]; fileout = argv[2]; if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); /* Clean noise in LR corner of witten.tif */ pixSetPixel(pixs, 2252, 3051, 0); pixSetPixel(pixs, 2252, 3050, 0); pixSetPixel(pixs, 2251, 3050, 0); pta = pixFindCornerPixels(pixs); ptaWriteStream(stderr, pta, 1); /* Test pta and ptaa I/O */ #if 1 ptaa = ptaaCreate(3); ptaaAddPta(ptaa, pta, L_COPY); ptaaAddPta(ptaa, pta, L_COPY); ptaaAddPta(ptaa, pta, L_COPY); ptaaWriteStream(stderr, ptaa, 1); ptaaWrite("/tmp/junkptaa", ptaa, 1); ptaa2 = ptaaRead("/tmp/junkptaa"); ptaaWrite("/tmp/junkptaa2", ptaa2, 1); ptaaWrite("/tmp/junkptaa3", ptaa, 0); ptaa3 = ptaaRead("/tmp/junkptaa3"); ptaaWrite("/tmp/junkptaa4", ptaa3, 0); ptaaDestroy(&ptaa); ptaaDestroy(&ptaa2); ptaaDestroy(&ptaa3); #endif /* mark corner pixels */ n = ptaGetCount(pta); for (i = 0; i < n; i++) { ptaGetIPt(pta, i, &x, &y); pixRenderLine(pixs, x - LINE_SIZE, y, x + LINE_SIZE, y, 5, L_FLIP_PIXELS); pixRenderLine(pixs, x, y - LINE_SIZE, x, y + LINE_SIZE, 5, L_FLIP_PIXELS); } pixWrite(fileout, pixs, IFF_PNG); pixDestroy(&pixs); ptaDestroy(&pta); ptaDestroy(&pta); return 0; }
/*! * pixGetTextlineCenters() * * Input: pixs (1 bpp) * debugflag (1 for debug output) * Return: ptaa (of center values of textlines) * * Notes: * (1) This in general does not have a point for each value * of x, because there will be gaps between words. * It doesn't matter because we will fit a quadratic to the * points that we do have. */ PTAA * pixGetTextlineCenters(PIX *pixs, l_int32 debugflag) { l_int32 i, w, h, bx, by, nsegs; BOXA *boxa; PIX *pix, *pixt1, *pixt2, *pixt3; PIXA *pixa1, *pixa2; PTA *pta; PTAA *ptaa; PROCNAME("pixGetTextlineCenters"); if (!pixs || pixGetDepth(pixs) != 1) return (PTAA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); pixGetDimensions(pixs, &w, &h, NULL); /* Filter to solidify the text lines within the x-height region, * and to remove most of the ascenders and descenders. */ pixt1 = pixMorphSequence(pixs, "c15.1 + o15.1 + c30.1", 0); pixDisplayWithTitle(pixt1, 0, 800, "pix1", debugflag); /* Get the 8-connected components ... */ boxa = pixConnComp(pixt1, &pixa1, 8); pixDestroy(&pixt1); boxaDestroy(&boxa); if (pixaGetCount(pixa1) == 0) { pixaDestroy(&pixa1); return NULL; } /* ... and remove the short and thin c.c */ pixa2 = pixaSelectBySize(pixa1, 100, 4, L_SELECT_IF_BOTH, L_SELECT_IF_GT, 0); if ((nsegs = pixaGetCount(pixa2)) == 0) { pixaDestroy(&pixa2); return NULL; } if (debugflag) { pixt2 = pixaDisplay(pixa2, w, h); pixDisplayWithTitle(pixt2, 800, 800, "pix2", 1); pixDestroy(&pixt2); } /* For each c.c., get the weighted center of each vertical column. * The result is a set of points going approximately through * the center of the x-height part of the text line. */ ptaa = ptaaCreate(nsegs); for (i = 0; i < nsegs; i++) { pixaGetBoxGeometry(pixa2, i, &bx, &by, NULL, NULL); pix = pixaGetPix(pixa2, i, L_CLONE); pta = pixGetMeanVerticals(pix, bx, by); ptaaAddPta(ptaa, pta, L_INSERT); pixDestroy(&pix); } if (debugflag) { pixt3 = pixCreateTemplate(pixt2); pix = pixDisplayPtaa(pixt3, ptaa); pixDisplayWithTitle(pix, 0, 1400, "pix3", 1); pixDestroy(&pix); pixDestroy(&pixt3); } pixaDestroy(&pixa1); pixaDestroy(&pixa2); return ptaa; }
/*! * 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; }
/*! * \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; }
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); }