Sponsors of Wiimoteproject.com
IR Pens for Wiimote Whiteboard
Wiimote Project » Wiimote Projects » Wiimote Desktop VR/Head Tracking » Explanation of Source Code
Pages: [1]
  Print  
Author Topic: Explanation of Source Code  (Read 10131 times)
0 Members and 1 Guest are viewing this topic.
*
Karma: +0/-0
Posts: 6
Offline Offline
View Profile
« on: February 27, 2008, 12:00:13 AM »

Hi all,

Im pretty average at maths but there was one part of the code that I didnt understand and that is how the distance from the TV/Monitor is calculated.

I gathered that this part of the code was relied on:

Line 261:

double angle = Math.Acos(.5 / headDist)-Math.PI / 2;//angle of head to screen

Line 777:
headDist = movementScaling * (float)((dotDistanceInMM / 2) / Math.Tan(angle)) / screenHeightinMM;

If anyone could explain why it is 0.5 that is being divided and how it is calculated.

Thanks
Logged
*
Karma: +0/-0
Posts: 6
Offline Offline
View Profile
« Reply #1 on: February 27, 2008, 10:30:34 PM »

ok, sincere apologies to everyone thats not the code i needed help with its the wrong one >.<

Quote
                float angle = radiansPerPixel * pointDist / 2;
                //in units of screen hieght since the box is a unit cube and box hieght is 1
                headDist = movementScaling * (float)((dotDistanceInMM / 2) / Math.Tan(angle)) / screenHeightinMM;


                float avgX = (firstPoint.x + secondPoint.x) / 2.0f;
                float avgY = (firstPoint.y + secondPoint.y) / 2.0f;


                //should  calaculate based on distance

                headX = (float)(movementScaling *  Math.Sin(radiansPerPixel * (avgX - 512)) * headDist);

                relativeVerticalAngle = (avgY - 384) * radiansPerPixel;//relative angle to camera axis

                if(cameraIsAboveScreen)
                    headY = .5f+(float)(movementScaling * Math.Sin(relativeVerticalAngle + cameraVerticaleAngle)  *headDist);
                else
                    headY = -.5f + (float)(movementScaling * Math.Sin(relativeVerticalAngle + cameraVerticaleAngle) * headDist);
            }

the lines i need explained are highlighted

in the first line: why is it divided by 2? is it because the triangle that is formed is divided to make a right angle triangle?

the second line: what is the significance of dividing the dot distance with the Tangent of the angle retrieved?

in the third and fourth could someone just give me a general explanation of whats going on.

Thanks in advance.

Tarantula
Logged
*
Karma: +0/-0
Posts: 1
Offline Offline
View Profile
« Reply #2 on: April 22, 2008, 04:02:54 PM »

Your right about 1), and that leads into 2)



we know the actual length of the top side, as it dotDistanceInMM.
From the first line we know the angle (each pixel on the camera in the wiimote represents a set amount of angle).

This is a isoceles triangle, so dividing both by 2 gives us a right angle triangle, the white area in the picture. Pythagorean rules for right angle triangles define
Tan(angle) = opposite / adjacent

or in our variable terms
Tan(angle) = (dotDistanceInMM/2) / headDist
adjacent is what we want to find (headDist), so rearranging:
headDist = (dotDistanceInMM/2) / Tan(angle)

the other 2 terms (confusingly 1 at the start and 1 at the end) are just scaling factors, the first allows use to exaggerate all movement if we want to, and the second normalises by the size of the screen. Not totally sure about this bit, it means if you have a large screen everything seems bigger, bit if you have your head in the same place you see the same thing (as opposed to be being able to see more)

3) combines a few operations into 1 line of code. So working outwards from the middle:

avgX is the midpoint of the head from the far left of the camera
avg-512 is the midpoint of the head, with 0 being right in the centre of the screen. -ve 1 side and +ve the other.

radiansPerPixel * (avgX - 512) = the angle of the centre of the head from the centerline of the camera, so again -ve angle is on 1 side and +ve on the other.

Now we construct a very similar triangle to last time:

where we know headDist, and angle, and want to headX.

Sin(angle) = opposite / hypotenuse

Sin(radiansPerPixel * (avgX - 512)) = headX / headDist

rearranging:
headX = Sin(radiansPerPixel * (avgX - 512)) * headDist

again add in the movementScaling term to allow exaggeration.

headY requires a bit more, as we dont assume the camera is horizontal (but we did assume it was perpedicular to the screen for headX).Also it needs to take into account being above or below the screen (again for X we assumed the wiimote was in the middle of the screen).

so we add on cameraVerticaleAngle (nicely misspelt).

and then add or subtract 0.5 depending on where the camera is.

