MathGroup Archive 2001

[Date Index] [Thread Index] [Author Index]

Search the Archive

Faster rotate bitmap

  • To: mathgroup at smc.vnet.net
  • Subject: [mg29031] Faster rotate bitmap
  • From: Simon Chandler <simon_chandler at agilent.com>
  • Date: Fri, 25 May 2001 01:48:07 -0400 (EDT)
  • Sender: owner-wri-mathgroup at wolfram.com

I need to be able to rotate a bitmap image (1280 x 960 pixels) through a specified angle so that a feature is aligned with the image columns (i.e., is "vertical"). This is to be done automatically to many images, with no user intervention. After completing the rotation various features are automatically measured. I can now do this, but the actual image rotation takes too long (approx 10 seconds). Can you help me find a faster rotation method. I'd really like the rotation of my 1280 x 960 image to take less than 1 second.

Q1: Firstly, are there any pre-existing standard routines/packages - either 
    free or commercial - that will do the job?

Q2: Do you think that my method (see below) can be made 10x faster 
    by improving the code?

Q3: Will I have to resort to a Mathlinked low-level program to achieve the 
    10x speed increase I'm looking for?


Thanks for your time and attention,

Simon

----------

My Mathematica routine is based on RotateScanline and variants thereof that I found by searching the web. See

 http://efg2.com/Lab/ImageProcessing/RotateScanline.htm 

In my routine I'm trying to return the largest rectangle (with vertical and horizontal sides) from within the rotated image that is wholly from within the original image. i.e., I do not want any of the four triangular "padding" regions that are created around the rotated image to make it rectangular. To achieve this I use the ancillary functions:

sCrit[w_, h_, theta_] := 
   (h Cos[theta Degree] - 
        w Sin[theta Degree])/(2 Cos[2 theta Degree])

optSCaseA[w_, h_, theta_] := w/4/Sin[theta Degree]

optSCaseB[w_, h_, theta_] := h/4/Cos[theta Degree]

sOptimum[w_, h_, theta_] :=
  If[
    w > h,
    If[
      Sin[2 theta Degree] < h/w,
      sCrit[w, h, theta],
      optSCaseB[w, h, theta]
      ],
    (* so w < h *)
    If[
      Sin[2 theta Degree] < w/h,
      sCrit[w, h, theta],
      optSCaseA[w, h, theta]
      ]
    ]

rOptimum[w_, h_, theta_] := sOptimum[h, w, theta]


The main part of my Mathematica routine is:

