Leptonica 1.68
C Image Processing Library

rotateam.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 
00017 /*
00018  *  rotateam.c
00019  *
00020  *     Grayscale and color rotation for area mapping (== interpolation)
00021  *
00022  *         Rotation about the image center
00023  *                  PIX     *pixRotateAM()
00024  *                  PIX     *pixRotateAMColor()
00025  *                  PIX     *pixRotateAMGray()
00026  *
00027  *         Rotation about the UL corner of the image
00028  *                  PIX     *pixRotateAMCorner()
00029  *                  PIX     *pixRotateAMColorCorner()
00030  *                  PIX     *pixRotateAMGrayCorner()
00031  *
00032  *         Faster color rotation about the image center
00033  *                  PIX     *pixRotateAMColorFast()
00034  *
00035  *     Rotations are measured in radians; clockwise is positive.
00036  *
00037  *     The basic area mapping grayscale rotation works on 8 bpp images.
00038  *     For color, the same method is applied to each color separately.
00039  *     This can be done in two ways: (1) as here, computing each dest
00040  *     rgb pixel from the appropriate four src rgb pixels, or (2) separating
00041  *     the color image into three 8 bpp images, rotate each of these,
00042  *     and then combine the result.  Method (1) is about 2.5x faster.
00043  *     We have also implemented a fast approximation for color area-mapping
00044  *     rotation (pixRotateAMColorFast()), which is about 25% faster
00045  *     than the standard color rotator.  If you need the extra speed,
00046  *     use it.
00047  *
00048  *     Area mapping works as follows.  For each dest
00049  *     pixel you find the 4 source pixels that it partially
00050  *     covers.  You then compute the dest pixel value as
00051  *     the area-weighted average of those 4 source pixels.
00052  *     We make two simplifying approximations:
00053  *
00054  *       -  For simplicity, compute the areas as if the dest
00055  *          pixel were translated but not rotated.
00056  *
00057  *       -  Compute area overlaps on a discrete sub-pixel grid.
00058  *          Because we are using 8 bpp images with 256 levels,
00059  *          it is convenient to break each pixel into a
00060  *          16x16 sub-pixel grid, and count the number of
00061  *          overlapped sub-pixels.
00062  *
00063  *     It is interesting to note that the digital filter that
00064  *     implements the area mapping algorithm for rotation
00065  *     is identical to the digital filter used for linear
00066  *     interpolation when arbitrarily scaling grayscale images.
00067  *
00068  *     The advantage of area mapping over pixel sampling
00069  *     in grayscale rotation is that the former naturally
00070  *     blurs sharp edges ("anti-aliasing"), so that stair-step
00071  *     artifacts are not introduced.  The disadvantage is that
00072  *     it is significantly slower.
00073  *
00074  *     But it is still pretty fast.  With standard 3 GHz hardware,
00075  *     the anti-aliased (area-mapped) color rotation speed is
00076  *     about 15 million pixels/sec.
00077  *
00078  *     The function pixRotateAMColorFast() is about 10-20% faster
00079  *     than pixRotateAMColor().  The quality is slightly worse,
00080  *     and if you make many successive small rotations, with a
00081  *     total angle of 360 degrees, it has been noted that the
00082  *     center wanders -- it seems to be doing a 1 pixel translation
00083  *     in addition to the rotation.
00084  */
00085 
00086 #include <stdio.h>
00087 #include <string.h>
00088 #include "allheaders.h"
00089 
00090 static const l_float32  VERY_SMALL_ANGLE = 0.001;  /* radians; ~0.06 degrees */
00091 
00092 
00093 /*------------------------------------------------------------------*
00094  *                     Rotation about the center                    *
00095  *------------------------------------------------------------------*/
00096 /*!
00097  *  pixRotateAM()
00098  *
00099  *      Input:  pixs (2, 4, 8 bpp gray or colormapped, or 32 bpp RGB)
00100  *              angle (radians; clockwise is positive)
00101  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00102  *      Return: pixd, or null on error
00103  *
00104  *  Notes:
00105  *      (1) Rotates about image center.
00106  *      (2) A positive angle gives a clockwise rotation.
00107  *      (3) Brings in either black or white pixels from the boundary.
00108  */
00109 PIX *
00110 pixRotateAM(PIX       *pixs,
00111             l_float32  angle,
00112             l_int32    incolor)
00113 {
00114 l_int32   d;
00115 l_uint32  fillval;
00116 PIX      *pixt1, *pixt2, *pixd;
00117 
00118     PROCNAME("pixRotateAM");
00119 
00120     if (!pixs)
00121         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00122     if (pixGetDepth(pixs) == 1)
00123         return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL);
00124 
00125     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00126         return pixClone(pixs);
00127 
00128         /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
00129     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00130     d = pixGetDepth(pixt1);
00131     if (d < 8)
00132         pixt2 = pixConvertTo8(pixt1, FALSE);
00133     else
00134         pixt2 = pixClone(pixt1);
00135     d = pixGetDepth(pixt2);
00136 
00137         /* Compute actual incoming color */
00138     fillval = 0;
00139     if (incolor == L_BRING_IN_WHITE) {
00140         if (d == 8)
00141             fillval = 255;
00142         else  /* d == 32 */
00143             fillval = 0xffffff00;
00144     }
00145 
00146     if (d == 8)
00147         pixd = pixRotateAMGray(pixt2, angle, fillval);
00148     else   /* d == 32 */
00149         pixd = pixRotateAMColor(pixt2, angle, fillval);
00150 
00151     pixDestroy(&pixt1);
00152     pixDestroy(&pixt2);
00153     return pixd;
00154 }
00155 
00156 
00157 /*!
00158  *  pixRotateAMColor()
00159  *
00160  *      Input:  pixs (32 bpp)
00161  *              angle (radians; clockwise is positive)
00162  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00163  *      Return: pixd, or null on error
00164  *
00165  *  Notes:
00166  *      (1) Rotates about image center.
00167  *      (2) A positive angle gives a clockwise rotation.
00168  *      (3) Specify the color to be brought in from outside the image.
00169  */
00170 PIX *
00171 pixRotateAMColor(PIX       *pixs,
00172                  l_float32  angle,
00173                  l_uint32   colorval)
00174 {
00175 l_int32    w, h, wpls, wpld;
00176 l_uint32  *datas, *datad;
00177 PIX       *pixd;
00178 
00179     PROCNAME("pixRotateAMColor");
00180 
00181     if (!pixs)
00182         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00183     if (pixGetDepth(pixs) != 32)
00184         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00185 
00186     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00187         return pixClone(pixs);
00188 
00189     pixGetDimensions(pixs, &w, &h, NULL);
00190     datas = pixGetData(pixs);
00191     wpls = pixGetWpl(pixs);
00192     pixd = pixCreateTemplate(pixs);
00193     datad = pixGetData(pixd);
00194     wpld = pixGetWpl(pixd);
00195 
00196     rotateAMColorLow(datad, w, h, wpld, datas, wpls, angle, colorval);
00197 
00198     return pixd;
00199 }
00200 
00201 
00202 /*!
00203  *  pixRotateAMGray()
00204  *
00205  *      Input:  pixs (8 bpp)
00206  *              angle (radians; clockwise is positive)
00207  *              grayval (0 to bring in BLACK, 255 for WHITE)
00208  *      Return: pixd, or null on error
00209  *
00210  *  Notes:
00211  *      (1) Rotates about image center.
00212  *      (2) A positive angle gives a clockwise rotation.
00213  *      (3) Specify the grayvalue to be brought in from outside the image.
00214  */
00215 PIX *
00216 pixRotateAMGray(PIX       *pixs,
00217                 l_float32  angle,
00218                 l_uint8    grayval)
00219 {
00220 l_int32    w, h, wpls, wpld;
00221 l_uint32  *datas, *datad;
00222 PIX        *pixd;
00223 
00224     PROCNAME("pixRotateAMGray");
00225 
00226     if (!pixs)
00227         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00228     if (pixGetDepth(pixs) != 8)
00229         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00230 
00231     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00232         return pixClone(pixs);
00233 
00234     pixGetDimensions(pixs, &w, &h, NULL);
00235     datas = pixGetData(pixs);
00236     wpls = pixGetWpl(pixs);
00237     pixd = pixCreateTemplate(pixs);
00238     datad = pixGetData(pixd);
00239     wpld = pixGetWpl(pixd);
00240 
00241     rotateAMGrayLow(datad, w, h, wpld, datas, wpls, angle, grayval);
00242 
00243     return pixd;
00244 }
00245 
00246 
00247 /*------------------------------------------------------------------*
00248  *                    Rotation about the UL corner                  *
00249  *------------------------------------------------------------------*/
00250 /*!
00251  *  pixRotateAMCorner()
00252  *
00253  *      Input:  pixs (1, 2, 4, 8 bpp gray or colormapped, or 32 bpp RGB)
00254  *              angle (radians; clockwise is positive)
00255  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00256  *      Return: pixd, or null on error
00257  *
00258  *  Notes:
00259  *      (1) Rotates about the UL corner of the image.
00260  *      (2) A positive angle gives a clockwise rotation.
00261  *      (3) Brings in either black or white pixels from the boundary.
00262  */
00263 PIX *
00264 pixRotateAMCorner(PIX       *pixs,
00265                   l_float32  angle,
00266                   l_int32    incolor)
00267 {
00268 l_int32   d;
00269 l_uint32  fillval;
00270 PIX      *pixt1, *pixt2, *pixd;
00271 
00272     PROCNAME("pixRotateAMCorner");
00273 
00274     if (!pixs)
00275         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00276 
00277     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00278         return pixClone(pixs);
00279 
00280         /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
00281     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00282     d = pixGetDepth(pixt1);
00283     if (d < 8)
00284         pixt2 = pixConvertTo8(pixt1, FALSE);
00285     else
00286         pixt2 = pixClone(pixt1);
00287     d = pixGetDepth(pixt2);
00288 
00289         /* Compute actual incoming color */
00290     fillval = 0;
00291     if (incolor == L_BRING_IN_WHITE) {
00292         if (d == 8)
00293             fillval = 255;
00294         else  /* d == 32 */
00295             fillval = 0xffffff00;
00296     }
00297 
00298     if (d == 8)
00299         pixd = pixRotateAMGrayCorner(pixt2, angle, fillval);
00300     else   /* d == 32 */
00301         pixd = pixRotateAMColorCorner(pixt2, angle, fillval);
00302 
00303     pixDestroy(&pixt1);
00304     pixDestroy(&pixt2);
00305     return pixd;
00306 }
00307 
00308 
00309 /*!
00310  *  pixRotateAMColorCorner()
00311  *
00312  *      Input:  pixs
00313  *              angle (radians; clockwise is positive)
00314  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00315  *      Return: pixd, or null on error
00316  *
00317  *  Notes:
00318  *      (1) Rotates the image about the UL corner.
00319  *      (2) A positive angle gives a clockwise rotation.
00320  *      (3) Specify the color to be brought in from outside the image.
00321  */
00322 PIX *
00323 pixRotateAMColorCorner(PIX       *pixs,
00324                        l_float32  angle,
00325                        l_uint32   fillval)
00326 {
00327 l_int32    w, h, wpls, wpld;
00328 l_uint32  *datas, *datad;
00329 PIX       *pixd;
00330 
00331     PROCNAME("pixRotateAMColorCorner");
00332 
00333     if (!pixs)
00334         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00335     if (pixGetDepth(pixs) != 32)
00336         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00337 
00338     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00339         return pixClone(pixs);
00340 
00341     pixGetDimensions(pixs, &w, &h, NULL);
00342     datas = pixGetData(pixs);
00343     wpls = pixGetWpl(pixs);
00344     pixd = pixCreateTemplate(pixs);
00345     datad = pixGetData(pixd);
00346     wpld = pixGetWpl(pixd);
00347 
00348     rotateAMColorCornerLow(datad, w, h, wpld, datas, wpls, angle, fillval);
00349 
00350     return pixd;
00351 }
00352 
00353 
00354 /*!
00355  *  pixRotateAMGrayCorner()
00356  *
00357  *      Input:  pixs
00358  *              angle (radians; clockwise is positive)
00359  *              grayval (0 to bring in BLACK, 255 for WHITE)
00360  *      Return: pixd, or null on error
00361  *
00362  *  Notes:
00363  *      (1) Rotates the image about the UL corner.
00364  *      (2) A positive angle gives a clockwise rotation.
00365  *      (3) Specify the grayvalue to be brought in from outside the image.
00366  */
00367 PIX *
00368 pixRotateAMGrayCorner(PIX       *pixs,
00369                       l_float32  angle,
00370                       l_uint8    grayval)
00371 {
00372 l_int32    w, h, wpls, wpld;
00373 l_uint32  *datas, *datad;
00374 PIX       *pixd;
00375 
00376     PROCNAME("pixRotateAMGrayCorner");
00377 
00378     if (!pixs)
00379         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00380     if (pixGetDepth(pixs) != 8)
00381         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00382 
00383     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00384         return pixClone(pixs);
00385 
00386     pixGetDimensions(pixs, &w, &h, NULL);
00387     datas = pixGetData(pixs);
00388     wpls = pixGetWpl(pixs);
00389     pixd = pixCreateTemplate(pixs);
00390     datad = pixGetData(pixd);
00391     wpld = pixGetWpl(pixd);
00392 
00393     rotateAMGrayCornerLow(datad, w, h, wpld, datas, wpls, angle, grayval);
00394 
00395     return pixd;
00396 }
00397 
00398 
00399 /*------------------------------------------------------------------*
00400  *                    Fast rotation about the center                *
00401  *------------------------------------------------------------------*/
00402 /*!
00403  *  pixRotateAMColorFast()
00404  *
00405  *      Input:  pixs
00406  *              angle (radians; clockwise is positive)
00407  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00408  *      Return: pixd, or null on error
00409  *
00410  *  Notes:
00411  *      (1) This rotates a color image about the image center.
00412  *      (2) A positive angle gives a clockwise rotation.
00413  *      (3) It uses area mapping, dividing each pixel into
00414  *          16 subpixels.
00415  *      (4) It is about 10% to 20% faster than the more accurate linear
00416  *          interpolation function pixRotateAMColor(),
00417  *          which uses 256 subpixels.
00418  *
00419  *  *** Warning: implicit assumption about RGB component ordering ***
00420  */
00421 PIX *
00422 pixRotateAMColorFast(PIX       *pixs,
00423                      l_float32  angle,
00424                      l_uint32   colorval)
00425 {
00426 l_int32    w, h, wpls, wpld;
00427 l_uint32  *datas, *datad;
00428 PIX       *pixd;
00429 
00430     PROCNAME("pixRotateAMColorFast");
00431 
00432     if (!pixs)
00433         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00434     if (pixGetDepth(pixs) != 32)
00435         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00436 
00437     if (L_ABS(angle) < VERY_SMALL_ANGLE)
00438         return pixClone(pixs);
00439 
00440     pixGetDimensions(pixs, &w, &h, NULL);
00441     datas = pixGetData(pixs);
00442     wpls = pixGetWpl(pixs);
00443     pixd = pixCreateTemplate(pixs);
00444     datad = pixGetData(pixd);
00445     wpld = pixGetWpl(pixd);
00446 
00447     rotateAMColorFastLow(datad, w, h, wpld, datas, wpls, angle, colorval);
00448 
00449     return pixd;
00450 }
00451 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines