Morph one image into another?

BlitzMax Forums/BlitzMax Programming/Morph one image into another?

Does anyone have a function to smoothly morph one image into another? Kind of like the terminator but not turning silver?

I need it to take into account a passed scale and color along with the original image. Images also have a single background color.

I need to draw the image as it morphs ideally at 35 FPS and it should take 1 or 2 seconds and not lag my game too much. Images size only about 30x50

Thanks

.

I would suggest you get a morphing program, freeware or something and prerender the stuff?

Morphing based on to operations:
Alphablending and "Morphing"

Alphablending is clear and the morphing is based on a net of triangles. You define significant points(like eyes, nose, corners of the mouth, brows etc.) and your program should compute around these points a net of triangles. These defined points have to set in start and end image. So you can interpolate between start and end positions of these points. The stretching and alphablending making the known morphin effect.

The hardest part is, to compute the net of triangles based on the given points.

cu olli

You can try simply drawing both images and slowly increase the alpha on one and decrease the alpha on the other.
The alternative is to pre-morph BUT that's either a lot of
frames or impossible with large number of from/to morphs.
Not sure what effect you are really after but I thought about changing image1 to a single colour using code from here then expanding it into and ellipse before shrinking it to the new images size, displaying the new images as a single colour then fade to normal colours.

Yah you'll need your own textured polygon routine for each part of the grid.

You start out with either a regular # grid or one that you've positioned some points to align with certain features, then you are basically interpolating from the position of each point to its position in the destination image - which may or may not be a modified grid. You just need to figure out how far away the two points are in X and Y and then you need what is basically a `line draw` routine without the drawing part - look at the code archives at my integer line draw bresenham code. You step along the line for each frame - and you do so in total steps/length of line sections.

Thanks for the suggestions I should have realized I needed it dynamic, I can't really prerender becuase there are so many images that can morph to eachother. I thought this would be easier.

I just made each pixel an object and had each one move to a random target position of the new image. But ofcourse it looks like sand now. Any ideas on how to make it look more like goo?
Strict
Graphics 555,555

Local i1:timage,i2:timage
i1=CreateImage(50,50)
i2=CreateImage(50,50)

SetColor 0,0,255
DrawOval 0,0,40,50
GrabImage i1,0,0
Cls
SetColor 255,100,0
DrawRect 0,30,50,50
GrabImage i2,0,0
Cls

Local m:tmorph
m=tmorph.make(i1,i2)


Local tog
Repeat
	If m.update() Then
		If tog Then
			m=tmorph.make(i1,i2)
		Else
			m=tmorph.make(i2,i1)
		EndIf
		tog=Not tog
	EndIf
	
	m.draw(200,200)
	
	SetColor 255,255,255
	DrawImage i1,0,0
	DrawImage i2,100,0

	Flip
	Cls
	If KeyHit(key_escape) Then End
Forever


