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 > > ======================================================================