Dark Bit Factory & Gravity
PROGRAMMING => Other languages => Blitz => Topic started by: mike_g on August 20, 2007
-
Heres some code I made today for fast image scaling. Basically each image is a type with a number of frame handles dependant on SCALE_DETAIL. The CreateScaledImage() function then creates and draws an appropriately sized image for each frame.
Heres the code:
AppTitle "Fast Image Scaling"
Graphics 640, 480, 32, 2
SetBuffer BackBuffer()
;Each image has an array of handles for scaled versions
;The more handles the greater the scale detail
Const SCALE_DETAIL = 50 ;50 frames
Const SCALE_RANGE = 2 ;between 2 and 0.1
;Each image has a number of frames and a name as an identifier
Type image
Field name$
Field frames[SCALE_DETAIL]
End Type
pic = LoadImage("tree.png")
CreateScaledImage(pic, "tree")
FreeImage(image)
;---------------------------------------------------------------------------------------------------;
;******************************** DEMO PROGRAM *****************************************************;
;---------------------------------------------------------------------------------------------------;
SeedRnd MilliSecs()
;FRAME RATE VARIABLES
Global old_time = MilliSecs()
Global frame_count, fps
Type tree
Field image
Field scale
Field x, y
End Type
InitTrees()
inc=1: i=5
While Not KeyHit(1)
Cls
DrawTrees()
KeyInput()
FPS()
Flip
Wend
ClearScaled() ;free scaled images
;---------------------------------------------------------------------------------------------------;
;******************************** SCALE FUNCTIONS **************************************************;
;---------------------------------------------------------------------------------------------------;
Function CreateScaledImage(image, name$)
im.image = New image
im\name = "tree"
Local src_x, src_y ;co-ords to read from original image
Local src_w, src_h ;width and height of original
Local dst_x, dst_y ;co-ords to draw to scaled image
Local dst_w, dst_h ;width and height of scaled image
Local col, inc# ;colour to draw , scale size increment
src_w = ImageWidth(image)
src_h = ImageHeight(image)
inc# = Float(SCALE_RANGE) / Float(SCALE_DETAIL)
SetBuffer ImageBuffer(image, mask)
For i = 1 To SCALE_DETAIL
image_size# = image_size# + inc#
dst_w = Floor(src_w * image_size#)
dst_h = Floor(src_h * image_size#)
im\frames[i] = CreateImage(dst_w, dst_h)
LockBuffer ImageBuffer(image)
LockBuffer ImageBuffer(im\frames[i])
For dst_y=0 To dst_h
src_y = Floor(dst_y / image_size#)
For dst_x=0 To dst_w
src_x = Floor(dst_x / image_size)
col = ReadPixelFast(src_x, src_y)
WritePixelFast(dst_x, dst_y, col, ImageBuffer(im\frames[i]))
Next
Next
UnlockBuffer ImageBuffer(image)
UnlockBuffer ImageBuffer(im\frames[i])
MaskImage im\frames[i], 255, 0, 255
Next
SetBuffer BackBuffer()
End Function
Function ClearScaled()
For im.image = Each image
For i = 1 To SCALE_DETAIL
FreeImage(im\frames[i])
Next
Next
End Function
;---------------------------------------------------------------------------------------------------;
;******************************** DEMO FUNCTIONS ***************************************************;
;---------------------------------------------------------------------------------------------------;
Function KeyInput()
If KeyDown(200)
ResizeTrees(1)
Else If KeyDown(208)
ResizeTrees(-1)
EndIf
End Function
Function ResizeTrees(inc)
im.image = First image
For t.tree = Each tree
go=0
If t\scale < SCALE_DETAIL And t\scale > 1 Then go =1
t\scale = t\scale +inc
If go = 1
t\image = im\frames[t\scale]
t\y = 240-(ImageHeight(t\image)/2)
EndIf
Next
End Function
Function DrawTrees()
For t.tree = Each tree
DrawImage t\image, t\x, t\y
Next
End Function
Function InitTrees()
;Make trees
im.image = First image
For i = 1 To 100
t.tree = New tree
t\scale = Rand(1, SCALE_DETAIL)
t\image = im\frames[t\scale]
t\x = Rand(0, 600)
t\y = 240-(ImageHeight(t\image)/2)
Next
;Sort trees by distance
a.tree = First tree
flag = True
While flag
flag = False
b.tree = Last tree
While a <> b
c.tree = Before b
If c = Null Then Exit
If b\scale < c\scale
Insert c After b
flag=True
Else
b=c
EndIf
Wend
a = After b
Wend
End Function
Function FPS()
If MilliSecs() > old_time+1000
old_time = MilliSecs()
fps=frame_count
frame_count=0
EndIf
Color 255, 255, 255
Text 0, 0, "FPS: "+fps
frame_count=frame_count+1
End Function And heres an image for the test program:
(http://i92.photobucket.com/albums/l15/mikegrundel/tree.png)
-
Thanks for posting these routines mike! K+
In the case of scaling you can do a bit better than this routine. Right now you have a divide per pixel which can be very slow. What you can do instead is called interpolation.
You know that dst_x only increases by 1 each pixel, so the src_x is easy to calculate, it would go
dst = 0 src = 0/image_size
dst = 1 src = 1/image_size
dst = 2 src = 2/image_size
dst = 3 src = 3/image_size
etc.
You can see that src is increasing by 1/image_size for each pixel, and you can take advantage of that.
inc_x# = 1/image_size
dst = 0 src = 0
dst = 1 src = 0+inc_x
dst = 2 src = 0+inc_x+inc_x
dst = 2 src = 0+inc_x+inc_x_inc_x
etc.
So for each pixel you just need to add inc_x to src_x instead of performing a divide.
You can do the same with the y. The only thing to remember is inc_x and src_x would need to be a float.
Cheers!
Jim
-
Thanks for the tips jim. TBH I wasn't really worried about the speed with the dividing as its all just pre-calc. But its good to know. Some sort of interpolation/pixel guessing/anti aliasing type thing would definitely be good though for cleaning up the images that are zoomed in on. I might work on that :)
-
It's definately worth working on and getting fast, you'll be surprised how useful a routine like that is.
-
I think the scaling is about as fast as you can get as its all pre-drawn, the prog just flicks through image handles. The bad part is it uses tons of RAM tho. As in: SCALE_DETAIL * the image size as a bitmap.
-
Thats pretty smart mate, 50 fps here.
Welldone :)