Image Rotation routines for 24/32 bit with optional AA

Share your advanced PureBasic knowledge/code with the community.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Image Rotation routines for 24/32 bit with optional AA

Post by djes »

Badly, it's not my own routine, even if I optimised it, and I really have no time by now... But yours "does the job", and is clean :)
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

Optimized a little for speed.

1) Splitted the code and macros for 24 / 32 bit to remove the select/case branch (2% gain)

2) Removed the clipping test (RGB_Clamp macro) using a little trick (the - 0.000005 in the code) to eliminate the rounding problems who caused sometimes the overflow/underflow in the 0/255 range. This way a lot of if were removed (around 1% gain probably less).

3) Eliminated the copy of the data from the image to the structure in the main loop. It wasn't needed. My bad. Now I simply move a pointer in memory and read the data directly without copy it to the temp structure until the moment I need to write it to the destination (changed the ReadPixel?? macro). This is where the gain is (big error, big gain I guess). 10% maybe a little more.

So, at the end should be around 15% faster for the heavier scenario (32 bit and antialias enabled).

Hope I don't broke something in the process, but it seem working !

Bye!
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Image Rotation routines for 24/32 bit with optional AA

Post by djes »

Nice code, clean and nice to read! Just for info, to optimise (not useful in my opinion as it's not designed to be realtime), you could use lines routines as x and y have a linear progression. Then you only have to compute the four source corners (not the dest). The second optimisation (harder), is to have a linear progression along the memory, as you could somehow add the x and y components of the source image. The third optimisation is to transform the source image to something more manageable by the processor. All of this could benefit from assembler, but will be not as portable.
However, as dest is memory and fully linear, you can speed up things a bit by removing some computations in the main loop, as in this topic : http://www.purebasic.fr/english/viewtop ... 13&t=39036

But honestly I prefer this code like it is now, as it is convenient ;)
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

Your points are very interesting djes! I'm not quite sure how to implement them, especially the first one.
djes wrote:you could use lines routines as x and y have a linear progression. Then you only have to compute the four source corners (not the dest).

Probably I don't have the concept very clear in my mind and should I give it some thought... a little over my head I believe :)

If you have time and the will, could you explain a little more in detail the first suggestion you make ?

In any case thank you and thank you for the link too, I'll read it this afternoon!


EDIT: I lied, I din't resist and read it now!
AHHH! I see what you mean, yes I thought about that but I skipped it because it would have meant to loose my nice ReadPixel WritePixel macros and have them diluted along the main loop. It will be faster (very little I think) but I will be less easy to read and to derive maybe other routines from the same code. Well it's often that way when optimize for speed, you loose something else. But I understand your point. Maybe I'll try it just for fun!
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Image Rotation routines for 24/32 bit with optional AA

Post by djes »

In any case, keep your original code :)
User avatar
Le Soldat Inconnu
Enthusiast
Enthusiast
Posts: 306
Joined: Wed Jul 09, 2003 11:33 am
Location: France

Re: Image Rotation routines for 24/32 bit with optional AA

Post by Le Soldat Inconnu »

hi,

i do code to rotate image with AA

i just adapt for alpha channel

so let go :)

Code: Select all

