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; }
/* * pixaWriteCompressedToPS() * * Input: pixa (any set of images) * fileout (output ps file) * res (of input image) * level (compression: 2 or 3) * Return: 0 if OK, 1 on error * * Notes: * (1) This generates a PS file of multiple page images, all * with bounding boxes. * (2) It compresses to: * cmap + level2: jpeg * cmap + level3: flate * 1 bpp: tiffg4 * 2 or 4 bpp + level2: jpeg * 2 or 4 bpp + level3: flate * 8 bpp: jpeg * 16 bpp: flate * 32 bpp: jpeg * (3) To generate a pdf, use: ps2pdf <infile.ps> <outfile.pdf> */ l_int32 pixaWriteCompressedToPS(PIXA *pixa, const char *fileout, l_int32 res, l_int32 level) { char *tname, *g4_name, *jpeg_name, *png_name; l_int32 i, n, firstfile, index, writeout, d; PIX *pix, *pixt; PIXCMAP *cmap; PROCNAME("pixaWriteCompressedToPS"); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); if (level != 2 && level != 3) { L_ERROR("only levels 2 and 3 permitted; using level 2\n", procName); level = 2; } n = pixaGetCount(pixa); firstfile = TRUE; index = 0; lept_mkdir("lept/comp"); g4_name = genTempFilename("/tmp/lept/comp", "temp.tif", 0, 0); jpeg_name = genTempFilename("/tmp/lept/comp", "temp.jpg", 0, 0); png_name = genTempFilename("/tmp/lept/comp", "temp.png", 0, 0); for (i = 0; i < n; i++) { writeout = TRUE; pix = pixaGetPix(pixa, i, L_CLONE); d = pixGetDepth(pix); cmap = pixGetColormap(pix); if (d == 1) { tname = g4_name; pixWrite(tname, pix, IFF_TIFF_G4); } else if (cmap) { if (level == 2) { pixt = pixConvertForPSWrap(pix); tname = jpeg_name; pixWrite(tname, pixt, IFF_JFIF_JPEG); pixDestroy(&pixt); } else { /* level == 3 */ tname = png_name; pixWrite(tname, pix, IFF_PNG); } } else if (d == 16) { if (level == 2) L_WARNING("d = 16; must write out flate\n", procName); tname = png_name; pixWrite(tname, pix, IFF_PNG); } else if (d == 2 || d == 4) { if (level == 2) { pixt = pixConvertTo8(pix, 0); tname = jpeg_name; pixWrite(tname, pixt, IFF_JFIF_JPEG); pixDestroy(&pixt); } else { /* level == 3 */ tname = png_name; pixWrite(tname, pix, IFF_PNG); } } else if (d == 8 || d == 32) { tname = jpeg_name; pixWrite(tname, pix, IFF_JFIF_JPEG); } else { /* shouldn't happen */ L_ERROR("invalid depth: %d\n", procName, d); writeout = FALSE; } pixDestroy(&pix); if (writeout) writeImageCompressedToPSFile(tname, fileout, res, &firstfile, &index); } LEPT_FREE(g4_name); LEPT_FREE(jpeg_name); LEPT_FREE(png_name); 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; }
int main(int argc, char **argv) { char buf[32]; char *filein, *fileout, *fontdir, *textstr; l_int32 n, i, maxdepth, ntext, border, lossless, display, showtext; l_float32 scalefact; L_BMF *bmf; PIX *pix1, *pix2, *pix3, *pix4, *pixd; PIXA *pixa, *pixad; static char mainName[] = "displaypixa"; if (argc != 3 && argc != 4 && argc != 7 && argc != 8) { fprintf(stderr, "Syntax error in displaypixa:\n" " displaypixa filein fileout [showtext]\n" " displaypixa filein scalefact border" " lossless disp fileout [showtext]\n"); return 1; } filein = argv[1]; if ((pixa = pixaRead(filein)) == NULL) return ERROR_INT("pixa not made", mainName, 1); pixaCountText(pixa, &ntext); if (argc == 3 || argc == 4) fileout = argv[2]; if (argc == 4) showtext = atoi(argv[3]); /* Simple specification; no output text */ if (argc == 3 || (argc == 4 && (ntext == 0 || showtext == 0))) { /* no text output */ pixaVerifyDepth(pixa, &maxdepth); pixd = pixaDisplayTiledInRows(pixa, maxdepth, 1400, 1.0, 0, 10, 0); pixDisplay(pixd, 100, 100); if (pixGetDepth(pixd) == 1) pixWrite(fileout, pixd, IFF_PNG); else pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); return 0; } /* Simple specification with output text */ if (argc == 4) { /* showtext == 1 && ntext > 0 */ n = pixaGetCount(pixa); bmf = bmfCreate(NULL, 6); pixad = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixa, i, L_CLONE); pix2 = pixConvertTo32(pix1); pix3 = pixAddBorderGeneral(pix2, 10, 10, 5, 5, 0xffffff00); textstr = pixGetText(pix1); if (textstr && strlen(textstr) > 0) { snprintf(buf, sizeof(buf), "%s", textstr); pix4 = pixAddSingleTextblock(pix3, bmf, buf, 0xff000000, L_ADD_BELOW, NULL); } else { pix4 = pixClone(pix3); } pixaAddPix(pixad, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } bmfDestroy(&bmf); pixaVerifyDepth(pixad, &maxdepth); pixd = pixaDisplayTiledInRows(pixad, maxdepth, 1400, 1.0, 0, 10, 0); pixDisplay(pixd, 100, 100); if (pixGetDepth(pixd) == 1) pixWrite(fileout, pixd, IFF_PNG); else pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); pixaDestroy(&pixad); return 0; } /* Full specification */ scalefact = atof(argv[2]); border = atoi(argv[3]); lossless = atoi(argv[4]); display = atoi(argv[5]); fileout = argv[6]; showtext = (argc == 8) ? atoi(argv[7]) : 0; if (showtext && ntext == 0) L_INFO("No text found in any of the pix\n", mainName); bmf = (showtext && ntext > 0) ? bmfCreate(NULL, 6) : NULL; n = pixaGetCount(pixa); pixad = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixa, i, L_CLONE); pix2 = pixConvertTo32(pix1); pix3 = pixAddBorderGeneral(pix2, 10, 10, 5, 5, 0xffffff00); textstr = pixGetText(pix1); if (bmf && textstr && strlen(textstr) > 0) { snprintf(buf, sizeof(buf), "%s", textstr); pix4 = pixAddSingleTextblock(pix3, bmf, buf, 0xff000000, L_ADD_BELOW, NULL); } else { pix4 = pixClone(pix3); } pixaAddPix(pixad, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } bmfDestroy(&bmf); pixaVerifyDepth(pixad, &maxdepth); pixd = pixaDisplayTiledInRows(pixad, maxdepth, 1400, scalefact, 0, 10, border); if (display) pixDisplay(pixd, 20, 20); if (pixGetDepth(pixd) == 1 || lossless) pixWrite(fileout, pixd, IFF_PNG); else pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); pixaDestroy(&pixad); return 0; }
main(int argc, char **argv) { l_int32 d; PIX *pixs, *pixc, *pixr, *pixg, *pixb, *pixsg, *pixsm, *pixd; PIXA *pixa; static char mainName[] = "livre_adapt"; if (argc != 1) exit(ERROR_INT(" Syntax: livre_adapt", mainName, 1)); /* Read the image in at 150 ppi. */ pixDisplayWrite(NULL, -1); if ((pixs = pixRead("brothers.150.jpg")) == NULL) exit(ERROR_INT("pix not made", mainName, 1)); pixDisplayWriteFormat(pixs, 2, IFF_JFIF_JPEG); /* Normalize for uneven illumination on RGB image */ pixBackgroundNormRGBArraysMorph(pixs, NULL, 4, 5, 200, &pixr, &pixg, &pixb); pixd = pixApplyInvBackgroundRGBMap(pixs, pixr, pixg, pixb, 4, 4); pixDisplayWriteFormat(pixd, 2, IFF_JFIF_JPEG); pixDestroy(&pixr); pixDestroy(&pixg); pixDestroy(&pixb); pixDestroy(&pixd); /* Convert the RGB image to grayscale. */ pixsg = pixConvertRGBToLuminance(pixs); pixDisplayWriteFormat(pixsg, 2, IFF_JFIF_JPEG); /* Remove the text in the fg. */ pixc = pixCloseGray(pixsg, 25, 25); pixDisplayWriteFormat(pixc, 2, IFF_JFIF_JPEG); /* Smooth the bg with a convolution. */ pixsm = pixBlockconv(pixc, 15, 15); pixDisplayWriteFormat(pixsm, 2, IFF_JFIF_JPEG); pixDestroy(&pixc); /* Normalize for uneven illumination on gray image. */ pixBackgroundNormGrayArrayMorph(pixsg, NULL, 4, 5, 200, &pixg); pixc = pixApplyInvBackgroundGrayMap(pixsg, pixg, 4, 4); pixDisplayWriteFormat(pixc, 2, IFF_JFIF_JPEG); pixDestroy(&pixg); /* Increase the dynamic range. */ pixd = pixGammaTRC(NULL, pixc, 1.0, 30, 180); pixDisplayWriteFormat(pixd, 2, IFF_JFIF_JPEG); pixDestroy(&pixc); /* Threshold to 1 bpp. */ pixb = pixThresholdToBinary(pixd, 120); pixDisplayWriteFormat(pixb, 2, IFF_PNG); pixDestroy(&pixd); pixDestroy(&pixb); /* Generate the output image */ pixa = pixaReadFiles("/tmp", "junk_write_display"); pixd = pixaDisplayTiledAndScaled(pixa, 8, 350, 4, 0, 25, 2); pixWrite("/tmp/adapt.jpg", pixd, IFF_JFIF_JPEG); pixDisplayWithTitle(pixd, 100, 100, NULL, 1); pixDestroy(&pixd); pixDestroy(&pixs); pixDestroy(&pixsg); return 0; }
/*! * pixConnCompBB() * * Input: pixs (1 bpp) * connectivity (4 or 8) * Return: boxa, or null on error * * Notes: * (1) Finds bounding boxes of 4- or 8-connected components * in a binary image. * (2) This works on a copy of the input pix. The c.c. are located * in raster order and erased one at a time. In the process, * the b.b. is computed and saved. */ BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity) { l_int32 h, iszero; l_int32 x, y, xstart, ystart; PIX *pixt; BOX *box; BOXA *boxa; L_STACK *stack, *auxstack; PROCNAME("pixConnCompBB"); 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); pixZero(pixs, &iszero); if (iszero) return boxaCreate(1); /* return empty boxa */ if ((pixt = pixCopy(NULL, pixs)) == NULL) return (BOXA *)ERROR_PTR("pixt not made", procName, NULL); h = pixGetHeight(pixs); if ((stack = lstackCreate(h)) == NULL) return (BOXA *)ERROR_PTR("stack not made", procName, NULL); if ((auxstack = lstackCreate(0)) == NULL) return (BOXA *)ERROR_PTR("auxstack not made", procName, NULL); stack->auxstack = auxstack; if ((boxa = boxaCreate(0)) == NULL) return (BOXA *)ERROR_PTR("boxa not made", procName, NULL); xstart = 0; ystart = 0; while (1) { if (!nextOnPixelInRaster(pixt, xstart, ystart, &x, &y)) break; if ((box = pixSeedfillBB(pixt, stack, x, y, connectivity)) == NULL) return (BOXA *)ERROR_PTR("box not made", procName, NULL); boxaAddBox(boxa, box, L_INSERT); xstart = x; ystart = y; } #if DEBUG pixCountPixels(pixt, &iszero, NULL); fprintf(stderr, "Number of remaining pixels = %d\n", iszero); pixWrite("junkremain", pixt1, IFF_PNG); #endif /* DEBUG */ /* Cleanup, freeing the fillsegs on each stack */ lstackDestroy(&stack, TRUE); pixDestroy(&pixt); return boxa; }
int main(int argc, char **argv) { l_int32 i, n, w, h, nactual, imax; BOX *box; BOXA *boxa; PIX *pixs, *pixd, *pix; PIXA *pixas, *pixat, *pixac; L_PTRA *papix, *pabox, *papix2, *pabox2; static char mainName[] = "ptra1_reg"; if (argc != 1) return ERROR_INT(" Syntax: ptra1_reg", mainName, 1); setLeptDebugOK(1); pixac = pixaCreate(0); if ((pixs = pixRead("lucasta.1.300.tif")) == NULL) return ERROR_INT("pixs not made", mainName, 1); pixGetDimensions(pixs, &w, &h, NULL); boxa = pixConnComp(pixs, &pixas, 8); pixDestroy(&pixs); boxaDestroy(&boxa); n = pixaGetCount(pixas); /* Fill ptras with clones and reconstruct */ fprintf(stderr, "Fill with clones and reconstruct\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* Remove every other one for the first half; * with compaction at each removal */ fprintf(stderr, "Remove every other in 1st half, with compaction\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_COPY); for (i = 0; i < n / 2; i++) { if (i % 2 == 0) { pix = (PIX *)ptraRemove(papix, i, L_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_COMPACTION); pixDestroy(&pix); boxDestroy(&box); } } pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Remove every other one for the entire set, * but without compaction at each removal */ fprintf(stderr, "Remove every other in 1st half, without & then with compaction\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_COPY); for (i = 0; i < n; i++) { if (i % 2 == 0) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); pixDestroy(&pix); boxDestroy(&box); } } ptraCompactArray(papix); /* now do the compaction */ ptraCompactArray(pabox); pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Fill ptras using insert at head, and reconstruct */ fprintf(stderr, "Insert at head and reconstruct\n"); papix = ptraCreate(n); pabox = ptraCreate(n); for (i = 0; i < n; i++) { pix = pixaGetPix(pixas, i, L_CLONE); box = pixaGetBox(pixas, i, L_CLONE); ptraInsert(papix, 0, pix, L_MIN_DOWNSHIFT); ptraInsert(pabox, 0, box, L_FULL_DOWNSHIFT); } pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* Reverse the arrays by swapping */ fprintf(stderr, "Reverse by swapping\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); for (i = 0; i < n / 2; i++) { ptraSwap(papix, i, n - i - 1); ptraSwap(pabox, i, n - i - 1); } ptraCompactArray(papix); /* already compact; shouldn't do anything */ ptraCompactArray(pabox); pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Remove at the top of the array and push the hole to the end * by neighbor swapping (!). This is O(n^2), so it's not a * recommended way to copy a ptra. [joke] */ fprintf(stderr, "Remove at top, pushing hole to end by swapping -- O(n^2)\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); papix2 = ptraCreate(0); pabox2 = ptraCreate(0); while (1) { ptraGetActualCount(papix, &nactual); if (nactual == 0) break; ptraGetMaxIndex(papix, &imax); pix = (PIX *)ptraRemove(papix, 0, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, 0, L_NO_COMPACTION); ptraAdd(papix2, pix); ptraAdd(pabox2, box); for (i = 1; i <= imax; i++) { ptraSwap(papix, i - 1, i); ptraSwap(pabox, i - 1, i); } } ptraCompactArray(papix); /* should be empty */ ptraCompactArray(pabox); /* ditto */ pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* nothing there */ pixat = ReconstructPixa(papix2, pabox2, CHOOSE_RECON); ptraDestroy(&papix2, 0, 1); ptraDestroy(&pabox2, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); /* Remove and insert one position above, allowing minimum downshift. * If you specify L_AUTO_DOWNSHIFT, because there is only 1 hole, * it will do a full downshift at each insert. This is a * situation where the heuristic (expected number of holes) * fails to do the optimal thing. */ fprintf(stderr, "Remove and insert one position above (min downshift)\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); for (i = 1; i < n; i++) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); ptraInsert(papix, i - 1, pix, L_MIN_DOWNSHIFT); ptraInsert(pabox, i - 1, box, L_MIN_DOWNSHIFT); } pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 1); /* Remove and insert one position above, but this time * forcing a full downshift at each step. */ fprintf(stderr, "Remove and insert one position above (full downshift)\n"); MakePtrasFromPixa(pixas, &papix, &pabox, L_CLONE); for (i = 1; i < n; i++) { pix = (PIX *)ptraRemove(papix, i, L_NO_COMPACTION); box = (BOX *)ptraRemove(pabox, i, L_NO_COMPACTION); ptraInsert(papix, i - 1, pix, L_AUTO_DOWNSHIFT); ptraInsert(pabox, i - 1, box, L_AUTO_DOWNSHIFT); } /* ptraCompactArray(papix); ptraCompactArray(pabox); */ pixat = ReconstructPixa(papix, pabox, CHOOSE_RECON); ptraDestroy(&papix, 0, 1); ptraDestroy(&pabox, 0, 1); DisplayResult(pixac, &pixat, w, h, 0); pixd = pixaDisplay(pixac, 0, 0); pixDisplay(pixd, 100, 100); pixWrite("/tmp/junkptra1.png", pixd, IFF_PNG); pixDestroy(&pixd); pixaDestroy(&pixac); pixaDestroy(&pixas); return 0; }
main(int argc, char **argv) { char *filein, *fileout; char buffer[512]; const char *psfile = "/tmp/junk_split_image.ps"; l_int32 nx, ny, i, w, h, d, ws, hs, n, res, ignore; l_float32 scale; PIX *pixs, *pixt, *pixr; PIXA *pixa; static char mainName[] = "splitimage2pdf"; if (argc != 5) return ERROR_INT(" Syntax: splitimage2pdf filein nx ny fileout", mainName, 1); filein = argv[1]; nx = atoi(argv[2]); ny = atoi(argv[3]); fileout = argv[4]; lept_rm(NULL, "junk_split_image.ps"); if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); d = pixGetDepth(pixs); if (d == 1 ) lept_rm(NULL, "junk_split_image.tif"); else if (d == 8 || d == 32) lept_rm(NULL, "junk_split_image.jpg"); else return ERROR_INT("d not in {1,8,32} bpp", mainName, 1); ws = pixGetWidth(pixs); hs = pixGetHeight(pixs); if (ny * ws > nx * hs) pixr = pixRotate90(pixs, 1); else pixr = pixClone(pixs); pixa = pixaSplitPix(pixr, nx, ny, 0, 0); n = pixaGetCount(pixa); res = 300; for (i = 0; i < n; i++) { pixt = pixaGetPix(pixa, i, L_CLONE); w = pixGetWidth(pixt); h = pixGetHeight(pixt); scale = L_MIN(FILL_FACTOR * 2550 / w, FILL_FACTOR * 3300 / h); if (d == 1) { pixWrite("/tmp/junk_split_image.tif", pixt, IFF_TIFF_G4); if (i == 0) convertG4ToPS("/tmp/junk_split_image.tif", psfile, "w", 0, 0, 300, scale, 1, FALSE, TRUE); else convertG4ToPS("/tmp/junk_split_image.tif", psfile, "a", 0, 0, 300, scale, 1, FALSE, TRUE); } else { pixWrite("/tmp/junk_split_image.jpg", pixt, IFF_JFIF_JPEG); if (i == 0) convertJpegToPS("/tmp/junk_split_image.jpg", psfile, "w", 0, 0, 300, scale, 1, TRUE); else convertJpegToPS("/tmp/junk_split_image.jpg", psfile, "a", 0, 0, 300, scale, 1, TRUE); } pixDestroy(&pixt); } sprintf(buffer, "ps2pdf %s %s", psfile, fileout); ignore = system(buffer); pixaDestroy(&pixa); pixDestroy(&pixr); pixDestroy(&pixs); return 0; }
int main_find_pattern(int argc, char **argv) { char *filein, *fileout, *patternfile; l_int32 w, h, i, n; BOX *box, *boxe; BOXA *boxa1, *boxa2; PIX *pixs, *pixp, *pixpe; PIX *pixd, *pixt1, *pixt2, *pixhmt; SEL *sel_2h, *sel; static char mainName[] = "findpattern1"; filein = "feyn.tif"; patternfile = "char.tif"; fileout = "result.findpattern1"; if ((pixs = pixRead(filein)) == NULL) printf("pixs not made\n"); if ((pixp = pixRead(patternfile)) == NULL) printf("pixp not made\n"); w = pixGetWidth(pixp); h = pixGetHeight(pixp); /* generate the hit-miss Sel with runs */ sel = pixGenerateSelWithRuns(pixp, NumHorLines, NumVertLines, 0, MinRunlength, 7, 7, 0, 0, &pixpe); /* display the Sel two ways */ selWriteStream(stderr, sel); pixt1 = pixDisplayHitMissSel(pixpe, sel, 9, HitColor, MissColor); pixDisplay(pixt1, 200, 200); pixWrite("junkpixt", pixt1, IFF_PNG); /* use the Sel to find all instances in the page */ startTimer(); pixhmt = pixHMT(NULL, pixs, sel); fprintf(stderr, "Time to find patterns = %7.3f\n", stopTimer()); /* small erosion to remove noise; typically not necessary if * there are enough elements in the Sel */ sel_2h = selCreateBrick(1, 2, 0, 0, SEL_HIT); pixt2 = pixErode(NULL, pixhmt, sel_2h); /* display the result visually by placing the Sel at each * location found */ pixd = pixDilate(NULL, pixt2, sel); pixWrite(fileout, pixd, IFF_TIFF_G4); /* display outut with an outline around each located pattern */ boxa1 = pixConnCompBB(pixt2, 8); n = boxaGetCount(boxa1); boxa2 = boxaCreate(n); for (i = 0; i < n; i++) { box = boxaGetBox(boxa1, i, L_COPY); boxe = boxCreate(box->x - w / 2, box->y - h / 2, w + 4, h + 4); boxaAddBox(boxa2, boxe, L_INSERT); pixRenderBox(pixs, boxe, 4, L_FLIP_PIXELS); boxDestroy(&box); } pixWrite("junkoutline", pixs, IFF_TIFF_G4); //boxaWriteStream(stderr, boxa2); //TODO ??? pixDestroy(&pixs); pixDestroy(&pixp); pixDestroy(&pixpe); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixhmt); pixDestroy(&pixd); selDestroy(&sel); selDestroy(&sel_2h); boxaDestroy(&boxa1); boxaDestroy(&boxa2); printf("\n---\nEND\n"); getchar(); return 0; }
// This method dumps a debug image to the specified location. void ShiroRekhaSplitter::DumpDebugImage(const char* filename) const { pixWrite(filename, debug_image_, IFF_PNG); }
l_int32 main(int argc, char **argv) { l_int32 i, n; l_float32 a, b, c, d, e; NUMA *nax, *nafit; PIX *pixs, *pixn, *pixg, *pixb, *pixt1, *pixt2; PIXA *pixa; PTA *pta, *ptad; PTAA *ptaa1, *ptaa2; pixs = pixRead("cat-35.jpg"); /* Normalize for varying background and binarize */ pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); pixDestroy(&pixn); pixDestroy(&pixg); /* Get the textline centers */ pixa = pixaCreate(6); ptaa1 = dewarpGetTextlineCenters(pixb, 0); pixt1 = pixCreateTemplate(pixs); pixSetAll(pixt1); pixt2 = pixDisplayPtaa(pixt1, ptaa1); pixWrite("/tmp/textline1.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 0, 100, "textline centers 1", 1); pixaAddPix(pixa, pixt2, L_INSERT); pixDestroy(&pixt1); /* Remove short lines */ fprintf(stderr, "Num all lines = %d\n", ptaaGetCount(ptaa1)); ptaa2 = dewarpRemoveShortLines(pixb, ptaa1, 0.8, 0); pixt1 = pixCreateTemplate(pixs); pixSetAll(pixt1); pixt2 = pixDisplayPtaa(pixt1, ptaa2); pixWrite("/tmp/textline2.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 300, 100, "textline centers 2", 1); pixaAddPix(pixa, pixt2, L_INSERT); pixDestroy(&pixt1); n = ptaaGetCount(ptaa2); fprintf(stderr, "Num long lines = %d\n", n); ptaaDestroy(&ptaa1); pixDestroy(&pixb); /* Long lines over input image */ pixt1 = pixCopy(NULL, pixs); pixt2 = pixDisplayPtaa(pixt1, ptaa2); pixWrite("/tmp/textline3.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 600, 100, "textline centers 3", 1); pixaAddPix(pixa, pixt2, L_INSERT); pixDestroy(&pixt1); /* Quadratic fit to curve */ pixt1 = pixCopy(NULL, pixs); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetQuadraticLSF(pta, &a, &b, &c, &nafit); fprintf(stderr, "Quadratic: a = %10.6f, b = %7.3f, c = %7.3f\n", a, b, c); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt1, pixt1, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixWrite("/tmp/textline4.png", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 900, 100, "textline centers 4", 1); pixaAddPix(pixa, pixt1, L_INSERT); /* Cubic fit to curve */ pixt1 = pixCopy(NULL, pixs); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetCubicLSF(pta, &a, &b, &c, &d, &nafit); fprintf(stderr, "Cubic: a = %10.6f, b = %10.6f, c = %7.3f, d = %7.3f\n", a, b, c, d); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt1, pixt1, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixWrite("/tmp/textline5.png", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 1200, 100, "textline centers 5", 1); pixaAddPix(pixa, pixt1, L_INSERT); /* Quartic fit to curve */ pixt1 = pixCopy(NULL, pixs); for (i = 0; i < n; i++) { pta = ptaaGetPta(ptaa2, i, L_CLONE); ptaGetArrays(pta, &nax, NULL); ptaGetQuarticLSF(pta, &a, &b, &c, &d, &e, &nafit); fprintf(stderr, "Quartic: a = %7.3f, b = %7.3f, c = %9.5f, d = %7.3f, e = %7.3f\n", a, b, c, d, e); ptad = ptaCreateFromNuma(nax, nafit); pixDisplayPta(pixt1, pixt1, ptad); ptaDestroy(&pta); ptaDestroy(&ptad); numaDestroy(&nax); numaDestroy(&nafit); } pixWrite("/tmp/textline6.png", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 1500, 100, "textline centers 6", 1); pixaAddPix(pixa, pixt1, L_INSERT); pixaConvertToPdf(pixa, 300, 0.5, L_JPEG_ENCODE, 75, "LS fittings to textlines", "/tmp/dewarp_fittings.pdf"); pixaDestroy(&pixa); pixDestroy(&pixs); ptaaDestroy(&ptaa2); return 0; }
main(int argc, char **argv) { l_int32 i, n, ws, hs, w, h, rval, gval, bval, order; l_float32 *mat1, *mat2, *mat3; l_float32 matd[9]; BOX *box, *boxt; BOXA *boxa, *boxat, *boxa1, *boxa2, *boxa3, *boxa4, *boxa5; PIX *pix, *pixs, *pixb, *pixc, *pixt, *pixt1, *pixt2, *pixt3; PIXA *pixa; static char mainName[] = "xformbox_reg"; /* ----------------------------------------------------------- * * Test hash rendering in 3 modes * * ----------------------------------------------------------- */ pixs = pixRead("feyn.tif"); box = boxCreate(461, 429, 1393, 342); pixt1 = pixClipRectangle(pixs, box, NULL); boxa = pixConnComp(pixt1, NULL, 8); n = boxaGetCount(boxa); pixt2 = pixConvertTo8(pixt1, 1); pixt3 = pixConvertTo32(pixt1); for (i = 0; i < n; i++) { boxt = boxaGetBox(boxa, i, L_CLONE); rval = (1413 * i) % 256; gval = (4917 * i) % 256; bval = (7341 * i) % 256; pixRenderHashBox(pixt1, boxt, 8, 2, i % 4, 1, L_SET_PIXELS); pixRenderHashBoxArb(pixt2, boxt, 7, 2, i % 4, 1, rval, gval, bval); pixRenderHashBoxBlend(pixt3, boxt, 7, 2, i % 4, 1, rval, gval, bval, 0.5); boxDestroy(&boxt); } pixDisplay(pixt1, 0, 0); pixDisplay(pixt2, 0, 300); pixDisplay(pixt3, 0, 570); pixWrite("/tmp/junkpixt1.png", pixt1, IFF_PNG); pixWrite("/tmp/junkpixt2.png", pixt2, IFF_PNG); pixWrite("/tmp/junkpixt3.png", pixt3, IFF_PNG); boxaDestroy(&boxa); boxDestroy(&box); pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); /* ----------------------------------------------------------- * * Test box transforms with either translation or scaling * * combined with rotation, using the simple 'ordered' * * function. Show that the order of the operations does * * not matter; different hashing schemes end up in the * * identical boxes. * * ----------------------------------------------------------- */ pix = pixRead("feyn.tif"); box = boxCreate(420, 360, 1500, 465); pixt = pixClipRectangle(pix, box, NULL); pixs = pixAddBorderGeneral(pixt, 0, 200, 0, 0, 0); boxDestroy(&box); pixDestroy(&pix); pixDestroy(&pixt); boxa = pixConnComp(pixs, NULL, 8); n = boxaGetCount(boxa); pixa = pixaCreate(0); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_TR_SC_RO; else if (i == 1) order = L_TR_RO_SC; else order = L_SC_TR_RO; boxat = boxaTransformOrdered(boxa, SHIFTX_2, SHIFTY_2, 1.0, 1.0, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1, 1, 30, 32); pixDestroy(&pixt); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_RO_TR_SC; else if (i == 1) order = L_RO_SC_TR; else order = L_SC_RO_TR; boxat = boxaTransformOrdered(boxa, SHIFTX_2, SHIFTY_2, 1.0, 1.0, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i + 4); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1, 1, 30, 0); pixDestroy(&pixt); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_TR_SC_RO; else if (i == 1) order = L_SC_RO_TR; else order = L_SC_TR_RO; boxat = boxaTransformOrdered(boxa, 0, 0, SCALEX_2, SCALEY_2, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i + 8); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1, 1, 30, 0); pixDestroy(&pixt); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_RO_TR_SC; else if (i == 1) order = L_RO_SC_TR; else order = L_TR_RO_SC; boxat = boxaTransformOrdered(boxa, 0, 0, SCALEX_2, SCALEY_2, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i + 16); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1, 1, 30, 0); pixDestroy(&pixt); pixt = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/junkxform1.png", pixt, IFF_PNG); pixDisplay(pixt, 1000, 0); pixDestroy(&pixt); pixDestroy(&pixs); boxaDestroy(&boxa); pixaDestroy(&pixa); /* ----------------------------------------------------------- * * Do more testing of box and pta transforms. Show that * * resulting boxes are identical by three methods. * * ----------------------------------------------------------- */ /* Set up pix and boxa */ pixa = pixaCreate(0); pix = pixRead("lucasta.1.300.tif"); pixTranslate(pix, pix, 70, 0, L_BRING_IN_WHITE); pixt = pixCloseBrick(NULL, pix, 14, 5); pixOpenBrick(pixt, pixt, 1, 2); boxa = pixConnComp(pixt, NULL, 8); pixs = pixConvertTo32(pix); pixc = pixCopy(NULL, pixs); RenderTransformedBoxa(pixc, boxa, 113); pixSaveTiled(pixc, pixa, 2, 1, 30, 32); pixDestroy(&pix); pixDestroy(&pixc); pixDestroy(&pixt); /* (a) Do successive discrete operations: shift, scale, rotate */ pixt1 = pixTranslate(NULL, pixs, SHIFTX_3, SHIFTY_3, L_BRING_IN_WHITE); boxa1 = boxaTranslate(boxa, SHIFTX_3, SHIFTY_3); pixc = pixCopy(NULL, pixt1); RenderTransformedBoxa(pixc, boxa1, 213); pixSaveTiled(pixc, pixa, 2, 0, 30, 32); pixDestroy(&pixc); pixt2 = pixScale(pixt1, SCALEX_3, SCALEY_3); boxa2 = boxaScale(boxa1, SCALEX_3, SCALEY_3); pixc = pixCopy(NULL, pixt2); RenderTransformedBoxa(pixc, boxa2, 313); pixSaveTiled(pixc, pixa, 2, 1, 30, 32); pixDestroy(&pixc); pixGetDimensions(pixt2, &w, &h, NULL); pixt3 = pixRotateAM(pixt2, ROTATION_3, L_BRING_IN_WHITE); boxa3 = boxaRotate(boxa2, w / 2, h / 2, ROTATION_3); pixc = pixCopy(NULL, pixt3); RenderTransformedBoxa(pixc, boxa3, 413); pixSaveTiled(pixc, pixa, 2, 0, 30, 32); pixDestroy(&pixc); /* (b) Set up and use the composite transform */ mat1 = createMatrix2dTranslate(SHIFTX_3, SHIFTY_3); mat2 = createMatrix2dScale(SCALEX_3, SCALEY_3); mat3 = createMatrix2dRotate(w / 2, h / 2, ROTATION_3); l_productMat3(mat3, mat2, mat1, matd, 3); boxa4 = boxaAffineTransform(boxa, matd); pixc = pixCopy(NULL, pixt3); RenderTransformedBoxa(pixc, boxa4, 513); pixSaveTiled(pixc, pixa, 2, 1, 30, 32); pixDestroy(&pixc); /* (c) Use the special 'ordered' function */ pixGetDimensions(pixs, &ws, &hs, NULL); boxa5 = boxaTransformOrdered(boxa, SHIFTX_3, SHIFTY_3, SCALEX_3, SCALEY_3, ws / 2, hs / 2, ROTATION_3, L_TR_SC_RO); pixc = pixCopy(NULL, pixt3); RenderTransformedBoxa(pixc, boxa5, 613); pixSaveTiled(pixc, pixa, 2, 0, 30, 32); pixDestroy(&pixc); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); boxaDestroy(&boxa1); boxaDestroy(&boxa2); boxaDestroy(&boxa3); boxaDestroy(&boxa4); boxaDestroy(&boxa5); lept_free(mat1); lept_free(mat2); lept_free(mat3); pixt = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/junkxform2.png", pixt, IFF_PNG); pixDisplay(pixt, 1000, 300); pixDestroy(&pixt); pixDestroy(&pixs); boxaDestroy(&boxa); pixaDestroy(&pixa); return 0; }
int main(int argc, char **argv) { l_int32 i, j; l_float32 f; l_uint32 redval, greenval; PIX *pixs, *pixd, *pix0, *pix1, *pix2; static char mainName[] = "locminmax_reg"; if (argc != 1) return ERROR_INT("syntax: locminmax_reg", mainName, 1); pixs = pixCreate(500, 500, 8); for (i = 0; i < 500; i++) { for (j = 0; j < 500; j++) { f = 128.0 + 26.3 * sin(0.0438 * (l_float32)i); f += 33.4 * cos(0.0712 * (l_float32)i); f += 18.6 * sin(0.0561 * (l_float32)j); f += 23.6 * cos(0.0327 * (l_float32)j); pixSetPixel(pixs, j, i, (l_int32)f); } } pixDisplay(pixs, 0, 0); pixWrite("/tmp/junkpattern.png", pixs, IFF_PNG); startTimer(); /* pixSelectedLocalExtrema(pixs, 1, &pix1, &pix2); */ pixLocalExtrema(pixs, 0, 0, &pix1, &pix2); fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer()); composeRGBPixel(255, 0, 0, &redval); composeRGBPixel(0, 255, 0, &greenval); pixd = pixConvertTo32(pixs); pixPaintThroughMask(pixd, pix2, 0, 0, greenval); pixPaintThroughMask(pixd, pix1, 0, 0, redval); pixDisplay(pixd, 510, 0); pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pixs); pixDestroy(&pixd); pix0 = pixRead("karen8.jpg"); pixs = pixBlockconv(pix0, 10, 10); pixDisplay(pixs, 0, 400); pixWrite("/tmp/junkconv.png", pixs, IFF_PNG); startTimer(); /* pixSelectedLocalExtrema(pixs, 1, &pix1, &pix2); */ pixLocalExtrema(pixs, 50, 100, &pix1, &pix2); fprintf(stderr, "Time for extrema: %7.3f\n", stopTimer()); composeRGBPixel(255, 0, 0, &redval); composeRGBPixel(0, 255, 0, &greenval); pixd = pixConvertTo32(pixs); pixPaintThroughMask(pixd, pix2, 0, 0, greenval); pixPaintThroughMask(pixd, pix1, 0, 0, redval); pixDisplay(pixd, 350, 400); pixWrite("/tmp/junkpixd2.png", pixd, IFF_PNG); pixDestroy(&pix0); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pixs); pixDestroy(&pixd); return 0; }
main(int argc, char **argv) { char *str; l_int32 i, j, same, ok; l_float32 sum, avediff, rmsdiff; L_KERNEL *kel1, *kel2, *kel3, *kel4, *kelx, *kely; BOX *box; PIX *pix, *pixs, *pixb, *pixg, *pixr, *pixd, *pixp, *pixt; PIX *pixt1, *pixt2, *pixt3; PIXA *pixa; SARRAY *sa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixa = pixaCreate(0); /* Test creating from a string */ kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr); pixd = kernelDisplayInPix(kel1, 41, 2); pixWrite("/tmp/pixkern.png", pixd, IFF_PNG); regTestCheckFile(rp, "/tmp/pixkern.png"); /* 0 */ pixSaveTiled(pixd, pixa, 1, 1, 20, 8); pixDestroy(&pixd); kernelDestroy(&kel1); /* Test read/write for kernel. Note that both get * compared to the same golden file, which is * overwritten with a copy of /tmp/kern2.kel */ kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr); kernelWrite("/tmp/kern1.kel", kel1); regTestCheckFile(rp, "/tmp/kern1.kel"); /* 1 */ kel2 = kernelRead("/tmp/kern1.kel"); kernelWrite("/tmp/kern2.kel", kel2); regTestCheckFile(rp, "/tmp/kern2.kel"); /* 2 */ regTestCompareFiles(rp, 1, 2); /* 3 */ kernelDestroy(&kel1); kernelDestroy(&kel2); /* Test creating from a file */ sa = sarrayCreate(0); sarrayAddString(sa, (char *)"# small 3x3 kernel", L_COPY); sarrayAddString(sa, (char *)"3 5", L_COPY); sarrayAddString(sa, (char *)"1 2", L_COPY); sarrayAddString(sa, (char *)"20.5 50 80 50 20", L_COPY); sarrayAddString(sa, (char *)"82. 120 180 120 80", L_COPY); sarrayAddString(sa, (char *)"22.1 50 80 50 20", L_COPY); str = sarrayToString(sa, 1); l_binaryWrite("/tmp/kernfile.kel", "w", str, strlen(str)); kel2 = kernelCreateFromFile("/tmp/kernfile.kel"); pixd = kernelDisplayInPix(kel2, 41, 2); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixWrite("/tmp/ker1.png", pixd, IFF_PNG); regTestCheckFile(rp, "/tmp/ker1.png"); /* 4 */ pixDestroy(&pixd); sarrayDestroy(&sa); lept_free(str); kernelDestroy(&kel2); /* Test creating from a pix */ pixt = pixCreate(5, 3, 8); pixSetPixel(pixt, 0, 0, 20); pixSetPixel(pixt, 1, 0, 50); pixSetPixel(pixt, 2, 0, 80); pixSetPixel(pixt, 3, 0, 50); pixSetPixel(pixt, 4, 0, 20); pixSetPixel(pixt, 0, 1, 80); pixSetPixel(pixt, 1, 1, 120); pixSetPixel(pixt, 2, 1, 180); pixSetPixel(pixt, 3, 1, 120); pixSetPixel(pixt, 4, 1, 80); pixSetPixel(pixt, 0, 0, 20); pixSetPixel(pixt, 1, 2, 50); pixSetPixel(pixt, 2, 2, 80); pixSetPixel(pixt, 3, 2, 50); pixSetPixel(pixt, 4, 2, 20); kel3 = kernelCreateFromPix(pixt, 1, 2); pixd = kernelDisplayInPix(kel3, 41, 2); pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker2.png", pixd, IFF_PNG); regTestCheckFile(rp, "/tmp/ker2.png"); /* 5 */ pixDestroy(&pixd); pixDestroy(&pixt); kernelDestroy(&kel3); /* Test convolution with kel1 */ pixs = pixRead("test24.jpg"); pixg = pixScaleRGBToGrayFast(pixs, 3, COLOR_GREEN); pixSaveTiled(pixg, pixa, 1, 1, 20, 0); kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr); pixd = pixConvolve(pixg, kel1, 8, 1); pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker3.png", pixd, IFF_PNG); regTestCheckFile(rp, "/tmp/ker3.png"); /* 6 */ pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixd); kernelDestroy(&kel1); /* Test convolution with flat rectangular kel; also test * block convolution with tiling. */ pixs = pixRead("test24.jpg"); pixg = pixScaleRGBToGrayFast(pixs, 3, COLOR_GREEN); kel2 = makeFlatKernel(11, 11, 5, 5); pixd = pixConvolve(pixg, kel2, 8, 1); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixWrite("/tmp/ker4.png", pixd, IFF_PNG); regTestCheckFile(rp, "/tmp/ker4.png"); /* 7 */ pixt = pixBlockconv(pixg, 5, 5); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker5.png", pixt, IFF_PNG); regTestCheckFile(rp, "/tmp/ker5.png"); /* 8 */ if (rp->display) pixCompareGray(pixd, pixt, L_COMPARE_ABS_DIFF, GPLOT_X11, NULL, NULL, NULL, NULL); pixt2 = pixBlockconvTiled(pixg, 5, 5, 3, 6); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker5a.png", pixt2, IFF_PNG); regTestCheckFile(rp, "/tmp/ker5a.png"); /* 9 */ pixDestroy(&pixt2); ok = TRUE; for (i = 1; i <= 7; i++) { for (j = 1; j <= 7; j++) { if (i == 1 && j == 1) continue; pixt2 = pixBlockconvTiled(pixg, 5, 5, j, i); pixEqual(pixt2, pixd, &same); if (!same) { fprintf(stderr," Error for nx = %d, ny = %d\n", j, i); ok = FALSE; } pixDestroy(&pixt2); } } if (ok) fprintf(stderr, "OK: Tiled results identical to pixConvolve()\n"); else fprintf(stderr, "ERROR: Tiled results not identical to pixConvolve()\n"); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixd); pixDestroy(&pixt); kernelDestroy(&kel2); /* Do another flat rectangular test; this time with white at edge. * About 1% of the pixels near the image edge differ by 1 between * the pixConvolve() and pixBlockconv(). For what it's worth, * pixConvolve() gives the more accurate result; namely, 255 for * pixels at the edge. */ pix = pixRead("pageseg1.tif"); box = boxCreate(100, 100, 2260, 3160); pixb = pixClipRectangle(pix, box, NULL); pixs = pixScaleToGray4(pixb); kel3 = makeFlatKernel(7, 7, 3, 3); startTimer(); pixt = pixConvolve(pixs, kel3, 8, 1); fprintf(stderr, "Generic convolution time: %5.3f sec\n", stopTimer()); pixSaveTiled(pixt, pixa, 1, 1, 20, 0); pixWrite("/tmp/conv1.png", pixt, IFF_PNG); regTestCheckFile(rp, "/tmp/conv1.png"); /* 10 */ startTimer(); pixt2 = pixBlockconv(pixs, 3, 3); fprintf(stderr, "Flat block convolution time: %5.3f sec\n", stopTimer()); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/conv2.png", pixt2, IFF_PNG); /* ditto */ regTestCheckFile(rp, "/tmp/conv2.png"); /* 11 */ pixCompareGray(pixt, pixt2, L_COMPARE_ABS_DIFF, GPLOT_PNG, NULL, &avediff, &rmsdiff, NULL); #ifndef _WIN32 sleep(1); /* give gnuplot time to write out the file */ #else Sleep(1000); #endif /* _WIN32 */ pixp = pixRead("/tmp/grayroot.png"); pixSaveTiled(pixp, pixa, 1, 0, 20, 0); pixWrite("/tmp/conv3.png", pixp, IFF_PNG); regTestCheckFile(rp, "/tmp/conv3.png"); /* 12 */ fprintf(stderr, "Ave diff = %6.4f, RMS diff = %6.4f\n", avediff, rmsdiff); if (avediff <= 0.01) fprintf(stderr, "OK: avediff = %6.4f <= 0.01\n", avediff); else fprintf(stderr, "Bad?: avediff = %6.4f > 0.01\n", avediff); pixDestroy(&pixt); pixDestroy(&pixt2); pixDestroy(&pixs); pixDestroy(&pixp); pixDestroy(&pix); pixDestroy(&pixb); boxDestroy(&box); kernelDestroy(&kel3); /* Do yet another set of flat rectangular tests, this time * on an RGB image */ pixs = pixRead("test24.jpg"); kel4 = makeFlatKernel(7, 7, 3, 3); startTimer(); pixt1 = pixConvolveRGB(pixs, kel4); fprintf(stderr, "Time 7x7 non-separable: %7.3f sec\n", stopTimer()); pixWrite("/tmp/conv4.jpg", pixt1, IFF_JFIF_JPEG); regTestCheckFile(rp, "/tmp/conv4.jpg"); /* 13 */ kelx = makeFlatKernel(1, 7, 0, 3); kely = makeFlatKernel(7, 1, 3, 0); startTimer(); pixt2 = pixConvolveRGBSep(pixs, kelx, kely); fprintf(stderr, "Time 7x1,1x7 separable: %7.3f sec\n", stopTimer()); pixWrite("/tmp/conv5.jpg", pixt2, IFF_JFIF_JPEG); regTestCheckFile(rp, "/tmp/conv5.jpg"); /* 14 */ startTimer(); pixt3 = pixBlockconv(pixs, 3, 3); fprintf(stderr, "Time 7x7 blockconv: %7.3f sec\n", stopTimer()); pixWrite("/tmp/conv6.jpg", pixt3, IFF_JFIF_JPEG); regTestCheckFile(rp, "/tmp/conv6.jpg"); /* 15 */ regTestComparePix(rp, pixt1, pixt2); /* 16 */ regTestCompareSimilarPix(rp, pixt2, pixt3, 15, 0.0005, 0); /* 17 */ pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); kernelDestroy(&kel4); kernelDestroy(&kelx); kernelDestroy(&kely); /* Test generation and convolution with gaussian kernel */ pixs = pixRead("test8.jpg"); pixSaveTiled(pixs, pixa, 1, 1, 20, 0); kel1 = makeGaussianKernel(5, 5, 3.0, 5.0); kernelGetSum(kel1, &sum); fprintf(stderr, "Sum for gaussian kernel = %f\n", sum); kernelWrite("/tmp/gauss.kel", kel1); pixt = pixConvolve(pixs, kel1, 8, 1); pixt2 = pixConvolve(pixs, kel1, 16, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker6.png", pixt, IFF_PNG); regTestCheckFile(rp, "/tmp/ker6.png"); /* 18 */ pixDestroy(&pixt); pixDestroy(&pixt2); pixt = kernelDisplayInPix(kel1, 25, 2); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); kernelDestroy(&kel1); pixDestroy(&pixs); /* Test generation and convolution with separable gaussian kernel */ pixs = pixRead("test8.jpg"); pixSaveTiled(pixs, pixa, 1, 1, 20, 0); makeGaussianKernelSep(5, 5, 3.0, 5.0, &kelx, &kely); kernelGetSum(kelx, &sum); fprintf(stderr, "Sum for x gaussian kernel = %f\n", sum); kernelGetSum(kely, &sum); fprintf(stderr, "Sum for y gaussian kernel = %f\n", sum); kernelWrite("/tmp/gauss.kelx", kelx); kernelWrite("/tmp/gauss.kely", kely); pixt = pixConvolveSep(pixs, kelx, kely, 8, 1); pixt2 = pixConvolveSep(pixs, kelx, kely, 16, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker7.png", pixt, IFF_PNG); regTestCheckFile(rp, "/tmp/ker7.png"); /* 19 */ pixDestroy(&pixt); pixDestroy(&pixt2); pixt = kernelDisplayInPix(kelx, 25, 2); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); pixt = kernelDisplayInPix(kely, 25, 2); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); kernelDestroy(&kelx); kernelDestroy(&kely); pixDestroy(&pixs); /* Test generation and convolution with diff of gaussians kernel */ /* pixt = pixRead("marge.jpg"); pixs = pixConvertRGBToLuminance(pixt); pixDestroy(&pixt); */ pixs = pixRead("test8.jpg"); pixSaveTiled(pixs, pixa, 1, 1, 20, 0); kel1 = makeDoGKernel(7, 7, 1.5, 2.7); kernelGetSum(kel1, &sum); fprintf(stderr, "Sum for DoG kernel = %f\n", sum); kernelWrite("/tmp/dog.kel", kel1); pixt = pixConvolve(pixs, kel1, 8, 0); /* pixInvert(pixt, pixt); */ pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixWrite("/tmp/ker8.png", pixt, IFF_PNG); regTestCheckFile(rp, "/tmp/ker8.png"); /* 20 */ pixDestroy(&pixt); pixt = kernelDisplayInPix(kel1, 20, 2); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); kernelDestroy(&kel1); pixDestroy(&pixs); pixd = pixaDisplay(pixa, 0, 0); pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); pixWrite("/tmp/kernel.jpg", pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); regTestCleanup(rp); return 0; }
int main(int argc, char **argv) { l_int32 i, w, h; l_float32 factor, scale; BOX *box; FILE *fp1; PIX *pixs, *pixt; PIXA *pixa; SARRAY *sa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; factor = 0.95; /* Uncompressed PS with scaling but centered on the page */ pixs = pixRead("feyn-fract.tif"); pixGetDimensions(pixs, &w, &h, NULL); scale = L_MIN(factor * 2550 / w, factor * 3300 / h); fp1 = lept_fopen("/tmp/regout/psio0.ps", "wb+"); pixWriteStreamPS(fp1, pixs, NULL, 300, scale); lept_fclose(fp1); regTestCheckFile(rp, "/tmp/regout/psio0.ps"); /* 0 */ pixDestroy(&pixs); /* Uncompressed PS with scaling, with LL corner at (1500, 1500) mils */ pixs = pixRead("weasel4.11c.png"); pixGetDimensions(pixs, &w, &h, NULL); scale = L_MIN(factor * 2550 / w, factor * 3300 / h); box = boxCreate(1500, 1500, (l_int32)(1000 * scale * w / 300), (l_int32)(1000 * scale * h / 300)); fp1 = lept_fopen("/tmp/regout/psio1.ps", "wb+"); pixWriteStreamPS(fp1, pixs, box, 300, 1.0); lept_fclose(fp1); regTestCheckFile(rp, "/tmp/regout/psio1.ps"); /* 1 */ boxDestroy(&box); pixDestroy(&pixs); /* DCT compressed PS with LL corner at (300, 1000) pixels */ pixs = pixRead("marge.jpg"); pixt = pixConvertTo32(pixs); pixWrite("/tmp/regout/psio2.jpg", pixt, IFF_JFIF_JPEG); convertJpegToPS("/tmp/regout/psio2.jpg", "/tmp/regout/psio3.ps", "w", 300, 1000, 0, 4.0, 1, 1); regTestCheckFile(rp, "/tmp/regout/psio2.jpg"); /* 2 */ regTestCheckFile(rp, "/tmp/regout/psio3.ps"); /* 3 */ pixDestroy(&pixt); pixDestroy(&pixs); /* For each page, apply tiff g4 image first; then jpeg or png over it */ convertG4ToPS("feyn.tif", "/tmp/regout/psio4.ps", "w", 0, 0, 0, 1.0, 1, 1, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio4.ps", "a", 500, 100, 300, 2.0, 1, 0); convertFlateToPS("weasel4.11c.png", "/tmp/regout/psio4.ps", "a", 300, 400, 300, 6.0, 1, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio4.ps", "a", 100, 800, 300, 1.5, 1, 1); convertG4ToPS("feyn.tif", "/tmp/regout/psio4.ps", "a", 0, 0, 0, 1.0, 2, 1, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio4.ps", "a", 1000, 700, 300, 2.0, 2, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio4.ps", "a", 100, 200, 300, 2.0, 2, 1); convertG4ToPS("feyn.tif", "/tmp/regout/psio4.ps", "a", 0, 0, 0, 1.0, 3, 1, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio4.ps", "a", 200, 200, 300, 2.0, 3, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio4.ps", "a", 200, 900, 300, 2.0, 3, 1); regTestCheckFile(rp, "/tmp/regout/psio4.ps"); /* 4 */ /* Now apply jpeg first; then paint through a g4 mask. * For gv, the first image with a b.b. determines the * window size for the canvas, so we put down the largest * image first. If we had rendered a small image first, * gv and evince will not show the entire page. However, after * conversion to pdf, everything works fine, regardless of the * order in which images are placed into the PS. That is * because the pdf interpreter is robust to bad hints, ignoring * the page hints and computing the bounding box from the * set of images rendered on the page. * * Concatenate several pages, with colormapped png, color * jpeg and tiffg4 images (with the g4 image acting as a mask * that we're painting black through. If the text layer * is painted first, the following images occlude it; otherwise, * the images remain in the background of the text. */ pixs = pixRead("wyom.jpg"); pixt = pixScaleToSize(pixs, 2528, 3300); pixWrite("/tmp/regout/psio5.jpg", pixt, IFF_JFIF_JPEG); pixDestroy(&pixs); pixDestroy(&pixt); convertJpegToPS("/tmp/regout/psio5.jpg", "/tmp/regout/psio5.ps", "w", 0, 0, 300, 1.0, 1, 0); convertFlateToPS("weasel8.240c.png", "/tmp/regout/psio5.ps", "a", 100, 100, 300, 5.0, 1, 0); convertFlateToPS("weasel8.149g.png", "/tmp/regout/psio5.ps", "a", 200, 300, 300, 5.0, 1, 0); convertFlateToPS("weasel4.11c.png", "/tmp/regout/psio5.ps", "a", 300, 500, 300, 5.0, 1, 0); convertG4ToPS("feyn.tif", "/tmp/regout/psio5.ps", "a", 0, 0, 0, 1.0, 1, 1, 1); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 500, 100, 300, 2.0, 2, 0); convertFlateToPS("weasel4.11c.png", "/tmp/regout/psio5.ps", "a", 300, 400, 300, 6.0, 2, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 100, 800, 300, 1.5, 2, 0); convertG4ToPS("feyn.tif", "/tmp/regout/psio5.ps", "a", 0, 0, 0, 1.0, 2, 1, 1); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 500, 100, 300, 2.0, 3, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 100, 800, 300, 2.0, 3, 0); convertG4ToPS("feyn.tif", "/tmp/regout/psio5.ps", "a", 0, 0, 0, 1.0, 3, 1, 1); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 700, 700, 300, 2.0, 4, 0); convertFlateToPS("weasel8.149g.png", "/tmp/regout/psio5.ps", "a", 400, 400, 300, 5.0, 4, 0); convertG4ToPS("feyn.tif", "/tmp/regout/psio5.ps", "a", 0, 0, 0, 1.0, 4, 1, 0); convertFlateToPS("weasel8.240c.png", "/tmp/regout/psio5.ps", "a", 100, 220, 300, 5.0, 4, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 100, 200, 300, 2.0, 4, 1); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 200, 200, 300, 1.5, 5, 0); convertFlateToPS("weasel8.240c.png", "/tmp/regout/psio5.ps", "a", 140, 80, 300, 7.0, 5, 0); convertG4ToPS("feyn.tif", "/tmp/regout/psio5.ps", "a", 0, 0, 0, 1.0, 5, 1, 0); convertFlateToPS("weasel8.149g.png", "/tmp/regout/psio5.ps", "a", 280, 310, 300, 5.0, 4, 0); convertJpegToPS("marge.jpg", "/tmp/regout/psio5.ps", "a", 200, 900, 300, 2.0, 5, 1); regTestCheckFile(rp, "/tmp/regout/psio5.ps"); /* 5 */ /* Generation using segmentation masks */ convertSegmentedPagesToPS(".", "lion-page", 10, ".", "lion-mask", 10, 0, 100, 2.0, 0.8, 190, "/tmp/regout/psio6.ps"); regTestCheckFile(rp, "/tmp/regout/psio6.ps"); /* 6 */ /* PS generation for embeddding */ convertJpegToPSEmbed("tetons.jpg", "/tmp/regout/psio7.ps"); regTestCheckFile(rp, "/tmp/regout/psio7.ps"); /* 7 */ convertG4ToPSEmbed("feyn-fract.tif", "/tmp/regout/psio8.ps"); regTestCheckFile(rp, "/tmp/regout/psio8.ps"); /* 8 */ convertFlateToPSEmbed("weasel8.240c.png", "/tmp/regout/psio9.ps"); regTestCheckFile(rp, "/tmp/regout/psio9.ps"); /* 9 */ /* Writing compressed from a pixa */ sa = sarrayCreate(0); for (i = 0; i < 11; i++) sarrayAddString(sa, WeaselNames[i], L_COPY); pixa = pixaReadFilesSA(sa); pixaWriteCompressedToPS(pixa, "/tmp/regout/psio10.ps", 0, 3); regTestCheckFile(rp, "/tmp/regout/psio10.ps"); /* 10 */ pixaDestroy(&pixa); sarrayDestroy(&sa); return regTestCleanup(rp); }
/*! * pixDisplayWithTitle() * * Input: pix (1, 2, 4, 8, 16, 32 bpp) * x, y (location of display frame) * title (<optional> on frame; can be NULL); * dispflag (1 to write, else disabled) * Return: 0 if OK; 1 on error * * Notes: * (1) See notes for pixDisplay(). * (2) This displays the image if dispflag == 1. */ l_int32 pixDisplayWithTitle(PIX *pixs, l_int32 x, l_int32 y, const char *title, l_int32 dispflag) { char *tempname; char buffer[L_BUF_SIZE]; static l_int32 index = 0; /* caution: not .so or thread safe */ l_int32 w, h, d, ignore; l_float32 ratw, rath, ratmin; PIX *pixt; #ifndef _WIN32 l_int32 wt, ht; #else char pathname[_MAX_PATH]; #endif /* _WIN32 */ PROCNAME("pixDisplayWithTitle"); if (dispflag != 1) return 0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (ChosenDisplayProg != L_DISPLAY_WITH_XV && ChosenDisplayProg != L_DISPLAY_WITH_XLI && ChosenDisplayProg != L_DISPLAY_WITH_XZGV && ChosenDisplayProg != L_DISPLAY_WITH_IV) return ERROR_INT("no program chosen for display", procName, 1); pixGetDimensions(pixs, &w, &h, &d); if (w <= MAX_DISPLAY_WIDTH && h <= MAX_DISPLAY_HEIGHT) { if (d == 16) /* take MSB */ pixt = pixConvert16To8(pixs, 1); else pixt = pixClone(pixs); } else { ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w; rath = (l_float32)MAX_DISPLAY_HEIGHT / (l_float32)h; ratmin = L_MIN(ratw, rath); if (ratmin < 0.125 && d == 1) pixt = pixScaleToGray8(pixs); else if (ratmin < 0.25 && d == 1) pixt = pixScaleToGray4(pixs); else if (ratmin < 0.33 && d == 1) pixt = pixScaleToGray3(pixs); else if (ratmin < 0.5 && d == 1) pixt = pixScaleToGray2(pixs); else pixt = pixScale(pixs, ratmin, ratmin); if (!pixt) return ERROR_INT("pixt not made", procName, 1); } if (index == 0) { snprintf(buffer, L_BUF_SIZE, "rm -f /tmp/junk_display.*"); ignore = system(buffer); } index++; if (pixGetDepth(pixt) < 8 || (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) { snprintf(buffer, L_BUF_SIZE, "/tmp/junk_display.%03d.png", index); pixWrite(buffer, pixt, IFF_PNG); } else { snprintf(buffer, L_BUF_SIZE, "/tmp/junk_display.%03d.jpg", index); pixWrite(buffer, pixt, IFF_JFIF_JPEG); } tempname = stringNew(buffer); #ifndef _WIN32 /* Unix */ if (ChosenDisplayProg == L_DISPLAY_WITH_XV) { if (title) snprintf(buffer, L_BUF_SIZE, "xv -quit -geometry +%d+%d -name \"%s\" %s &", x, y, title, tempname); else snprintf(buffer, L_BUF_SIZE, "xv -quit -geometry +%d+%d %s &", x, y, tempname); } else if (ChosenDisplayProg == L_DISPLAY_WITH_XLI) { if (title) snprintf(buffer, L_BUF_SIZE, "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &", x, y, title, tempname); else snprintf(buffer, L_BUF_SIZE, "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &", x, y, tempname); } else if (ChosenDisplayProg == L_DISPLAY_WITH_XZGV) { /* no way to display title */ pixGetDimensions(pixt, &wt, &ht, NULL); snprintf(buffer, L_BUF_SIZE, "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10, x, y, tempname); } ignore = system(buffer); #else /* _WIN32 */ /* Windows: L_DISPLAY_WITH_IV */ _fullpath(pathname, tempname, sizeof(pathname)); if (title) snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"", pathname, x, y, title); else snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d)", pathname, x, y); ignore = system(buffer); #endif /* _WIN32 */ pixDestroy(&pixt); FREE(tempname); return 0; }
/*! * pixConnCompPixa() * * Input: pixs (1 bpp) * &pixa (<return> pixa of each c.c.) * connectivity (4 or 8) * Return: boxa, or null on error * * 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. */ BOXA * pixConnCompPixa(PIX *pixs, PIXA **ppixa, l_int32 connectivity) { l_int32 h, iszero; l_int32 x, y, xstart, ystart; PIX *pixt1, *pixt2, *pixt3, *pixt4; 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); pixa = pixaCreate(0); *ppixa = pixa; pixZero(pixs, &iszero); if (iszero) return boxaCreate(1); /* return empty boxa */ if ((pixt1 = pixCopy(NULL, pixs)) == NULL) return (BOXA *)ERROR_PTR("pixt1 not made", procName, NULL); if ((pixt2 = pixCopy(NULL, pixs)) == NULL) return (BOXA *)ERROR_PTR("pixt2 not made", procName, NULL); h = pixGetHeight(pixs); if ((stack = lstackCreate(h)) == NULL) return (BOXA *)ERROR_PTR("stack not made", procName, NULL); if ((auxstack = lstackCreate(0)) == NULL) return (BOXA *)ERROR_PTR("auxstack not made", procName, NULL); stack->auxstack = auxstack; if ((boxa = boxaCreate(0)) == NULL) return (BOXA *)ERROR_PTR("boxa not made", procName, NULL); xstart = 0; ystart = 0; while (1) { if (!nextOnPixelInRaster(pixt1, xstart, ystart, &x, &y)) break; if ((box = pixSeedfillBB(pixt1, stack, x, y, connectivity)) == NULL) return (BOXA *)ERROR_PTR("box not made", procName, NULL); boxaAddBox(boxa, box, L_INSERT); /* Save the c.c. and remove from pixt2 as well */ pixt3 = pixClipRectangle(pixt1, box, NULL); pixt4 = pixClipRectangle(pixt2, box, NULL); pixXor(pixt3, pixt3, pixt4); pixRasterop(pixt2, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST, pixt3, 0, 0); pixaAddPix(pixa, pixt3, L_INSERT); pixDestroy(&pixt4); xstart = x; ystart = y; } #if DEBUG pixCountPixels(pixt1, &iszero, NULL); fprintf(stderr, "Number of remaining pixels = %d\n", iszero); pixWrite("junkremain", pixt1, IFF_PNG); #endif /* DEBUG */ /* Remove old boxa of pixa and replace with a clone copy */ boxaDestroy(&pixa->boxa); pixa->boxa = boxaCopy(boxa, L_CLONE); /* Cleanup, freeing the fillsegs on each stack */ lstackDestroy(&stack, TRUE); pixDestroy(&pixt1); pixDestroy(&pixt2); return boxa; }
/*! * pixDisplayWriteFormat() * * Input: pix (1, 2, 4, 8, 16, 32 bpp) * reduction (-1 to reset/erase; 0 to disable; * otherwise this is a reduction factor) * format (IFF_PNG or IFF_JFIF_JPEG) * Return: 0 if OK; 1 on error * * Notes: * (1) This writes files if reduction > 0. These can be displayed using * pixDisplayMultiple("/tmp/junk_write_display*"); * (2) All previously written files can be erased by calling with * reduction < 0; the value of pixs is ignored. * (3) If reduction > 1 and depth == 1, this does a scale-to-gray * reduction. * (4) This function uses a static internal variable to number * output files written by a single process. Behavior * with a shared library may be unpredictable. * (5) Output file format is as follows: * format == IFF_JFIF_JPEG: * png if d < 8 or d == 16 or if the output pix * has a colormap. Otherwise, output is jpg. * format == IFF_PNG: * png (lossless) on all images. * (6) For 16 bpp, the choice of full dynamic range with log scale * is the best for displaying these images. Alternative outputs are * pix8 = pixMaxDynamicRange(pixt, L_LINEAR_SCALE); * pix8 = pixConvert16To8(pixt, 0); // low order byte * pix8 = pixConvert16To8(pixt, 1); // high order byte */ l_int32 pixDisplayWriteFormat(PIX *pixs, l_int32 reduction, l_int32 format) { char buffer[L_BUF_SIZE]; l_int32 ignore; l_float32 scale; PIX *pixt, *pix8; static l_int32 index = 0; /* caution: not .so or thread safe */ PROCNAME("pixDisplayWriteFormat"); if (reduction == 0) return 0; if (reduction < 0) { index = 0; /* reset; this will cause erasure at next call to write */ return 0; } if (format != IFF_JFIF_JPEG && format != IFF_PNG) return ERROR_INT("invalid format", procName, 1); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (index == 0) { snprintf(buffer, L_BUF_SIZE, "rm -f /tmp/junk_write_display.*.png /tmp/junk_write_display.*.jpg"); ignore = system(buffer); } index++; if (reduction == 1) pixt = pixClone(pixs); else { scale = 1. / (l_float32)reduction; if (pixGetDepth(pixs) == 1) pixt = pixScaleToGray(pixs, scale); else pixt = pixScale(pixs, scale, scale); } if (pixGetDepth(pixt) == 16) { pix8 = pixMaxDynamicRange(pixt, L_LOG_SCALE); snprintf(buffer, L_BUF_SIZE, "/tmp/junk_write_display.%03d.png", index); pixWrite(buffer, pix8, IFF_PNG); pixDestroy(&pix8); } else if (pixGetDepth(pixt) < 8 || pixGetColormap(pixt) || format == IFF_PNG) { snprintf(buffer, L_BUF_SIZE, "/tmp/junk_write_display.%03d.png", index); pixWrite(buffer, pixt, IFF_PNG); } else { snprintf(buffer, L_BUF_SIZE, "/tmp/junk_write_display.%03d.jpg", index); pixWrite(buffer, pixt, format); } pixDestroy(&pixt); return 0; }
// Creates and returns a Pix with the same resolution as the original // in which 1 (black) pixels represent likely non text (photo, line drawing) // areas of the page, deleting from the blob_block the blobs that were // determined to be non-text. // The photo_map is used to bias the decision towards non-text, rather than // supplying definite decision. // The blob_block is the usual result of connected component analysis, // holding the detected blobs. // The returned Pix should be PixDestroyed after use. Pix* CCNonTextDetect::ComputeNonTextMask(bool debug, Pix* photo_map, TO_BLOCK* blob_block) { // Insert the smallest blobs into the grid. InsertBlobList(&blob_block->small_blobs); InsertBlobList(&blob_block->noise_blobs); // Add the medium blobs that don't have a good strokewidth neighbour. // Those that do go into good_grid as an antidote to spreading beyond the // real reaches of a noise region. BlobGrid good_grid(gridsize(), bleft(), tright()); BLOBNBOX_IT blob_it(&blob_block->blobs); for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) { BLOBNBOX* blob = blob_it.data(); double perimeter_area_ratio = blob->cblob()->perimeter() / 4.0; perimeter_area_ratio *= perimeter_area_ratio / blob->enclosed_area(); if (blob->GoodTextBlob() == 0 || perimeter_area_ratio < kMinGoodTextPARatio) InsertBBox(true, true, blob); else good_grid.InsertBBox(true, true, blob); } noise_density_ = ComputeNoiseDensity(debug, photo_map, &good_grid); good_grid.Clear(); // Not needed any more. Pix* pix = noise_density_->ThresholdToPix(max_noise_count_); if (debug) { pixWrite("junknoisemask.png", pix, IFF_PNG); } ScrollView* win = NULL; #ifndef GRAPHICS_DISABLED if (debug) { win = MakeWindow(0, 400, "Photo Mask Blobs"); } #endif // GRAPHICS_DISABLED // Large and medium blobs are not text if they overlap with "a lot" of small // blobs. MarkAndDeleteNonTextBlobs(&blob_block->large_blobs, kMaxLargeOverlapsWithSmall, win, ScrollView::DARK_GREEN, pix); MarkAndDeleteNonTextBlobs(&blob_block->blobs, kMaxMediumOverlapsWithSmall, win, ScrollView::WHITE, pix); // Clear the grid of small blobs and insert the medium blobs. Clear(); InsertBlobList(&blob_block->blobs); MarkAndDeleteNonTextBlobs(&blob_block->large_blobs, kMaxLargeOverlapsWithMedium, win, ScrollView::DARK_GREEN, pix); // Clear again before we start deleting the blobs in the grid. Clear(); MarkAndDeleteNonTextBlobs(&blob_block->noise_blobs, -1, win, ScrollView::CORAL, pix); MarkAndDeleteNonTextBlobs(&blob_block->small_blobs, -1, win, ScrollView::GOLDENROD, pix); MarkAndDeleteNonTextBlobs(&blob_block->blobs, -1, win, ScrollView::WHITE, pix); if (debug) { #ifndef GRAPHICS_DISABLED win->Update(); #endif // GRAPHICS_DISABLED pixWrite("junkccphotomask.png", pix, IFF_PNG); #ifndef GRAPHICS_DISABLED delete win->AwaitEvent(SVET_DESTROY); delete win; #endif // GRAPHICS_DISABLED } return pix; }
main(int argc, char **argv) { char label[512]; l_int32 w, h, i, j, rwhite, gwhite, bwhite, count; GPLOT *gplot1, *gplot2; NUMA *naseq, *na; NUMAA *naa1, *naa2; PIX *pixs, *pixt, *pixt0, *pixt1, *pixt2; PIX *pixr, *pixg, *pixb; /* for color content extraction */ PIXA *pixa; PIXCMAP *cmap; static char mainName[] = "colorspacetest"; if (argc != 2) exit(ERROR_INT(" Syntax: colorspacetest filein", mainName, 1)); if ((pixs = pixRead(argv[1])) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); /* Colorspace conversion in rgb */ pixDisplayWrite(pixs, 1); pixt = pixConvertRGBToHSV(NULL, pixs); pixDisplayWrite(pixt, 1); pixConvertHSVToRGB(pixt, pixt); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); /* Colorspace conversion on a colormap */ pixt = pixOctreeQuantNumColors(pixs, 25, 0); pixDisplayWrite(pixt, 1); cmap = pixGetColormap(pixt); pixcmapWriteStream(stderr, cmap); pixcmapConvertRGBToHSV(cmap); pixcmapWriteStream(stderr, cmap); pixDisplayWrite(pixt, 1); pixcmapConvertHSVToRGB(cmap); pixcmapWriteStream(stderr, cmap); pixDisplayWrite(pixt, 1); pixDestroy(&pixt); /* Color content extraction */ pixColorContent(pixs, 0, 0, 0, 0, &pixr, &pixg, &pixb); pixDisplayWrite(pixr, 1); pixDisplayWrite(pixg, 1); pixDisplayWrite(pixb, 1); pixDestroy(&pixr); pixDestroy(&pixg); pixDestroy(&pixb); /* Color content measurement */ pixa = pixaCreate(20); naseq = numaMakeSequence(100, 5, 20); naa1 = numaaCreate(6); naa2 = numaaCreate(6); for (i = 0; i < 6; i++) { na = numaCreate(20); numaaAddNuma(naa1, na, L_COPY); numaaAddNuma(naa2, na, L_INSERT); } pixGetDimensions(pixs, &w, &h, NULL); for (i = 0; i < 20; i++) { rwhite = 100 + 5 * i; gwhite = 200 - 5 * i; bwhite = 150; pixt0 = pixGlobalNormRGB(NULL, pixs, rwhite, gwhite, bwhite, 255); pixaAddPix(pixa, pixt0, L_INSERT); pixt1 = pixColorMagnitude(pixs, rwhite, gwhite, bwhite, L_MAX_DIFF_FROM_AVERAGE_2); for (j = 0; j < 6; j++) { pixt2 = pixThresholdToBinary(pixt1, 30 + 10 * j); pixInvert(pixt2, pixt2); pixCountPixels(pixt2, &count, NULL); na = numaaGetNuma(naa1, j, L_CLONE); numaAddNumber(na, (l_float32)count / (l_float32)(w * h)); numaDestroy(&na); pixDestroy(&pixt2); } pixDestroy(&pixt1); pixt1 = pixColorMagnitude(pixs, rwhite, gwhite, bwhite, L_MAX_MIN_DIFF_FROM_2); for (j = 0; j < 6; j++) { pixt2 = pixThresholdToBinary(pixt1, 30 + 10 * j); pixInvert(pixt2, pixt2); pixCountPixels(pixt2, &count, NULL); na = numaaGetNuma(naa2, j, L_CLONE); numaAddNumber(na, (l_float32)count / (l_float32)(w * h)); numaDestroy(&na); pixDestroy(&pixt2); } pixDestroy(&pixt1); } gplot1 = gplotCreate("/tmp/junkplot1", GPLOT_X11, "Fraction with given color (diff from average)", "white point space for red", "amount of color"); gplot2 = gplotCreate("/tmp/junkplot2", GPLOT_X11, "Fraction with given color (min diff)", "white point space for red", "amount of color"); for (j = 0; j < 6; j++) { na = numaaGetNuma(naa1, j, L_CLONE); sprintf(label, "thresh %d", 30 + 10 * j); gplotAddPlot(gplot1, naseq, na, GPLOT_LINES, label); numaDestroy(&na); na = numaaGetNuma(naa2, j, L_CLONE); gplotAddPlot(gplot2, naseq, na, GPLOT_LINES, label); numaDestroy(&na); } gplotMakeOutput(gplot1); gplotMakeOutput(gplot2); gplotDestroy(&gplot1); gplotDestroy(&gplot2); pixt1 = pixaDisplayTiledAndScaled(pixa, 32, 250, 4, 0, 10, 2); pixWrite("/tmp/junkcolormag", pixt1, IFF_PNG); pixDisplayWithTitle(pixt1, 0, 100, "Color magnitude", 1); pixDestroy(&pixt1); pixaDestroy(&pixa); numaDestroy(&naseq); numaaDestroy(&naa1); numaaDestroy(&naa2); pixDisplayMultiple("/tmp/junk_write_display*"); pixDestroy(&pixs); return 0; }
/*! * pixFindLargestRectangle() * * Input: pixs (1 bpp) * polarity (0 within background, 1 within foreground) * &box (<return> largest rectangle, either by area or * by perimeter) * debugflag (1 to output image with rectangle drawn on it) * Return: 0 if OK, 1 on error * * Notes: * (1) Why is this here? This is a simple and elegant solution to * a problem in computational geometry that at first appears * quite difficult: what is the largest rectangle that can * be placed in the image, covering only pixels of one polarity * (bg or fg)? The solution is O(n), where n is the number * of pixels in the image, and it requires nothing more than * using a simple recursion relation in a single sweep of the image. * (2) In a sweep from UL to LR with left-to-right being the fast * direction, calculate the largest white rectangle at (x, y), * using previously calculated values at pixels #1 and #2: * #1: (x, y - 1) * #2: (x - 1, y) * We also need the most recent "black" pixels that were seen * in the current row and column. * Consider the largest area. There are only two possibilities: * (a) Min(w(1), horizdist) * (h(1) + 1) * (b) Min(h(2), vertdist) * (w(2) + 1) * where * horizdist: the distance from the rightmost "black" pixel seen * in the current row across to the current pixel * vertdist: the distance from the lowest "black" pixel seen * in the current column down to the current pixel * and we choose the Max of (a) and (b). * (3) To convince yourself that these recursion relations are correct, * it helps to draw the maximum rectangles at #1 and #2. * Then for #1, you try to extend the rectangle down one line, * so that the height is h(1) + 1. Do you get the full * width of #1, w(1)? It depends on where the black pixels are * in the current row. You know the final width is bounded by w(1) * and w(2) + 1, but the actual value depends on the distribution * of black pixels in the current row that are at a distance * from the current pixel that is between these limits. * We call that value "horizdist", and the area is then given * by the expression (a) above. Using similar reasoning for #2, * where you attempt to extend the rectangle to the right * by 1 pixel, you arrive at (b). The largest rectangle is * then found by taking the Max. */ l_int32 pixFindLargestRectangle(PIX *pixs, l_int32 polarity, BOX **pbox, const char *debugfile) { l_int32 i, j, w, h, d, wpls, val; l_int32 wp, hp, w1, w2, h1, h2, wmin, hmin, area1, area2; l_int32 xmax, ymax; /* LR corner of the largest rectangle */ l_int32 maxarea, wmax, hmax, vertdist, horizdist, prevfg; l_int32 *lowestfg; l_uint32 *datas, *lines; l_uint32 **linew, **lineh; BOX *box; PIX *pixw, *pixh; /* keeps the width and height for the largest */ /* rectangles whose LR corner is located there. */ PROCNAME("pixFindLargestRectangle"); if (!pbox) return ERROR_INT("&box not defined", procName, 1); *pbox = NULL; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); pixGetDimensions(pixs, &w, &h, &d); if (d != 1) return ERROR_INT("pixs not 1 bpp", procName, 1); if (polarity != 0 && polarity != 1) return ERROR_INT("invalid polarity", procName, 1); /* Initialize lowest "fg" seen so far for each column */ lowestfg = (l_int32 *)CALLOC(w, sizeof(l_int32)); for (i = 0; i < w; i++) lowestfg[i] = -1; /* The combination (val ^ polarity) is the color for which we * are searching for the maximum rectangle. For polarity == 0, * we search in the bg (white). */ pixw = pixCreate(w, h, 32); /* stores width */ pixh = pixCreate(w, h, 32); /* stores height */ linew = (l_uint32 **)pixGetLinePtrs(pixw, NULL); lineh = (l_uint32 **)pixGetLinePtrs(pixh, NULL); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); maxarea = xmax = ymax = wmax = hmax = 0; for (i = 0; i < h; i++) { lines = datas + i * wpls; prevfg = -1; for (j = 0; j < w; j++) { val = GET_DATA_BIT(lines, j); if ((val ^ polarity) == 0) { /* bg (0) if polarity == 0, etc. */ if (i == 0 && j == 0) { wp = hp = 1; } else if (i == 0) { wp = linew[i][j - 1] + 1; hp = 1; } else if (j == 0) { wp = 1; hp = lineh[i - 1][j] + 1; } else { /* Expand #1 prev rectangle down */ w1 = linew[i - 1][j]; h1 = lineh[i - 1][j]; horizdist = j - prevfg; wmin = L_MIN(w1, horizdist); /* width of new rectangle */ area1 = wmin * (h1 + 1); /* Expand #2 prev rectangle to right */ w2 = linew[i][j - 1]; h2 = lineh[i][j - 1]; vertdist = i - lowestfg[j]; hmin = L_MIN(h2, vertdist); /* height of new rectangle */ area2 = hmin * (w2 + 1); if (area1 > area2) { wp = wmin; hp = h1 + 1; } else { wp = w2 + 1; hp = hmin; } } } else { /* fg (1) if polarity == 0; bg (0) if polarity == 1 */ prevfg = j; lowestfg[j] = i; wp = hp = 0; } linew[i][j] = wp; lineh[i][j] = hp; if (wp * hp > maxarea) { maxarea = wp * hp; xmax = j; ymax = i; wmax = wp; hmax = hp; } } } /* Translate from LR corner to Box coords (UL corner, w, h) */ box = boxCreate(xmax - wmax + 1, ymax - hmax + 1, wmax, hmax); *pbox = box; if (debugfile) { PIX *pixdb; pixdb = pixConvertTo8(pixs, TRUE); pixRenderHashBoxArb(pixdb, box, 6, 2, L_NEG_SLOPE_LINE, 1, 255, 0, 0); pixWrite(debugfile, pixdb, IFF_PNG); pixDestroy(&pixdb); } FREE(linew); FREE(lineh); FREE(lowestfg); pixDestroy(&pixw); pixDestroy(&pixh); return 0; }
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; }
main(int argc, char **argv) { BOX *box; PIX *pixs, *pixc, *pixp, *pixsel, *pixhmt; PIX *pixd1, *pixd2, *pixd3; SEL *selhm; static char mainName[] = "findpattern3"; if (argc != 1) exit(ERROR_INT(" Syntax: findpattern3", mainName, 1)); if ((pixs = pixRead("feyn.tif")) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); /* -------------------------------------------- * * Extract the pattern for a single character * * ---------------------------------------------*/ box = boxCreate(599, 1055, 18, 23); pixc = pixClipRectangle(pixs, box, NULL); /* Make a hit-miss sel */ selhm = pixGenerateSelBoundary(pixc, 1, 2, 2, 2, 1, 1, 0, 0, &pixp); /* Display the sel */ pixsel = pixDisplayHitMissSel(pixp, selhm, 7, HitColor, MissColor); pixDisplay(pixsel, 200, 200); pixWrite("/tmp/junkpixsel1", pixsel, IFF_PNG); /* Use the Sel to find all instances in the page */ startTimer(); pixhmt = pixHMT(NULL, pixs, selhm); fprintf(stderr, "Time to find patterns = %7.3f\n", stopTimer()); /* Color each instance at full res */ pixd1 = pixDisplayMatchedPattern(pixs, pixp, pixhmt, selhm->cx, selhm->cy, 0x0000ff00, 1.0, 5); pixWrite("/tmp/junkpixd11", pixd1, IFF_PNG); /* Color each instance at 0.3 scale */ pixd2 = pixDisplayMatchedPattern(pixs, pixp, pixhmt, selhm->cx, selhm->cy, 0x0000ff00, 0.5, 5); pixWrite("/tmp/junkpixd12", pixd2, IFF_PNG); /* Remove each instance from the input image */ pixd3 = pixCopy(NULL, pixs); pixRemoveMatchedPattern(pixd3, pixp, pixhmt, selhm->cx, selhm->cy, 1); pixWrite("/tmp/junkpixr1", pixd3, IFF_PNG); boxDestroy(&box); selDestroy(&selhm); pixDestroy(&pixc); pixDestroy(&pixp); pixDestroy(&pixsel); pixDestroy(&pixhmt); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pixd3); /* -------------------------------------------- * * Extract the pattern for a word * * ---------------------------------------------*/ box = boxCreate(208, 872, 130, 35); pixc = pixClipRectangle(pixs, box, NULL); /* Make a hit-miss sel */ selhm = pixGenerateSelBoundary(pixc, 2, 2, 1, 4, 1, 1, 0, 0, &pixp); /* Display the sel */ pixsel = pixDisplayHitMissSel(pixp, selhm, 7, HitColor, MissColor); pixDisplay(pixsel, 200, 200); pixWrite("/tmp/junkpixsel2", pixsel, IFF_PNG); /* Use the Sel to find all instances in the page */ startTimer(); pixhmt = pixHMT(NULL, pixs, selhm); fprintf(stderr, "Time to find word patterns = %7.3f\n", stopTimer()); /* Color each instance at full res */ pixd1 = pixDisplayMatchedPattern(pixs, pixp, pixhmt, selhm->cx, selhm->cy, 0x0000ff00, 1.0, 5); pixWrite("/tmp/junkpixd21", pixd1, IFF_PNG); /* Color each instance at 0.3 scale */ pixd2 = pixDisplayMatchedPattern(pixs, pixp, pixhmt, selhm->cx, selhm->cy, 0x0000ff00, 0.5, 5); pixWrite("/tmp/junkpixd22", pixd2, IFF_PNG); /* Remove each instance from the input image */ pixd3 = pixCopy(NULL, pixs); pixRemoveMatchedPattern(pixd3, pixp, pixhmt, selhm->cx, selhm->cy, 1); pixWrite("/tmp/junkpixr2", pixd3, IFF_PNG); selDestroy(&selhm); boxDestroy(&box); pixDestroy(&pixc); pixDestroy(&pixp); pixDestroy(&pixsel); pixDestroy(&pixhmt); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pixd3); pixDestroy(&pixs); return 0; }
/*! * pixFindBaselines() * * Input: pixs (1 bpp) * &pta (<optional return> pairs of pts corresponding to * approx. ends of each text line) * debug (usually 0; set to 1 for debugging output) * Return: na (of baseline y values), or null on error * * Notes: * (1) Input binary image must have text lines already aligned * horizontally. This can be done by either rotating the * image with pixDeskew(), or, if a projective transform * is required, by doing pixDeskewLocal() first. * (2) Input null for &pta if you don't want this returned. * The pta will come in pairs of points (left and right end * of each baseline). * (3) Caution: this will not work properly on text with multiple * columns, where the lines are not aligned between columns. * If there are multiple columns, they should be extracted * separately before finding the baselines. * (4) This function constructs different types of output * for baselines; namely, a set of raster line values and * a set of end points of each baseline. * (5) This function was designed to handle short and long text lines * without using dangerous thresholds on the peak heights. It does * this by combining the differential signal with a morphological * analysis of the locations of the text lines. One can also * combine this data to normalize the peak heights, by weighting * the differential signal in the region of each baseline * by the inverse of the width of the text line found there. * (6) There are various debug sections that can be turned on * with the debug flag. */ NUMA * pixFindBaselines(PIX *pixs, PTA **ppta, l_int32 debug) { l_int32 h, i, j, nbox, val1, val2, ndiff, bx, by, bw, bh; l_int32 imaxloc, peakthresh, zerothresh, inpeak; l_int32 mintosearch, max, maxloc, nloc, locval; l_int32 *array; l_float32 maxval; BOXA *boxa1, *boxa2, *boxa3; GPLOT *gplot; NUMA *nasum, *nadiff, *naloc, *naval; PIX *pixt1, *pixt2; PTA *pta; PROCNAME("pixFindBaselines"); if (!pixs) return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL); pta = NULL; if (ppta) { pta = ptaCreate(0); *ppta = pta; } lept_mkdir("/lept/baseline"); /* Close up the text characters, removing noise */ pixt1 = pixMorphSequence(pixs, "c25.1 + e3.1", 0); /* Save the difference of adjacent row sums. * The high positive-going peaks are the baselines */ if ((nasum = pixCountPixelsByRow(pixt1, NULL)) == NULL) return (NUMA *)ERROR_PTR("nasum not made", procName, NULL); h = pixGetHeight(pixs); nadiff = numaCreate(h); numaGetIValue(nasum, 0, &val2); for (i = 0; i < h - 1; i++) { val1 = val2; numaGetIValue(nasum, i + 1, &val2); numaAddNumber(nadiff, val1 - val2); } if (debug) /* show the difference signal */ gplotSimple1(nadiff, GPLOT_PNG, "/tmp/lept/baseline/diff", "Diff Sig"); /* Use the zeroes of the profile to locate each baseline. */ array = numaGetIArray(nadiff); ndiff = numaGetCount(nadiff); numaGetMax(nadiff, &maxval, &imaxloc); /* Use this to begin locating a new peak: */ peakthresh = (l_int32)maxval / PEAK_THRESHOLD_RATIO; /* Use this to begin a region between peaks: */ zerothresh = (l_int32)maxval / ZERO_THRESHOLD_RATIO; naloc = numaCreate(0); naval = numaCreate(0); inpeak = FALSE; for (i = 0; i < ndiff; i++) { if (inpeak == FALSE) { if (array[i] > peakthresh) { /* transition to in-peak */ inpeak = TRUE; mintosearch = i + MIN_DIST_IN_PEAK; /* accept no zeros * between i and mintosearch */ max = array[i]; maxloc = i; } } else { /* inpeak == TRUE; look for max */ if (array[i] > max) { max = array[i]; maxloc = i; mintosearch = i + MIN_DIST_IN_PEAK; } else if (i > mintosearch && array[i] <= zerothresh) { /* leave */ inpeak = FALSE; numaAddNumber(naval, max); numaAddNumber(naloc, maxloc); } } } /* If array[ndiff-1] is max, eg. no descenders, baseline at bottom */ if (inpeak) { numaAddNumber(naval, max); numaAddNumber(naloc, maxloc); } LEPT_FREE(array); if (debug) { /* show the raster locations for the peaks */ gplot = gplotCreate("/tmp/lept/baseline/loc", GPLOT_PNG, "Peak locs", "rasterline", "height"); gplotAddPlot(gplot, naloc, naval, GPLOT_POINTS, "locs"); gplotMakeOutput(gplot); gplotDestroy(&gplot); } /* Generate an approximate profile of text line width. * First, filter the boxes of text, where there may be * more than one box for a given textline. */ pixt2 = pixMorphSequence(pixt1, "r11 + c25.1 + o7.1 +c1.3", 0); boxa1 = pixConnComp(pixt2, NULL, 4); boxa2 = boxaTransform(boxa1, 0, 0, 4., 4.); boxa3 = boxaSort(boxa2, L_SORT_BY_Y, L_SORT_INCREASING, NULL); /* Then find the baseline segments */ if (pta) { nloc = numaGetCount(naloc); nbox = boxaGetCount(boxa3); for (i = 0; i < nbox; i++) { boxaGetBoxGeometry(boxa3, i, &bx, &by, &bw, &bh); for (j = 0; j < nloc; j++) { numaGetIValue(naloc, j, &locval); if (L_ABS(locval - (by + bh)) > 25) continue; ptaAddPt(pta, bx, locval); ptaAddPt(pta, bx + bw, locval); break; } } } if (debug) { /* display baselines */ PIX *pixd; l_int32 npts, x1, y1, x2, y2; if (pta) { pixd = pixConvertTo32(pixs); npts = ptaGetCount(pta); for (i = 0; i < npts; i += 2) { ptaGetIPt(pta, i, &x1, &y1); ptaGetIPt(pta, i + 1, &x2, &y2); pixRenderLineArb(pixd, x1, y1, x2, y2, 1, 255, 0, 0); } pixDisplay(pixd, 200, 200); pixWrite("/tmp/lept/baseline/baselines.png", pixd, IFF_PNG); pixDestroy(&pixd); } } boxaDestroy(&boxa1); boxaDestroy(&boxa2); boxaDestroy(&boxa3); pixDestroy(&pixt1); pixDestroy(&pixt2); numaDestroy(&nasum); numaDestroy(&nadiff); numaDestroy(&naval); return naloc; }
/* * convertToPSEmbed() * * Input: filein (input image file -- any format) * fileout (output ps file) * level (compression: 1 (uncompressed), 2 or 3) * Return: 0 if OK, 1 on error * * Notes: * (1) This is a wrapper function that generates a PS file with * a bounding box, from any input image file. * (2) Do the best job of compression given the specified level. * @level=3 does flate compression on anything that is not * tiffg4 (1 bpp) or jpeg (8 bpp or rgb). * (3) If @level=2 and the file is not tiffg4 or jpeg, it will * first be written to file as jpeg with quality = 75. * This will remove the colormap and cause some degradation * in the image. * (4) The bounding box is required when a program such as TeX * (through epsf) places and rescales the image. It is * sized for fitting the image to an 8.5 x 11.0 inch page. */ l_int32 convertToPSEmbed(const char *filein, const char *fileout, l_int32 level) { const char nametif[] = "/tmp/junk_convert_ps_embed.tif"; const char namejpg[] = "/tmp/junk_convert_ps_embed.jpg"; l_int32 d, format; PIX *pix, *pixs; PROCNAME("convertToPSEmbed"); if (!filein) return ERROR_INT("filein not defined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); if (level != 1 && level != 2 && level != 3) { L_ERROR("invalid level specified; using level 2\n", procName); level = 2; } if (level == 1) { /* no compression */ pixWritePSEmbed(filein, fileout); return 0; } /* Find the format and write out directly if in jpeg or tiff g4 */ findFileFormat(filein, &format); if (format == IFF_JFIF_JPEG) { convertJpegToPSEmbed(filein, fileout); return 0; } else if (format == IFF_TIFF_G4) { convertG4ToPSEmbed(filein, fileout); return 0; } else if (format == IFF_UNKNOWN) { L_ERROR("format of %s not known\n", procName, filein); return 1; } /* If level 3, flate encode. */ if (level == 3) { convertFlateToPSEmbed(filein, fileout); return 0; } /* OK, it's level 2, so we must convert to jpeg or tiff g4 */ if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("image not read from file", procName, 1); d = pixGetDepth(pixs); if ((d == 2 || d == 4) && !pixGetColormap(pixs)) pix = pixConvertTo8(pixs, 0); else if (d == 16) pix = pixConvert16To8(pixs, 1); else pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pix); if (d == 1) { pixWrite(nametif, pix, IFF_TIFF_G4); convertG4ToPSEmbed(nametif, fileout); } else { pixWrite(namejpg, pix, IFF_JFIF_JPEG); convertJpegToPSEmbed(namejpg, fileout); } pixDestroy(&pix); pixDestroy(&pixs); return 0; }
/*! * pixaGenerateFont() * * Input: pix (of 95 characters in 3 rows) * fontsize (4, 6, 8, ... , 20, in pts at 300 ppi) * &bl1 (<return> baseline of row 1) * &bl2 (<return> baseline of row 2) * &bl3 (<return> baseline of row 3) * Return: pixa of font bitmaps for 95 characters, or null on error * * Notes: * (1) This does all the work. See pixaGenerateFontFromFile() * for an overview. * (2) The pix is for one of the 9 fonts. @fontsize is only * used here for debugging. */ PIXA * pixaGenerateFont(PIX *pixs, l_int32 fontsize, l_int32 *pbl0, l_int32 *pbl1, l_int32 *pbl2) { l_int32 i, j, nrows, nrowchars, nchars, h, yval; l_int32 width, height; l_int32 baseline[3]; l_int32 *tab = NULL; BOX *box, *box1, *box2; BOXA *boxar, *boxac, *boxacs; PIX *pix1, *pix2, *pixr, *pixrc, *pixc; PIXA *pixa; l_int32 n, w, inrow, top; l_int32 *ia; NUMA *na; PROCNAME("pixaGenerateFont"); if (!pbl0 || !pbl1 || !pbl2) return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL); *pbl0 = *pbl1 = *pbl2 = 0; if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); /* Locate the 3 rows of characters */ w = pixGetWidth(pixs); na = pixCountPixelsByRow(pixs, NULL); boxar = boxaCreate(0); n = numaGetCount(na); ia = numaGetIArray(na); inrow = 0; for (i = 0; i < n; i++) { if (!inrow && ia[i] > 0) { inrow = 1; top = i; } else if (inrow && ia[i] == 0) { inrow = 0; box = boxCreate(0, top, w, i - top); boxaAddBox(boxar, box, L_INSERT); } } FREE(ia); numaDestroy(&na); nrows = boxaGetCount(boxar); #if DEBUG_FONT_GEN L_INFO("For fontsize %s, have %d rows\n", procName, fontsize, nrows); #endif /* DEBUG_FONT_GEN */ if (nrows != 3) { L_INFO("nrows = %d; skipping fontsize %d\n", procName, nrows, fontsize); return (PIXA *)ERROR_PTR("3 rows not generated", procName, NULL); } /* Grab the character images and baseline data */ #if DEBUG_BASELINE lept_rmdir("baseline"); lept_mkdir("baseline"); #endif /* DEBUG_BASELINE */ tab = makePixelSumTab8(); pixa = pixaCreate(95); for (i = 0; i < nrows; i++) { box = boxaGetBox(boxar, i, L_CLONE); pixr = pixClipRectangle(pixs, box, NULL); /* row of chars */ pixGetTextBaseline(pixr, tab, &yval); baseline[i] = yval; #if DEBUG_BASELINE L_INFO("Baseline info: row %d, yval = %d, h = %d\n", procName, i, yval, pixGetHeight(pixr)); pix1 = pixCopy(NULL, pixr); pixRenderLine(pix1, 0, yval, pixGetWidth(pix1), yval, 1, L_FLIP_PIXELS); if (i == 0 ) pixWrite("/tmp/baseline/row0.png", pix1, IFF_PNG); else if (i == 1) pixWrite("/tmp/baseline/row1.png", pix1, IFF_PNG); else pixWrite("/tmp/baseline/row2.png", pix1, IFF_PNG); pixDestroy(&pix1); #endif /* DEBUG_BASELINE */ boxDestroy(&box); pixrc = pixCloseSafeBrick(NULL, pixr, 1, 35); boxac = pixConnComp(pixrc, NULL, 8); boxacs = boxaSort(boxac, L_SORT_BY_X, L_SORT_INCREASING, NULL); if (i == 0) { /* consolidate the two components of '"' */ box1 = boxaGetBox(boxacs, 1, L_CLONE); box2 = boxaGetBox(boxacs, 2, L_CLONE); box1->w = box2->x + box2->w - box1->x; /* increase width */ boxDestroy(&box1); boxDestroy(&box2); boxaRemoveBox(boxacs, 2); } h = pixGetHeight(pixr); nrowchars = boxaGetCount(boxacs); for (j = 0; j < nrowchars; j++) { box = boxaGetBox(boxacs, j, L_COPY); if (box->w <= 2 && box->h == 1) { /* skip 1x1, 2x1 components */ boxDestroy(&box); continue; } box->y = 0; box->h = h - 1; pixc = pixClipRectangle(pixr, box, NULL); boxDestroy(&box); if (i == 0 && j == 0) /* add a pix for the space; change later */ pixaAddPix(pixa, pixc, L_COPY); if (i == 2 && j == 0) /* add a pix for the '\'; change later */ pixaAddPix(pixa, pixc, L_COPY); pixaAddPix(pixa, pixc, L_INSERT); } pixDestroy(&pixr); pixDestroy(&pixrc); boxaDestroy(&boxac); boxaDestroy(&boxacs); } FREE(tab); nchars = pixaGetCount(pixa); if (nchars != 95) return (PIXA *)ERROR_PTR("95 chars not generated", procName, NULL); *pbl0 = baseline[0]; *pbl1 = baseline[1]; *pbl2 = baseline[2]; /* Fix the space character up; it should have no ON pixels, * and be about twice as wide as the '!' character. */ pix1 = pixaGetPix(pixa, 0, L_CLONE); width = 2 * pixGetWidth(pix1); height = pixGetHeight(pix1); pixDestroy(&pix1); pix1 = pixCreate(width, height, 1); pixaReplacePix(pixa, 0, pix1, NULL); /* Fix up the '\' character; use a LR flip of the '/' char */ pix1 = pixaGetPix(pixa, 15, L_CLONE); pix2 = pixFlipLR(NULL, pix1); pixDestroy(&pix1); pixaReplacePix(pixa, 60, pix2, NULL); #if DEBUG_CHARS pix1 = pixaDisplayTiled(pixa, 1500, 0, 10); pixDisplay(pix1, 100 * i, 200); pixDestroy(&pix1); #endif /* DEBUG_CHARS */ boxaDestroy(&boxar); return pixa; }
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); }
int main(int argc, char **argv) { char buffer[512]; char *tempfile1, *tempfile2; l_uint8 *data; l_int32 i, j, w, h, seq, ret, same; size_t nbytes; const char *title; BOX *box; BOXA *boxa1, *boxa2; L_BYTEA *ba; L_PDF_DATA *lpd; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6; PIX *pixs, *pixt, *pixg, *pixgc, *pixc; static char mainName[] = "pdfiotest"; if (argc != 1) return ERROR_INT("syntax: pdfiotest", mainName, 1); l_pdfSetDateAndVersion(0); lept_mkdir("lept/pdf"); #if 1 /* --------------- Single image tests ------------------- */ fprintf(stderr, "\n*** Writing single images as pdf files\n"); convertToPdf("weasel2.4c.png", L_FLATE_ENCODE, 0, "/tmp/lept/pdf/file01.pdf", 0, 0, 72, "weasel2.4c.png", NULL, 0); convertToPdf("test24.jpg", L_JPEG_ENCODE, 0, "/tmp/lept/pdf/file02.pdf", 0, 0, 72, "test24.jpg", NULL, 0); convertToPdf("feyn.tif", L_G4_ENCODE, 0, "/tmp/lept/pdf/file03.pdf", 0, 0, 300, "feyn.tif", NULL, 0); pixs = pixRead("feyn.tif"); pixConvertToPdf(pixs, L_G4_ENCODE, 0, "/tmp/lept/pdf/file04.pdf", 0, 0, 300, "feyn.tif", NULL, 0); pixDestroy(&pixs); pixs = pixRead("test24.jpg"); pixConvertToPdf(pixs, L_JPEG_ENCODE, 5, "/tmp/lept/pdf/file05.pdf", 0, 0, 72, "test24.jpg", NULL, 0); pixDestroy(&pixs); pixs = pixRead("feyn.tif"); pixt = pixScaleToGray2(pixs); pixWrite("/tmp/lept/pdf/feyn8.png", pixt, IFF_PNG); convertToPdf("/tmp/lept/pdf/feyn8.png", L_JPEG_ENCODE, 0, "/tmp/lept/pdf/file06.pdf", 0, 0, 150, "feyn8.png", NULL, 0); pixDestroy(&pixs); pixDestroy(&pixt); convertToPdf("weasel4.16g.png", L_FLATE_ENCODE, 0, "/tmp/lept/pdf/file07.pdf", 0, 0, 30, "weasel4.16g.png", NULL, 0); pixs = pixRead("test24.jpg"); pixg = pixConvertTo8(pixs, 0); box = boxCreate(100, 100, 100, 100); pixc = pixClipRectangle(pixs, box, NULL); pixgc = pixClipRectangle(pixg, box, NULL); pixWrite("/tmp/lept/pdf/pix32.jpg", pixc, IFF_JFIF_JPEG); pixWrite("/tmp/lept/pdf/pix8.jpg", pixgc, IFF_JFIF_JPEG); convertToPdf("/tmp/lept/pdf/pix32.jpg", L_FLATE_ENCODE, 0, "/tmp/lept/pdf/file08.pdf", 0, 0, 72, "pix32.jpg", NULL, 0); convertToPdf("/tmp/lept/pdf/pix8.jpg", L_FLATE_ENCODE, 0, "/tmp/lept/pdf/file09.pdf", 0, 0, 72, "pix8.jpg", NULL, 0); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixc); pixDestroy(&pixgc); boxDestroy(&box); #endif #if 1 /* --------------- Multiple image tests ------------------- */ fprintf(stderr, "\n*** Writing multiple images as single page pdf files\n"); pix1 = pixRead("feyn-fract.tif"); pix2 = pixRead("weasel8.240c.png"); /* l_pdfSetDateAndVersion(0); */ /* First, write the 1 bpp image through the mask onto the weasels */ for (i = 0; i < 5; i++) { for (j = 0; j < 10; j++) { seq = (i == 0 && j == 0) ? L_FIRST_IMAGE : L_NEXT_IMAGE; title = (i == 0 && j == 0) ? "feyn-fract.tif" : NULL; pixConvertToPdf(pix2, L_FLATE_ENCODE, 0, NULL, 100 * j, 100 * i, 70, title, &lpd, seq); } } pixConvertToPdf(pix1, L_G4_ENCODE, 0, "/tmp/lept/pdf/file10.pdf", 0, 0, 80, NULL, &lpd, L_LAST_IMAGE); /* Now, write the 1 bpp image over the weasels */ l_pdfSetG4ImageMask(0); for (i = 0; i < 5; i++) { for (j = 0; j < 10; j++) { seq = (i == 0 && j == 0) ? L_FIRST_IMAGE : L_NEXT_IMAGE; title = (i == 0 && j == 0) ? "feyn-fract.tif" : NULL; pixConvertToPdf(pix2, L_FLATE_ENCODE, 0, NULL, 100 * j, 100 * i, 70, title, &lpd, seq); } } pixConvertToPdf(pix1, L_G4_ENCODE, 0, "/tmp/lept/pdf/file11.pdf", 0, 0, 80, NULL, &lpd, L_LAST_IMAGE); l_pdfSetG4ImageMask(1); pixDestroy(&pix1); pixDestroy(&pix2); #endif #if 1 /* -------- pdf convert segmented with no image regions -------- */ fprintf(stderr, "\n*** Writing segmented images without image regions\n"); pix1 = pixRead("rabi.png"); pix2 = pixScaleToGray2(pix1); pixWrite("/tmp/lept/pdf/rabi8.jpg", pix2, IFF_JFIF_JPEG); pix3 = pixThresholdTo4bpp(pix2, 16, 1); pixWrite("/tmp/lept/pdf/rabi4.png", pix3, IFF_PNG); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* 1 bpp input */ convertToPdfSegmented("rabi.png", 300, L_G4_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file12.pdf"); convertToPdfSegmented("rabi.png", 300, L_JPEG_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file13.pdf"); convertToPdfSegmented("rabi.png", 300, L_FLATE_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file14.pdf"); /* 8 bpp input, no cmap */ convertToPdfSegmented("/tmp/lept/pdf/rabi8.jpg", 150, L_G4_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file15.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi8.jpg", 150, L_JPEG_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file16.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi8.jpg", 150, L_FLATE_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file17.pdf"); /* 4 bpp input, cmap */ convertToPdfSegmented("/tmp/lept/pdf/rabi4.png", 150, L_G4_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file18.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi4.png", 150, L_JPEG_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file19.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi4.png", 150, L_FLATE_ENCODE, 128, NULL, 0, 0, NULL, "/tmp/lept/pdf/file20.pdf"); #endif #if 1 /* ---------- pdf convert segmented with image regions ---------- */ fprintf(stderr, "\n*** Writing segmented images with image regions\n"); /* Get the image region(s) for rabi.png. There are two * small bogus regions at the top, but we'll keep them for * the demonstration. */ pix1 = pixRead("rabi.png"); pixSetResolution(pix1, 300, 300); pixGetDimensions(pix1, &w, &h, NULL); pix2 = pixGenerateHalftoneMask(pix1, NULL, NULL, NULL); pix3 = pixMorphSequence(pix2, "c20.1 + c1.20", 0); boxa1 = pixConnComp(pix3, NULL, 8); boxa2 = boxaTransform(boxa1, 0, 0, 0.5, 0.5); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* 1 bpp input */ convertToPdfSegmented("rabi.png", 300, L_G4_ENCODE, 128, boxa1, 0, 0.25, NULL, "/tmp/lept/pdf/file21.pdf"); convertToPdfSegmented("rabi.png", 300, L_JPEG_ENCODE, 128, boxa1, 0, 0.25, NULL, "/tmp/lept/pdf/file22.pdf"); convertToPdfSegmented("rabi.png", 300, L_FLATE_ENCODE, 128, boxa1, 0, 0.25, NULL, "/tmp/lept/pdf/file23.pdf"); /* 8 bpp input, no cmap */ convertToPdfSegmented("/tmp/lept/pdf/rabi8.jpg", 150, L_G4_ENCODE, 128, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file24.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi8.jpg", 150, L_JPEG_ENCODE, 128, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file25.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi8.jpg", 150, L_FLATE_ENCODE, 128, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file26.pdf"); /* 4 bpp input, cmap */ convertToPdfSegmented("/tmp/lept/pdf/rabi4.png", 150, L_G4_ENCODE, 128, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file27.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi4.png", 150, L_JPEG_ENCODE, 128, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file28.pdf"); convertToPdfSegmented("/tmp/lept/pdf/rabi4.png", 150, L_FLATE_ENCODE, 128, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file29.pdf"); /* 4 bpp input, cmap, data output */ data = NULL; convertToPdfDataSegmented("/tmp/lept/pdf/rabi4.png", 150, L_G4_ENCODE, 128, boxa2, 0, 0.5, NULL, &data, &nbytes); l_binaryWrite("/tmp/lept/pdf/file30.pdf", "w", data, nbytes); lept_free(data); convertToPdfDataSegmented("/tmp/lept/pdf/rabi4.png", 150, L_JPEG_ENCODE, 128, boxa2, 0, 0.5, NULL, &data, &nbytes); l_binaryWrite("/tmp/lept/pdf/file31.pdf", "w", data, nbytes); lept_free(data); convertToPdfDataSegmented("/tmp/lept/pdf/rabi4.png", 150, L_FLATE_ENCODE, 128, boxa2, 0, 0.5, NULL, &data, &nbytes); l_binaryWrite("/tmp/lept/pdf/file32.pdf", "w", data, nbytes); lept_free(data); boxaDestroy(&boxa1); boxaDestroy(&boxa2); #endif #if 1 /* -------- pdf convert segmented from color image -------- */ fprintf(stderr, "\n*** Writing color segmented images\n"); pix1 = pixRead("candelabrum.011.jpg"); pix2 = pixScale(pix1, 3.0, 3.0); pixWrite("/tmp/lept/pdf/candelabrum3.jpg", pix2, IFF_JFIF_JPEG); GetImageMask(pix2, 200, &boxa1, "/tmp/lept/pdf/seg1.jpg"); convertToPdfSegmented("/tmp/lept/pdf/candelabrum3.jpg", 200, L_G4_ENCODE, 100, boxa1, 0, 0.25, NULL, "/tmp/lept/pdf/file33.pdf"); convertToPdfSegmented("/tmp/lept/pdf/candelabrum3.jpg", 200, L_JPEG_ENCODE, 100, boxa1, 0, 0.25, NULL, "/tmp/lept/pdf/file34.pdf"); convertToPdfSegmented("/tmp/lept/pdf/candelabrum3.jpg", 200, L_FLATE_ENCODE, 100, boxa1, 0, 0.25, NULL, "/tmp/lept/pdf/file35.pdf"); pixDestroy(&pix1); pixDestroy(&pix2); boxaDestroy(&boxa1); pix1 = pixRead("lion-page.00016.jpg"); pix2 = pixScale(pix1, 3.0, 3.0); pixWrite("/tmp/lept/pdf/lion16.jpg", pix2, IFF_JFIF_JPEG); pix3 = pixRead("lion-mask.00016.tif"); boxa1 = pixConnComp(pix3, NULL, 8); boxa2 = boxaTransform(boxa1, 0, 0, 3.0, 3.0); convertToPdfSegmented("/tmp/lept/pdf/lion16.jpg", 200, L_G4_ENCODE, 190, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file36.pdf"); convertToPdfSegmented("/tmp/lept/pdf/lion16.jpg", 200, L_JPEG_ENCODE, 190, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file37.pdf"); convertToPdfSegmented("/tmp/lept/pdf/lion16.jpg", 200, L_FLATE_ENCODE, 190, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file38.pdf"); /* Quantize the non-image part and flate encode. * This is useful because it results in a smaller file than * when you flate-encode the un-quantized non-image regions. */ pix4 = pixScale(pix3, 3.0, 3.0); /* higher res mask, for combining */ pix5 = QuantizeNonImageRegion(pix2, pix4, 12); pixWrite("/tmp/lept/pdf/lion16-quant.png", pix5, IFF_PNG); convertToPdfSegmented("/tmp/lept/pdf/lion16-quant.png", 200, L_FLATE_ENCODE, 190, boxa2, 0, 0.5, NULL, "/tmp/lept/pdf/file39.pdf"); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); boxaDestroy(&boxa1); boxaDestroy(&boxa2); #endif #if 1 /* ------------------ Test multipage pdf generation ----------------- */ fprintf(stderr, "\n*** Writing multipage pdfs from single page pdfs\n"); /* Generate a multi-page pdf from all these files */ startTimer(); concatenatePdf("/tmp/lept/pdf", "file", "/tmp/lept/pdf/cat_lept.pdf"); fprintf(stderr, "All files have been concatenated: /tmp/lept/pdf/cat_lept.pdf\n" "Concatenation time: %7.3f\n", stopTimer()); #endif #if 1 /* ----------- Test corruption recovery by concatenation ------------ */ /* Put two good pdf files in a directory */ lept_rmdir("lept/good"); lept_mkdir("lept/good"); lept_cp("testfile1.pdf", "lept/good", NULL, NULL); lept_cp("testfile2.pdf", "lept/good", NULL, NULL); concatenatePdf("/tmp/lept/good", "file", "/tmp/lept/pdf/good.pdf"); /* Make a bad version with the pdf id removed, so that it is not * recognized as a pdf */ lept_rmdir("lept/bad"); lept_mkdir("lept/bad"); ba = l_byteaInitFromFile("testfile2.pdf"); data = l_byteaGetData(ba, &nbytes); l_binaryWrite("/tmp/lept/bad/testfile0.notpdf.pdf", "w", data + 10, nbytes - 10); /* Make a version with a corrupted trailer */ if (data) data[2297] = '2'; /* munge trailer object 6: change 458 --> 428 */ l_binaryWrite("/tmp/lept/bad/testfile2.bad.pdf", "w", data, nbytes); l_byteaDestroy(&ba); /* Copy testfile1.pdf to the /tmp/lept/bad directory. Then * run concat on the bad files. The "not pdf" file should be * ignored, and the corrupted pdf file should be properly parsed, * so the resulting concatenated pdf files should be identical. */ fprintf(stderr, "\nWe attempt to build from the bad directory\n"); lept_cp("testfile1.pdf", "lept/bad", NULL, NULL); concatenatePdf("/tmp/lept/bad", "file", "/tmp/lept/pdf/bad.pdf"); filesAreIdentical("/tmp/lept/pdf/good.pdf", "/tmp/lept/pdf/bad.pdf", &same); if (same) fprintf(stderr, "Fixed: files are the same\n" "Attempt succeeded\n"); else fprintf(stderr, "Busted: files are different\n"); #endif #if 0 fprintf(stderr, "\n*** pdftk writes multipage pdfs from images\n"); tempfile1 = genPathname("/tmp/lept/pdf", "file*.pdf"); tempfile2 = genPathname("/tmp/lept/pdf", "cat_pdftk.pdf"); snprintf(buffer, sizeof(buffer), "pdftk %s output %s", tempfile1, tempfile2); ret = system(buffer); /* pdftk */ lept_free(tempfile1); lept_free(tempfile2); #endif #if 1 /* -- Test simple interface for generating multi-page pdf from images -- */ fprintf(stderr, "\n*** Writing multipage pdfs from images\n"); /* Put four image files in a directory. They will be encoded thus: * file1.png: flate (8 bpp, only 10 colors) * file2.jpg: dct (8 bpp, 256 colors because of the jpeg encoding) * file3.tif: g4 (1 bpp) * file4.jpg: dct (32 bpp) */ lept_mkdir("lept/image"); pix1 = pixRead("feyn.tif"); pix2 = pixRead("rabi.png"); pix3 = pixScaleToGray3(pix1); pix4 = pixScaleToGray3(pix2); pix5 = pixScale(pix1, 0.33, 0.33); pix6 = pixRead("test24.jpg"); pixWrite("/tmp/lept/image/file1.png", pix3, IFF_PNG); /* 10 colors */ pixWrite("/tmp/lept/image/file2.jpg", pix4, IFF_JFIF_JPEG); /* 256 colors */ pixWrite("/tmp/lept/image/file3.tif", pix5, IFF_TIFF_G4); pixWrite("/tmp/lept/image/file4.jpg", pix6, IFF_JFIF_JPEG); startTimer(); convertFilesToPdf("/tmp/lept/image", "file", 100, 0.8, 0, 75, "4 file test", "/tmp/lept/pdf/fourimages.pdf"); fprintf(stderr, "4-page pdf generated: /tmp/lept/pdf/fourimages.pdf\n" "Time: %7.3f\n", stopTimer()); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); #endif return 0; }
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; }
/** * Sets up auto page segmentation, determines the orientation, and corrects it. * Somewhat arbitrary chunk of functionality, factored out of AutoPageSeg to * facilitate testing. * photo_mask_pix is a pointer to a NULL pointer that will be filled on return * with the leptonica photo mask, which must be pixDestroyed by the caller. * to_blocks is an empty list that will be filled with (usually a single) * block that is used during layout analysis. This ugly API is required * because of the possibility of a unlv zone file. * TODO(rays) clean this up. * See AutoPageSeg for other arguments. * The returned ColumnFinder must be deleted after use. */ ColumnFinder* Tesseract::SetupPageSegAndDetectOrientation( bool single_column, bool osd, bool only_osd, BLOCK_LIST* blocks, Tesseract* osd_tess, OSResults* osr, TO_BLOCK_LIST* to_blocks, Pix** photo_mask_pix, Pix** music_mask_pix) { int vertical_x = 0; int vertical_y = 1; TabVector_LIST v_lines; TabVector_LIST h_lines; ICOORD bleft(0, 0); ASSERT_HOST(pix_binary_ != NULL); if (tessedit_dump_pageseg_images) { pixWrite("tessinput.png", pix_binary_, IFF_PNG); } // Leptonica is used to find the rule/separator lines in the input. LineFinder::FindAndRemoveLines(source_resolution_, textord_tabfind_show_vlines, pix_binary_, &vertical_x, &vertical_y, music_mask_pix, &v_lines, &h_lines); if (tessedit_dump_pageseg_images) pixWrite("tessnolines.png", pix_binary_, IFF_PNG); // Leptonica is used to find a mask of the photo regions in the input. *photo_mask_pix = ImageFind::FindImages(pix_binary_); if (tessedit_dump_pageseg_images) pixWrite("tessnoimages.png", pix_binary_, IFF_PNG); if (single_column) v_lines.clear(); // The rest of the algorithm uses the usual connected components. textord_.find_components(pix_binary_, blocks, to_blocks); TO_BLOCK_IT to_block_it(to_blocks); // There must be exactly one input block. // TODO(rays) handle new textline finding with a UNLV zone file. ASSERT_HOST(to_blocks->singleton()); TO_BLOCK* to_block = to_block_it.data(); TBOX blkbox = to_block->block->bounding_box(); ColumnFinder* finder = NULL; if (to_block->line_size >= 2) { finder = new ColumnFinder(static_cast<int>(to_block->line_size), blkbox.botleft(), blkbox.topright(), source_resolution_, &v_lines, &h_lines, vertical_x, vertical_y); finder->SetupAndFilterNoise(*photo_mask_pix, to_block); if (equ_detect_) { equ_detect_->LabelSpecialText(to_block); } BLOBNBOX_CLIST osd_blobs; // osd_orientation is the number of 90 degree rotations to make the // characters upright. (See osdetect.h for precise definition.) // We want the text lines horizontal, (vertical text indicates vertical // textlines) which may conflict (eg vertically written CJK). int osd_orientation = 0; bool vertical_text = finder->IsVerticallyAlignedText(to_block, &osd_blobs); if (osd && osd_tess != NULL && osr != NULL) { os_detect_blobs(&osd_blobs, osr, osd_tess); if (only_osd) { delete finder; return NULL; } osd_orientation = osr->best_result.orientation_id; double osd_score = osr->orientations[osd_orientation]; double osd_margin = min_orientation_margin * 2; for (int i = 0; i < 4; ++i) { if (i != osd_orientation && osd_score - osr->orientations[i] < osd_margin) { osd_margin = osd_score - osr->orientations[i]; } } if (osd_margin < min_orientation_margin) { // The margin is weak. int best_script_id = osr->best_result.script_id; bool cjk = (best_script_id == osd_tess->unicharset.han_sid()) || (best_script_id == osd_tess->unicharset.hiragana_sid()) || (best_script_id == osd_tess->unicharset.katakana_sid()); if (!cjk && !vertical_text && osd_orientation == 2) { // upside down latin text is improbable with such a weak margin. tprintf("OSD: Weak margin (%.2f), horiz textlines, not CJK: " "Don't rotate.\n", osd_margin); osd_orientation = 0; } else { tprintf("OSD: Weak margin (%.2f) for %d blob text block, " "but using orientation anyway: %d\n", osd_blobs.length(), osd_margin, osd_orientation); } } } osd_blobs.shallow_clear(); finder->CorrectOrientation(to_block, vertical_text, osd_orientation); } return finder; }