Type TMorph
	Field Loops:Int=0
	Field Image1:timage
	Field Image2:timage
	Field array1:tmorphpixel[,]
	Field array2:Int[,]
	
	Function Make:tmorph(image1:timage, image2:timage)
		Local morph:tmorph
		
		morph=New tmorph
		
		morph.image1=image1
		morph.image2=image2
		
		morph.setup()
		
		Return morph
	EndFunction
	
	
	Method Setup()
		Local x,y,c
		Local pixmap:TPixmap
		
		
		'store pixel data of new image
		array2=New Int[image2.width, image2.height]
		
		pixmap=LockImage(image2)
		For y=0 Until image2.height
			For x=0 Until image2.width
				c=ReadPixel(pixmap,x,y) & $FFFFFF
				If c<>$FF00FF Then
					array2[x,y]=c
				EndIf
			Next
		Next
		UnlockImage image2
		
		
		'make pixs from old image
		Local x2,y2
		Local pix:tmorphpixel
		array1=New tmorphpixel[image1.width, image1.height]
		
		pixmap=LockImage(image1)
		For y=0 Until image1.height
			For x=0 Until image1.width
				c=ReadPixel(pixmap,x,y) & $FFFFFF
				If c<>0 Then
					pix=New tmorphpixel
					array1[x,y]=pix
					pix.x=x
					pix.y=y
					pix.b=c & $FF
					pix.g=c Shr 8 & $FF
					pix.r=c Shr 16 & $FF
					'Print pix.r+","+pix.g+","+pix.b+","+c
					
					'give the pix a target pixel
					Repeat
						x2=Rand(0, image2.width-1)
						y2=Rand(0, image2.height-1)
						If array2[x2, y2] <> 0 Then Exit
					Forever
					pix.targetx=x2
					pix.targety=y2
					c=array2[x2,y2]
					pix.targetb=c & $FF
					pix.targetg=c Shr 8 & $FF
					pix.targetr=c Shr 16 & $FF
				EndIf
			Next
		Next
		UnlockImage image1
		
	EndMethod
	
	
	Method Update()
		loops:+1
		If loops>=70 Then Return 1
		
		
		Local x,y
		Local pix:tmorphpixel
		
		For y=0 Until image1.height
			For x=0 Until image1.width
				pix=array1[x,y]
				If pix<>Null Then
					movetovar(pix.r, pix.targetr, 3)
					movetovar(pix.g, pix.targetg, 3)
					movetovar(pix.b, pix.targetb, 3)
					
					pix.speedx:+ Sgn(pix.targetx-pix.x)*.15
					pix.speedy:+ Sgn(pix.targety-pix.y)*.15
					'pix.speedx = Sgn(pix.targetx-pix.x)*.8
					'pix.speedy = Sgn(pix.targety-pix.y)*.8
					
					movetovarfloat(pix.speedx,0 , (1-1/loops)*.1)
					movetovarfloat(pix.speedy,0 , (1-1/loops)*.1)
					
					pix.x:+ pix.speedx
					pix.y:+ pix.speedy
				EndIf
			Next
		Next
		
	EndMethod
	
	Method Draw(pixelx,pixely)
		Local x,y
		Local pix:tmorphpixel
		
		For y=0 Until image1.height
			For x=0 Until image1.width
				pix=array1[x,y]
				If pix<>Null Then
					SetColor pix.r, pix.g, pix.b
					DrawRect pixelx+pix.x, pixely+pix.y, 1,1
				EndIf
			Next
		Next
	EndMethod
	
	
	Function MoveToVarFloat(Number:Float Var,Target:Float,Speed:Float)
		If Abs(number-target)<=speed Then
			number=target
			Return
		EndIf
		If number<target Then
			number:+speed
		Else
			number:-speed
		EndIf
	EndFunction
	
	Function MoveToVar(Number:Int Var, Target:Int, Speed:Int)
		If Abs(number-target)<=speed Then
			number=target
			Return
		EndIf
		If number<target Then
			number:+speed
		Else
			number:-speed
		EndIf
	EndFunction
	
EndType

Type TMorphPixel
	Field x:Float,y:Float
	Field targetx,targety
	Field r,g,b
	Field targetr,targetg,targetb
	Field speedx:Float, speedy:Float
EndType



How about :
A bounding box utility where you specify, say, 6 points around each image which would morph and save them in a file to be read in when the image is loaded.
The morph then reads the source position and plots a course to the target position drawing them with SetUV.
It *might* be possible to dynamically find these points using either hull algo or simple line to point collisions.

just done this.... its not pefect.
I'll post up some code when I'm happy with it.
(its all real time morphing)



output is a lot better now


going to have to finalise the morph file format and then I'll release it

PantsOn: that looks good, does it also work with a single background color and images that are very different?

like this to this

No I'm not doing a frog-to-prince game! hmmm actually I could add that..


Tonyg: That sounds hard anyone wanna code it for me?:)

This seems a lot harder than I thought and I don't want to spend more time coding on it, its okay I'll just use the code I posted, thanks everyone for the help.

it can do any shape you want to any shape
(I've not tested it on large images)

but here you go...

(excuse the white background, but it will morph the alpha channel in realtime as well)

Before i release it, I'm going to make a gui for it.
I'll probably do that tomorrow.

wow that looks good!

sorry for the delay... the editor is taking longer than expected.
The gfx lib took 2 hours to write, the editor has taken a good 8 hours and still not finished. Typical ;-)

I'm going to make a very basic editor tonight (chop down what I got) and realease this baby ASAP.

With this kind of thing, positioning the grid well is harf the challenge, besides the morphing routine itself. That strip by PantsOn is a little off because you see the feet of the frog seeming to only fade out in a cross-fade and not actually move into the shape of the character. It's getting things to move well that is the key. But this look like it's coming along pretty well.

It seems to use alpha and scale to make the morph which can look very good and is a good, simple solution if acceptable (it's what I would use).
'Real' morph is going to be more difficult.

it uses crossfading while moving a mesh... certainly not perfect, but quite fast.

It does look better the more detailed the mesh. currently I'm using a 4*4 mesh. The enegine allows any size mesh.

I wouldn't know where to start to do propper morphing..
didn't DpaintIV use 'propper' morphing in its day and not cross fade?

I'll do some research. ;-)

module released here
http://www.blitzbasic.co.nz/Community/posts.php?topic=71043