Why 0.5? because ever since we "/screenHeightinMM" in 2) we have been work in terms of screen heights. so headX would say "head is 1 screen height left" and headY would say "head is 0.7 screen heights up". So if the camera is half a screen height above the TV we need to subtract 0.5 to move to the middle of the TV.

so From this we have an X,Y,Z (headX,headY,headDist) co-ordinate of the head relative to the dead centre of the TV screen.
Logged
*
Karma: +0/-0
Posts: 37
Offline Offline
View Profile
« Reply #3 on: January 27, 2009, 03:28:34 PM »

Hi!

To Wilco:
Thanks man! That explanation really helped!

But I have querstion too. If you have the sketch of Horizontal and Vertical Position in front of you, would see
that headDist is different in two positions but why they are used as being similar! I guessit is a mistake unless I am ignoring something! The relation is as below:

headDist_Y^2=headDist_X^2+DheadY^2        or similarly

tan(teta_headY)=DheadY/headDist_Y         where headDist_Y is not what was previously calculated as headDist_X;


Can you help me?!
« Last Edit: January 27, 2009, 03:30:28 PM by yashardel » Logged
*
Karma: +0/-0
Posts: 37
Offline Offline
View Profile
« Reply #4 on: January 27, 2009, 03:38:25 PM »

By the way, when the camera is above the acreen 0.5f is added not subtracted!?You know why!?

if(cameraIsAboveScreen)
            headY = .5f+(float)(movementScaling * Math.Sin(relativeVerticalAngle + cameraVerticaleAngle)  *headDist);
Logged
*
Karma: +0/-0
Posts: 3
Offline Offline
View Profile
« Reply #5 on: February 26, 2009, 07:36:41 PM »

Thanks from me too for that, helped a lot.

I have a question, early in that maths Johnny calculates the distance between the two dots as follows (code is c++ and using a different library so will be different to Johnny's but the maths is the same):

float dx = firstPoint->GetX() - secondPoint->GetX();
      float dy = firstPoint->GetY() - secondPoint->GetY();
      float pointDist = (float)sqrt(dx * dx + dy * dy);

This gives us the distance between the two points.

Why then, do we also need to manually give the width of our sensor bar in the form of dotDistanceInMM?

In addition, why is avgX - 512 the midpoint of the head?  Is it because the camera is 1024 wide?

Cheers
« Last Edit: February 26, 2009, 07:48:14 PM by ministe2003 » Logged
*
Karma: +0/-0
Posts: 3
Offline Offline
View Profile
« Reply #6 on: March 05, 2009, 07:10:36 PM »

In addition, in your diagrams you show headDist as at one stage being the Adjacent and in the next, the Hypotenuse... this isn't right surely?  The value of headDist isn't changed between these two diagrams so how can the one value possibly be used to represent two different length sides?

Thanks
Logged
*
Karma: +0/-0
Posts: 5
Offline Offline
View Profile Email
« Reply #7 on: May 02, 2009, 09:11:24 AM »

Cheers for the explanation, cleared things up a bit. I actually went ahead and did things differently and worked out the head distance based on the fact you know how wide the sensor bar is in reality, and you know how wide it looks to the wiimote camera, so from that you can work out how far away it is, using the inverse of 3D projection.

Whereas normally you would have:
Code:
point2D.x = (znear*point3D.x)/point3D.z;
point2D.y = (znear*point3D.y)/point3D.z;
Solving for z gives:
Code:
z = (znear*x3D)/x2D;
// or in this case
z = (znear*widthReal)/widthOnCamera;
It actually didn't occur to me to do the radians per pixel, thinking about it that's a much more logical idea.. There's something about messing with 3D to 2D projections (and vice versa) which instantly makes me start picturing a buttload of right angle triangles!
Logged
*
Karma: +0/-0
Posts: 1
Offline Offline
View Profile Email
« Reply #8 on: July 24, 2010, 12:28:31 AM »

hey people Smiley
I'm sorry that I'm taking this old topic up again.
But I still don't get this:

Code:
                if(cameraIsAboveScreen)
                    headY = .5f+(float)(movementScaling * Math.Sin(relativeVerticalAngle + cameraVerticaleAngle)  *headDist);
                else
                    headY = -.5f + (float)(movementScaling * Math.Sin(relativeVerticalAngle + cameraVerticaleAngle) * headDist);
            }

Quote
and then add or subtract 0.5 depending on where the camera is.

Why 0.5? because ever since we "/screenHeightinMM" in 2) we have been work in terms of screen heights. so headX would say "head is 1 screen height left" and headY would say "head is 0.7 screen heights up". So if the camera is half a screen height above the TV we need to subtract 0.5 to move to the middle of the TV.

But the opposite is done: if the camera is above screen 0.5 is added. Why this? I'd be very happy if someone could explain that to me Wink

Greets
Logged
Pages: [1]
  Print  
 
Jump to:  

Clicky Web Analytics