Leptonica  1.82.0
Image processing and image analysis suite
rotateam.c File Reference
#include <string.h>
#include <math.h>
#include "allheaders.h"

Go to the source code of this file.

Functions

static void rotateAMColorLow (l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_float32 angle, l_uint32 colorval)
 
static void rotateAMGrayLow (l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_float32 angle, l_uint8 grayval)
 
static void rotateAMColorCornerLow (l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_float32 angle, l_uint32 colorval)
 
static void rotateAMGrayCornerLow (l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_float32 angle, l_uint8 grayval)
 
static void rotateAMColorFastLow (l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_float32 angle, l_uint32 colorval)
 
PIXpixRotateAM (PIX *pixs, l_float32 angle, l_int32 incolor)
 
PIXpixRotateAMColor (PIX *pixs, l_float32 angle, l_uint32 colorval)
 
PIXpixRotateAMGray (PIX *pixs, l_float32 angle, l_uint8 grayval)
 
PIXpixRotateAMCorner (PIX *pixs, l_float32 angle, l_int32 incolor)
 
PIXpixRotateAMColorCorner (PIX *pixs, l_float32 angle, l_uint32 fillval)
 
PIXpixRotateAMGrayCorner (PIX *pixs, l_float32 angle, l_uint8 grayval)
 
PIXpixRotateAMColorFast (PIX *pixs, l_float32 angle, l_uint32 colorval)
 

Variables

static const l_float32 MinAngleToRotate = 0.001
 

Detailed Description


    Grayscale and color rotation for area mapping (== interpolation)

        Rotation about the image center
               PIX         *pixRotateAM()
               PIX         *pixRotateAMColor()
               PIX         *pixRotateAMGray()
               static void  rotateAMColorLow()
               static void  rotateAMGrayLow()

        Rotation about the UL corner of the image
               PIX         *pixRotateAMCorner()
               PIX         *pixRotateAMColorCorner()
               PIX         *pixRotateAMGrayCorner()
               static void  rotateAMColorCornerLow()
               static void  rotateAMGrayCornerLow()

        Faster color rotation about the image center
               PIX         *pixRotateAMColorFast()
               static void  rotateAMColorFastLow()

    Rotations are measured in radians; clockwise is positive.

    The basic area mapping grayscale rotation works on 8 bpp images.
    For color, the same method is applied to each color separately.
    This can be done in two ways: (1) as here, computing each dest
    rgb pixel from the appropriate four src rgb pixels, or (2) separating
    the color image into three 8 bpp images, rotate each of these,
    and then combine the result.  Method (1) is about 2.5x faster.
    We have also implemented a fast approximation for color area-mapping
    rotation (pixRotateAMColorFast()), which is about 25% faster
    than the standard color rotator.  If you need the extra speed,
    use it.

    Area mapping works as follows.  For each dest
    pixel you find the 4 source pixels that it partially
    covers.  You then compute the dest pixel value as
    the area-weighted average of those 4 source pixels.
    We make two simplifying approximations:

      ~  For simplicity, compute the areas as if the dest
         pixel were translated but not rotated.

      ~  Compute area overlaps on a discrete sub-pixel grid.
         Because we are using 8 bpp images with 256 levels,
         it is convenient to break each pixel into a
         16x16 sub-pixel grid, and count the number of
         overlapped sub-pixels.

    It is interesting to note that the digital filter that
    implements the area mapping algorithm for rotation
    is identical to the digital filter used for linear
    interpolation when arbitrarily scaling grayscale images.

    The advantage of area mapping over pixel sampling
    in grayscale rotation is that the former naturally
    blurs sharp edges ("anti-aliasing"), so that stair-step
    artifacts are not introduced.  The disadvantage is that
    it is significantly slower.

    But it is still pretty fast.  With standard 3 GHz hardware,
    the anti-aliased (area-mapped) color rotation speed is
    about 15 million pixels/sec.

    The function pixRotateAMColorFast() is about 10-20% faster
    than pixRotateAMColor().  The quality is slightly worse,
    and if you make many successive small rotations, with a
    total angle of 360 degrees, it has been noted that the
    center wanders -- it seems to be doing a 1 pixel translation
    in addition to the rotation.

    Consider again the comparison of image quality between sampling
    and area mapping.  With sampling, sharp edges such as found in
    text images remain sharp.  However, sampling artifacts such as
    characters randomly bouncing up and down by one pixel, or
    one pixel horizontal shear lines going through a line of text
    (causing the characters to look like badly rendered italic),
    are highly visible.  It does not help to sample the source pixel
    with the largest area covering each dest pixel; the result has
    the same ugly sampling artifacts.

    With area mapping, these annoying artifacts are avoided, but the
    blurring of edges makes small text a bit more difficult to read.
    However, if you are willing to do more computation, you can have
    the best of both worlds: no sampling artifacts and sharp edges.
    Use area mapping to avoid sampling issues, and follow it with
    unsharp masking.  Experiment with the sharpening parameters.
    I have found that a small amount of sharpening is sufficient to
    restore the sharp edges in text; e.g.,
        pix2 = pixUnsharpMasking(pix1, 1, 0.3);

