Image Rotation

General FreeBASIC programming questions.
axipher
Posts: 891
Joined: Dec 27, 2005 16:37
Location: Sudbury,Ontario
Contact:

Image Rotation

Postby axipher » Apr 20, 2007 1:14

Well here's what I have so far

Code: Select all

#include "fbgfx.bi"
# if __FB_LANG__ = "fb"
using FB
# endif

const PI = 4 * atn(1)

sub multiput(xmid as integer,ymid as integer,src as any ptr,rot as double)
  dim as integer sx,sy,nx,ny
  dim as double ang,dist
  sx = cptr(image ptr,src)->width
  sy = cptr(image ptr,src)->height
  for cy as double = 0 to (sy - 1) step 0.5
    for cx as double = 0 to (sx - 1) step 0.5
      ang = atan2(cy - (sy / 2),cx - (sx / 2))
      dist = sqr(((cx - (sx / 2)) ^ 2) + ((cy - (sy / 2)) ^ 2))
      nx = xmid + (cos(ang + rot) * dist)
      ny = ymid + (sin(ang + rot) * dist)
      pset (nx,ny),point(cx,cy,src)
    next
  next
end sub


If I make the For...Next integers, the rotated image gets holes in it, but with doubles, it's damn slow with only 4 sprites. Can anyone help me?
counting_pine
Site Admin
Posts: 6169
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Postby counting_pine » Apr 20, 2007 1:47

You won't get holes if you go the other way:
Instead of going through each pixel in the source image and working out where to Put it, go through all the (possible) pixel positions in the destination image, and work out what pixel to Put there.
Instead of:
for x, y in source image
work out where to put the pixel (dx, dy)
put it at (dx, dy)

Do:
for x, y in destination image
work out what pixel (if any) from the source image to put here
put it at (x, y)

It's slightly more complicated, because unless you want to check each and every pixel in the destination, you have to work out the area in the destination where pixels might get Put. It's not too hard though.

The working out bit in the loop isn't much harder either, you just reverse the transformation.
Richard
Posts: 2939
Joined: Jan 15, 2007 20:44
Location: Australia

Postby Richard » Apr 20, 2007 2:06

You are using trigonometry. Better to do vector rotation which is a complex multiply. It is much faster. This will speed it up but not fill in the holes.

dim as double (all but loop counter)

To rotate by a radian angle rot, firstly
rotx = cos(rot) ' convert angle to a unity vector
roty = sin(rot)

thent get coordinates of the centre of rotation
mx = ?
my = ?

These can be precomputed before the following loop

for every point on image
x = x - mx ' translate to origin
y = y - my
nx = x*rotx - y*roty ' complex multiply
ny = x*roty + y*rotx
nx = nx + mx ' restore translation
ny = ny + my
next point

done
axipher
Posts: 891
Joined: Dec 27, 2005 16:37
Location: Sudbury,Ontario
Contact:

Postby axipher » Apr 20, 2007 2:34

I tried and failed:

Code: Select all

#include "fbgfx.bi"
# if __FB_LANG__ = "fb"
using FB
# endif

const PI = 4 * atn(1)

sub multiput(xmid as integer,ymid as integer,src as any ptr,rot as double)
  dim as double rotx,roty,nx,ny,dx,dy,x,y
  dim as integer sx,sy
  sx = cptr(image ptr,src)->width
  sy = cptr(image ptr,src)->height

  rotx = cos(rot)
  roty = sin(rot)

  for cy as integer = 0 to (sy - 1)
    for cx as integer = 0 to (sx - 1)
      x = x - xmid
      y = y - ymid
      nx = (x * rotx) - (y * roty) + xmid
      ny = (x * roty) + (y * rotx) + ymid
      pset (nx,ny),point(cx,cy,src)
    next
  next
end sub
Richard
Posts: 2939
Joined: Jan 15, 2007 20:44
Location: Australia

Postby Richard » Apr 20, 2007 3:01

you have not assigned values of cx and cy to x and y inside the loop
D.J.Peters
Posts: 7667
Joined: May 28, 2005 3:28

Postby D.J.Peters » Apr 20, 2007 15:56

' from a paper rotate.txt by Karl Lager

Code: Select all

sub rotate(byval sx   as double,byval sy   as double, _
           byval dx   as double,byval dy   as double, _
           byval minx as double,byval maxx as double, _
           byval miny as double,byval maxy as double, _
           byval angle as double)

  dim as double c=cos(angle)
  dim as double s=sin(angle)
  dim as uinteger col

  for y as integer= miny to maxy
    dim as double srcx = (minx-sx) * c + (y   -sy) * s + sx
    dim as double srcy = (y   -sy) * c - (minx-sx) * s + sy
    for x as integer = minx to maxx
       ' test first here if srcx and srcy in image bondary
       if srcx>=minx and srcx<=maxx and _
          srcy>=miny and srcy<=maxy then
          col=point(srcx,srcy)
       else
          col=0
       end if
       pset (x+dx,y+dy),col

       srcx += c
       srcy -= s
    next
  next
