main(int argc, char **argv) { l_int32 i, index; l_float32 cputime, epo; char *filein, *fileout; PIX *pixs, *pixd; SEL *sel; SELA *sela; static char mainName[] = "morphtest1"; if (argc != 3) exit(ERROR_INT(" Syntax: morphtest1 filein fileout", mainName, 1)); filein = argv[1]; fileout = argv[2]; if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pix not made", mainName, 1)); sela = selaAddBasic(NULL); /* ------------------------ Timing -------------------------------*/ #if 1 selaFindSelByName(sela, "sel_9h", &index, &sel); selWriteStream(stderr, sel); pixd = pixCreateTemplate(pixs); startTimer(); for (i = 0; i < NTIMES; i++) { pixDilate(pixd, pixs, sel); /* if ((i % 10) == 0) fprintf(stderr, "%d iters\n", i); */ } cputime = stopTimer(); /* Get the elementary pixel operations/sec */ epo = BASIC_OPS * SEL_SIZE * NTIMES * IMAGE_SIZE /(cputime * CPU_SPEED); fprintf(stderr, "Time: %7.3f sec\n", cputime); fprintf(stderr, "Speed: %7.3f epo/cycle\n", epo); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixd); #endif /* ------------------ Example operation from repository --------------*/ #if 1 /* Select a structuring element */ selaFindSelByName(sela, "sel_50h", &index, &sel); selWriteStream(stderr, sel); /* Do these operations. See below for other ops * that can be substituted here. */ pixd = pixOpen(NULL, pixs, sel); pixXor(pixd, pixd, pixs); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixd); #endif pixDestroy(&pixs); exit(0); }
/*! * \brief recogShowPath() * * \param[in] recog with LUT's pre-computed * \param[in] select 0 for Viterbi; 1 for rescored * \return pix debug output), or NULL on error */ static PIX * recogShowPath(L_RECOG *recog, l_int32 select) { char textstr[16]; l_int32 i, n, index, xloc, dely; l_float32 score; L_BMF *bmf; NUMA *natempl_s, *nascore_s, *naxloc_s, *nadely_s; PIX *pixs, *pix0, *pix1, *pix2, *pix3, *pix4, *pix5; L_RDID *did; PROCNAME("recogShowPath"); if (!recog) return (PIX *)ERROR_PTR("recog not defined", procName, NULL); if ((did = recogGetDid(recog)) == NULL) return (PIX *)ERROR_PTR("did not defined", procName, NULL); bmf = bmfCreate(NULL, 8); pixs = pixScale(did->pixs, 4.0, 4.0); pix0 = pixAddBorderGeneral(pixs, 0, 0, 0, 40, 0); pix1 = pixConvertTo32(pix0); if (select == 0) { /* Viterbi */ natempl_s = did->natempl; nascore_s = did->nascore; naxloc_s = did->naxloc; nadely_s = did->nadely; } else { /* rescored */ natempl_s = did->natempl_r; nascore_s = did->nascore_r; naxloc_s = did->naxloc_r; nadely_s = did->nadely_r; } n = numaGetCount(natempl_s); for (i = 0; i < n; i++) { numaGetIValue(natempl_s, i, &index); pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE); pix3 = pixScale(pix2, 4.0, 4.0); pix4 = pixErodeBrick(NULL, pix3, 5, 5); pixXor(pix4, pix4, pix3); numaGetFValue(nascore_s, i, &score); snprintf(textstr, sizeof(textstr), "%5.3f", score); pix5 = pixAddTextlines(pix4, bmf, textstr, 1, L_ADD_BELOW); numaGetIValue(naxloc_s, i, &xloc); numaGetIValue(nadely_s, i, &dely); pixPaintThroughMask(pix1, pix5, 4 * xloc, 4 * dely, 0xff000000); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); } pixDestroy(&pixs); pixDestroy(&pix0); bmfDestroy(&bmf); return pix1; }
/*! * \brief pixColorSegmentClean() * * \param[in] pixs 8 bpp, colormapped * \param[in] selsize for closing * \param[in] countarray ptr to array containing the number of pixels * found in each color in the colormap * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This operation is in-place. * (2) This is phase 3 of color segmentation. It is the first * part of a two-step noise removal process. Colors with a * large population are closed first; this operation absorbs * small sets of intercolated pixels of a different color. * </pre> */ l_ok pixColorSegmentClean(PIX *pixs, l_int32 selsize, l_int32 *countarray) { l_int32 i, ncolors, val; l_uint32 val32; NUMA *na, *nasi; PIX *pixt1, *pixt2; PIXCMAP *cmap; PROCNAME("pixColorSegmentClean"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (pixGetDepth(pixs) != 8) return ERROR_INT("pixs not 8 bpp", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("cmap not found", procName, 1); if (!countarray) return ERROR_INT("countarray not defined", procName, 1); if (selsize <= 1) return 0; /* nothing to do */ /* Sort colormap indices in decreasing order of pixel population */ ncolors = pixcmapGetCount(cmap); na = numaCreate(ncolors); for (i = 0; i < ncolors; i++) numaAddNumber(na, countarray[i]); nasi = numaGetSortIndex(na, L_SORT_DECREASING); numaDestroy(&na); if (!nasi) return ERROR_INT("nasi not made", procName, 1); /* For each color, in order of decreasing population, * do a closing and absorb the added pixels. Note that * if the closing removes pixels at the border, they'll * still appear in the xor and will be properly (re)set. */ for (i = 0; i < ncolors; i++) { numaGetIValue(nasi, i, &val); pixt1 = pixGenerateMaskByValue(pixs, val, 1); pixt2 = pixCloseSafeCompBrick(NULL, pixt1, selsize, selsize); pixXor(pixt2, pixt2, pixt1); /* pixels to be added to type 'val' */ pixcmapGetColor32(cmap, val, &val32); pixSetMasked(pixs, pixt2, val32); /* add them */ pixDestroy(&pixt1); pixDestroy(&pixt2); } numaDestroy(&nasi); return 0; }
// clean up the image Pix *CubeLineSegmenter::CleanUp(Pix *orig_img) { // get rid of long horizontal lines Pix *pix_temp0 = pixMorphCompSequence(orig_img, "o300.2", 0); pixXor(pix_temp0, pix_temp0, orig_img); // get rid of long vertical lines Pix *pix_temp1 = pixMorphCompSequence(pix_temp0, "o2.300", 0); pixXor(pix_temp1, pix_temp1, pix_temp0); pixDestroy(&pix_temp0); // detect connected components Pixa *con_comps; Boxa *boxa = pixConnComp(pix_temp1, &con_comps, 8); if (boxa == NULL) { return NULL; } // detect and remove suspicious conn comps for (int con = 0; con < con_comps->n; con++) { Box *box = boxa->box[con]; // remove if suspc. conn comp if ((box->w > (box->h * kMaxHorzAspectRatio)) || (box->h > (box->w * kMaxVertAspectRatio)) || (box->w < kMinWid && box->h < kMinHgt)) { pixRasterop(pix_temp1, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST, con_comps->pix[con], 0, 0); } } pixaDestroy(&con_comps); boxaDestroy(&boxa); return pix_temp1; }
PIX * MakeReplacementMask(PIX *pixs) { PIX *pix1, *pix2, *pix3, *pix4; pix1 = pixMaskOverColorPixels(pixs, 95, 3); pix2 = pixMorphSequence(pix1, "o15.15", 0); pixSeedfillBinary(pix2, pix2, pix1, 8); pix3 = pixMorphSequence(pix2, "c15.15 + d61.31", 0); pix4 = pixRemoveBorderConnComps(pix3, 8); pixXor(pix4, pix4, pix3); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); return pix4; }
int main(int argc, char **argv) { l_int32 w, h, d, w2, h2, i, ncols, ret; l_float32 angle, conf; BOX *box; BOXA *boxa, *boxa2; PIX *pix, *pixs, *pixb, *pixb2, *pixd; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6; PIXA *pixam; /* mask with a single component over each column */ PIXA *pixac, *pixad, *pixat; PIXAA *pixaa, *pixaa2; SEL *selsplit; static char mainName[] = "arabic_lines"; if (argc != 1) return ERROR_INT(" Syntax: arabic_lines", mainName, 1); pixDisplayWrite(NULL, -1); /* init debug output */ /* Binarize input */ pixs = pixRead("arabic.png"); pixGetDimensions(pixs, &w, &h, &d); pix = pixConvertTo1(pixs, 128); /* Deskew */ pixb = pixFindSkewAndDeskew(pix, 1, &angle, &conf); pixDestroy(&pix); fprintf(stderr, "Skew angle: %7.2f degrees; %6.2f conf\n", angle, conf); pixDisplayWrite(pixb, 1); /* Use full image morphology to find columns, at 2x reduction. This only works for very simple layouts where each column of text extends the full height of the input image. */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pix1 = pixMorphCompSequence(pixb2, "c5.500", 0); boxa = pixConnComp(pix1, &pixam, 8); ncols = boxaGetCount(boxa); fprintf(stderr, "Num columns: %d\n", ncols); pixDisplayWrite(pix1, 1); /* Use selective region-based morphology to get the textline mask. */ pixad = pixaMorphSequenceByRegion(pixb2, pixam, "c100.3", 0, 0); pixGetDimensions(pixb2, &w2, &h2, NULL); pix2 = pixaDisplay(pixad, w2, h2); pixDisplayWrite(pix2, 1); pixDestroy(&pix2); /* Some of the lines may be touching, so use a HMT to split the lines in each column, and use a pixaa to save the results. */ selsplit = selCreateFromString(seltext, 17, 7, "selsplit"); pixaa = pixaaCreate(ncols); for (i = 0; i < ncols; i++) { pix3 = pixaGetPix(pixad, i, L_CLONE); box = pixaGetBox(pixad, i, L_COPY); pix4 = pixHMT(NULL, pix3, selsplit); pixXor(pix4, pix4, pix3); boxa2 = pixConnComp(pix4, &pixac, 8); pixaaAddPixa(pixaa, pixac, L_INSERT); pixaaAddBox(pixaa, box, L_INSERT); pix5 = pixaDisplayRandomCmap(pixac, 0, 0); pixDisplayWrite(pix5, 1); fprintf(stderr, "Num textlines in col %d: %d\n", i, boxaGetCount(boxa2)); pixDestroy(&pix5); pixDestroy(&pix3); pixDestroy(&pix4); boxaDestroy(&boxa2); } /* Visual output */ ret = system("gthumb /tmp/display/file* &"); pixat = pixaReadFiles("/tmp/display", "file"); pix5 = selDisplayInPix(selsplit, 31, 2); pixaAddPix(pixat, pix5, L_INSERT); pix6 = pixaDisplayTiledAndScaled(pixat, 32, 400, 3, 0, 35, 3); pixWrite("/tmp/result.png", pix6, IFF_PNG); pixaDestroy(&pixat); pixDestroy(&pix6); /* Test pixaa I/O */ pixaaWrite("/tmp/pixaa", pixaa); pixaa2 = pixaaRead("/tmp/pixaa"); pixaaWrite("/tmp/pixaa2", pixaa2); /* Test pixaa display */ pixd = pixaaDisplay(pixaa, w2, h2); pixWrite("/tmp/textlines.png", pixd, IFF_PNG); pixDestroy(&pixd); /* Cleanup */ pixDestroy(&pixb2); pixDestroy(&pix1); pixaDestroy(&pixam); pixaDestroy(&pixad); pixaaDestroy(&pixaa); pixaaDestroy(&pixaa2); boxaDestroy(&boxa); selDestroy(&selsplit); pixDestroy(&pixs); pixDestroy(&pixb); return 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; }
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; }
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); }
l_int32 DoComparisonDwa2(PIX *pixs, PIX *pixt1, PIX *pixt2, PIX *pixt3, PIX *pixt4, PIX *pixt5, PIX *pixt6, l_int32 size) /* exactly decomposable */ { fprintf(stderr, "..%d..", size); if (TIMING) startTimer(); pixDilateCompBrickExtendDwa(pixt1, pixs, size, 1); pixDilateCompBrickExtendDwa(pixt3, pixs, 1, size); pixDilateCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixDilateBrick(pixt2, pixs, size, 1); pixDilateBrick(pixt4, pixs, 1, size); pixDilateBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "dilate", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixErodeCompBrickExtendDwa(pixt1, pixs, size, 1); pixErodeCompBrickExtendDwa(pixt3, pixs, 1, size); pixErodeCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixErodeBrick(pixt2, pixs, size, 1); pixErodeBrick(pixt4, pixs, 1, size); pixErodeBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "erode", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixOpenCompBrickExtendDwa(pixt1, pixs, size, 1); pixOpenCompBrickExtendDwa(pixt3, pixs, 1, size); pixOpenCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixOpenBrick(pixt2, pixs, size, 1); pixOpenBrick(pixt4, pixs, 1, size); pixOpenBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "open", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixCloseCompBrickExtendDwa(pixt1, pixs, size, 1); pixCloseCompBrickExtendDwa(pixt3, pixs, 1, size); pixCloseCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixCloseSafeBrick(pixt2, pixs, size, 1); pixCloseSafeBrick(pixt4, pixs, 1, size); pixCloseSafeBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "close", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); #if 0 pixWrite("/tmp/junkpixt3.png", pixt3, IFF_PNG); pixWrite("/tmp/junkpixt4.png", pixt4, IFF_PNG); pixXor(pixt3, pixt3, pixt4); pixWrite("/tmp/junkxor.png", pixt3, IFF_PNG); #endif return 0; }
void RotateOrthTest(PIX *pixs, L_REGPARAMS *rp) { l_int32 zero, count; PIX *pixt, *pixd; PIXCMAP *cmap; cmap = pixGetColormap(pixs); /* Test 4 successive 90 degree rotations */ pixt = pixRotate90(pixs, 1); pixd = pixRotate90(pixt, 1); pixDestroy(&pixt); pixt = pixRotate90(pixd, 1); pixDestroy(&pixd); pixd = pixRotate90(pixt, 1); pixDestroy(&pixt); regTestComparePix(rp, pixs, pixd); if (!cmap) { pixXor(pixd, pixd, pixs); pixZero(pixd, &zero); if (zero) fprintf(stderr, "OK. Four 90-degree rotations gives I\n"); else { pixCountPixels(pixd, &count, NULL); fprintf(stderr, "Failure for four 90-degree rots; count = %d\n", count); } } pixDestroy(&pixd); /* Test 2 successive 180 degree rotations */ pixt = pixRotate180(NULL, pixs); pixRotate180(pixt, pixt); regTestComparePix(rp, pixs, pixt); if (!cmap) { pixXor(pixt, pixt, pixs); pixZero(pixt, &zero); if (zero) fprintf(stderr, "OK. Two 180-degree rotations gives I\n"); else { pixCountPixels(pixt, &count, NULL); fprintf(stderr, "Failure for two 180-degree rots; count = %d\n", count); } } pixDestroy(&pixt); /* Test 2 successive LR flips */ pixt = pixFlipLR(NULL, pixs); pixFlipLR(pixt, pixt); regTestComparePix(rp, pixs, pixt); if (!cmap) { pixXor(pixt, pixt, pixs); pixZero(pixt, &zero); if (zero) fprintf(stderr, "OK. Two LR flips gives I\n"); else { pixCountPixels(pixt, &count, NULL); fprintf(stderr, "Failure for two LR flips; count = %d\n", count); } } pixDestroy(&pixt); /* Test 2 successive TB flips */ pixt = pixFlipTB(NULL, pixs); pixFlipTB(pixt, pixt); regTestComparePix(rp, pixs, pixt); if (!cmap) { pixXor(pixt, pixt, pixs); pixZero(pixt, &zero); if (zero) fprintf(stderr, "OK. Two TB flips gives I\n"); else { pixCountPixels(pixt, &count, NULL); fprintf(stderr, "Failure for two TB flips; count = %d\n", count); } } pixDestroy(&pixt); return; }
main(int argc, char **argv) { l_int32 i, nsels, same, xorcount; char *selname; PIX *pixs, *pixs1, *pixt1, *pixt2, *pixt3; SEL *sel; SELA *sela; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; if ((pixs = pixRead("feyn-fract.tif")) == NULL) { rp->success = FALSE; regTestCleanup(rp); return 1; } sela = selaAddDwaLinear(NULL); nsels = selaGetCount(sela); for (i = 0; i < nsels; i++) { sel = selaGetSel(sela, i); selname = selGetName(sel); /* --------- dilation ----------*/ pixt1 = pixDilate(NULL, pixs, sel); pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_DILATE, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "dilations are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "dilations differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); /* --------- erosion with asymmetric b.c ----------*/ resetMorphBoundaryCondition(ASYMMETRIC_MORPH_BC); fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC); pixt1 = pixErode(NULL, pixs, sel); pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_ERODE, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "erosions are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "erosions differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); /* --------- erosion with symmetric b.c ----------*/ resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC); fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC); pixt1 = pixErode(NULL, pixs, sel); pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_ERODE, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "erosions are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "erosions differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); /* --------- opening with asymmetric b.c ----------*/ resetMorphBoundaryCondition(ASYMMETRIC_MORPH_BC); fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC); pixt1 = pixOpen(NULL, pixs, sel); pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_OPEN, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "openings are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "openings differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); /* --------- opening with symmetric b.c ----------*/ resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC); fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC); pixt1 = pixOpen(NULL, pixs, sel); pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_OPEN, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "openings are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "openings differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); /* --------- safe closing with asymmetric b.c ----------*/ resetMorphBoundaryCondition(ASYMMETRIC_MORPH_BC); fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC); pixt1 = pixCloseSafe(NULL, pixs, sel); /* must use safe version */ pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_CLOSE, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "closings are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "closings differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); /* --------- safe closing with symmetric b.c ----------*/ resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC); fprintf(stderr, "MORPH_BC = %d ... ", MORPH_BC); pixt1 = pixClose(NULL, pixs, sel); /* safe version not required */ pixt2 = pixMorphDwa_3(NULL, pixs, L_MORPH_CLOSE, selname); pixEqual(pixt1, pixt2, &same); if (same == 1) { fprintf(stderr, "closings are identical for sel %d (%s)\n", i, selname); } else { rp->success = FALSE; fprintf(rp->fp, "closings differ for sel %d (%s)\n", i, selname); pixt3 = pixXor(NULL, pixt1, pixt2); pixCountPixels(pixt3, &xorcount, NULL); fprintf(rp->fp, "Number of pixels in XOR: %d\n", xorcount); pixDestroy(&pixt3); } pixDestroy(&pixt1); pixDestroy(&pixt2); } selaDestroy(&sela); pixDestroy(&pixs); return regTestCleanup(rp); }
/*! * pixMirrorDetectDwa() * * Input: pixs (1 bpp, deskewed, English text) * &conf (<return> confidence that text is not LR mirror reversed) * mincount (min number of left + right; use 0 for default) * debug (1 for debug output; 0 otherwise) * Return: 0 if OK, 1 on error * * Notes: * (1) We assume the text is horizontally oriented, with * ascenders going up. * (2) See notes in pixMirrorDetect(). */ l_int32 pixMirrorDetectDwa(PIX *pixs, l_float32 *pconf, l_int32 mincount, l_int32 debug) { char flipsel1[] = "flipsel1"; char flipsel2[] = "flipsel2"; l_int32 count1, count2, nmax; l_float32 nleft, nright; PIX *pixt0, *pixt1, *pixt2, *pixt3; PROCNAME("pixMirrorDetectDwa"); if (!pconf) return ERROR_INT("&conf not defined", procName, 1); *pconf = 0.0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (mincount == 0) mincount = DEFAULT_MIN_MIRROR_FLIP_COUNT; /* Fill x-height characters but not space between them, sort of. */ pixt3 = pixMorphSequenceDwa(pixs, "d1.30", 0); pixXor(pixt3, pixt3, pixs); pixt0 = pixMorphSequenceDwa(pixs, "c15.1", 0); pixXor(pixt0, pixt0, pixs); pixAnd(pixt0, pixt0, pixt3); pixOr(pixt3, pixt0, pixs); pixDestroy(&pixt0); pixt0 = pixAddBorderGeneral(pixt3, ADDED_BORDER, ADDED_BORDER, ADDED_BORDER, ADDED_BORDER, 0); pixDestroy(&pixt3); /* Filter the right-facing characters. */ pixt1 = pixFlipFHMTGen(NULL, pixt0, flipsel1); pixt3 = pixReduceRankBinaryCascade(pixt1, 1, 1, 0, 0); pixCountPixels(pixt3, &count1, NULL); pixDestroy(&pixt1); pixDestroy(&pixt3); /* Filter the left-facing characters. */ pixt2 = pixFlipFHMTGen(NULL, pixt0, flipsel2); pixt3 = pixReduceRankBinaryCascade(pixt2, 1, 1, 0, 0); pixCountPixels(pixt3, &count2, NULL); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt0); nright = (l_float32)count1; nleft = (l_float32)count2; nmax = L_MAX(count1, count2); if (nmax > mincount) *pconf = 2. * ((nright - nleft) / sqrt(nright + nleft)); if (debug) { fprintf(stderr, "nright = %f, nleft = %f\n", nright, nleft); if (*pconf > DEFAULT_MIN_MIRROR_FLIP_CONF) fprintf(stderr, "Text is not mirror reversed\n"); if (*pconf < -DEFAULT_MIN_MIRROR_FLIP_CONF) fprintf(stderr, "Text is mirror reversed\n"); } return 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); }
/*! * \brief pixConnCompPixa() * * \param[in] pixs 1 bpp * \param[out] ppixa pixa of each c.c. * \param[in] connectivity 4 or 8 * \return boxa, or NULL on error * * <pre> * Notes: * (1) This finds bounding boxes of 4- or 8-connected components * in a binary image, and saves images of each c.c * in a pixa array. * (2) It sets up 2 temporary pix, and for each c.c. that is * located in raster order, it erases the c.c. from one pix, * then uses the b.b. to extract the c.c. from the two pix using * an XOR, and finally erases the c.c. from the second pix. * (3) A clone of the returned boxa (where all boxes in the array * are clones) is inserted into the pixa. * (4) If the input is valid, this always returns a boxa and a pixa. * If pixs is empty, the boxa and pixa will be empty. * </pre> */ BOXA * pixConnCompPixa(PIX *pixs, PIXA **ppixa, l_int32 connectivity) { l_int32 h, iszero; l_int32 x, y, xstart, ystart; PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixa; BOX *box; BOXA *boxa; L_STACK *stack, *auxstack; PROCNAME("pixConnCompPixa"); if (!ppixa) return (BOXA *)ERROR_PTR("&pixa not defined", procName, NULL); *ppixa = NULL; if (!pixs || pixGetDepth(pixs) != 1) return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); if (connectivity != 4 && connectivity != 8) return (BOXA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL); boxa = NULL; pix1 = pix2 = pix3 = pix4 = NULL; stack = NULL; pixZero(pixs, &iszero); if (iszero) return boxaCreate(1); /* return empty boxa */ pix1 = pixCopy(NULL, pixs); pix2 = pixCopy(NULL, pixs); if (!pix1 || !pix2) { L_ERROR("pix1 or pix2 not made\n", procName); goto cleanup; } h = pixGetHeight(pixs); if ((stack = lstackCreate(h)) == NULL) { L_ERROR("stack not made\n", procName); goto cleanup; } auxstack = lstackCreate(0); stack->auxstack = auxstack; pixa = pixaCreate(0); boxa = boxaCreate(0); xstart = 0; ystart = 0; while (1) { if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y)) break; if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) { L_ERROR("box not made\n", procName); pixaDestroy(&pixa); boxaDestroy(&boxa); goto cleanup; } boxaAddBox(boxa, box, L_INSERT); /* Save the c.c. and remove from pix2 as well */ pix3 = pixClipRectangle(pix1, box, NULL); pix4 = pixClipRectangle(pix2, box, NULL); pixXor(pix3, pix3, pix4); pixRasterop(pix2, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST, pix3, 0, 0); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix4); xstart = x; ystart = y; } #if DEBUG pixCountPixels(pix1, &iszero, NULL); fprintf(stderr, "Number of remaining pixels = %d\n", iszero); pixWrite("junkremain", pix1, IFF_PNG); #endif /* DEBUG */ /* Remove old boxa of pixa and replace with a clone copy */ boxaDestroy(&pixa->boxa); pixa->boxa = boxaCopy(boxa, L_CLONE); *ppixa = pixa; /* Cleanup, freeing the fillsegs on each stack */ cleanup: lstackDestroy(&stack, TRUE); pixDestroy(&pix1); pixDestroy(&pix2); return boxa; }
l_int32 DoPageSegmentation(PIX *pixs, /* should be at least 300 ppi */ l_int32 which) /* 1, 2, 3, 4 */ { char buf[256]; l_int32 zero; BOXA *boxatm, *boxahm; PIX *pixr; /* image reduced to 150 ppi */ PIX *pixhs; /* image of halftone seed, 150 ppi */ PIX *pixm; /* image of mask of components, 150 ppi */ PIX *pixhm1; /* image of halftone mask, 150 ppi */ PIX *pixhm2; /* image of halftone mask, 300 ppi */ PIX *pixht; /* image of halftone components, 150 ppi */ PIX *pixnht; /* image without halftone components, 150 ppi */ PIX *pixi; /* inverted image, 150 ppi */ PIX *pixvws; /* image of vertical whitespace, 150 ppi */ PIX *pixm1; /* image of closed textlines, 150 ppi */ PIX *pixm2; /* image of refined text line mask, 150 ppi */ PIX *pixm3; /* image of refined text line mask, 300 ppi */ PIX *pixb1; /* image of text block mask, 150 ppi */ PIX *pixb2; /* image of text block mask, 300 ppi */ PIX *pixnon; /* image of non-text or halftone, 150 ppi */ PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixa; PIXCMAP *cmap; PTAA *ptaa; l_int32 ht_flag = 0; l_int32 ws_flag = 0; l_int32 text_flag = 0; l_int32 block_flag = 0; PROCNAME("DoPageSegmentation"); if (which == 1) ht_flag = 1; else if (which == 2) ws_flag = 1; else if (which == 3) text_flag = 1; else if (which == 4) block_flag = 1; else return ERROR_INT("invalid parameter: not in [1...4]", procName, 1); pixa = pixaCreate(0); lept_mkdir("lept/livre"); /* Reduce to 150 ppi */ pix1 = pixScaleToGray2(pixs); if (ws_flag || ht_flag || block_flag) pixaAddPix(pixa, pix1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/orig.gray.150.png", pix1, IFF_PNG); pixDestroy(&pix1); pixr = pixReduceRankBinaryCascade(pixs, 1, 0, 0, 0); /* Get seed for halftone parts */ pix1 = pixReduceRankBinaryCascade(pixr, 4, 4, 3, 0); pix2 = pixOpenBrick(NULL, pix1, 5, 5); pixhs = pixExpandBinaryPower2(pix2, 8); if (ht_flag) pixaAddPix(pixa, pixhs, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/htseed.150.png", pixhs, IFF_PNG); pixDestroy(&pix1); pixDestroy(&pix2); /* Get mask for connected regions */ pixm = pixCloseSafeBrick(NULL, pixr, 4, 4); if (ht_flag) pixaAddPix(pixa, pixm, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/ccmask.150.png", pixm, IFF_PNG); /* Fill seed into mask to get halftone mask */ pixhm1 = pixSeedfillBinary(NULL, pixhs, pixm, 4); if (ht_flag) pixaAddPix(pixa, pixhm1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/htmask.150.png", pixhm1, IFF_PNG); pixhm2 = pixExpandBinaryPower2(pixhm1, 2); /* Extract halftone stuff */ pixht = pixAnd(NULL, pixhm1, pixr); if (which == 1) pixWrite("/tmp/lept/livre/ht.150.png", pixht, IFF_PNG); /* Extract non-halftone stuff */ pixnht = pixXor(NULL, pixht, pixr); if (text_flag) pixaAddPix(pixa, pixnht, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/text.150.png", pixnht, IFF_PNG); pixZero(pixht, &zero); if (zero) fprintf(stderr, "No halftone parts found\n"); else fprintf(stderr, "Halftone parts found\n"); /* Get bit-inverted image */ pixi = pixInvert(NULL, pixnht); if (ws_flag) pixaAddPix(pixa, pixi, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/invert.150.png", pixi, IFF_PNG); /* The whitespace mask will break textlines where there * is a large amount of white space below or above. * We can prevent this by identifying regions of the * inverted image that have large horizontal (bigger than * the separation between columns) and significant * vertical extent (bigger than the separation between * textlines), and subtracting this from the whitespace mask. */ pix1 = pixMorphCompSequence(pixi, "o80.60", 0); pix2 = pixSubtract(NULL, pixi, pix1); if (ws_flag) pixaAddPix(pixa, pix2, L_COPY); pixDestroy(&pix1); /* Identify vertical whitespace by opening inverted image */ pix3 = pixOpenBrick(NULL, pix2, 5, 1); /* removes thin vertical lines */ pixvws = pixOpenBrick(NULL, pix3, 1, 200); /* gets long vertical lines */ if (text_flag || ws_flag) pixaAddPix(pixa, pixvws, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/vertws.150.png", pixvws, IFF_PNG); pixDestroy(&pix2); pixDestroy(&pix3); /* Get proto (early processed) text line mask. */ /* First close the characters and words in the textlines */ pixm1 = pixCloseSafeBrick(NULL, pixnht, 30, 1); if (text_flag) pixaAddPix(pixa, pixm1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textmask1.150.png", pixm1, IFF_PNG); /* Next open back up the vertical whitespace corridors */ pixm2 = pixSubtract(NULL, pixm1, pixvws); if (which == 1) pixWrite("/tmp/lept/livre/textmask2.150.png", pixm2, IFF_PNG); /* Do a small opening to remove noise */ pixOpenBrick(pixm2, pixm2, 3, 3); if (text_flag) pixaAddPix(pixa, pixm2, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textmask3.150.png", pixm2, IFF_PNG); pixm3 = pixExpandBinaryPower2(pixm2, 2); /* Join pixels vertically to make text block mask */ pixb1 = pixMorphSequence(pixm2, "c1.10 + o4.1", 0); if (block_flag) pixaAddPix(pixa, pixb1, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textblock1.150.png", pixb1, IFF_PNG); /* Solidify the textblock mask and remove noise: * (1) For each c.c., close the blocks and dilate slightly * to form a solid mask. * (2) Small horizontal closing between components * (3) Open the white space between columns, again * (4) Remove small components */ pix1 = pixMorphSequenceByComponent(pixb1, "c30.30 + d3.3", 8, 0, 0, NULL); pixCloseSafeBrick(pix1, pix1, 10, 1); if (block_flag) pixaAddPix(pixa, pix1, L_COPY); pix2 = pixSubtract(NULL, pix1, pixvws); pix3 = pixSelectBySize(pix2, 25, 5, 8, L_SELECT_IF_BOTH, L_SELECT_IF_GTE, NULL); if (block_flag) pixaAddPix(pixa, pix3, L_COPY); if (which == 1) pixWrite("/tmp/lept/livre/textblock2.150.png", pix3, IFF_PNG); pixb2 = pixExpandBinaryPower2(pix3, 2); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Identify the outlines of each textblock */ ptaa = pixGetOuterBordersPtaa(pixb2); pix1 = pixRenderRandomCmapPtaa(pixb2, ptaa, 1, 8, 1); cmap = pixGetColormap(pix1); pixcmapResetColor(cmap, 0, 130, 130, 130); /* set interior to gray */ if (which == 1) pixWrite("/tmp/lept/livre/textblock3.300.png", pix1, IFF_PNG); pixDisplayWithTitle(pix1, 480, 360, "textblock mask with outlines", DFLAG); ptaaDestroy(&ptaa); pixDestroy(&pix1); /* Fill line mask (as seed) into the original */ pix1 = pixSeedfillBinary(NULL, pixm3, pixs, 8); pixOr(pixm3, pixm3, pix1); pixDestroy(&pix1); if (which == 1) pixWrite("/tmp/lept/livre/textmask.300.png", pixm3, IFF_PNG); pixDisplayWithTitle(pixm3, 480, 360, "textline mask 4", DFLAG); /* Fill halftone mask (as seed) into the original */ pix1 = pixSeedfillBinary(NULL, pixhm2, pixs, 8); pixOr(pixhm2, pixhm2, pix1); pixDestroy(&pix1); if (which == 1) pixWrite("/tmp/lept/livre/htmask.300.png", pixhm2, IFF_PNG); pixDisplayWithTitle(pixhm2, 520, 390, "halftonemask 2", DFLAG); /* Find objects that are neither text nor halftones */ pix1 = pixSubtract(NULL, pixs, pixm3); /* remove text pixels */ pixnon = pixSubtract(NULL, pix1, pixhm2); /* remove halftone pixels */ pixDestroy(&pix1); if (which == 1) pixWrite("/tmp/lept/livre/other.300.png", pixnon, IFF_PNG); pixDisplayWithTitle(pixnon, 540, 420, "other stuff", DFLAG); /* Write out b.b. for text line mask and halftone mask components */ boxatm = pixConnComp(pixm3, NULL, 4); boxahm = pixConnComp(pixhm2, NULL, 8); if (which == 1) { boxaWrite("/tmp/lept/livre/textmask.boxa", boxatm); boxaWrite("/tmp/lept/livre/htmask.boxa", boxahm); } pix1 = pixaDisplayTiledAndScaled(pixa, 8, 250, 4, 0, 25, 2); pixDisplay(pix1, 0, 375 * (which - 1)); snprintf(buf, sizeof(buf), "/tmp/lept/livre/segout.%d.png", which); pixWrite(buf, pix1, IFF_PNG); pixDestroy(&pix1); pixaDestroy(&pixa); /* clean up to test with valgrind */ pixDestroy(&pixr); pixDestroy(&pixhs); pixDestroy(&pixm); pixDestroy(&pixhm1); pixDestroy(&pixhm2); pixDestroy(&pixht); pixDestroy(&pixi); pixDestroy(&pixnht); pixDestroy(&pixvws); pixDestroy(&pixm1); pixDestroy(&pixm2); pixDestroy(&pixm3); pixDestroy(&pixb1); pixDestroy(&pixb2); pixDestroy(&pixnon); boxaDestroy(&boxatm); boxaDestroy(&boxahm); return 0; }
/*! * pixMirrorDetect() * * Input: pixs (1 bpp, deskewed, English text) * &conf (<return> confidence that text is not LR mirror reversed) * mincount (min number of left + right; use 0 for default) * debug (1 for debug output; 0 otherwise) * Return: 0 if OK, 1 on error * * Notes: * (1) For this test, it is necessary that the text is horizontally * oriented, with ascenders going up. * (2) conf is the normalized difference between the number of * right and left facing characters with ascenders. * Left-facing are {d}; right-facing are {b, h, k}. * At least that was the expectation. In practice, we can * really just say that it is the normalized difference in * hits using two specific hit-miss filters, textsel1 and textsel2, * after the image has been suitably pre-filtered so that * these filters are effective. See (4) for what's really happening. * (3) A large positive conf value indicates normal text, whereas * a large negative conf value means the page is mirror reversed. * (4) The implementation is a bit tricky. The general idea is * to fill the x-height part of characters, but not the space * between them, before doing the HMT. This is done by * finding pixels added using two different operations -- a * horizontal close and a vertical dilation -- and adding * the intersection of these sets to the original. It turns * out that the original intuition about the signal was largely * in error: much of the signal for right-facing characters * comes from the lower part of common x-height characters, like * the e and c, that remain open after these operations. * So it's important that the operations to close the x-height * parts of the characters are purposely weakened sufficiently * to allow these characters to remain open. The wonders * of morphology! */ l_int32 pixMirrorDetect(PIX *pixs, l_float32 *pconf, l_int32 mincount, l_int32 debug) { l_int32 count1, count2, nmax; l_float32 nleft, nright; PIX *pixt0, *pixt1, *pixt2, *pixt3; SEL *sel1, *sel2; PROCNAME("pixMirrorDetect"); if (!pconf) return ERROR_INT("&conf not defined", procName, 1); *pconf = 0.0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (mincount == 0) mincount = DEFAULT_MIN_MIRROR_FLIP_COUNT; sel1 = selCreateFromString(textsel1, 5, 6, NULL); sel2 = selCreateFromString(textsel2, 5, 6, NULL); /* Fill x-height characters but not space between them, sort of. */ pixt3 = pixMorphCompSequence(pixs, "d1.30", 0); pixXor(pixt3, pixt3, pixs); pixt0 = pixMorphCompSequence(pixs, "c15.1", 0); pixXor(pixt0, pixt0, pixs); pixAnd(pixt0, pixt0, pixt3); pixOr(pixt0, pixt0, pixs); pixDestroy(&pixt3); /* pixDisplayWrite(pixt0, 1); */ /* Filter the right-facing characters. */ pixt1 = pixHMT(NULL, pixt0, sel1); pixt3 = pixReduceRankBinaryCascade(pixt1, 1, 1, 0, 0); pixCountPixels(pixt3, &count1, NULL); pixDebugFlipDetect("junkpixright", pixs, pixt1, debug); pixDestroy(&pixt1); pixDestroy(&pixt3); /* Filter the left-facing characters. */ pixt2 = pixHMT(NULL, pixt0, sel2); pixt3 = pixReduceRankBinaryCascade(pixt2, 1, 1, 0, 0); pixCountPixels(pixt3, &count2, NULL); pixDebugFlipDetect("junkpixleft", pixs, pixt2, debug); pixDestroy(&pixt2); pixDestroy(&pixt3); nright = (l_float32)count1; nleft = (l_float32)count2; nmax = L_MAX(count1, count2); pixDestroy(&pixt0); selDestroy(&sel1); selDestroy(&sel2); if (nmax > mincount) *pconf = 2. * ((nright - nleft) / sqrt(nright + nleft)); if (debug) { fprintf(stderr, "nright = %f, nleft = %f\n", nright, nleft); if (*pconf > DEFAULT_MIN_MIRROR_FLIP_CONF) fprintf(stderr, "Text is not mirror reversed\n"); if (*pconf < -DEFAULT_MIN_MIRROR_FLIP_CONF) fprintf(stderr, "Text is mirror reversed\n"); } return 0; }
int main(int argc, char **argv) { char filename[BUF_SIZE]; char *dirin, *rootname, *fname; l_int32 i, firstpage, npages, nfiles; l_float32 thresh, weight; JBDATA *data; JBCLASSER *classer; SARRAY *safiles; PIX *pix, *pixt; PIXA *pixa, *pixadb; static char mainName[] = "jbcorrelation"; if (argc != 5 && argc != 7) return ERROR_INT(" Syntax: jbcorrelation dirin thresh weight " "rootname [firstpage, npages]", mainName, 1); dirin = argv[1]; thresh = atof(argv[2]); weight = atof(argv[3]); rootname = argv[4]; if (argc == 5) { firstpage = 0; npages = 0; } else { firstpage = atoi(argv[5]); npages = atoi(argv[6]); } #if 0 /*--------------------------------------------------------------*/ jbCorrelation(dirin, thresh, weight, COMPONENTS, rootname, firstpage, npages, 1); /*--------------------------------------------------------------*/ #else /*--------------------------------------------------------------*/ safiles = getSortedPathnamesInDirectory(dirin, NULL, firstpage, npages); nfiles = sarrayGetCount(safiles); sarrayWriteStream(stderr, safiles); /* Classify components on requested pages */ startTimer(); classer = jbCorrelationInit(COMPONENTS, 0, 0, thresh, weight); jbAddPages(classer, safiles); fprintf(stderr, "Time to generate classes: %6.3f sec\n", stopTimer()); /* Save and write out the result */ data = jbDataSave(classer); jbDataWrite(rootname, data); fprintf(stderr, "Number of classes: %d\n", classer->nclass); /* Render the pages from the classifier data. * Use debugflag == FALSE to omit outlines of each component. */ pixa = jbDataRender(data, FALSE); /* Write the pages out */ npages = pixaGetCount(pixa); if (npages != nfiles) fprintf(stderr, "npages = %d, nfiles = %d, not equal!\n", npages, nfiles); for (i = 0; i < npages; i++) { pix = pixaGetPix(pixa, i, L_CLONE); snprintf(filename, BUF_SIZE, "%s.%05d", rootname, i); fprintf(stderr, "filename: %s\n", filename); pixWrite(filename, pix, IFF_PNG); pixDestroy(&pix); } #if DISPLAY_DIFFERENCE fname = sarrayGetString(safiles, 0, 0); pixt = pixRead(fname); pix = pixaGetPix(pixa, 0, L_CLONE); pixXor(pixt, pixt, pix); pixWrite("junk_output_diff", pixt, IFF_PNG); pixDestroy(&pix); pixDestroy(&pixt); #endif /* DISPLAY_DIFFERENCE */ #if DEBUG_TEST_DATA_IO { JBDATA *newdata; PIX *newpix; PIXA *newpixa; l_int32 same, iofail; /* Read the data back in and render the pages */ newdata = jbDataRead(rootname); newpixa = jbDataRender(newdata, FALSE); iofail = FALSE; for (i = 0; i < npages; i++) { pix = pixaGetPix(pixa, i, L_CLONE); newpix = pixaGetPix(newpixa, i, L_CLONE); pixEqual(pix, newpix, &same); if (!same) { iofail = TRUE; fprintf(stderr, "pix on page %d are unequal!\n", i); } pixDestroy(&pix); pixDestroy(&newpix); } if (iofail) fprintf(stderr, "read/write for jbdata fails\n"); else fprintf(stderr, "read/write for jbdata succeeds\n"); jbDataDestroy(&newdata); pixaDestroy(&newpixa); } #endif /* DEBUG_TEST_DATA_IO */ #if RENDER_DEBUG /* Use debugflag == TRUE to see outlines of each component. */ pixadb = jbDataRender(data, TRUE); /* Write the debug pages out */ npages = pixaGetCount(pixadb); for (i = 0; i < npages; i++) { pix = pixaGetPix(pixadb, i, L_CLONE); snprintf(filename, BUF_SIZE, "%s.db.%05d", rootname, i); fprintf(stderr, "filename: %s\n", filename); pixWrite(filename, pix, IFF_PNG); pixDestroy(&pix); } pixaDestroy(&pixadb); #endif /* RENDER_DEBUG */ #if DISPLAY_ALL_INSTANCES /* display all instances, organized by template */ pix = pixaaDisplayByPixa(classer->pixaa, X_SPACING, Y_SPACING, MAX_OUTPUT_WIDTH); pixWrite("output_instances", pix, IFF_PNG); pixDestroy(&pix); #endif /* DISPLAY_ALL_INSTANCES */ pixaDestroy(&pixa); sarrayDestroy(&safiles); jbClasserDestroy(&classer); jbDataDestroy(&data); /*--------------------------------------------------------------*/ #endif return 0; }
/*! * pixGenerateSelBoundary() * * Input: pix (1 bpp, typically small, to be used as a pattern) * hitdist (min distance from fg boundary pixel) * missdist (min distance from bg boundary pixel) * hitskip (number of boundary pixels skipped between hits) * missskip (number of boundary pixels skipped between misses) * topflag (flag for extra pixels of bg added above) * botflag (flag for extra pixels of bg added below) * leftflag (flag for extra pixels of bg added to left) * rightflag (flag for extra pixels of bg added to right) * &pixe (<optional return> input pix expanded by extra pixels) * Return: sel (hit-miss for input pattern), or null on error * * 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. */ 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; }
int main(int argc, char **argv) { PIX *pixs, *pix1, *pix2, *pix3, *pix4; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("test1.png"); /* pixInvert */ pix1 = pixInvert(NULL, pixs); pix2 = pixCreateTemplate(pixs); /* into pixd of same size */ pixInvert(pix2, pixs); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ regTestComparePix(rp, pix1, pix2); /* 1 */ pix3 = pixRead("marge.jpg"); /* into pixd of different size */ pixInvert(pix3, pixs); regTestComparePix(rp, pix1, pix3); /* 2 */ pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pix1 = pixOpenBrick(NULL, pixs, 1, 9); pix2 = pixDilateBrick(NULL, pixs, 1, 9); /* pixOr */ pix3 = pixCreateTemplate(pixs); pixOr(pix3, pixs, pix1); /* existing */ pix4 = pixOr(NULL, pixs, pix1); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 3 */ regTestComparePix(rp, pix3, pix4); /* 4 */ pixCopy(pix4, pix1); pixOr(pix4, pix4, pixs); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 5 */ pixDestroy(&pix3); pixDestroy(&pix4); pix3 = pixCreateTemplate(pixs); pixOr(pix3, pixs, pix2); /* existing */ pix4 = pixOr(NULL, pixs, pix2); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 6 */ regTestComparePix(rp, pix3, pix4); /* 7 */ pixCopy(pix4, pix2); pixOr(pix4, pix4, pixs); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 8 */ pixDestroy(&pix3); pixDestroy(&pix4); /* pixAnd */ pix3 = pixCreateTemplate(pixs); pixAnd(pix3, pixs, pix1); /* existing */ pix4 = pixAnd(NULL, pixs, pix1); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 9 */ regTestComparePix(rp, pix3, pix4); /* 10 */ pixCopy(pix4, pix1); pixAnd(pix4, pix4, pixs); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 11 */ pixDestroy(&pix3); pixDestroy(&pix4); pix3 = pixCreateTemplate(pixs); pixAnd(pix3, pixs, pix2); /* existing */ pix4 = pixAnd(NULL, pixs, pix2); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 12 */ regTestComparePix(rp, pix3, pix4); /* 13 */ pixCopy(pix4, pix2); pixAnd(pix4, pix4, pixs); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 14 */ pixDestroy(&pix3); pixDestroy(&pix4); /* pixXor */ pix3 = pixCreateTemplate(pixs); pixXor(pix3, pixs, pix1); /* existing */ pix4 = pixXor(NULL, pixs, pix1); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 15 */ regTestComparePix(rp, pix3, pix4); /* 16 */ pixCopy(pix4, pix1); pixXor(pix4, pix4, pixs); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 17 */ pixDestroy(&pix3); pixDestroy(&pix4); pix3 = pixCreateTemplate(pixs); pixXor(pix3, pixs, pix2); /* existing */ pix4 = pixXor(NULL, pixs, pix2); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 18 */ regTestComparePix(rp, pix3, pix4); /* 19 */ pixCopy(pix4, pix2); pixXor(pix4, pix4, pixs); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 20 */ pixDestroy(&pix3); pixDestroy(&pix4); /* pixSubtract */ pix3 = pixCreateTemplate(pixs); pixSubtract(pix3, pixs, pix1); /* existing */ pix4 = pixSubtract(NULL, pixs, pix1); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 21 */ regTestComparePix(rp, pix3, pix4); /* 22 */ pixCopy(pix4, pix1); pixSubtract(pix4, pixs, pix4); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 23 */ pixDestroy(&pix3); pixDestroy(&pix4); pix3 = pixCreateTemplate(pixs); pixSubtract(pix3, pixs, pix2); /* existing */ pix4 = pixSubtract(NULL, pixs, pix2); /* new */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 24 */ regTestComparePix(rp, pix3, pix4); /* 25 */ pixCopy(pix4, pix2); pixSubtract(pix4, pixs, pix4); /* in-place */ regTestComparePix(rp, pix3, pix4); /* 26 */ pixDestroy(&pix3); pixDestroy(&pix4); pix4 = pixRead("marge.jpg"); pixSubtract(pix4, pixs, pixs); /* subtract from itself; should be empty */ pix3 = pixCreateTemplate(pixs); regTestComparePix(rp, pix3, pix4); /* 27*/ pixDestroy(&pix3); pixDestroy(&pix4); pixSubtract(pixs, pixs, pixs); /* subtract from itself; should be empty */ pix3 = pixCreateTemplate(pixs); regTestComparePix(rp, pix3, pixs); /* 28*/ pixDestroy(&pix3); pixDestroy(&pixs); pixDestroy(&pix1); pixDestroy(&pix2); return regTestCleanup(rp); }
* that might be used * * -------------------------------------------------------------------- */ #if 0 pixd = pixCreateTemplate(pixs); pixd = pixDilate(NULL, pixs, sel); pixd = pixErode(NULL, pixs, sel); pixd = pixOpen(NULL, pixs, sel); pixd = pixClose(NULL, pixs, sel); pixDilate(pixd, pixs, sel); pixErode(pixd, pixs, sel); pixOpen(pixd, pixs, sel); pixClose(pixd, pixs, sel); pixAnd(pixd, pixd, pixs); pixOr(pixd, pixd, pixs); pixXor(pixd, pixd, pixs); pixSubtract(pixd, pixd, pixs); pixInvert(pixd, pixs); pixd = pixAnd(NULL, pixd, pixs); pixd = pixOr(NULL, pixd, pixs); pixd = pixXor(NULL, pixd, pixs); pixd = pixSubtract(NULL, pixd, pixs); pixd = pixInvert(NULL, pixs); pixInvert(pixs, pixs); #endif /* 0 */
main(int argc, char **argv) { l_int32 i, ok, same; char sequence[512]; PIX *pixs, *pixref; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIX *pixt7, *pixt8, *pixt9, *pixt10, *pixt11; PIX *pixt12, *pixt13, *pixt14; SEL *sel; static char mainName[] = "binmorph1_reg"; if (argc != 1) exit(ERROR_INT(" Syntax: binmorph1_reg", mainName, 1)); if ((pixs = pixRead("feyn.tif")) == NULL) exit(ERROR_INT("pix not made", mainName, 1)); #if TEST_SYMMETRIC /* This works properly if there is an added border */ resetMorphBoundaryCondition(SYMMETRIC_MORPH_BC); #if 1 pixt1 = pixAddBorder(pixs, 32, 0); pixTransferAllData(pixs, &pixt1, 0, 0); #endif #endif /* TEST_SYMMETRIC */ /* This is our test sel */ sel = selCreateBrick(HEIGHT, WIDTH, HEIGHT / 2, WIDTH / 2, SEL_HIT); /* Dilation */ fprintf(stderr, "Testing dilation\n"); ok = TRUE; pixref = pixDilate(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixDilate(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixDilate(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "d%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "d%d.1 + d1.%d", WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixt5 = pixDilateBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCreateTemplate(pixs); pixDilateBrick(pixt6, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCopy(NULL, pixs); pixDilateBrick(pixt7, pixt7, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixDilateBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixCreateTemplate(pixs); pixDilateBrickDwa(pixt9, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCopy(NULL, pixs); pixDilateBrickDwa(pixt10, pixt10, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCreateTemplate(pixs); pixDilateCompBrickDwa(pixt11, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "d%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); /* Erosion */ fprintf(stderr, "Testing erosion\n"); pixref = pixErode(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixErode(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixErode(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "e%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "e%d.1 + e1.%d", WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixt5 = pixErodeBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCreateTemplate(pixs); pixErodeBrick(pixt6, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCopy(NULL, pixs); pixErodeBrick(pixt7, pixt7, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixErodeBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixCreateTemplate(pixs); pixErodeBrickDwa(pixt9, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCopy(NULL, pixs); pixErodeBrickDwa(pixt10, pixt10, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCreateTemplate(pixs); pixErodeCompBrickDwa(pixt11, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "e%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); /* Opening */ fprintf(stderr, "Testing opening\n"); pixref = pixOpen(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixOpen(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixOpen(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "o%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "e%d.%d + d%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } sprintf(sequence, "e%d.1 + e1.%d + d%d.1 + d1.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt5 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable^2 */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixOpenBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCreateTemplate(pixs); pixOpenBrick(pixt7, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixCopy(NULL, pixs); /* in-place */ pixOpenBrick(pixt8, pixt8, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixOpenBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCreateTemplate(pixs); pixOpenBrickDwa(pixt10, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCopy(NULL, pixs); pixOpenBrickDwa(pixt11, pixt11, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "o%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } #if 0 pixWrite("/tmp/junkref.png", pixref, IFF_PNG); pixWrite("/tmp/junk12.png", pixt12, IFF_PNG); pixt13 = pixXor(NULL, pixref, pixt12); pixWrite("/tmp/junk12a.png", pixt13, IFF_PNG); pixDestroy(&pixt13); #endif pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixt14 = pixCreateTemplate(pixs); pixOpenCompBrickDwa(pixt14, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt14, &same); if (!same) { fprintf(stderr, "pixref != pixt14 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); pixDestroy(&pixt14); /* Closing */ fprintf(stderr, "Testing closing\n"); pixref = pixClose(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixClose(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixClose(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "d%d.%d + e%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "d%d.1 + d1.%d + e%d.1 + e1.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable^2 */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } pixt5 = pixCloseBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCreateTemplate(pixs); pixCloseBrick(pixt6, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCopy(NULL, pixs); /* in-place */ pixCloseBrick(pixt7, pixt7, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); /* Safe closing (using pix, not pixs) */ fprintf(stderr, "Testing safe closing\n"); pixref = pixCloseSafe(NULL, pixs, sel); /* new one */ pixt1 = pixCreateTemplate(pixs); pixCloseSafe(pixt1, pixs, sel); /* existing one */ pixEqual(pixref, pixt1, &same); if (!same) { fprintf(stderr, "pixref != pixt1 !\n"); ok = FALSE; } pixt2 = pixCopy(NULL, pixs); pixCloseSafe(pixt2, pixt2, sel); /* in-place */ pixEqual(pixref, pixt2, &same); if (!same) { fprintf(stderr, "pixref != pixt2 !\n"); ok = FALSE; } sprintf(sequence, "c%d.%d", WIDTH, HEIGHT); pixt3 = pixMorphSequence(pixs, sequence, 0); /* sequence, atomic */ pixEqual(pixref, pixt3, &same); if (!same) { fprintf(stderr, "pixref != pixt3 !\n"); ok = FALSE; } sprintf(sequence, "b32 + d%d.%d + e%d.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt4 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable */ pixEqual(pixref, pixt4, &same); if (!same) { fprintf(stderr, "pixref != pixt4 !\n"); ok = FALSE; } sprintf(sequence, "b32 + d%d.1 + d1.%d + e%d.1 + e1.%d", WIDTH, HEIGHT, WIDTH, HEIGHT); pixt5 = pixMorphSequence(pixs, sequence, 0); /* sequence, separable^2 */ pixEqual(pixref, pixt5, &same); if (!same) { fprintf(stderr, "pixref != pixt5 !\n"); ok = FALSE; } pixt6 = pixCloseSafeBrick(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt6, &same); if (!same) { fprintf(stderr, "pixref != pixt6 !\n"); ok = FALSE; } pixt7 = pixCreateTemplate(pixs); pixCloseSafeBrick(pixt7, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt7, &same); if (!same) { fprintf(stderr, "pixref != pixt7 !\n"); ok = FALSE; } pixt8 = pixCopy(NULL, pixs); /* in-place */ pixCloseSafeBrick(pixt8, pixt8, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt8, &same); if (!same) { fprintf(stderr, "pixref != pixt8 !\n"); ok = FALSE; } pixt9 = pixCloseBrickDwa(NULL, pixs, WIDTH, HEIGHT); /* new one */ pixEqual(pixref, pixt9, &same); if (!same) { fprintf(stderr, "pixref != pixt9 !\n"); ok = FALSE; } pixt10 = pixCreateTemplate(pixs); pixCloseBrickDwa(pixt10, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt10, &same); if (!same) { fprintf(stderr, "pixref != pixt10 !\n"); ok = FALSE; } pixt11 = pixCopy(NULL, pixs); pixCloseBrickDwa(pixt11, pixt11, WIDTH, HEIGHT); /* in-place */ pixEqual(pixref, pixt11, &same); if (!same) { fprintf(stderr, "pixref != pixt11 !\n"); ok = FALSE; } sprintf(sequence, "c%d.%d", WIDTH, HEIGHT); pixt12 = pixMorphCompSequence(pixs, sequence, 0); /* comp sequence */ pixEqual(pixref, pixt12, &same); if (!same) { fprintf(stderr, "pixref != pixt12!\n"); ok = FALSE; } pixt13 = pixMorphSequenceDwa(pixs, sequence, 0); /* dwa sequence */ pixEqual(pixref, pixt13, &same); if (!same) { fprintf(stderr, "pixref != pixt13!\n"); ok = FALSE; } pixt14 = pixCreateTemplate(pixs); pixCloseCompBrickDwa(pixt14, pixs, WIDTH, HEIGHT); /* existing one */ pixEqual(pixref, pixt14, &same); if (!same) { fprintf(stderr, "pixref != pixt14 !\n"); ok = FALSE; } #if 0 pixWrite("/tmp/junkref.png", pixref, IFF_PNG); pixWrite("/tmp/junk12.png", pixt12, IFF_PNG); pixt13 = pixXor(NULL, pixref, pixt12); pixWrite("/tmp/junk12a.png", pixt13, IFF_PNG); pixDestroy(&pixt13); #endif pixDestroy(&pixref); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); pixDestroy(&pixt8); pixDestroy(&pixt9); pixDestroy(&pixt10); pixDestroy(&pixt11); pixDestroy(&pixt12); pixDestroy(&pixt13); pixDestroy(&pixt14); if (ok) fprintf(stderr, "All morph tests OK!\n"); pixDestroy(&pixs); selDestroy(&sel); exit(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; 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) exit(ERROR_INT(" Syntax: affine_reg", mainName, 1)); if ((pixs = pixRead("feyn.tif")) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); #if ALL /* 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, 3, 1, 20, 8); pixt2 = pixAffineSequential(pixt1, ptas, ptad, 0, 0); pixSaveTiled(pixt2, pixa, 3, 0, 20, 0); pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS); pixXor(pixd, pixd, pixs); pixSaveTiled(pixd, pixa, 3, 0, 20, 0); sprintf(bufname, "/tmp/junkseq%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/junkaffine1.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, 3, 1, 20, 8); pixt2 = pixAffineSampledPta(pixt1, ptas, ptad, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, 3, 0, 20, 0); pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS); pixXor(pixd, pixd, pixs); pixSaveTiled(pixd, pixa, 3, 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/junkaffine2.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, 1, 20, 8); pixt2 = pixAffinePta(pixt1, ptas, ptad, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS / 3); 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/junkaffine3.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, 1, 20, 32); pixt2 = pixAffinePta(pixt1, ptas, ptad, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixd = pixRemoveBorder(pixt2, ADDED_BORDER_PIXELS / 4); 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/junkaffine4.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, 2, 0, 20, 8); /* Use sampled transform */ pixt2 = pixAffineSampledPta(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/junkaffine5.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, 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, 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, 20, 8); pixXor(pixt1, pixt1, pixt2); pixSaveTiled(pixt1, pixa, 1, 1, 20, 8); pixXor(pixt2, pixt2, pixt3); pixSaveTiled(pixt2, pixa, 1, 0, 20, 8); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixd = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/junkaffine6.png", pixd, IFF_PNG); pixDisplay(pixd, 100, 900); pixDestroy(&pixd); pixDestroy(&pixg); pixaDestroy(&pixa); ptaDestroy(&ptas); ptaDestroy(&ptad); #endif pixDestroy(&pixs); #if 1 /* 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, 2, 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, 2, 0, 30, 32); pixDestroy(&pixd); pixd = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/junkaffine7.png", pixd, IFF_PNG); pixDisplay(pixd, 100, 900); pixDestroy(&pixd); pixDestroy(&pixs); pixaDestroy(&pixa); boxaDestroy(&boxa); boxaDestroy(&boxa2); FREE(mat1); FREE(mat2); FREE(mat3); FREE(mat1i); FREE(mat2i); FREE(mat3i); #endif return 0; }
main(int argc, char **argv) { char *filein, *fileout; l_int32 w, h, d, w2, h2, i, ncols; l_float32 angle, conf; BOX *box; BOXA *boxa, *boxas, *boxad, *boxa2; NUMA *numa; PIX *pixs, *pixt, *pixb, *pixb2, *pixd; PIX *pixtlm, *pixvws; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIXA *pixam, *pixac, *pixad, *pixat; PIXAA *pixaa, *pixaa2; PTA *pta; SEL *selsplit; static char mainName[] = "textlinemask"; if (argc != 3) exit(ERROR_INT(" Syntax: textlinemask filein fileout", mainName, 1)); filein = argv[1]; fileout = argv[2]; pixDisplayWrite(NULL, -1); /* init debug output */ if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); pixGetDimensions(pixs, &w, &h, &d); /* Binarize input */ if (d == 8) pixt = pixThresholdToBinary(pixs, 128); else if (d == 1) pixt = pixClone(pixs); else { fprintf(stderr, "depth is %d\n", d); exit(1); } /* Deskew */ pixb = pixFindSkewAndDeskew(pixt, 1, &angle, &conf); pixDestroy(&pixt); fprintf(stderr, "Skew angle: %7.2f degrees; %6.2f conf\n", angle, conf); pixDisplayWrite(pixb, DEBUG_OUTPUT); #if 1 /* Use full image morphology to find columns, at 2x reduction. * This only works for very simple layouts where each column * of text extends the full height of the input image. * pixam has a pix component over each column. */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pixt1 = pixMorphCompSequence(pixb2, "c5.500", 0); boxa = pixConnComp(pixt1, &pixam, 8); ncols = boxaGetCount(boxa); fprintf(stderr, "Num columns: %d\n", ncols); pixDisplayWrite(pixt1, DEBUG_OUTPUT); /* Use selective region-based morphology to get the textline mask. */ pixad = pixaMorphSequenceByRegion(pixb2, pixam, "c100.3", 0, 0); pixGetDimensions(pixb2, &w2, &h2, NULL); if (DEBUG_OUTPUT) { pixt2 = pixaDisplay(pixad, w2, h2); pixDisplayWrite(pixt2, DEBUG_OUTPUT); pixDestroy(&pixt2); } /* Some of the lines may be touching, so use a HMT to split the * lines in each column, and use a pixaa to save the results. */ selsplit = selCreateFromString(seltext, 17, 7, "selsplit"); pixaa = pixaaCreate(ncols); for (i = 0; i < ncols; i++) { pixt3 = pixaGetPix(pixad, i, L_CLONE); box = pixaGetBox(pixad, i, L_COPY); pixt4 = pixHMT(NULL, pixt3, selsplit); pixXor(pixt4, pixt4, pixt3); boxa2 = pixConnComp(pixt4, &pixac, 8); pixaaAddPixa(pixaa, pixac, L_INSERT); pixaaAddBox(pixaa, box, L_INSERT); if (DEBUG_OUTPUT) { pixt5 = pixaDisplayRandomCmap(pixac, 0, 0); pixDisplayWrite(pixt5, DEBUG_OUTPUT); fprintf(stderr, "Num textlines in col %d: %d\n", i, boxaGetCount(boxa2)); pixDestroy(&pixt5); } pixDestroy(&pixt3); pixDestroy(&pixt4); boxaDestroy(&boxa2); } /* Visual output */ if (DEBUG_OUTPUT) { pixDisplayMultiple("/tmp/junk_write_display*"); pixat = pixaReadFiles("/tmp", "junk_write_display"); pixt5 = selDisplayInPix(selsplit, 31, 2); pixaAddPix(pixat, pixt5, L_INSERT); pixt6 = pixaDisplayTiledAndScaled(pixat, 32, 400, 3, 0, 35, 3); pixWrite(fileout, pixt6, IFF_PNG); pixaDestroy(&pixat); pixDestroy(&pixt6); } /* Test pixaa I/O */ pixaaWrite("/tmp/junkpixaa", pixaa); pixaa2 = pixaaRead("/tmp/junkpixaa"); pixaaWrite("/tmp/junkpixaa2", pixaa2); /* Test pixaa display */ pixd = pixaaDisplay(pixaa, w2, h2); pixWrite("/tmp/junkdisplay", pixd, IFF_PNG); pixDestroy(&pixd); /* Cleanup */ pixDestroy(&pixb2); pixDestroy(&pixt1); pixaDestroy(&pixam); pixaDestroy(&pixad); pixaaDestroy(&pixaa); pixaaDestroy(&pixaa2); boxaDestroy(&boxa); selDestroy(&selsplit); #endif #if 0 /* Use the baseline finder; not really what is needed */ numa = pixFindBaselines(pixb, &pta, 1); #endif #if 0 /* Use the textline mask function; parameters are not quite right */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pixtlm = pixGenTextlineMask(pixb2, &pixvws, NULL, 1); pixDisplay(pixtlm, 0, 100); pixDisplay(pixvws, 500, 100); pixDestroy(&pixb2); pixDestroy(&pixtlm); pixDestroy(&pixvws); #endif #if 0 /* Use the Breuel whitespace partition method; slow and we would * still need to work to extract the fg regions. */ pixb2 = pixReduceRankBinary2(pixb, 2, NULL); boxas = pixConnComp(pixb2, NULL, 8); boxad = boxaGetWhiteblocks(boxas, NULL, L_SORT_BY_HEIGHT, 3, 0.1, 200, 0.2, 0); pixd = pixDrawBoxa(pixb2, boxad, 7, 0xe0708000); pixDisplay(pixd, 100, 500); pixDestroy(&pixb2); pixDestroy(&pixd); boxaDestroy(&boxas); boxaDestroy(&boxad); #endif #if 0 /* Use morphology to find columns and then selective * region-based morphology to get the textline mask. * This is for display; we really want to get a pixa of the * specific textline masks. */ startTimer(); pixb2 = pixReduceRankBinary2(pixb, 2, NULL); pixt1 = pixMorphCompSequence(pixb2, "c5.500", 0); /* column mask */ pixt2 = pixMorphSequenceByRegion(pixb2, pixt1, "c100.3", 8, 0, 0, &boxa); fprintf(stderr, "time = %7.3f sec\n", stopTimer()); pixDisplay(pixt1, 100, 500); pixDisplay(pixt2, 800, 500); pixDestroy(&pixb2); pixDestroy(&pixt1); pixDestroy(&pixt2); boxaDestroy(&boxa); #endif pixDestroy(&pixs); pixDestroy(&pixb); exit(0); }
main(int argc, char **argv) { char *filein; l_int32 count; CCBORDA *ccba, *ccba2; PIX *pixs, *pixd, *pixd2, *pixd3; PIX *pixt, *pixc, *pixc2; static char mainName[] = "ccbordtest"; if (argc != 2) exit(ERROR_INT(" Syntax: ccbordtest filein", mainName, 1)); filein = argv[1]; if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); fprintf(stderr, "Get border representation..."); startTimer(); ccba = pixGetAllCCBorders(pixs); fprintf(stderr, "%6.3f sec\n", stopTimer()); #if 0 /* get global locs directly and display borders */ fprintf(stderr, "Convert from local to global locs..."); startTimer(); ccbaGenerateGlobalLocs(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); fprintf(stderr, "Display border representation..."); startTimer(); pixd = ccbaDisplayBorder(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); pixWrite("/tmp/junkborder1.png", pixd, IFF_PNG); #else /* get step chain code, then global coords, and display borders */ fprintf(stderr, "Get step chain code..."); startTimer(); ccbaGenerateStepChains(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); fprintf(stderr, "Convert from step chain to global locs..."); startTimer(); ccbaStepChainsToPixCoords(ccba, CCB_GLOBAL_COORDS); fprintf(stderr, "%6.3f sec\n", stopTimer()); fprintf(stderr, "Display border representation..."); startTimer(); pixd = ccbaDisplayBorder(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); pixWrite("/tmp/junkborder1.png", pixd, IFF_PNG); #endif /* check if border pixels are in original set */ fprintf(stderr, "Check if border pixels are in original set ...\n"); pixt = pixSubtract(NULL, pixd, pixs); pixCountPixels(pixt, &count, NULL); if (count == 0) fprintf(stderr, " all border pixels are in original set\n"); else fprintf(stderr, " %d border pixels are not in original set\n", count); pixDestroy(&pixt); /* display image */ fprintf(stderr, "Reconstruct image ..."); startTimer(); /* pixc = ccbaDisplayImage1(ccba); */ pixc = ccbaDisplayImage2(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); pixWrite("/tmp/junkrecon1.png", pixc, IFF_PNG); /* check with original to see if correct */ fprintf(stderr, "Check with original to see if correct ...\n"); pixXor(pixc, pixc, pixs); pixCountPixels(pixc, &count, NULL); if (count == 0) fprintf(stderr, " perfect direct recon\n"); else { l_int32 w, h, i, j; l_uint32 val; fprintf(stderr, " %d pixels in error in recon\n", count); #if 1 w = pixGetWidth(pixc); h = pixGetHeight(pixc); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixc, j, i, &val); if (val == 1) fprintf(stderr, "bad pixel at (%d, %d)\n", j, i); } } pixWrite("/tmp/junkbadpixels.png", pixc, IFF_PNG); #endif } /*----------------------------------------------------------* * write to file (compressed) and read back * *----------------------------------------------------------*/ fprintf(stderr, "Write serialized step data..."); startTimer(); ccbaWrite("/tmp/junkstepout", ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); fprintf(stderr, "Read serialized step data..."); startTimer(); ccba2 = ccbaRead("/tmp/junkstepout"); fprintf(stderr, "%6.3f sec\n", stopTimer()); /* display the border pixels again */ fprintf(stderr, "Convert from step chain to global locs..."); startTimer(); ccbaStepChainsToPixCoords(ccba2, CCB_GLOBAL_COORDS); fprintf(stderr, "%6.3f sec\n", stopTimer()); fprintf(stderr, "Display border representation..."); startTimer(); pixd2 = ccbaDisplayBorder(ccba2); fprintf(stderr, "%6.3f sec\n", stopTimer()); pixWrite("/tmp/junkborder2.png", pixd2, IFF_PNG); /* check if border pixels are same as first time */ pixXor(pixd2, pixd2, pixd); pixCountPixels(pixd2, &count, NULL); if (count == 0) fprintf(stderr, " perfect w/r border recon\n"); else { l_int32 w, h, i, j, val; fprintf(stderr, " %d pixels in error in w/r recon\n", count); } pixDestroy(&pixd2); /* display image again */ fprintf(stderr, "Convert from step chain to local coords..."); startTimer(); ccbaStepChainsToPixCoords(ccba2, CCB_LOCAL_COORDS); fprintf(stderr, "%6.3f sec\n", stopTimer()); fprintf(stderr, "Reconstruct image from file ..."); startTimer(); /* pixc2 = ccbaDisplayImage1(ccba2); */ pixc2 = ccbaDisplayImage2(ccba2); fprintf(stderr, "%6.3f sec\n", stopTimer()); pixWrite("/tmp/junkrecon2.png", pixc2, IFF_PNG); /* check with original to see if correct */ fprintf(stderr, "Check with original to see if correct ...\n"); pixXor(pixc2, pixc2, pixs); pixCountPixels(pixc2, &count, NULL); if (count == 0) fprintf(stderr, " perfect image recon\n"); else { l_int32 w, h, i, j; l_uint32 val; fprintf(stderr, " %d pixels in error in image recon\n", count); #if 1 w = pixGetWidth(pixc2); h = pixGetHeight(pixc2); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixc2, j, i, &val); if (val == 1) fprintf(stderr, "bad pixel at (%d, %d)\n", j, i); } } pixWrite("/tmp/junkbadpixels2.png", pixc2, IFF_PNG); #endif } /*----------------------------------------------------------* * make, display and check single path border for svg * *----------------------------------------------------------*/ /* make local single path border for svg */ fprintf(stderr, "Make local single path borders for svg ..."); startTimer(); ccbaGenerateSinglePath(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); /* generate global single path border */ fprintf(stderr, "Generate global single path borders ..."); startTimer(); ccbaGenerateSPGlobalLocs(ccba, CCB_SAVE_TURNING_PTS); fprintf(stderr, "%6.3f sec\n", stopTimer()); /* display border pixels from single path */ fprintf(stderr, "Display border from single path..."); startTimer(); pixd3 = ccbaDisplaySPBorder(ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); pixWrite("/tmp/junkborder3.png", pixd3, IFF_PNG); /* check if border pixels are in original set */ fprintf(stderr, "Check if border pixels are in original set ...\n"); pixt = pixSubtract(NULL, pixd3, pixs); pixCountPixels(pixt, &count, NULL); if (count == 0) fprintf(stderr, " all border pixels are in original set\n"); else fprintf(stderr, " %d border pixels are not in original set\n", count); pixDestroy(&pixt); pixDestroy(&pixd3); /* output in svg file format */ fprintf(stderr, "Write output in svg file format ...\n"); startTimer(); ccbaWriteSVG("/tmp/junksvg", ccba); fprintf(stderr, "%6.3f sec\n", stopTimer()); ccbaDestroy(&ccba2); ccbaDestroy(&ccba); pixDestroy(&pixs); pixDestroy(&pixd); pixDestroy(&pixc); pixDestroy(&pixc2); return 0; }
l_int32 DoComparisonDwa1(PIX *pixs, PIX *pixt1, PIX *pixt2, PIX *pixt3, PIX *pixt4, PIX *pixt5, PIX *pixt6, l_int32 isize) { l_int32 fact1, fact2, size; selectComposableSizes(isize, &fact1, &fact2); size = fact1 * fact2; fprintf(stderr, "..%d..", size); if (TIMING) startTimer(); pixDilateCompBrickExtendDwa(pixt1, pixs, size, 1); pixDilateCompBrickExtendDwa(pixt3, pixs, 1, size); pixDilateCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixDilateCompBrick(pixt2, pixs, size, 1); pixDilateCompBrick(pixt4, pixs, 1, size); pixDilateCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "dilate", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixErodeCompBrickExtendDwa(pixt1, pixs, size, 1); pixErodeCompBrickExtendDwa(pixt3, pixs, 1, size); pixErodeCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixErodeCompBrick(pixt2, pixs, size, 1); pixErodeCompBrick(pixt4, pixs, 1, size); pixErodeCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "erode", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixOpenCompBrickExtendDwa(pixt1, pixs, size, 1); pixOpenCompBrickExtendDwa(pixt3, pixs, 1, size); pixOpenCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixOpenCompBrick(pixt2, pixs, size, 1); pixOpenCompBrick(pixt4, pixs, 1, size); pixOpenCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "open", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); if (TIMING) startTimer(); pixCloseCompBrickExtendDwa(pixt1, pixs, size, 1); pixCloseCompBrickExtendDwa(pixt3, pixs, 1, size); pixCloseCompBrickExtendDwa(pixt5, pixs, size, size); if (TIMING) fprintf(stderr, "Time Dwa: %7.3f sec\n", stopTimer()); if (TIMING) startTimer(); pixCloseSafeCompBrick(pixt2, pixs, size, 1); pixCloseSafeCompBrick(pixt4, pixs, 1, size); pixCloseSafeCompBrick(pixt6, pixs, size, size); if (TIMING) fprintf(stderr, "Time Rop: %7.3f sec\n", stopTimer()); PixCompareDwa(size, "close", pixt1, pixt2, pixt3, pixt4, pixt5, pixt6); #if 0 pixWrite("/tmp/junkpixt3.png", pixt3, IFF_PNG); pixWrite("/tmp/junkpixt4.png", pixt4, IFF_PNG); pixXor(pixt3, pixt3, pixt4); pixWrite("/tmp/junkxor.png", pixt3, IFF_PNG); #endif return 0; }