ProcedureDLL.l RotateImageEx2(ImageID, Angle.f, Mode.l) ; Rotation d'une image d'un angle en °
	Protected bmi.BITMAPINFO, bmi2.BITMAPINFO, hdc.l, NewImageID, Mem, n, nn, bm.BITMAP
	
	Angle = Angle * #PI / 180 ; On convertit en radian
	
	Cos.f = Cos(Angle)
	Sin.f = Sin(Angle)
	
	CouleurFond = 0
	
	GetObject_(ImageID, SizeOf(BITMAP), @bm.BITMAP)
	
	bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
	bmi\bmiHeader\biWidth = bm\bmWidth
	bmi\bmiHeader\biHeight = bm\bmHeight
	bmi\bmiHeader\biPlanes = 1
	bmi\bmiHeader\biBitCount = 32
	
	bmi2\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
	Select Mode
		Case 1
			bmi2\bmiHeader\biWidth = bm\bmWidth
			bmi2\bmiHeader\biHeight = bm\bmHeight
		Case 2
			bmi2\bmiHeader\biWidth = Round(Sqr(bm\bmWidth * bm\bmWidth + bm\bmHeight * bm\bmHeight), 1)
			bmi2\bmiHeader\biHeight = bmi2\bmiHeader\biWidth
		Default
			bmi2\bmiHeader\biWidth = Round(bm\bmWidth * Abs(Cos) + bm\bmHeight * Abs(Sin), 1)
			bmi2\bmiHeader\biHeight = Round(bm\bmHeight * Abs(Cos) + bm\bmWidth * Abs(Sin), 1)
	EndSelect
	bmi2\bmiHeader\biPlanes = 1
	bmi2\bmiHeader\biBitCount = 32
	
	Mem = AllocateMemory(bm\bmWidth * bm\bmHeight * 4)
	If Mem
		Mem2 = AllocateMemory(bmi2\bmiHeader\biWidth * bmi2\bmiHeader\biHeight * 4)
		If Mem2
			
			hdc = CreateCompatibleDC_(GetDC_(ImageID))
			If hdc
				GetDIBits_(hdc, ImageID, 0, bm\bmHeight, Mem, @bmi, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
				DeleteDC_(hdc)
			EndIf
			
			CX1 = bm\bmWidth - 1
			CY1 = bm\bmHeight - 1
			CX2 = bmi2\bmiHeader\biWidth - 1
			CY2 = bmi2\bmiHeader\biHeight - 1
			
			Mem01 = Mem + bm\bmWidth * 4
			Mem10 = Mem + 4
			Mem11 = Mem01 + 4
			
			Mem2Temp = Mem2
			
			For nn = 0 To CY2
				y1b.l = nn * 2 - CY2
				Temp1.f = CX1 - y1b * Sin
				Temp2.f = CY1 + y1b * Cos
				For n = 0 To CX2
					x1b.l = n * 2 - CX2
					
					x1.f = (Temp1 + x1b * Cos) / 2
					y1.f = (Temp2 + x1b * Sin) / 2
					
					x2.l = x1
					y2.l = y1
					
					If x1 < x2
						DEC x2
					EndIf
					If y1 < y2
						DEC y2
					EndIf
					
					x2b = x2 + 1
					y2b = y2 + 1
					
					If x2b >= 0 And x2 <= CX1 And y2b >= 0 And y2 <= CY1 ; On filtre si on est completement en dehors de l'image
						
						fx.f = x1 - x2
						fy.f = y1 - y2
						f00.f = (1 - fx) * (1 - fy)
						f01.f = (1 - fx) * fy
						f10.f = fx * (1 - fy)
						f11.f = fx * fy
						
						MemTemp = (x2 + y2 * bm\bmWidth) * 4
						
						If x2 >= 0 And x2 <= CX1
							If y2 >= 0 And y2 <= CY1
								c00 = PeekL(Mem + MemTemp)
							Else
								c00 = 0
							EndIf
							If y2b >= 0 And y2b <= CY1
								c01 = PeekL(Mem01 + MemTemp)
							Else
								c01 = 0
							EndIf
						Else
							c00 = 0
							c01 = 0
						EndIf
						If x2b >= 0 And x2b <= CX1
							If y2 >= 0 And y2 <= CY1
								c10 = PeekL(Mem10 + MemTemp)
							Else
								c10 = 0
							EndIf
							If y2b >= 0 And y2b <= CY1
								c11 = PeekL(Mem11 + MemTemp)
							Else
								c11 = 0
							EndIf
						Else
							c10 = 0
							c11 = 0
						EndIf
						
						Channel00 = c00 >> 24 & $FF
						Channel01 = c01 >> 24 & $FF
						Channel10 = c10 >> 24 & $FF
						Channel11 = c11 >> 24 & $FF
						Alpha = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
						Channel00 = c00 >> 16 & $FF
						Channel01 = c01 >> 16 & $FF
						Channel10 = c10 >> 16 & $FF
						Channel11 = c11 >> 16 & $FF
						Rouge = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
						Channel00 = c00 >> 8 & $FF
						Channel01 = c01 >> 8 & $FF
						Channel10 = c10 >> 8 & $FF
						Channel11 = c11 >> 8 & $FF
						Vert = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
						Channel00 = c00 & $FF
						Channel01 = c01 & $FF
						Channel10 = c10 & $FF
						Channel11 = c11 & $FF
						Bleu = Channel00 * f00 + Channel01 * f01 + Channel10 * f10 + Channel11 * f11
						
						PokeL(Mem2Temp, Rouge | Vert << 8 | Bleu << 16 | Alpha << 24)
						
					Else
						PokeL(Mem2Temp, 0)
					EndIf
					
					Mem2Temp + 4
					
				Next
			Next
			
			; On crée la nouvelle image
			NewImageID = CreateImage(#PB_Any, bmi2\bmiHeader\biWidth, bmi2\bmiHeader\biHeight, 32)
			hdc = CreateCompatibleDC_(GetDC_(ImageID(NewImageID)))
			If hdc
				SetDIBits_(hdc, ImageID(NewImageID), 0, bmi2\bmiHeader\biHeight, Mem2, @bmi2, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
				DeleteDC_(hdc)
			EndIf
			
			FreeMemory(Mem2)
		EndIf
		FreeMemory(Mem)
	EndIf
	
	ProcedureReturn NewImageID
EndProcedure


;- ----------------------------------------
;- Test  d'affichage d'image avec rotation
; On dessine une image

ImageNormale = CreateImage(#PB_Any, 80, 100, 32)
StartDrawing(ImageOutput(ImageNormale))
	DrawingMode(#PB_2DDrawing_AlphaChannel)
	Box(0, 0, 80, 100, $00000000)
	DrawingMode(#PB_2DDrawing_Gradient | #PB_2DDrawing_AlphaBlend)
	LinearGradient(0, 0, 80, 100)
	GradientColor(0.0, $00000000)
	GradientColor(1.0, $FF000000)
	Box(0, 0, 80, 100)
	DrawingMode(#PB_2DDrawing_AlphaBlend)
	Box(5, 5, 35, 45, $B00000FF)
	Box(40, 5, 35, 45, $FF00FF00)
	Box(5, 50, 35, 45, $FFFF0000)
	Box(40, 50, 35, 45, $80FFFFFF)
StopDrawing()

; Création de la fenêtre et de la GadgetList
If OpenWindow(0, 0, 0, 350, 400, "Effect - Rotation d'image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget) = 0
	End
EndIf

Angle.f = 30
Mode = 0
ImageRotation = RotateImageEx2(ImageID(ImageNormale), Angle, Mode)

TextGadget(#PB_Any, 10, 10, 100, 15, "Image normale")
ImageGadget(#PB_Any, 10, 25, 0, 0, ImageID(ImageNormale))

RotationTexte = TextGadget(#PB_Any, 10, 200, 100, 15, "Rotation de 30°")
Rotation = ImageGadget(#PB_Any, 10, 215, 0, 0, ImageID(ImageRotation))
RotationTemps = TextGadget(#PB_Any, 180, 270, 170, 15, "")

TextGadget(#PB_Any, 180, 200, 100, 15, "Mode :")
OptionGadget(0, 180, 215, 170, 15, "normal")
OptionGadget(1, 180, 230, 170, 15, "sans redimensionnement")
OptionGadget(2, 180, 245, 170, 15, "avec redimensionnement fixe")
SetGadgetState(0, 1)

AddWindowTimer(0, 1, 200)

Repeat
	Event = WaitWindowEvent()
	
	If Event = #PB_Event_Timer
		If EventTimer() = 1
			Angle + 1
			If Angle = 360
				Angle = 0
			EndIf
			Temps1 = ElapsedMilliseconds()
			For n = 1 To 100
				FreeImage(ImageRotation)
				ImageRotation = RotateImageEx2(ImageID(ImageNormale), Angle, Mode)
			Next
			Temps2 = ElapsedMilliseconds()
			SetGadgetState(Rotation, ImageID(ImageRotation))
			SetGadgetText(RotationTexte, "Rotation de " + Str(Angle) + "°")
			SetGadgetText(RotationTemps, StrF((Temps2 - Temps1) / 100, 2) + "ms")
			
		EndIf
	ElseIf Event = #PB_Event_Gadget
		Select EventGadget()
			Case 0
				Mode = 0
			Case 1
				Mode = 1
			Case 2
				Mode = 2
		EndSelect
	EndIf
	
Until Event = #PB_Event_CloseWindow

End

Full librairie is here
http://www.lsi-dev.com/index.php?mod=do ... erid&id=40

Image symetry, rotation, and some effect about color
LSI
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

Thanks luis, great code!

The only thing I dislike is the heavy line count. The code I'm using right now has about 100 lines and fits into one procedure.
But I think I have to accept this for AA, alpha support and non rectangle rotation. ;)
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

c4s wrote:The code I'm using right now has about 100 lines and fits into one procedure.
But I think I have to accept this for AA, alpha support and non rectangle rotation. ;)
Well, if with "non rectangle rotation" you mean "free angle rotation" (I'm not sure) you can see there are a couple of routines included to do 90 degrees rotations and flipping/mirroring too. They are also obviously faster than the generic one. If you need only a subset of what this one does you can trim it down (that's the good thing of having the source !).

Thanks for the thanks, they are always appreciated!
"Have you tried turning it off and on again ?"
A little PureBasic review
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

luis wrote:Well, if with "non rectangle rotation" you mean "free angle rotation" (I'm not sure) you can see there are a couple of routines included to do 90 degrees rotations and flipping/mirroring too. They are also obviously faster than the generic one. If you need only a subset of what this one does you can trim it down (that's the good thing of having the source !).

Thanks for the thanks, they are always appreciated!
Sorry, I meant the rectangular rotation (90, 180, 270).
You are right. I can pick out the procedures I need so when I would remove the comments etc. the same line count will come up and it's then even cross-platform and supports alpha and retains the depth (in contrast to the code I used).

Now when I realized this your code is even better!

Maybe you should add a small note in the first post about having this only-rectangular-rotation-procedure thing?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

After playing a bit with the code, taking out the things I need etc. I found out that I could need handling of images with lower depth like 16 bit.
Is it possible to just modifiy the CopyPixelXX(), ReadPixelXX(), WritePixelXX() procedures to support this or are there higher restrictions?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

It should work without modifications if I'm not mistaken... the real difference it's between 32 bit (rgb + alpha) and 24 bit (rgb without alpha).

The 24 bit routines should work for 16 bits also. I should try but I'm reasonably sure.
"Have you tried turning it off and on again ?"
A little PureBasic review
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Image Rotation routines for 24/32 bit with optional AA

Post by c4s »

luis wrote:The 24 bit routines should work for 16 bits also. I should try but I'm reasonably sure.
Yes, you are right. Seems to work. But I forgot that PureBasic can't save in the "correct" bitrate, right?

Note, I just found a nasty memory leak or at least this behavior wasn't clear for me: The source image still exists after the modification!
To fix it I just added FreeImage(nSrcImage) after AllocateImageData(nSrcImage, @iBufferPitchSrc).


Anyway, thanks again for your great code and help. :)
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Image Rotation routines for 24/32 bit with optional AA

Post by luis »

c4s wrote: Yes, you are right. Seems to work. But I forgot that PureBasic can't save in the "correct" bitrate, right?
Bitdepths for loading, saving and catchimage are not particulary clear, at least to me.
The best thing is to try and check the results I'm afraid.

See this bugreport for example:

http://www.purebasic.fr/english/viewtop ... 13#p303913
c4s wrote: Note, I just found a nasty memory leak or at least this behavior wasn't clear for me: The source image still exists after the modification!
It's by design. You get a new image rotated, but the original is not deleted. You could have still some very good use for it for what I know.

That's why in the examples I wrote there is a FreeImage() for that. The intention was to make that clear, but maybe I should have wrote it explicitly. Well, I'm saying that here and now!
c4s wrote: Anyway, thanks again for your great code and help. :)
No problem :)
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
oryaaaaa
Addict
Addict
Posts: 825
Joined: Mon Jan 12, 2004 11:40 pm
Location: Okazaki, JAPAN

Re: Image Rotation routines for 24/32 bit with optional AA

Post by oryaaaaa »

Thank you very much. :D
ozzie
Enthusiast
Enthusiast
Posts: 443
Joined: Sun Apr 06, 2008 12:54 pm
Location: Brisbane, Qld, Australia
Contact:

Re: Image Rotation routines for 24/32 bit with optional AA

Post by ozzie »

Many thanks, luis - just what I need.
Post Reply