[comp.graphics] Wanted: Bitmap rotation algorithm

ericf@persoft.UUCP (Eric R. Feigenson) (06/10/89)

[Please excuse me if this type of thing has been requested before.  I don't
 normally read this newsgroup]

I am look for any and all algorithms relating to rotating a bitmap an
aribtrary amount.  Efficiency and accuracy (minimal distortion) are,
of course, important considerations.  An English or pseudo-code
description would be fine, but any high level language implementation
would do nicely.  Pointers to books and/or articles on the subject
are also welcome.  Please e-mail responses.  If there is sufficient
interest, I will post results to the net.

Thanks in advance!
                                -Eric
---------------------------------------------------------------------------
                        -Eric Feigenson
                        Persoft, Inc.
            (Internet)  ericf@Persoft.COM
            (UUCP)      {ihnp4, seismo, uunet, allegra}!uwvax!persoft!ericf

mike@relgyro.stanford.edu (Mike Macgirvin) (06/13/89)

In article <8.UUL1.2#261@persoft.UUCP> ericf@persoft.UUCP (Eric R. Feigenson) writes:
>I am look for any and all algorithms relating to rotating a bitmap an
>aribtrary amount.  Efficiency and accuracy (minimal distortion) are,
>of course, important considerations.  An English or pseudo-code

#include <math.h>

#define radians(angle) ((angle) / 5.729578E+01)
#define HEIGHT   some_integer_number
#define WIDTH    some_integer_number


unsigned char image[WIDTH][HEIGHT];