RotateArrayC4 = 
    Compile[
      {
        {bitmapOriginal, _Real, 2},
        {thetaDegrees, _Real}
        },
      Module[
        {theta, oldHeight, oldWidth, newWidth, newHeight, iRotationAxis, 
          jRotationAxis, bitmapRotated, i, j, iPrime, jPrime, iPrimeRotated, 
          jPrimeRotated, iOriginal, jOriginal, sint, cost, x0, y0, 
          innerHeight, innerWidth, leftBound, rightBound, lowerBound, 
          upperBound},
        
        theta = thetaDegrees*Degree;
        sint = Sin[theta];
        cost = Cos[theta];
        
        oldHeight = Dimensions[bitmapOriginal][[1]];
        oldWidth = Dimensions[bitmapOriginal][[2]];
        
        (* Print["oldWidth = ", oldWidth];
          Print["oldHeight = ", oldHeight];*)
        
        newWidth = Abs[Round[oldHeight*sint]] + Abs[Round[oldWidth*cost]];
        newHeight = Abs[Round[oldWidth*sint]] + Abs[Round[oldHeight*cost]];
        
        (*Print["newWidth = ", newWidth];
          Print["newHeight = ", newHeight];*)
        
        
        x0 = Abs[Round[cost*oldWidth]];
        y0 = Abs[Round[sint*oldWidth]];
        
        (*Print["x0 = ", x0];
          Print["y0 = ", y0];*)
        
        innerHeight = Abs[Round[
              2*sOptimum[oldWidth, oldHeight, Abs[thetaDegrees]]
              ]];
        innerWidth = Abs[Round[
              2*rOptimum[oldWidth, oldHeight, Abs[thetaDegrees]]
              ]];
        
        (*Print["innerHeight = ", innerHeight];
          Print["innerWidth = ", innerWidth];*)
        
        leftBound = 
          Abs[Round[
                Quotient[newWidth - innerWidth, 2]
                ]] + 1;
        
        rightBound = 
          Abs[Round[
                Quotient[newWidth + innerWidth, 2]
                ]] - 1;
        
        lowerBound = 
          Abs[Round[
                Quotient[newHeight - innerHeight, 2]
                ]] + 1;
        
        upperBound = 
          Abs[Round[
                Quotient[newHeight + innerHeight, 2]
                ]] - 1;
        
        (*Print["leftBound = ", leftBound];
          Print["rightBound = ", rightBound];
          Print["lowerBound = ", lowerBound];
          Print["upperBound = ", upperBound];*)
        
        iRotationAxis = Quotient[oldWidth, 2];
        jRotationAxis = Quotient[oldHeight , 2];
        
        bitmapRotated = 
          Table[
            -1.1,
            {j, 1, newHeight}, {i, 1, newWidth}
            ];
        
        Do[
          
          jPrime = 
            2*(j2 - Quotient[newHeight - oldHeight, 2] - jRotationAxis) - 1;
          Do[
            
            iPrime = 
              2*(i2 - Quotient[newWidth - oldWidth, 2] - iRotationAxis) - 1;
            
            iPrimeRotated = Round[iPrime*cost - jPrime*sint];
            jPrimeRotated = Round[jPrime*cost + iPrime*sint];
            
            iOriginal = Quotient[iPrimeRotated + 1, 2] + iRotationAxis;
            jOriginal = Quotient[jPrimeRotated + 1, 2] + jRotationAxis;
            
            If[
              
              iOriginal > 0 && iOriginal <= oldWidth && jOriginal > 0 && 
                jOriginal <= oldHeight,
              (* then *)
              
              bitmapRotated[[j2, i2]] = 
                bitmapOriginal[[jOriginal, iOriginal]],
              (* else *)
              bitmapRotated[[j2, i2]] = 10
              ]
            
             ,
            {i2, leftBound + 1, rightBound - 1}
            ],
          {j2, lowerBound + 1, upperBound - 1}
          ]; 
        
        Take[
          bitmapRotated, {lowerBound + 1, upperBound - 1}, {leftBound + 1, 
            rightBound - 1}]
        
        ],
      {
        {theta, _Real}, {oldHeight, _Integer}, {oldWidth, _Integer}, 
        {newHeight, _Integer}, {newWidth, _Integer}, {iRotationAxis, _Integer}, 
        {jRotationAxis, _Integer}, {bitmapRotated, _Real, 2}, {i, _Integer}, 
        {j, _Integer}, {iPrime, _Integer}, {jPrime, _Integer}, 
        {iPrimeRotated, _Integer}, {jPrimeRotated, _Integer}, 
        {iOriginal, _Integer}, {jOriginal, _Integer}, {x0, _Integer}, 
        {y0, _Integer}, {innerHeight, _Integer}, {innerWidth, _Integer}, 
        {leftBound, _Integer}, {rightBound, _Integer}, {lowerBound, _Integer}, 
        {upperBound, _Integer}
        }
      ];

As a test image, use:

image = Table[x*y, {x, 0, 1280}, {y, 0, 960}];
ListDensityPlot[image, Mesh -> False];

As an example ...

Timing[rotatedImage = RotateArrayC4[image, 30];]
ListDensityPlot[rotatedImage, Mesh -> False];


-- 
----------------------------------------------------------------------

 Simon Chandler
 Agilent Technologies UK Ltd          Tel: +44 1473 465 943
 White House Road                     Fax: +44 1473 465 438               
 Ipswich                           mobile: 07803 588 306
 Suffolk, IP1 5PB
 United Kingdom                     email: simon_chandler at agilent.com

======================================================================


  • Prev by Date: Re: OOP in Mathematica
  • Next by Date: Please Help Simplify This
  • Previous by thread: Re: Importing EPS
  • Next by thread: Re: Faster rotate bitmap