main(int argc, char **argv) { PIX *pixs; l_int32 d; static char mainName[] = "scaletest2"; if (argc != 2) return ERROR_INT(" Syntax: scaletest2 filein", mainName, 1); if ((pixs = pixRead(argv[1])) == NULL) return ERROR_INT("pixs not made", mainName, 1); d = pixGetDepth(pixs); #if 1 /* Integer scale-to-gray functions */ if (d == 1) { PIX *pixd; pixd = pixScaleToGray2(pixs); pixWrite("/tmp/s2g_2x", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray3(pixs); pixWrite("/tmp/s2g_3x", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray4(pixs); pixWrite("/tmp/s2g_4x", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray6(pixs); pixWrite("/tmp/s2g_6x", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray8(pixs); pixWrite("/tmp/s2g_8x", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray16(pixs); pixWrite("/tmp/s2g_16x", pixd, IFF_PNG); pixDestroy(&pixd); } #endif #if 1 /* Various non-integer scale-to-gray, compared with * with different ways of getting similar results */ if (d == 1) { PIX *pixt, *pixd; pixd = pixScaleToGray8(pixs); pixWrite("/tmp/s2g_8.png", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray(pixs, 0.124); pixWrite("/tmp/s2g_124.png", pixd, IFF_PNG); pixDestroy(&pixd); pixd = pixScaleToGray(pixs, 0.284); pixWrite("/tmp/s2g_284.png", pixd, IFF_PNG); pixDestroy(&pixd); pixt = pixScaleToGray4(pixs); pixd = pixScaleBySampling(pixt, 284./250., 284./250.); pixWrite("/tmp/s2g_284.2.png", pixd, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); pixt = pixScaleToGray4(pixs); pixd = pixScaleGrayLI(pixt, 284./250., 284./250.); pixWrite("/tmp/s2g_284.3.png", pixd, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); pixt = pixScaleBinary(pixs, 284./250., 284./250.); pixd = pixScaleToGray4(pixt); pixWrite("/tmp/s2g_284.4.png", pixd, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); pixt = pixScaleToGray4(pixs); pixd = pixScaleGrayLI(pixt, 0.49, 0.49); pixWrite("/tmp/s2g_42.png", pixd, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); pixt = pixScaleToGray4(pixs); pixd = pixScaleSmooth(pixt, 0.49, 0.49); pixWrite("/tmp/s2g_4sm.png", pixd, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); pixt = pixScaleBinary(pixs, .16/.125, .16/.125); pixd = pixScaleToGray8(pixt); pixWrite("/tmp/s2g_16.png", pixd, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); pixd = pixScaleToGray(pixs, .16); pixWrite("/tmp/s2g_16.2.png", pixd, IFF_PNG); pixDestroy(&pixd); } #endif #if 1 /* Antialiased (smoothed) reduction, along with sharpening */ if (d != 1) { PIX *pixt1, *pixt2; startTimer(); pixt1 = pixScaleSmooth(pixs, 0.154, 0.154); fprintf(stderr, "fast scale: %5.3f sec\n", stopTimer()); pixDisplayWithTitle(pixt1, 0, 0, "smooth scaling", DISPLAY); pixWrite("/tmp/smooth1.png", pixt1, IFF_PNG); pixt2 = pixUnsharpMasking(pixt1, 1, 0.3); pixWrite("/tmp/smooth2.png", pixt2, IFF_PNG); pixDisplayWithTitle(pixt2, 200, 0, "sharp scaling", DISPLAY); pixDestroy(&pixt1); pixDestroy(&pixt2); } #endif #if 1 /* Test a large range of scale-to-gray reductions */ if (d == 1) { l_int32 i; l_float32 scale; PIX *pixd; for (i = 2; i < 15; i++) { scale = 1. / (l_float32)i; startTimer(); pixd = pixScaleToGray(pixs, scale); fprintf(stderr, "Time for scale %7.3f: %7.3f sec\n", scale, stopTimer()); pixDisplayWithTitle(pixd, 75 * i, 100, "scaletogray", DISPLAY); pixDestroy(&pixd); } for (i = 8; i < 14; i++) { scale = 1. / (l_float32)(2 * i); startTimer(); pixd = pixScaleToGray(pixs, scale); fprintf(stderr, "Time for scale %7.3f: %7.3f sec\n", scale, stopTimer()); pixDisplayWithTitle(pixd, 100 * i, 600, "scaletogray", DISPLAY); pixDestroy(&pixd); } } #endif #if 1 /* Test the same range of scale-to-gray mipmap reductions */ if (d == 1) { l_int32 i; l_float32 scale; PIX *pixd; for (i = 2; i < 15; i++) { scale = 1. / (l_float32)i; startTimer(); pixd = pixScaleToGrayMipmap(pixs, scale); fprintf(stderr, "Time for scale %7.3f: %7.3f sec\n", scale, stopTimer()); pixDisplayWithTitle(pixd, 75 * i, 100, "scale mipmap", DISPLAY); pixDestroy(&pixd); } for (i = 8; i < 12; i++) { scale = 1. / (l_float32)(2 * i); startTimer(); pixd = pixScaleToGrayMipmap(pixs, scale); fprintf(stderr, "Time for scale %7.3f: %7.3f sec\n", scale, stopTimer()); pixDisplayWithTitle(pixd, 100 * i, 600, "scale mipmap", DISPLAY); pixDestroy(&pixd); } } #endif #if 1 /* Test several methods for antialiased reduction, * along with sharpening */ if (d != 1) { PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6, *pixt7; l_float32 SCALING = 0.27; l_int32 SIZE = 7; l_int32 smooth; l_float32 FRACT = 1.0; smooth = SIZE / 2; startTimer(); pixt1 = pixScaleSmooth(pixs, SCALING, SCALING); fprintf(stderr, "fast scale: %5.3f sec\n", stopTimer()); pixDisplayWithTitle(pixt1, 0, 0, "smooth scaling", DISPLAY); pixWrite("/tmp/sm_1.png", pixt1, IFF_PNG); pixt2 = pixUnsharpMasking(pixt1, 1, 0.3); pixDisplayWithTitle(pixt2, 150, 0, "sharpened scaling", DISPLAY); startTimer(); pixt3 = pixBlockconv(pixs, smooth, smooth); pixt4 = pixScaleBySampling(pixt3, SCALING, SCALING); fprintf(stderr, "slow scale: %5.3f sec\n", stopTimer()); pixDisplayWithTitle(pixt4, 200, 200, "sampled scaling", DISPLAY); pixWrite("/tmp/sm_2.png", pixt4, IFF_PNG); startTimer(); pixt5 = pixUnsharpMasking(pixs, smooth, FRACT); pixt6 = pixBlockconv(pixt5, smooth, smooth); pixt7 = pixScaleBySampling(pixt6, SCALING, SCALING); fprintf(stderr, "very slow scale + sharp: %5.3f sec\n", stopTimer()); pixDisplayWithTitle(pixt7, 500, 200, "sampled scaling", DISPLAY); pixWrite("/tmp/sm_3.jpg", pixt7, IFF_JFIF_JPEG); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); pixDestroy(&pixt7); } #endif #if 1 /* Test the color scaling function, comparing the * special case of scaling factor 2.0 with the * general case. */ if (d == 32) { PIX *pix1, *pix2, *pixd; NUMA *nar, *nag, *nab, *naseq; GPLOT *gplot; startTimer(); pix1 = pixScaleColorLI(pixs, 2.00001, 2.0); fprintf(stderr, " Time with regular LI: %7.3f\n", stopTimer()); pixWrite("/tmp/color1.jpg", pix1, IFF_JFIF_JPEG); startTimer(); pix2 = pixScaleColorLI(pixs, 2.0, 2.0); fprintf(stderr, " Time with 2x LI: %7.3f\n", stopTimer()); pixWrite("/tmp/color2.jpg", pix2, IFF_JFIF_JPEG); pixd = pixAbsDifference(pix1, pix2); pixGetColorHistogram(pixd, 1, &nar, &nag, &nab); naseq = numaMakeSequence(0., 1., 256); gplot = gplotCreate("/tmp/plot_absdiff", GPLOT_X11, "Number vs diff", "diff", "number"); gplotSetScaling(gplot, GPLOT_LOG_SCALE_Y); gplotAddPlot(gplot, naseq, nar, GPLOT_POINTS, "red"); gplotAddPlot(gplot, naseq, nag, GPLOT_POINTS, "green"); gplotAddPlot(gplot, naseq, nab, GPLOT_POINTS, "blue"); gplotMakeOutput(gplot); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pixd); numaDestroy(&naseq); numaDestroy(&nar); numaDestroy(&nag); numaDestroy(&nab); gplotDestroy(&gplot); } #endif #if 1 /* Test the gray LI scaling function, comparing the * special cases of scaling factor 2.0 and 4.0 with the * general case */ if (d == 8 || d == 32) { PIX *pixt, *pix0, *pix1, *pix2, *pixd; NUMA *nagray, *naseq; GPLOT *gplot; if (d == 8) pixt = pixClone(pixs); else pixt = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pix0 = pixScaleGrayLI(pixt, 0.5, 0.5); #if 1 startTimer(); pix1 = pixScaleGrayLI(pix0, 2.00001, 2.0); fprintf(stderr, " Time with regular LI 2x: %7.3f\n", stopTimer()); startTimer(); pix2 = pixScaleGrayLI(pix0, 2.0, 2.0); fprintf(stderr, " Time with 2x LI: %7.3f\n", stopTimer()); #else startTimer(); pix1 = pixScaleGrayLI(pix0, 4.00001, 4.0); fprintf(stderr, " Time with regular LI 4x: %7.3f\n", stopTimer()); startTimer(); pix2 = pixScaleGrayLI(pix0, 4.0, 4.0); fprintf(stderr, " Time with 2x LI: %7.3f\n", stopTimer()); #endif pixWrite("/tmp/gray1", pix1, IFF_JFIF_JPEG); pixWrite("/tmp/gray2", pix2, IFF_JFIF_JPEG); pixd = pixAbsDifference(pix1, pix2); nagray = pixGetGrayHistogram(pixd, 1); naseq = numaMakeSequence(0., 1., 256); gplot = gplotCreate("/tmp/g_absdiff", GPLOT_X11, "Number vs diff", "diff", "number"); gplotSetScaling(gplot, GPLOT_LOG_SCALE_Y); gplotAddPlot(gplot, naseq, nagray, GPLOT_POINTS, "gray"); gplotMakeOutput(gplot); pixDestroy(&pixt); pixDestroy(&pix0); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pixd); numaDestroy(&naseq); numaDestroy(&nagray); gplotDestroy(&gplot); } #endif pixDestroy(&pixs); return 0; }
/* * pixWriteSegmentedPageToPS() * * Input: pixs (all depths; colormap ok) * pixm (<optional> 1 bpp segmentation mask over image region) * textscale (scale of text output relative to pixs) * imagescale (scale of image output relative to pixs) * threshold (threshold for binarization; typ. 190) * pageno (page number in set; use 1 for new output file) * fileout (output ps file) * Return: 0 if OK, 1 on error * * Notes: * (1) This generates the PS string for a mixed text/image page, * and adds it to an existing file if @pageno > 1. * The PS output is determined by fitting the result to * a letter-size (8.5 x 11 inch) page. * (2) The two images (pixs and pixm) are at the same resolution * (typically 300 ppi). They are used to generate two compressed * images, pixb and pixc, that are put directly into the output * PS file. * (3) pixb is the text component. In the PostScript world, we think of * it as a mask through which we paint black. It is produced by * scaling pixs by @textscale, and thresholding to 1 bpp. * (4) pixc is the image component, which is that part of pixs under * the mask pixm. It is scaled from pixs by @imagescale. * (5) Typical values are textscale = 2.0 and imagescale = 0.5. * (6) If pixm == NULL, the page has only text. If it is all black, * the page is all image and has no text. * (7) This can be used to write a multi-page PS file, by using * sequential page numbers with the same output file. It can * also be used to write separate PS files for each page, * by using different output files with @pageno = 0 or 1. */ l_int32 pixWriteSegmentedPageToPS(PIX *pixs, PIX *pixm, l_float32 textscale, l_float32 imagescale, l_int32 threshold, l_int32 pageno, const char *fileout) { l_int32 alltext, notext, d, ret; l_uint32 val; l_float32 scaleratio; PIX *pixmi, *pixmis, *pixt, *pixg, *pixsc, *pixb, *pixc; PROCNAME("pixWriteSegmentedPageToPS"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); if (imagescale <= 0.0 || textscale <= 0.0) return ERROR_INT("relative scales must be > 0.0", procName, 1); /* Analyze the page. Determine the ratio by which the * binary text mask is scaled relative to the image part. * If there is no image region (alltext == TRUE), the * text mask will be rendered directly to fit the page, * and scaleratio = 1.0. */ alltext = TRUE; notext = FALSE; scaleratio = 1.0; if (pixm) { pixZero(pixm, &alltext); /* pixm empty: all text */ if (alltext) pixm = NULL; /* treat it as not existing here */ else { pixmi = pixInvert(NULL, pixm); pixZero(pixmi, ¬ext); /* pixm full; no text */ pixDestroy(&pixmi); scaleratio = textscale / imagescale; } } if (pixGetDepth(pixs) == 1) { /* render tiff g4 */ pixb = pixClone(pixs); pixc = NULL; } else { pixt = pixConvertTo8Or32(pixs, 0, 0); /* this can be a clone of pixs */ /* Get the binary text mask. Note that pixg cannot be a * clone of pixs, because it may be altered by pixSetMasked(). */ pixb = NULL; if (notext == FALSE) { d = pixGetDepth(pixt); if (d == 8) pixg = pixCopy(NULL, pixt); else /* d == 32 */ pixg = pixConvertRGBToLuminance(pixt); if (pixm) /* clear out the image parts */ pixSetMasked(pixg, pixm, 255); if (textscale == 1.0) pixsc = pixClone(pixg); else if (textscale >= 0.7) pixsc = pixScaleGrayLI(pixg, textscale, textscale); else pixsc = pixScaleAreaMap(pixg, textscale, textscale); pixb = pixThresholdToBinary(pixsc, threshold); pixDestroy(&pixg); pixDestroy(&pixsc); } /* Get the scaled image region */ pixc = NULL; if (pixm) { if (imagescale == 1.0) pixsc = pixClone(pixt); /* can possibly be a clone of pixs */ else pixsc = pixScale(pixt, imagescale, imagescale); /* If pixm is not full, clear the pixels in pixsc * corresponding to bg in pixm, where there can be text * that is written through the mask pixb. Note that * we could skip this and use pixsc directly in * pixWriteMixedToPS(); however, clearing these * non-image regions to a white background will reduce * the size of pixc (relative to pixsc), and hence * reduce the size of the PS file that is generated. * Use a copy so that we don't accidentally alter pixs. */ if (notext == FALSE) { pixmis = pixScale(pixm, imagescale, imagescale); pixmi = pixInvert(NULL, pixmis); val = (d == 8) ? 0xff : 0xffffff00; pixc = pixCopy(NULL, pixsc); pixSetMasked(pixc, pixmi, val); /* clear non-image part */ pixDestroy(&pixmis); pixDestroy(&pixmi); } else pixc = pixClone(pixsc); pixDestroy(&pixsc); } pixDestroy(&pixt); } ret = pixWriteMixedToPS(pixb, pixc, scaleratio, pageno, fileout); pixDestroy(&pixb); pixDestroy(&pixc); return ret; }
Pix* expandGray4(Pix* pix){ return pixScaleGrayLI(pix, 4, 4); }