rotate(angle)
     double angle;     /* rotate image 'angle' degrees */
{
     int color;
     int xx,yy;
     for(y = 0;y < HEIGHT; y ++)
          for(x = 0;x < WIDTH; x ++) {
	       color = image[xx][yy];
               xx = (x * cos(radians(angle)) - (y * sin(radians(angle));
               yy = (x * sin(radians(angle)) + (y * cos(radians(angle));
               setpixel(xx,yy,color);
          }
}


	There are some 'holes' in an image using this method at angles
which are not right angles. I have experimented with methods that set
surrounding pixels to the same value (and covering some of them over later
with real values) to eliminate the 'holes', but have had limited success.




	-------------------------------------------------------
	     "There must be some kind of way out of here." 
        Mike Macgirvin - mike@relgyro.stanford.edu (36.64.0.50)
	-------------------------------------------------------

rokicki@polya.Stanford.EDU (Tomas G. Rokicki) (06/13/89)

mike@relgyro.stanford.edu (Mike Macgirvin) writes:
> >I am look for any and all algorithms relating to rotating a bitmap an
> >aribtrary amount.  Efficiency and accuracy (minimal distortion) are,
> >of course, important considerations.  An English or pseudo-code

> ericf@persoft.UUCP (Eric R. Feigenson) writes:
> unsigned char image[WIDTH][HEIGHT];
> rotate(angle)
>      double angle;     /* rotate image 'angle' degrees */
> {
>      int color;
>      int xx,yy;
>      for(y = 0;y < HEIGHT; y ++)
>           for(x = 0;x < WIDTH; x ++) {
> 	       color = image[xx][yy];
>                xx = (x * cos(radians(angle)) - (y * sin(radians(angle));
>                yy = (x * sin(radians(angle)) + (y * cos(radians(angle));
>                setpixel(xx,yy,color);
>           }
> }

This algorithm can be generalized and improved (eliminating the `holes')
quite easily; simply iterate over the output points rather than the
input points.  Thus,

   for (P = each point in the output) {
      P2 = TRANSFORM(P) ; /* can include rotations, scaling, etc */
      setpixel(destination, P, getpixel(source, P2)) ;
   }

TRANSFORM is the usual six-element matrix, that rounds the point after
it's done.

The resulting bitmap won't be beautiful.  Better results can often be
obtained by interpolating between source pixels.  For instance, if
the unrounded transformed result was (2.3, 4.6), then a better looking
image might be obtained by using

   .3[.6[g(2,4),g(2,5)],.6[g(3,4),g(3,5)]]

where n[a,b] means ((1-n) * a + n * b) and g(x,y) means the value of
the source at pixel (x,y).

The image may be more `blurry' this way, though . . .

If you are scaling up (to more bits), this type of interpolation is
probably not a bad idea.  If you are scaling down (to less bits), it
can give odd effects; you might want to high-pass filter the image
before scaling it down.

-tom

foster@tramp.Colorado.EDU (J. Gabriel Foster) (06/14/89)

In article <230@helens.Stanford.EDU> mike@relgyro.STANFORD.EDU (Mike Macgirvin) writes:
>In article <8.UUL1.2#261@persoft.UUCP> ericf@persoft.UUCP (Eric R. Feigenson) writes:
>>I am look for any and all algorithms relating to rotating a bitmap an
>>aribtrary amount.  Efficiency and accuracy (minimal distortion) are,
>>of course, important considerations.  An English or pseudo-code
>

Some code is included at this point.

>
>	There are some 'holes' in an image using this method at angles
>which are not right angles....
>

Two comments:
1) I think there is a bug in the included code.
2) There is a way that is less likely to produce holes.

Here are the proposed fixes.
>     for(y = 0;y < HEIGHT; y ++)
>          for(x = 0;x < WIDTH; x ++) {
>               xx = (x * cos(radians(angle)) - (y * sin(radians(angle));
>               yy = (x * sin(radians(angle)) + (y * cos(radians(angle));
>	        color = image[xx][yy];
>               setpixel(x,y,color);
>          }
Notice that you always fetch from the source picture at the rotated angle.
(The angle may need to be -angle by the way.  I have not tested it.)
This means that you set every pixel in the destination image, so
there are no rounding errors that leave holes.  (There are other problems,
mostly with some pixels getting spread out a bit.)

Hope this helps.
--> J. Gabriel Foster
--> foster@eprince.colorado.edu
--> foster%eprince@vaxf.colorado.edu.BITNET
University of Colorado @ Boulder.

levine@well.UUCP (Ron Levine) (06/22/89)

In article <8.UUL1.2#261@persoft.UUCP> ericf@persoft.UUCP (Eric R. Feigenson) writes:
>
>I am look for any and all algorithms relating to rotating a bitmap an
>aribtrary amount.  Efficiency and accuracy (minimal distortion) are,
>of course, important considerations.  ....
>

I believe that the fastest methods of rotating raster images, and 
the easiest to which to add filtering to fix the aliasing (holes 
in the image), are the so-called two-pass methods, in which one 
pass preserves horizontal scan lines and the other preserves 
vertical scan lines.  These are especially effective when frame 
buffer memory has been designed for efficient access by 
horizontal and vertical scan lines.  This is the basis of the 
ADO, (Ampex Digital Optics), the machine which makes most of the 
real-time video effects that we see so much of on TV, involving 
rotations and other 2D linear transformations.

References: 

        Ed Catmull and Alvy Ray Smith, 3-D Transformations of 
        Images in Scan-Line Order, Computer Graphics, Vol. 14, 
        No. 3, pp.279-285, July, 1980 (Siggraph Proceedings)  

        Philip P. Bennet and Steven A. Gabriel, System for 
        Spatially Transforming Images, U.S. Patent #4,472,732, 
        September 18, 1984. 

        Alvy Ray Smith, Planar 2-Pass Texture Mapping and 
        Warping, Computer Graphics, Vol 21, No. 4, July 1987 
        (Siggraph Proceedings)

--Ron Levine

awpaeth@watcgl.waterloo.edu (Alan Wm Paeth) (06/26/89)

>I am look for any and all algorithms relating to rotating a bitmap an
>aribtrary amount.  Efficiency and accuracy (minimal distortion) are,
>of course, important considerations.  An English or pseudo-code
>description would be fine, but any high level language implementation
>would do nicely.  Pointers to books and/or articles on the subject
>are also welcome.
                                
If rotation with scale invariance is required, then three simple image skewing
passes suffice. Each pass shears (like a deck of cards) pixels along a scan
line or column. Unlike the 2-pass approach, no potential degradation through
pixel (re)scaling is occurs, making a fast inner loop, but disallowing general
image warping. Rotations of up to 90-degrees are possible for pixel skews of
up to one unit on consecutive scanlines; in practice one normally limits to
45-degrees and takes advantage of 8-fold pixel symmetry. Anti-alising is done
for fractional pixel skews easily (read the paper).  Here is pseudocode from:

  Paeth, A. W.
  ``A Fast Algorithm for General Raster Rotation''
  PROCEEDINGS, Graphics Interface '86
  Vancouver, B.C. May 26-30, 1986

------------------------------------
IMPLEMENTATION
.PP
Scan line shearing is approximated by a blending of adjacent pixels.
In the following code segment, the ``pixmult'' function returns a pixel scaled
by a value $skewf$, where $0 <= skewf < 1$, is a constant parameter for all
``width'' passes through the inner-most loop:
.sp
.LP
.ft CW
PROCEDURE xshear(shear, width, height)
    FOR y := 0 TO height-1 DO
        skew  := shear * (y+0.5);
        skewi := floor(skew);
        skewf := frac(skew);
        oleft := 0;
        FOR x := 0 TO width-1 DO
            pixel := P(width-x, y);
            left  := pixmult(pixel, skewf);
                  /* pixel - left = right */
            pixel := pixel - left + oleft;
            P(width-x+skewi, y) := pixel;
            oleft := left;
        OD
        P(skewi, y) := oleft;
    OD
.sp

-----

The whole technique phrases the rotation question as a system of 2x2 matrices.
Ironically, the earliest reference I can find for decomposition of rotation
matrices into unit-determinant shear matrices is due C.F. Gauss. Ironically,
he was working on a unified approach to a major problem in Geometric Optics:
better ray tracing!

    /Alan Paeth
    Computer Graphics Laboratory
    University of Waterloo