/*! * pixRotateShearIP() * * Input: pixs (any depth; not colormapped) * xcen, ycen (center of rotation) * angle (radians) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: 0 if OK; 1 on error * * Notes: * (1) This does an in-place rotation of the image * about the image center, using the 3-shear method. * (2) A positive angle gives a clockwise rotation. * (3) 3-shear rotation by a specified angle is equivalent * to the sequential transformations * y' = y + tan(angle/2) * (x - xcen) for first y-shear * x' = x + sin(angle) * (y - ycen) for x-shear * y' = y + tan(angle/2) * (x - xcen) for second y-shear * (4) Computation of tan(angle) is performed in the shear operations. * (5) This brings in 'incolor' pixels from outside the image. * (6) The pix cannot be colormapped, because the in-place operation * only blits in 0 or 1 bits, not an arbitrary colormap index. */ l_int32 pixRotateShearIP(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor) { l_float32 hangle; PROCNAME("pixRotateShearIP"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return ERROR_INT("invalid value for incolor", procName, 1); if (pixGetColormap(pixs) != NULL) return ERROR_INT("pixs is colormapped", procName, 1); if (angle == 0.0) return 0; hangle = atan(sin(angle)); pixHShearIP(pixs, ycen, angle / 2., incolor); pixVShearIP(pixs, xcen, hangle, incolor); pixHShearIP(pixs, ycen, angle / 2., incolor); return 0; }
/*! * \brief pixRotateShearIP() * * \param[in] pixs any depth; not colormapped * \param[in] xcen, ycen center of rotation * \param[in] angle radians * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK * \return 0 if OK; 1 on error * * <pre> * Notes: * (1) This does an in-place rotation of the image about the * specified point, using the 3-shear method. It should only * be used for angles smaller than LIMIT_SHEAR_ANGLE. * For larger angles, a warning is issued. * (2) A positive angle gives a clockwise rotation. * (3) 3-shear rotation by a specified angle is equivalent * to the sequential transformations * y' = y + tan(angle/2) * (x - xcen) for first y-shear * x' = x + sin(angle) * (y - ycen) for x-shear * y' = y + tan(angle/2) * (x - xcen) for second y-shear * (4) Computation of tan(angle) is performed in the shear operations. * (5) This brings in 'incolor' pixels from outside the image. * (6) The pix cannot be colormapped, because the in-place operation * only blits in 0 or 1 bits, not an arbitrary colormap index. * </pre> */ l_int32 pixRotateShearIP(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor) { l_float32 hangle; PROCNAME("pixRotateShearIP"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return ERROR_INT("invalid value for incolor", procName, 1); if (pixGetColormap(pixs) != NULL) return ERROR_INT("pixs is colormapped", procName, 1); if (angle == 0.0) return 0; if (L_ABS(angle) > LIMIT_SHEAR_ANGLE) { L_WARNING("%6.2f radians; large angle for in-place 3-shear rotation\n", procName, L_ABS(angle)); } hangle = atan(sin(angle)); pixHShearIP(pixs, ycen, angle / 2., incolor); pixVShearIP(pixs, xcen, hangle, incolor); pixHShearIP(pixs, ycen, angle / 2., incolor); return 0; }
int main(int argc, char **argv) { char *filein, *fileout; l_int32 i, w, h, liney, linex, same; l_float32 angle, deg2rad; PIX *pixt1, *pixt2, *pixs, *pixd; static char mainName[] = "sheartest"; if (argc != 4) return ERROR_INT(" Syntax: sheartest filein angle fileout", mainName, 1); /* Compare in-place H shear with H shear to a new pix */ pixt1 = pixRead("marge.jpg"); pixGetDimensions(pixt1, &w, &h, NULL); pixt2 = pixHShear(NULL, pixt1, (l_int32)(0.3 * h), 0.17, L_BRING_IN_WHITE); pixHShearIP(pixt1, (l_int32)(0.3 * h), 0.17, L_BRING_IN_WHITE); pixEqual(pixt1, pixt2, &same); if (same) fprintf(stderr, "Correct for H shear\n"); else fprintf(stderr, "Error for H shear\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Compare in-place V shear with V shear to a new pix */ pixt1 = pixRead("marge.jpg"); pixGetDimensions(pixt1, &w, &h, NULL); pixt2 = pixVShear(NULL, pixt1, (l_int32)(0.3 * w), 0.17, L_BRING_IN_WHITE); pixVShearIP(pixt1, (l_int32)(0.3 * w), 0.17, L_BRING_IN_WHITE); pixEqual(pixt1, pixt2, &same); if (same) fprintf(stderr, "Correct for V shear\n"); else fprintf(stderr, "Error for V shear\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); 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); pixGetDimensions(pixs, &w, &h, NULL); #if 0 /* Select an operation from this list ... * ------------------------------------------ pixd = pixHShear(NULL, pixs, liney, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixVShear(NULL, pixs, linex, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixHShearCorner(NULL, pixs, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixVShearCorner(NULL, pixs, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixHShearCenter(NULL, pixs, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixVShearCenter(NULL, pixs, deg2rad * angle, L_BRING_IN_WHITE); pixHShearIP(pixs, liney, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixs; pixVShearIP(pixs, linex, deg2rad * angle, L_BRING_IN_WHITE); pixd = pixs; pixRasteropHip(pixs, 0, h/3, -50, L_BRING_IN_WHITE); pixd = pixs; pixRasteropVip(pixs, 0, w/3, -50, L_BRING_IN_WHITE); pixd = pixs; * ------------------------------------------ * ... and use it in the following: */ pixd = pixHShear(NULL, pixs, liney, deg2rad * angle, L_BRING_IN_WHITE); pixWrite(fileout, pixd, IFF_PNG); pixDisplay(pixd, 50, 50); pixDestroy(&pixd); #endif #if 0 /* Do a horizontal shear about a line */ for (i = 0; i < NTIMES; i++) { liney = i * h / (NTIMES - 1); if (liney >= h) liney = h - 1; pixd = pixHShear(NULL, pixs, liney, deg2rad * angle, L_BRING_IN_WHITE); pixDisplay(pixd, 50 + 10 * i, 50 + 10 * i); pixDestroy(&pixd); } #endif #if 0 /* Do a vertical shear about a line */ for (i = 0; i < NTIMES; i++) { linex = i * w / (NTIMES - 1); if (linex >= w) linex = w - 1; pixd = pixVShear(NULL, pixs, linex, deg2rad * angle, L_BRING_IN_WHITE); pixDisplay(pixd, 50 + 10 * i, 50 + 10 * i); pixDestroy(&pixd); } #endif #if 0 /* Do a horizontal in-place shear about a line */ pixSetPadBits(pixs, 0); for (i = 0; i < NTIMES; i++) { pixd = pixCopy(NULL, pixs); liney = i * h / (NTIMES - 1); if (liney >= h) liney = h - 1; pixHShearIP(pixd, liney, deg2rad * angle, L_BRING_IN_WHITE); pixDisplay(pixd, 50 + 10 * i, 50 + 10 * i); pixDestroy(&pixd); } #endif #if 0 /* Do a vertical in-place shear about a line */ for (i = 0; i < NTIMES; i++) { pixd = pixCopy(NULL, pixs); linex = i * w / (NTIMES - 1); if (linex >= w) linex = w - 1; pixVShearIP(pixd, linex, deg2rad * angle, L_BRING_IN_WHITE); pixDisplay(pixd, 50 + 10 * i, 50 + 10 * i); pixDestroy(&pixd); } #endif pixDestroy(&pixs); return 0; }
static PIX * shearTest(PIX *pixs, l_int32 reduction) { l_int32 w, h, d; PIX *pixt1, *pixt2, *pixd; PIXA *pixa; PROCNAME("shearTest"); pixa = pixaCreate(0); pixGetDimensions(pixs, &w, &h, &d); pixt1 = pixHShear(NULL, pixs, 0, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt1, pixa, reduction, 1, 20, 32); pixt2 = pixHShear(NULL, pixs, h / 2, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixHShear(NULL, pixs, 0, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt1, pixa, reduction, 0, 20, 0); pixt2 = pixHShear(NULL, pixs, h / 2, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); if (!pixGetColormap(pixs)) { pixt1 = pixCopy(NULL, pixs); pixHShearIP(pixt1, 0, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt1, pixa, reduction, 1, 20, 0); pixt2 = pixCopy(NULL, pixs); pixHShearIP(pixt2, h / 2, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixCopy(NULL, pixs); pixHShearIP(pixt1, 0, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt1, pixa, reduction, 0, 20, 0); pixt2 = pixCopy(NULL, pixs); pixHShearIP(pixt2, h / 2, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 32); pixDestroy(&pixt1); pixDestroy(&pixt2); } if (d == 8 || d == 32 || pixGetColormap(pixs)) { pixt1 = pixHShearLI(pixs, 0, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt1, pixa, reduction, 1, 20, 0); pixt2 = pixHShearLI(pixs, w / 2, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixHShearLI(pixs, 0, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt1, pixa, reduction, 0, 20, 0); pixt2 = pixHShearLI(pixs, w / 2, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); } pixt1 = pixVShear(NULL, pixs, 0, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt1, pixa, reduction, 1, 20, 0); pixt2 = pixVShear(NULL, pixs, w / 2, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixVShear(NULL, pixs, 0, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt1, pixa, reduction, 0, 20, 0); pixt2 = pixVShear(NULL, pixs, w / 2, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); if (!pixGetColormap(pixs)) { pixt1 = pixCopy(NULL, pixs); pixVShearIP(pixt1, 0, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt1, pixa, reduction, 1, 20, 0); pixt2 = pixCopy(NULL, pixs); pixVShearIP(pixt2, w / 2, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixCopy(NULL, pixs); pixVShearIP(pixt1, 0, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt1, pixa, reduction, 0, 20, 0); pixt2 = pixCopy(NULL, pixs); pixVShearIP(pixt2, w / 2, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 32); pixDestroy(&pixt1); pixDestroy(&pixt2); } if (d == 8 || d == 32 || pixGetColormap(pixs)) { pixt1 = pixVShearLI(pixs, 0, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt1, pixa, reduction, 1, 20, 0); pixt2 = pixVShearLI(pixs, w / 2, ANGLE1, L_BRING_IN_WHITE); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixVShearLI(pixs, 0, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt1, pixa, reduction, 0, 20, 0); pixt2 = pixVShearLI(pixs, w / 2, ANGLE1, L_BRING_IN_BLACK); pixSaveTiled(pixt2, pixa, reduction, 0, 20, 0); pixDestroy(&pixt1); pixDestroy(&pixt2); } pixd = pixaDisplay(pixa, 0, 0); pixaDestroy(&pixa); return pixd; }