/*! * \brief pixRotateShear() * * \param[in] pixs * \param[in] xcen x value for which there is no horizontal shear * \param[in] ycen y value for which there is no vertical shear * \param[in] angle radians * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK; * \return pixd, or NULL on error. * * <pre> * Notes: * (1) This rotates an image about the given point, using * either 2 or 3 shears. * (2) A positive angle gives a clockwise rotation. * (3) This brings in 'incolor' pixels from outside the image. * (4) For rotation angles larger than about 0.35 radians, we issue * a warning because you should probably be using another method * (either sampling or area mapping) * </pre> */ PIX * pixRotateShear(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor) { PROCNAME("pixRotateShear"); if (!pixs) return (PIX *)(PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)(PIX *)ERROR_PTR("invalid incolor value", procName, NULL); if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE) return pixClone(pixs); if (L_ABS(angle) <= MAX_2_SHEAR_ANGLE) return pixRotate2Shear(pixs, xcen, ycen, angle, incolor); if (L_ABS(angle) > LIMIT_SHEAR_ANGLE) L_WARNING("%6.2f radians; large angle for shear rotation\n", procName, L_ABS(angle)); return pixRotate3Shear(pixs, xcen, ycen, angle, incolor); }
/*! * \brief pixRotate2Shear() * * \param[in] pixs * \param[in] xcen, ycen center of rotation * \param[in] angle radians * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK; * \return pixd, or NULL on error. * * <pre> * Notes: * (1) This rotates the image about the given point, using the 2-shear * method. It should only be used for angles smaller than * MAX_2_SHEAR_ANGLE. For larger angles, a warning is issued. * (2) A positive angle gives a clockwise rotation. * (3) 2-shear rotation by a specified angle is equivalent * to the sequential transformations * x' = x + tan(angle) * (y - ycen) for x-shear * y' = y + tan(angle) * (x - xcen) for y-shear * (4) Computation of tan(angle) is performed within the shear operation. * (5) This brings in 'incolor' pixels from outside the image. * (6) If the image has an alpha layer, it is rotated separately by * two shears. * </pre> */ PIX * pixRotate2Shear(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor) { PIX *pix1, *pix2, *pixd; PROCNAME("pixRotate2Shear"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)(PIX *)ERROR_PTR("invalid incolor value", procName, NULL); if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE) return pixClone(pixs); if (L_ABS(angle) > MAX_2_SHEAR_ANGLE) L_WARNING("%6.2f radians; large angle for 2-shear rotation\n", procName, L_ABS(angle)); if ((pix1 = pixHShear(NULL, pixs, ycen, angle, incolor)) == NULL) return (PIX *)ERROR_PTR("pix1 not made", procName, NULL); pixd = pixVShear(NULL, pix1, xcen, angle, incolor); pixDestroy(&pix1); if (!pixd) return (PIX *)ERROR_PTR("pixd not made", procName, NULL); if (pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4) { pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL); /* L_BRING_IN_WHITE brings in opaque for the alpha component */ pix2 = pixRotate2Shear(pix1, xcen, ycen, angle, L_BRING_IN_WHITE); pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL); pixDestroy(&pix1); pixDestroy(&pix2); } return pixd; }
/*! * pixRotateShear() * * Input: pixs * xcen (x value for which there is no horizontal shear) * ycen (y value for which there is no vertical shear) * angle (radians) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK); * Return: pixd, or null on error. * * Notes: * (1) This rotates an image about the given point, using * either 2 or 3 shears. * (2) A positive angle gives a clockwise rotation. * (3) This brings in 'incolor' pixels from outside the image. */ PIX * pixRotateShear(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor) { PROCNAME("pixRotateShear"); if (!pixs) return (PIX *)(PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)(PIX *)ERROR_PTR("invalid incolor value", procName, NULL); if (L_ABS(angle) < VERY_SMALL_ANGLE) return pixClone(pixs); if (L_ABS(angle) <= MAX_2_SHEAR_ANGLE) return pixRotate2Shear(pixs, xcen, ycen, angle, incolor); else return pixRotate3Shear(pixs, xcen, ycen, angle, incolor); }
int main(int argc, char **argv) { l_int32 w, h, x, y, i, n; l_float32 *vc; PIX *pix1, *pix2, *pix3, *pix4, *pix5; PIXA *pixas, *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixas = pixaCreate(11); for (i = 0; i < 10; i++) { /* this preserves any alpha */ pix1 = pixRead(fnames[i]); pix2 = pixScaleBySamplingToSize(pix1, 250, 150); pixaAddPix(pixas, pix2, L_INSERT); pixDestroy(&pix1); } /* Add a transparent grid over the rgb image */ pix1 = pixaGetPix(pixas, 8, L_COPY); pixGetDimensions(pix1, &w, &h, NULL); pix2 = pixCreate(w, h, 1); for (i = 0; i < 5; i++) { y = h * (i + 1) / 6; pixRenderLine(pix2, 0, y, w, y, 3, L_SET_PIXELS); } for (i = 0; i < 7; i++) { x = w * (i + 1) / 8; pixRenderLine(pix2, x, 0, x, h, 3, L_SET_PIXELS); } pix3 = pixConvertTo8(pix2, 0); /* 1 --> 0 ==> transparent */ pixSetRGBComponent(pix1, pix3, L_ALPHA_CHANNEL); pixaAddPix(pixas, pix1, L_INSERT); n = pixaGetCount(pixas); pixDestroy(&pix2); pixDestroy(&pix3); #if DO_ALL /* Display with and without removing alpha with white bg */ pix1 = pixaDisplayTiledInRows(pixas, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ pixDisplayWithTitle(pix1, 0, 0, NULL, rp->display); pixDestroy(&pix1); pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRemoveAlpha(pix1); pixaAddPix(pixa, pix2, L_INSERT); pixDestroy(&pix1); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 1 */ pixDisplayWithTitle(pix1, 200, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Setting to gray */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pixSetAllGray(pix1, 170); pix2 = pixRemoveAlpha(pix1); pixaAddPix(pixa, pix2, L_INSERT); pixDestroy(&pix1); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 2 */ pixDisplayWithTitle(pix1, 400, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* General scaling */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixScaleToSize(pix1, 350, 650); pix3 = pixScaleToSize(pix2, 200, 200); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 3 */ pixDisplayWithTitle(pix1, 600, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Scaling by sampling */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixScaleBySamplingToSize(pix1, 350, 650); pix3 = pixScaleBySamplingToSize(pix2, 200, 200); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 4 */ pixDisplayWithTitle(pix1, 800, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by area mapping; no embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 0, 0); pix3 = pixRotate(pix2, -0.35, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 0, 0); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 5 */ pixDisplayWithTitle(pix1, 1000, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by area mapping; with embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 250, 150); pix3 = pixRotate(pix2, -0.35, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 250, 150); pix4 = pixRemoveBorderToSize(pix3, 250, 150); pix5 = pixRemoveAlpha(pix4); pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 6 */ pixDisplayWithTitle(pix1, 0, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by 3-shear; no embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 0, 0); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 0, 0); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 7 */ pixDisplayWithTitle(pix1, 200, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by 3-shear; with embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 250, 150); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 250, 150); pix4 = pixRemoveBorderToSize(pix3, 250, 150); pix5 = pixRemoveAlpha(pix4); pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 8 */ pixDisplayWithTitle(pix1, 400, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by 2-shear about the center */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pixGetDimensions(pix1, &w, &h, NULL); pix2 = pixRotate2Shear(pix1, w / 2, h / 2, 0.25, L_BRING_IN_WHITE); pix3 = pixRotate2Shear(pix2, w / 2, h / 2, -0.35, L_BRING_IN_WHITE); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 9 */ pixDisplayWithTitle(pix1, 600, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by sampling; no embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 0, 0); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 0, 0); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 10 */ pixDisplayWithTitle(pix1, 800, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by sampling; with embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 250, 150); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 250, 150); pix4 = pixRemoveBorderToSize(pix3, 250, 150); pix5 = pixRemoveAlpha(pix4); pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 11 */ pixDisplayWithTitle(pix1, 1000, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by area mapping at corner */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotateAMCorner(pix1, 0.25, L_BRING_IN_WHITE); pix3 = pixRotateAMCorner(pix2, -0.35, L_BRING_IN_WHITE); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 12 */ pixDisplayWithTitle(pix1, 0, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Affine transform by interpolation */ pixa = pixaCreate(n); vc = Generate3PtTransformVector(); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixAffine(pix1, vc, L_BRING_IN_WHITE); /* pix2 = pixAffineSampled(pix1, vc, L_BRING_IN_WHITE); */ pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 13 */ pixDisplayWithTitle(pix1, 200, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif #if DO_ALL /* Projective transform by sampling */ pixa = pixaCreate(n); vc = Generate4PtTransformVector(PROJECTIVE); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixProjectiveSampled(pix1, vc, L_BRING_IN_WHITE); pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 14 */ pixDisplayWithTitle(pix1, 400, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif #if DO_ALL /* Projective transform by interpolation */ pixa = pixaCreate(n); vc = Generate4PtTransformVector(PROJECTIVE); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixProjective(pix1, vc, L_BRING_IN_WHITE); pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 15 */ pixDisplayWithTitle(pix1, 600, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif #if DO_ALL /* Bilinear transform by interpolation */ pixa = pixaCreate(n); vc = Generate4PtTransformVector(BILINEAR); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixBilinear(pix1, vc, L_BRING_IN_WHITE); pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 16 */ pixDisplayWithTitle(pix1, 800, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif pixaDestroy(&pixas); return regTestCleanup(rp); }