English Amiga Board


Go Back   English Amiga Board > Coders > Coders. General

 
 
Thread Tools
Old 01 May 2007, 00:25   #1
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
C: Image rotation algorithm problem

I've written a small piece of code to rotate a 2D image. I loop through each pixel in the image and use the following to find the new values for x and y:
Code:
x2 = cos(angle) * x - sin(angle) * y;
y2 = sin(angle) * y - cos(angle) * x;
This kind of works, except the resulting image is badly skewed (squashed vertically). I thought this might be because of the conversion from doubles to ints for x2 and y2, but rounding them up produces the same results.

I've attached a small example below - original is on the left, "rotated" version on the right. Any ideas?
Attached Thumbnails
Click image for larger version

Name:	rot_example.png
Views:	1360
Size:	1.3 KB
ID:	13738  
TikTok is offline  
Old 01 May 2007, 00:33   #2
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
Well for one thing there's a sign error there, the second line should be plus, not minus. Also this will rotate around (0,0), if you want to rotate around the center you first have to translate the pixels so the center beoomes (0,0), then rotate, then translate back.
eLowar is offline  
Old 01 May 2007, 00:34   #3
thor
Registered User
 
thor's Avatar
 
Join Date: Mar 2006
Location: Germany
Posts: 899
y2 = sin(angle) * x + cos(angle) * y;

Quote:
Originally Posted by eLowar
Well for one thing there's a sign error there, the second line should be plus, not minus.
And sin/cos are wrong way round

Last edited by thor; 01 May 2007 at 00:40.
thor is offline  
Old 01 May 2007, 00:36   #4
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
While you're at it, you may also want to create a sort of lookup table for sin and cos, because the library functions are typically slow.

Edit: Hokay, don't want to get carried away, just a suggestion.

Edit 2: Whoops, thor is right of course, I missed that x and y were swapped.

Edit 3: Also to minimize computations, you might want to store intermediate values, like so:

Code:
coordinate_t wHalf = w / 2;   /* or shift by one for integer types */
coordinate_t hHalf = h / 2;
coordinate_t xt = x - wHalf;
coordinate_t yt = y - hHalf;
angle_t sinAngle = sin(angle);   /* or use a lookup table */
angle_t cosAngle = cos(angle);
x2 = (cosAngle * xt - sinAngle * yt) + wHalf;
y2 = (sinAngle * xt + cosAngle * yt) + hHalf;
xt and yt might actually be pointless, seeing as subtractions probably aren't very slow, but you definitely want to reduce sin/cos calls and divisions (unless you use integer coordinates and can shift instead).

Edit 4: Umm, w and h being the image's width and height of course.

Last edited by eLowar; 01 May 2007 at 01:11.
eLowar is offline  
Old 01 May 2007, 01:36   #5
girv
Mostly Harmless
 
girv's Avatar
 
Join Date: Aug 2004
Location: Northern Ireland
Posts: 1,109
Rather than map from original -> rotated, I believe the accepted wisdom in these things is that you get much, much better results if you go the other way round, ie: for every pixel in your new rotated shape determine which source pixel or pixels it came from.

Now don't you dare ask me how to do it I just remember reading that.
girv is offline  
Old 01 May 2007, 02:00   #6
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
That is most likely true, as that avoids gaps and in case of non-integer coordinates gives you a chance to interpolate. Err, I guess you'd just have to do the same thing the other way around?
eLowar is offline  
Old 01 May 2007, 09:22   #7
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
Thanks everyone for your help and suggestions. Even fixing the sign errors (oops) the results are not good. I'm pretty sure now that the skewed effect is because more than one source pixel ends up mapping to the same destination pixel, because of the rounding. As girv says it might be better to do things 'backwards', so I'll try that.
TikTok is offline  
Old 01 May 2007, 11:29   #8
Doc Mindie
In deep Trouble
 
Join Date: Sep 2004
Location: Manchester, Made in Norway
Age: 51
Posts: 841
I need to load up AMOS..... just to remind meself what I did "way back when" and such.... but I do believe I could produce the working (AMOS)code.... just hang out there for a few minutes... I mean, hours

:EDIT: Whoops, forgot that I've not touched it in years...

Last edited by Doc Mindie; 01 May 2007 at 12:30.
Doc Mindie is offline  
Old 01 May 2007, 13:40   #9
thor
Registered User
 
thor's Avatar
 
Join Date: Mar 2006
Location: Germany
Posts: 899
It all depends on how good you want the image and how complex it can be. You might read the rotation section at http://www.leptonica.com/local-sources.html and have a look at the C source there or look at image processing packages at sourceforge.
thor is offline  
Old 03 May 2007, 18:42   #10
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
Thanks thor - I looked at that site originally but could only understand the first simple example

I have actually given up for now and decided to temporarily rotate my images using a paint package instead
TikTok is offline  
Old 03 May 2007, 19:48   #11
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
Post simple example

Here's tested code for nearest match rotation:

Code:
/* assuming width and height are integers with the image's dimensions */

