Mathematica 9 is now available
Services & Resources / Wolfram Forums / MathGroup Archive
-----

MathGroup Archive 2001

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

Search the Archive

Re: Faster rotate bitmap

  • To: mathgroup at smc.vnet.net
  • Subject: [mg29115] Re: Faster rotate bitmap
  • From: Jens-Peer Kuska <kuska at informatik.uni-leipzig.de>
  • Date: Wed, 30 May 2001 05:50:30 -0400 (EDT)
  • Organization: Universitaet Leipzig
  • References: <9ektan$7un@smc.vnet.net>
  • Sender: owner-wri-mathgroup at wolfram.com

Hi,

if you don't care for aliasing effects you may try

Clear[RasterRotate]
Options[RasterRotate] = {RotationCenter -> Automatic, 
    Background -> Automatic}

(* Find the new bounding box for the rotated image *)

findRotationBox[{{x1_, y1_}, {x2_, y2_}}] :=
   
  Transpose[{Min[#], Max[#]} & /@ 
      Transpose[ rotate /@ {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}}]]

makeBackground[color_Integer, element_Integer, _] := color
makeBackground[color_Integer, lst : {_Integer ..}, _] := 
  Table[color, {Length[lst]}]

makeBackground[Automatic, elem_, range_] := 
  makeBackground[First[range], elem, range]

makeBackground[Black, elem_, range_] := 
  makeBackground[First[range], elem, range]

makeBackground[White, elem_, range_] := 
  makeBackground[Last[range], elem, range]

RasterRotate[Raster[data_, bound_, brange_, imgopt___], phi_?NumericQ, 
    opt___] := 
  Block[{rotate, backg, newraster, rotmat, center, center1, newbound, 
      newdata},
    center = RotationCenter /. {opt} /. Options[RasterRotate];
    backg = Background /. {opt} /. Options[RasterRotate];
    backg = makeBackground[backg, data[[1, 1]], brange];
    If[center === Automatic,
      center = (Plus @@ bound)/2
      ];
    rotmat = N[{{Cos[phi], -Sin[phi]},
                           {Sin[phi], Cos[phi]}}];
    rotate = Function[{pos}, Round /@ (center + rotmat.(pos - center))];
    newbound = findRotationBox[bound];
    (* Make a empty bitmap for the rotated image *)
    
    newdata = 
      Table[backg, 
        Evaluate[
          Sequence @@ ( ({Plus @@ ({-1, 1}*#)}) & /@
Transpose[newbound])]];
    (* compile the transformation *)
    
    rotate = Compile[{{pos, _Integer, 1}, {rotmat, _Real, 2}, {c1,
_Integer, 
            1}, {c2, _Integer, 1}}, 
        Max[Round[#], 1] & /@ (Dot[rotmat, (pos - c1)] + c2)];
    center1 = center - newbound[[1]];
    (* transform  every pixel *)
    MapIndexed[
      (Part[newdata, Sequence @@ rotate[#2, rotmat, center, center1]] =
#1) &,
       data, {2}];
    Raster[newdata, newbound, brange, imgopt]
    ]

But a MathLink program will be still much faster.

Regards
  Jens

Simon Chandler wrote:
> 
> 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: Importing EPS
  • Next by Date: FW: Animations and Options Inspector
  • Previous by thread: Re: Faster rotate bitmap
  • Next by thread: Please Help Simplify This