Definition in file rotateam.c.

Function Documentation

◆ pixRotateAM()

PIX* pixRotateAM ( PIX pixs,
l_float32  angle,
l_int32  incolor 
)

pixRotateAM()

Parameters
[in]pixs2, 4, 8 bpp gray or colormapped, or 32 bpp RGB
[in]angleradians; clockwise is positive
[in]incolorL_BRING_IN_WHITE, L_BRING_IN_BLACK
Returns
pixd, or NULL on error
Notes:
     (1) Rotates about image center.
     (2) A positive angle gives a clockwise rotation.
     (3) Brings in either black or white pixels from the boundary.

Definition at line 172 of file rotateam.c.

◆ pixRotateAMColor()

PIX* pixRotateAMColor ( PIX pixs,
l_float32  angle,
l_uint32  colorval 
)

pixRotateAMColor()

Parameters
[in]pixs32 bpp
[in]angleradians; clockwise is positive
[in]colorvale.g., 0 to bring in BLACK, 0xffffff00 for WHITE
Returns
pixd, or NULL on error
Notes:
     (1) Rotates about image center.
     (2) A positive angle gives a clockwise rotation.
     (3) Specify the color to be brought in from outside the image.

Definition at line 235 of file rotateam.c.

◆ pixRotateAMColorCorner()

PIX* pixRotateAMColorCorner ( PIX pixs,
l_float32  angle,
l_uint32  fillval 
)

pixRotateAMColorCorner()

Parameters
[in]pixs
[in]angleradians; clockwise is positive
[in]fillvale.g., 0 to bring in BLACK, 0xffffff00 for WHITE
Returns
pixd, or NULL on error
Notes:
     (1) Rotates the image about the UL corner.
     (2) A positive angle gives a clockwise rotation.
     (3) Specify the color to be brought in from outside the image.

Definition at line 531 of file rotateam.c.

◆ pixRotateAMColorFast()

PIX* pixRotateAMColorFast ( PIX pixs,
l_float32  angle,
l_uint32  colorval 
)

pixRotateAMColorFast()

Parameters
[in]pixs
[in]angleradians; clockwise is positive
[in]colorvale.g., 0 to bring in BLACK, 0xffffff00 for WHITE
Returns
pixd, or NULL on error
Notes:
     (1) This rotates a color image about the image center.
     (2) A positive angle gives a clockwise rotation.
     (3) It uses area mapping, dividing each pixel into
         16 subpixels.
     (4) It is about 10% to 20% faster than the more accurate linear
         interpolation function pixRotateAMColor(),
         which uses 256 subpixels.
     (5) For some reason it shifts the image center.
         No attempt is made to rotate the alpha component.

Definition at line 764 of file rotateam.c.

◆ pixRotateAMCorner()

PIX* pixRotateAMCorner ( PIX pixs,
l_float32  angle,
l_int32  incolor 
)

pixRotateAMCorner()

Parameters
[in]pixs1, 2, 4, 8 bpp gray or colormapped, or 32 bpp RGB
[in]angleradians; clockwise is positive
[in]incolorL_BRING_IN_WHITE, L_BRING_IN_BLACK
Returns
pixd, or NULL on error
Notes:
     (1) Rotates about the UL corner of the image.
     (2) A positive angle gives a clockwise rotation.
     (3) Brings in either black or white pixels from the boundary.

Definition at line 470 of file rotateam.c.

◆ pixRotateAMGray()

PIX* pixRotateAMGray ( PIX pixs,
l_float32  angle,
l_uint8  grayval 
)

