main(int argc, char **argv) { PIX *pixs, *pixd; l_int32 smooth; l_float32 fract; char *filein, *fileout; static char mainName[] = "sharptest"; if (argc != 5) exit(ERROR_INT(" Syntax: sharptest filein smooth fract fileout", mainName, 1)); filein = argv[1]; smooth = atoi(argv[2]); fract = atof(argv[3]); fileout = argv[4]; if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); pixd = pixUnsharpMasking(pixs, smooth, fract); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixs); pixDestroy(&pixd); exit(0); }
/*! * pixRotateBinaryNice() * * Input: pixs (1 bpp) * angle (radians; clockwise is positive; about the center) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) For very small rotations, just return a clone. * (2) This does a computationally expensive rotation of 1 bpp images. * The fastest rotators (using shears or subsampling) leave * visible horizontal and vertical shear lines across which * the image shear changes by one pixel. To ameliorate the * visual effect one can introduce random dithering. One * way to do this in a not-too-random fashion is given here. * We convert to 8 bpp, do a very small blur, rotate using * linear interpolation (same as area mapping), do a * small amount of sharpening to compensate for the initial * blur, and threshold back to binary. The shear lines * are magically removed. * (3) This operation is about 5x slower than rotation by sampling. */ PIX * pixRotateBinaryNice(PIX *pixs, l_float32 angle, l_int32 incolor) { PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixd; PROCNAME("pixRotateBinaryNice"); if (!pixs || pixGetDepth(pixs) != 1) return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); pixt1 = pixConvertTo8(pixs, 0); pixt2 = pixBlockconv(pixt1, 1, 1); /* smallest blur allowed */ pixt3 = pixRotateAM(pixt2, angle, incolor); pixt4 = pixUnsharpMasking(pixt3, 1, 1.0); /* sharpen a bit */ pixd = pixThresholdToBinary(pixt4, 128); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); return pixd; }
jint Java_com_googlecode_leptonica_android_Enhance_nativeUnsharpMasking(JNIEnv *env, jclass clazz, jint nativePix, jint halfwidth, jfloat fract) { PIX *pixs = (PIX *) nativePix; PIX *pixd = pixUnsharpMasking(pixs, (l_int32) halfwidth, (l_float32) fract); return (jint) pixd; }
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; }
int main(int argc, char **argv) { char textstr[256]; l_int32 w, h, d, i; l_uint32 srcval, dstval; l_float32 scalefact, sat, fract; L_BMF *bmf8; L_KERNEL *kel; NUMA *na; PIX *pix, *pixs, *pixs1, *pixs2, *pixd; PIX *pixt0, *pixt1, *pixt2, *pixt3, *pixt4; PIXA *pixa, *pixaf; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pix = pixRead(filein); pixGetDimensions(pix, &w, &h, &d); if (d != 32) return ERROR_INT("file not 32 bpp", argv[0], 1); scalefact = (l_float32)WIDTH / (l_float32)w; pixs = pixScale(pix, scalefact, scalefact); w = pixGetWidth(pixs); pixaf = pixaCreate(5); /* TRC: vary gamma */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixGammaTRC(NULL, pixs, 0.3 + 0.15 * i, 0, 255); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 32); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 0 */ pixDisplayWithTitle(pixt1, 0, 100, "TRC Gamma", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* TRC: vary black point */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixGammaTRC(NULL, pixs, 1.0, 5 * i, 255); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 1 */ pixDisplayWithTitle(pixt1, 300, 100, "TRC", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary hue */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixModifyHue(NULL, pixs, 0.01 + 0.05 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 2 */ pixDisplayWithTitle(pixt1, 600, 100, "Hue", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary saturation */ pixa = pixaCreate(20); na = numaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixModifySaturation(NULL, pixs, -0.9 + 0.1 * i); pixMeasureSaturation(pixt0, 1, &sat); pixaAddPix(pixa, pixt0, L_INSERT); numaAddNumber(na, sat); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); gplotSimple1(na, GPLOT_PNG, "/tmp/regout/enhance.7", "Average Saturation"); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 3 */ pixDisplayWithTitle(pixt1, 900, 100, "Saturation", rp->display); numaDestroy(&na); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary contrast */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixContrastTRC(NULL, pixs, 0.1 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 4 */ pixDisplayWithTitle(pixt1, 0, 400, "Contrast", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary sharpening */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixUnsharpMasking(pixs, 3, 0.01 + 0.15 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 5 */ pixDisplayWithTitle(pixt1, 300, 400, "Sharp", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Hue constant mapping to lighter background */ pixa = pixaCreate(11); bmf8 = bmfCreate("fonts", 8); pixt0 = pixRead("candelabrum-11.jpg"); composeRGBPixel(230, 185, 144, &srcval); /* select typical bg pixel */ for (i = 0; i <= 10; i++) { fract = 0.10 * i; pixelFractionalShift(230, 185, 144, fract, &dstval); pixt1 = pixLinearMapToTargetColor(NULL, pixt0, srcval, dstval); snprintf(textstr, 50, "Fract = %5.1f", fract); pixt2 = pixAddSingleTextblock(pixt1, bmf8, textstr, 0xff000000, L_ADD_BELOW, NULL); pixSaveTiledOutline(pixt2, pixa, 1.0, (i % 4 == 0) ? 1 : 0, 30, 2, 32); pixDestroy(&pixt1); pixDestroy(&pixt2); } pixDestroy(&pixt0); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 6 */ pixDisplayWithTitle(pixd, 600, 400, "Constant hue", rp->display); bmfDestroy(&bmf8); pixaDestroy(&pixa); pixDestroy(&pixd); /* Delayed testing of saturation plot */ regTestCheckFile(rp, "/tmp/regout/enhance.7.png"); /* 7 */ /* Display results */ pixd = pixaDisplay(pixaf, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 8 */ pixDisplayWithTitle(pixd, 100, 100, "All", rp->display); pixDestroy(&pixd); pixaDestroy(&pixaf); pixDestroy(&pix); pixDestroy(&pixs); /* -----------------------------------------------* * Test global color transforms * * -----------------------------------------------*/ /* Make identical cmap and rgb images */ pix = pixRead("wet-day.jpg"); pixs1 = pixOctreeColorQuant(pix, 200, 0); pixs2 = pixRemoveColormap(pixs1, REMOVE_CMAP_TO_FULL_COLOR); regTestComparePix(rp, pixs1, pixs2); /* 9 */ /* Make a diagonal color transform matrix */ kel = kernelCreate(3, 3); kernelSetElement(kel, 0, 0, 0.7); kernelSetElement(kel, 1, 1, 0.4); kernelSetElement(kel, 2, 2, 1.3); /* Apply to both cmap and rgb images. */ pixt1 = pixMultMatrixColor(pixs1, kel); pixt2 = pixMultMatrixColor(pixs2, kel); regTestComparePix(rp, pixt1, pixt2); /* 10 */ kernelDestroy(&kel); /* Apply the same transform in the simpler interface */ pixt3 = pixMultConstantColor(pixs1, 0.7, 0.4, 1.3); pixt4 = pixMultConstantColor(pixs2, 0.7, 0.4, 1.3); regTestComparePix(rp, pixt3, pixt4); /* 11 */ regTestComparePix(rp, pixt1, pixt3); /* 12 */ regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 13 */ pixDestroy(&pix); pixDestroy(&pixs1); pixDestroy(&pixs2); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); return regTestCleanup(rp); }
Pix* unsharpMasking(Pix* pix){ return pixUnsharpMasking(pix, 7, 0.7f); }