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},
},
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},

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[
]];
innerWidth = Abs[Round[
]];

(*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