pixRotateAMGray()

Parameters
[in]pixs8 bpp
[in]angleradians; clockwise is positive
[in]grayval0 to bring in BLACK, 255 for WHITE
Returns
pixd, or NULL on error
Notes:
     (1) Rotates about image center.
     (2) A positive angle gives a clockwise rotation.
     (3) Specify the grayvalue to be brought in from outside the image.

Definition at line 289 of file rotateam.c.

◆ pixRotateAMGrayCorner()

PIX* pixRotateAMGrayCorner ( PIX pixs,
l_float32  angle,
l_uint8  grayval 
)

pixRotateAMGrayCorner()

Parameters
[in]pixs
[in]angleradians; clockwise is positive
[in]grayval0 to bring in BLACK, 255 for WHITE
Returns
pixd, or NULL on error
Notes:
     (1) Rotates the image about the UL corner.
     (2) A positive angle gives a clockwise rotation.
     (3) Specify the grayvalue to be brought in from outside the image.

Definition at line 585 of file rotateam.c.

◆ rotateAMColorFastLow()

static void rotateAMColorFastLow ( l_uint32 *  datad,
l_int32  w,
l_int32  h,
l_int32  wpld,
l_uint32 *  datas,
l_int32  wpls,
l_float32  angle,
l_uint32  colorval 
)
static

rotateAMColorFastLow()

This is a special simplification of area mapping with division
of each pixel into 16 sub-pixels.  The exact coefficients that
should be used are the same as for the 4x linear interpolation
scaling case, and are given there.  I tried to approximate these
as weighted coefficients with a maximum sum of 4, which
allows us to do the arithmetic in parallel for the R, G and B
components in a 32 bit pixel.  However, there are three reasons
for not doing that:
   (1) the loss of accuracy in the parallel implementation
       is visually significant
   (2) the parallel implementation (described below) is slower
   (3) the parallel implementation requires allocation of
       a temporary color image

There are 16 cases for the choice of the subpixel, and
for each, the mapping to the relevant source
pixels is as follows:

 subpixel      src pixel weights
 --------      -----------------
    0          sp1
    1          (3 * sp1 + sp2) / 4
    2          (sp1 + sp2) / 2
    3          (sp1 + 3 * sp2) / 4
    4          (3 * sp1 + sp3) / 4
    5          (9 * sp1 + 3 * sp2 + 3 * sp3 + sp4) / 16
    6          (3 * sp1 + 3 * sp2 + sp3 + sp4) / 8
    7          (3 * sp1 + 9 * sp2 + sp3 + 3 * sp4) / 16
    8          (sp1 + sp3) / 2
    9          (3 * sp1 + sp2 + 3 * sp3 + sp4) / 8
    10         (sp1 + sp2 + sp3 + sp4) / 4
    11         (sp1 + 3 * sp2 + sp3 + 3 * sp4) / 8
    12         (sp1 + 3 * sp3) / 4
    13         (3 * sp1 + sp2 + 9 * sp3 + 3 * sp4) / 16
    14         (sp1 + sp2 + 3 * sp3 + 3 * sp4) / 8
    15         (sp1 + 3 * sp2 + 3 * sp3 + 9 * sp4) / 16

Another way to visualize this is to consider the area mapping
(or linear interpolation) coefficients  for the pixel sp1.
Expressed in fourths, they can be written as asymmetric matrix:

      4      3      2      1
      3      2.25   1.5    0.75
      2      1.5    1      0.5
      1      0.75   0.5    0.25

The coefficients for the three neighboring pixels can be
similarly written.

This is implemented here, where, for each color component,
we inline its extraction from each participating word,
construct the linear combination, and combine the results
into the destination 32 bit RGB pixel, using the appropriate shifts.

It is interesting to note that an alternative method, where
we do the arithmetic on the 32 bit pixels directly (after
shifting the components so they won't overflow into each other)
is significantly inferior.  Because we have only 8 bits for
internal overflows, which can be distributed as 2, 3, 3, it
is impossible to add these with the correct linear
interpolation coefficients, which require a sum of up to 16.
Rounding off to a sum of 4 causes appreciable visual artifacts
in the rotated image.  The code for the inferior method
can be found in prog/rotatefastalt.c, for reference.

Definition at line 863 of file rotateam.c.

References lept_stderr().