/*! * 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; }
/*! * deskew() * * Input: pixs * redsearch (for binary search: reduction factor = 1, 2 or 4) * Return: deskewed pix, or NULL on error */ PIX * deskew(PIX *pixs, l_int32 redsearch) { l_float32 angle, conf, deg2rad; PIX *pixg; /* gray version */ PIX *pixb; /* binary version */ PIX *pixd; /* destination image */ PROCNAME("deskew"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); /* Calculate a skew angle. We may need to make a binary version of the * image for this calculation. */ if (pixGetDepth(pixs) != 1) { /* FIX ME: We should probably pick a threshold value with more care. */ /* Create a grayscale image if we need one. */ if (pixGetDepth(pixs) >= 24) { pixg = pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0); } else { pixg = pixs; } pixb = pixThresholdToBinary(pixg, 127); if (pixg != pixs) { pixDestroy(&pixg); } /* Assert: We are done with any gray image. */ } else { pixb = pixs; } /* Assert: We have a valid binary image. */ if (redsearch != 1 && redsearch != 2 && redsearch != 4) return (PIX *)ERROR_PTR("redsearch not in {1,2,4}", procName, NULL); deg2rad = 3.1415926535 / 180.; if (pixFindSkewSweepAndSearch(pixb, &angle, &conf, DEFAULT_SWEEP_REDUCTION, redsearch, DEFAULT_SWEEP_RANGE, DEFAULT_SWEEP_DELTA, DEFAULT_MINBS_DELTA)) { pixd = pixClone(pixs); goto finish; } if (L_ABS(angle) < MIN_DESKEW_ANGLE || conf < MIN_ALLOWED_CONFIDENCE) { pixd = pixClone(pixs); goto finish; } /* If the pixel depth of pixs is 1, we need to use a bit-depth * independent rotate instead of the more accurate area mapping rotate. */ if (pixGetDepth(pixs) == 1) { if ((pixd = pixRotateShear(pixs, 0, 0, deg2rad * angle, 0xffffff00)) == NULL) { pixd = pixClone(pixs); } } else { #if defined(COLOR_ROTATE) if ((pixd = pixRotateAMColorFast(pixs, deg2rad * angle)) == NULL) { pixd = pixClone(pixs); } #else if ((pixd = pixRotateAM(pixs, deg2rad * angle, 0xffffff00)) == NULL) { pixd = pixClone(pixs); } #endif } finish: if (pixb != pixs) { pixDestroy(&pixb); } return pixd; }
int main(int argc, char **argv) { l_int32 i, w, h, d, rotflag; PIX *pixs, *pixt, *pixd; l_float32 angle, deg2rad, pops, ang; char *filein, *fileout; static char mainName[] = "rotatetest1"; if (argc != 4) return ERROR_INT(" Syntax: rotatetest1 filein angle fileout", mainName, 1); filein = argv[1]; angle = atof(argv[2]); fileout = argv[3]; deg2rad = 3.1415926535 / 180.; if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pix not made", mainName, 1); if (pixGetDepth(pixs) == 1) { pixt = pixScaleToGray3(pixs); pixDestroy(&pixs); pixs = pixAddBorderGeneral(pixt, 1, 0, 1, 0, 255); pixDestroy(&pixt); } pixGetDimensions(pixs, &w, &h, &d); fprintf(stderr, "w = %d, h = %d\n", w, h); #if 0 /* repertory of rotation operations to choose from */ pixd = pixRotateAM(pixs, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixRotateAMColor(pixs, deg2rad * angle, 0xffffff00); pixd = pixRotateAMColorFast(pixs, deg2rad * angle, 255); pixd = pixRotateAMCorner(pixs, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixRotateShear(pixs, w /2, h / 2, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixRotate3Shear(pixs, w /2, h / 2, deg2rad * angle, L_BRING_IN_WHITE); pixRotateShearIP(pixs, w / 2, h / 2, deg2rad * angle); pixd = pixs; #endif #if 0 /* timing of shear rotation */ for (i = 0; i < NITERS; i++) { pixd = pixRotateShear(pixs, (i * w) / NITERS, (i * h) / NITERS, deg2rad * angle, L_BRING_IN_WHITE); pixDisplay(pixd, 100 + 20 * i, 100 + 20 * i); pixDestroy(&pixd); } #endif #if 0 /* timing of in-place shear rotation */ for (i = 0; i < NITERS; i++) { pixRotateShearIP(pixs, w/2, h/2, deg2rad * angle, L_BRING_IN_WHITE); /* pixRotateShearCenterIP(pixs, deg2rad * angle, L_BRING_IN_WHITE); */ pixDisplay(pixs, 100 + 20 * i, 100 + 20 * i); } pixd = pixs; if (pixGetDepth(pixd) == 1) pixWrite(fileout, pixd, IFF_PNG); else pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixs); #endif #if 0 /* timing of various rotation operations (choose) */ startTimer(); w = pixGetWidth(pixs); h = pixGetHeight(pixs); for (i = 0; i < NTIMES; i++) { pixd = pixRotateShearCenter(pixs, deg2rad * angle, L_BRING_IN_WHITE); pixDestroy(&pixd); } pops = (l_float32)(w * h * NTIMES / 1000000.) / stopTimer(); fprintf(stderr, "vers. 1, mpops: %f\n", pops); startTimer(); w = pixGetWidth(pixs); h = pixGetHeight(pixs); for (i = 0; i < NTIMES; i++) { pixRotateShearIP(pixs, w/2, h/2, deg2rad * angle, L_BRING_IN_WHITE); } pops = (l_float32)(w * h * NTIMES / 1000000.) / stopTimer(); fprintf(stderr, "shear, mpops: %f\n", pops); pixWrite(fileout, pixs, IFF_PNG); for (i = 0; i < NTIMES; i++) { pixRotateShearIP(pixs, w/2, h/2, -deg2rad * angle, L_BRING_IN_WHITE); } pixWrite("/usr/tmp/junkout", pixs, IFF_PNG); #endif #if 0 /* area-mapping rotation operations */ pixd = pixRotateAM(pixs, deg2rad * angle, L_BRING_IN_WHITE); /* pixd = pixRotateAMColorFast(pixs, deg2rad * angle, 255); */ if (pixGetDepth(pixd) == 1) pixWrite(fileout, pixd, IFF_PNG); else pixWrite(fileout, pixd, IFF_JFIF_JPEG); #endif #if 0 /* compare the standard area-map color rotation with * the fast area-map color rotation, on a pixel basis */ { PIX *pix1, *pix2; NUMA *nar, *nag, *nab, *naseq; GPLOT *gplot; startTimer(); pix1 = pixRotateAMColor(pixs, 0.12, 0xffffff00); fprintf(stderr, " standard color rotate: %7.2f sec\n", stopTimer()); pixWrite("junkcolor1", pix1, IFF_JFIF_JPEG); startTimer(); pix2 = pixRotateAMColorFast(pixs, 0.12, 0xffffff00); fprintf(stderr, " fast color rotate: %7.2f sec\n", stopTimer()); pixWrite("junkcolor2", pix2, IFF_JFIF_JPEG); pixd = pixAbsDifference(pix1, pix2); pixGetColorHistogram(pixd, 1, &nar, &nag, &nab); naseq = numaMakeSequence(0., 1., 256); gplot = gplotCreate("junk_absdiff", GPLOT_X11, "Number vs diff", "diff", "number"); 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(&nar); numaDestroy(&nag); numaDestroy(&nab); numaDestroy(&naseq); gplotDestroy(&gplot); } #endif /* Do a succession of 180 7-degree rotations in a cw * direction, and unwind the result with another set in * a ccw direction. Although there is a considerable amount * of distortion after successive rotations, after all * 360 rotations, the resulting image is restored to * its original pristine condition! */ #if 1 rotflag = L_ROTATE_AREA_MAP; /* rotflag = L_ROTATE_SHEAR; */ /* rotflag = L_ROTATE_SAMPLING; */ ang = 7.0 * deg2rad; pixGetDimensions(pixs, &w, &h, NULL); pixd = pixRotate(pixs, ang, rotflag, L_BRING_IN_WHITE, w, h); pixWrite("junkrot7", pixd, IFF_PNG); for (i = 1; i < 180; i++) { pixs = pixd; pixd = pixRotate(pixs, ang, rotflag, L_BRING_IN_WHITE, w, h); if ((i % 30) == 0) pixDisplay(pixd, 600, 0); pixDestroy(&pixs); } pixWrite("junkspin", pixd, IFF_PNG); pixDisplay(pixd, 0, 0); for (i = 0; i < 180; i++) { pixs = pixd; pixd = pixRotate(pixs, -ang, rotflag, L_BRING_IN_WHITE, w, h); if (i && (i % 30) == 0) pixDisplay(pixd, 600, 500); pixDestroy(&pixs); } pixWrite("junkunspin", pixd, IFF_PNG); pixDisplay(pixd, 0, 500); pixDestroy(&pixd); #endif 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; }
main(int argc, char **argv) { l_int32 i; l_float32 pi, scale, angle; PIX *pixc, *pixm, *pix1, *pix2, *pix3; PIXA *pixa; PTA *pta1, *pta2, *pta3, *pta4; static char mainName[] = "smallpix_reg"; /* Make a small test image, the hard way! */ pi = 3.1415926535; pixc = pixCreate(9, 9, 32); pixm = pixCreate(9, 9, 1); pta1 = generatePtaLineFromPt(4, 4, 3.1, 0.0); pta2 = generatePtaLineFromPt(4, 4, 3.1, 0.5 * pi); pta3 = generatePtaLineFromPt(4, 4, 3.1, pi); pta4 = generatePtaLineFromPt(4, 4, 3.1, 1.5 * pi); ptaJoin(pta1, pta2, 0, 0); ptaJoin(pta1, pta3, 0, 0); ptaJoin(pta1, pta4, 0, 0); pixRenderPta(pixm, pta1, L_SET_PIXELS); pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000); ptaDestroy(&pta1); ptaDestroy(&pta2); ptaDestroy(&pta3); ptaDestroy(&pta4); pixDestroy(&pixm); /* Results differ for scaleSmoothLow() w/ and w/out + 0.5. * Neither is properly symmetric (with symm pattern on odd-sized * pix, because the smoothing is destroying the symmetry. */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 2); for (i = 0; i < 11; i++) { scale = 0.30 + 0.035 * (l_float32)i; pix2 = pixScaleSmooth(pix1, scale, scale); pix3 = pixExpandReplicate(pix2, 6); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 100, NULL); /* Results same for pixScaleAreaMap w/ and w/out + 0.5 */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 2); for (i = 0; i < 11; i++) { scale = 0.30 + 0.035 * (l_float32)i; pix2 = pixScaleAreaMap(pix1, scale, scale); pix3 = pixExpandReplicate(pix2, 6); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 200, NULL); /* Results better for pixScaleBySampling with + 0.5, for small, * odd-dimension pix. */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 2); for (i = 0; i < 11; i++) { scale = 0.30 + 0.035 * (l_float32)i; pix2 = pixScaleBySampling(pix1, scale, scale); pix3 = pixExpandReplicate(pix2, 6); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 300, NULL); /* Results same for pixRotateAM w/ and w/out + 0.5 */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 1); for (i = 0; i < 11; i++) { angle = 0.10 + 0.05 * (l_float32)i; pix2 = pixRotateAM(pix1, angle, L_BRING_IN_BLACK); pix3 = pixExpandReplicate(pix2, 8); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 400, NULL); /* If the size is odd, we express the center exactly, and the * results are better for pixRotateBySampling() w/out 0.5 * However, if the size is even, the center value is not * exact, and if we choose it 0.5 smaller than the actual * center, we get symmetrical results with +0.5. * So we choose not to include + 0.5. */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 1); for (i = 0; i < 11; i++) { angle = 0.10 + 0.05 * (l_float32)i; pix2 = pixRotateBySampling(pix1, 4, 4, angle, L_BRING_IN_BLACK); pix3 = pixExpandReplicate(pix2, 8); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 500, NULL); /* Results same for pixRotateAMCorner w/ and w/out + 0.5 */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 1); for (i = 0; i < 11; i++) { angle = 0.10 + 0.05 * (l_float32)i; pix2 = pixRotateAMCorner(pix1, angle, L_BRING_IN_BLACK); pix3 = pixExpandReplicate(pix2, 8); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 600, NULL); /* Results better for pixRotateAMColorFast without + 0.5 */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 1); for (i = 0; i < 11; i++) { angle = 0.10 + 0.05 * (l_float32)i; pix2 = pixRotateAMColorFast(pix1, angle, 0); pix3 = pixExpandReplicate(pix2, 8); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 700, NULL); /* Results slightly better for pixScaleColorLI() w/out + 0.5 */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 1); for (i = 0; i < 11; i++) { scale = 1.0 + 0.2 * (l_float32)i; pix2 = pixScaleColorLI(pix1, scale, scale); pix3 = pixExpandReplicate(pix2, 4); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 800, NULL); /* Results slightly better for pixScaleColorLI() w/out + 0.5 */ pixa = pixaCreate(11); pix1 = pixExpandReplicate(pixc, 1); for (i = 0; i < 11; i++) { scale = 1.0 + 0.2 * (l_float32)i; pix2 = pixScaleLI(pix1, scale, scale); pix3 = pixExpandReplicate(pix2, 4); pixSaveTiled(pix3, pixa, 1, (i == 0), 20, 32); pixDestroy(&pix2); pixDestroy(&pix3); } pixDestroy(&pix1); DisplayPix(&pixa, 100, 940, NULL); pixDestroy(&pixc); return 0; }