Exemplo n.º 1
0
/*!
 * \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);
}
Exemplo n.º 2
0
/*!
 * \brief   pixRotate3Shear()
 *
 * \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 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) If the image has an alpha layer, it is rotated separately by
 *          two shears.
 *      (7) The algorithm was published by Alan Paeth: "A Fast Algorithm
 *          for General Raster Rotation," Graphics Interface '86,
 *          pp. 77-81, May 1986.  A description of the method, along with
 *          an implementation, can be found in Graphics Gems, p. 179,
 *          edited by Andrew Glassner, published by Academic Press, 1990.
 * </pre>
 */
PIX *
pixRotate3Shear(PIX       *pixs,
                l_int32    xcen,
                l_int32    ycen,
                l_float32  angle,
                l_int32    incolor)
{
l_float32  hangle;
PIX       *pix1, *pix2, *pixd;

    PROCNAME("pixRotate3Shear");

    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) > LIMIT_SHEAR_ANGLE) {
        L_WARNING("%6.2f radians; large angle for 3-shear rotation\n",
                  procName, L_ABS(angle));
    }

    hangle = atan(sin(angle));
    if ((pixd = pixVShear(NULL, pixs, xcen, angle / 2., incolor)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    if ((pix1 = pixHShear(NULL, pixd, ycen, hangle, incolor)) == NULL) {
        pixDestroy(&pixd);
        return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
    }
    pixVShear(pixd, pix1, xcen, angle / 2., incolor);
    pixDestroy(&pix1);

    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 = pixRotate3Shear(pix1, xcen, ycen, angle, L_BRING_IN_WHITE);
        pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }
    return pixd;
}
Exemplo n.º 3
0
/*!
 *  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);

}
Exemplo n.º 4
0
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;
}