end sub

'
' main
'
screenres 640,480,32
for y as integer = 0 to 127
  for x as integer = 0 to 127
     pset(x,y),rgb(x*x,y*y,x+y)
  next
next

dim as double angle
while inkey=""
  screenlock
  rotate 63.5,63.5,320-64,240-64,0,127,0,127,angle
  screenunlock
  angle+=0.1
wend
sleep
h4tt3n
Posts: 678
Joined: Oct 22, 2005 21:12
Location: Denmark

Postby h4tt3n » Apr 20, 2007 17:43

The same thing can be done much, much faster like this...

Code: Select all

''                        rotating algorithm
''                    coded by Michael S. Nissen
''                        jernmager@yahoo.dk

Option Explicit

Type Pixel
  As Double X, Y
  As Integer C
End Type

''  dim vars
Dim As String X_Clicked = Chr(255)+"k"
Dim as Ubyte R, G, B
Dim as Ushort Img_Hgt, Img_Wid
Dim as Short Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
Dim as Integer scrn_wid, scrn_hgt
Dim As Double Rot_X, Rot_Y, Angle, Cos_Ang, Sin_Ang, Xdist, Ydist, Rot_Fac_X, Rot_Fac_Y

'ScreenInfo scrn_wid, scrn_hgt
scrn_wid = 640
scrn_hgt = 480
screenRes scrn_wid, scrn_hgt, 32

Dim As Uinteger Ptr Sptr = Screenptr

Rot_X = scrn_wid\2
Rot_Y = scrn_hgt\2

Cos_Ang = Cos(Angle)
Sin_Ang = Sin(Angle)

''  dimensions of image to be rotated
Img_Wid = 256
Img_Hgt = 256
Img_Rgt = Img_Wid\2
Img_Lft = -Img_Rgt
Img_Btm = Img_Hgt\2
Img_Top = -Img_Btm

Dim Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm) as Pixel

''  draw strange geometric pattern to image
For Y = Img_Top to Img_Btm
  For X = Img_Lft to Img_Rgt
    With Pixel(X, Y)
      .X = Rot_X+X
      .Y = Rot_Y+Y
      R = Sqr((X-Img_Lft)^2+(Y-Img_Top)^2)*0.705 and Sqr((X-Img_Rgt)^2+(Y-Img_Top)^2)*0.705
      G = Sqr((X-Img_RGT)^2+(Y-Img_Btm)^2)*0.705 and Sqr((X-Img_Lft)^2+(Y-Img_Btm)^2)*0.705
      B = R or G
      .C = RGB(R, G, B)
    End With
  Next X
Next Y

''  main program loop
Do
 
  ''  rotate left/right with leftarrow/rightarrow
  If Multikey(77) Then
    Angle -= 0.01
    Cos_Ang = Cos(Angle)
    Sin_Ang = Sin(Angle)
  ElseIf Multikey(75) Then
    Angle += 0.01
    Cos_Ang = Cos(Angle)
    Sin_Ang = Sin(Angle)
  End If
 
  ScreenLock
   
    ''  rotate & scale
    For Y = Img_Top to 0
      For X = Img_Lft to -1
        Xdist = Pixel(X, Y).X-Rot_X
        Ydist = Pixel(X, Y).Y-Rot_Y
        Rot_Fac_X = Xdist*Cos_Ang-Ydist*Sin_Ang
        Rot_Fac_Y = Xdist*Sin_Ang+Ydist*Cos_Ang
        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
        Sptr[ (Rot_X+X) + ((Rot_Y+Y) * scrn_wid) ] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
        Sptr[ (Rot_X-X) + ((Rot_Y-Y) * scrn_wid) ] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
        Sptr[ (Rot_X+Y) + ((Rot_Y-X) * scrn_wid) ] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
        Sptr[ (Rot_X-Y) + ((Rot_Y+X) * scrn_wid) ] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
      Next X
    Next Y
   
  ScreenUnlock
 
Loop Until Multikey(1) or Inkey = X_Clicked

end
h4tt3n
Posts: 678
Joined: Oct 22, 2005 21:12
Location: Denmark

Postby h4tt3n » Apr 25, 2007 13:59

Rotation algorithms are fun to tamper with in themselves, but now I actually need one to rotate a .bmp file. So what's the best way to go around it?

To load the .bmp into a Dim'ed array and then manipulate it? How is this done anyway?

Or to load load the .bmp into an Imagecreate'd memory block and then manipulate it. And how would that be done?

Or something else?

Return to “General”

Who is online

Users browsing this forum: No registered users and 4 guests