for(int x = 0; x < width; x++) {
	for(int y = 0; y < height; y++) {
		int hwidth = width / 2;
		int hheight = height / 2;
		
		int xt = x - hwidth;
		int yt = y - hheight;
		
		double sinma = sin(-angle);
		double cosma = cos(-angle);
		
		int xs = (int)round((cosma * xt - sinma * yt) + hwidth);
		int ys = (int)round((sinma * xt + cosma * yt) + hheight);

		if(xs >= 0 && xs < width && ys >= 0 && ys < height) {
			/* set target pixel (x,y) to color at (xs,ys) */
		} else {
			/* set target pixel (x,y) to some default background */
		}
	}
}
Substitute your own color setting code and your favorite datatypes. Please note that for the sake of being understandable this is not optimized in any way. (except storing values that are used more than once in variables)

Attached a demonstration with a 64x64 picture, rotated by 45 degrees with a black default background.
Attached Images
  

Last edited by eLowar; 03 May 2007 at 20:22. Reason: fixed tiny little mistake ;)
eLowar is offline  
Old 03 May 2007, 21:32   #12
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
Floppy disk more pictures

For a better idea of the "quality" this produces:
Attached Thumbnails
Click image for larger version

Name:	in.png
Views:	651
Size:	20.4 KB
ID:	13783   Click image for larger version

Name:	out015.png
Views:	616
Size:	39.1 KB
ID:	13784   Click image for larger version

Name:	out030.png
Views:	576
Size:	40.3 KB
ID:	13785   Click image for larger version

Name:	out060.png
Views:	550
Size:	39.7 KB
ID:	13786   Click image for larger version

Name:	out075.png
Views:	550
Size:	36.4 KB
ID:	13787  

Attached Files
File Type: zip out.zip (858.1 KB, 1198 views)

Last edited by eLowar; 03 May 2007 at 21:42.
eLowar is offline  
Old 04 May 2007, 15:34   #13
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
That looks pretty sweet eLowar, I'll work on it again tonight. Thanks
TikTok is offline  
Old 04 May 2007, 16:20   #14
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
By the way, that is working C++ code, not C code. Sorry, force of habit. But you should be able to make it work with a C compiler with minimal effort (just move the variable declarations to the beginning, etc.). It might even work just like that with C99.

Edit: <RANT>++x would be more efficient than x++, too, unless your compiler optimizes it away.</RANT>

Last edited by eLowar; 04 May 2007 at 16:26.
eLowar is offline  
Old 07 May 2007, 17:05   #15
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
Well, I got this working thanks to eLowar's code. The rotations are a little bit out (i.e. 180 degrees looks more like 178 degrees), but I guess that is due to the rounding, and I just compensated for it by rotating a bit more
TikTok is offline  
Old 07 May 2007, 17:16   #16
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
Hmm, must be. Look at my examples in out.zip above. The multiples of 90° all look perfect as far as I can tell.

Depending on what you're doing, you might want to write special cases for angles that are close to those, especially if you're only using integer angles anyway. Likewise, if you're only using integer angles and can spare the memory, you might want to compute the 360 values for cos and sin in advance, throw them in some array and then just read them from there, that should be a lot faster than computing them for every pixel--- (at this point I had one of those ouch-I'm-stupid experiences)

Speaking of which, my code is stupid.

Definitely pull this:
Code:
		double sinma = sin(-angle);
		double cosma = cos(-angle);
and this:
Code:
		int hwidth = width / 2;
		int hheight = height / 2;
out of the inner loop, that way you only have to compute the sines and cosines once per rotation, not once per pixel which is totally pointless.

*slaps self* sorry about that
eLowar is offline  
Old 07 May 2007, 19:57   #17
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
Doh, I missed that one myself too.
TikTok is offline  
Old 09 May 2007, 16:14   #18
eLowar
Citizen of Elthesh
 
eLowar's Avatar
 
Join Date: Sep 2003
Location: UK
Posts: 949
Hooooo If I may be nosy...

... what is it you're making anyways?
eLowar is offline  
Old 09 May 2007, 17:54   #19
Calgor
(Amigas && Amigos)++
 
Calgor's Avatar
 
Join Date: Sep 2005
Location: Anrea
Posts: 999
excellent stuff guys!
Calgor is offline  
Old 09 May 2007, 19:31   #20
TikTok
Registered User
 
TikTok's Avatar
 
Join Date: Jul 2001
Location: Malayasia
Age: 43
Posts: 657
Its a very basic game, just to help me learn C++ really. It will be a 'Scalextric' (slot cars) type overhead racing game (the first image posted above was the starting track piece).

I have actually gone off the idea a little bit since I started it, but I am a project person and I desperately need a project to keep me occupied My last 'project' was climbing mount Kilimanjaro with a group of my students, so now I am settling for something a bit more down to earth until something...crazier...comes along!
TikTok is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
cue image problem MrX_Cuci support.WinUAE 5 20 July 2013 16:17
Rotation matrix tolkien Coders. General 7 29 March 2013 10:32
Ziconix WHD problem with SPS image Ian support.Other 1 06 November 2011 11:58
2D Rotation problem rebb Coders. General 5 20 July 2009 16:21
WHDLoad problem with XPK packed disk image. oldpx support.Games 16 04 January 2005 22:11

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 00:53.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.10269 seconds with 16 queries