views:

70

answers:

1

Hi all,

how to project a lat/lon hotspot onto an 360x180 degree panorama image?
Using javascript?

Real data:
lat/lon in decimal degrees and altitude in meters:
Camera coordinates: 49.994249, 8.66539, 2
Hotspot coordinates: 49.994163, 8.665388, 2

Distance camera to hotspot in meters: 9.55
Compass bearing camera to hotspot in degrees (0-360): 170
Image direction: 130 degrees (x middle of image) Is this needed at all?
Horizon is y middle of image.

Image size width: 1024, height: 512 pixel

What I need is the javascript code to determine the x,y pixel image coordinate of the hotspot.
0 is top left corner.

Accuracy is of no importance. Distance will always be smaller than 100 meters.

Thanks,
Jan
janmartin AT diy-streetview DOT org

A: 

It looks like you have already done the hard part: converting the GPS coordinates into a relative bearing (and distance).

If the center of your 360° image points to 130° from North (assuming clockwise around the compass) and the bearing from the camera location and the hotspot is 170° from North, then it would appear that the hotspot is at 40° on your image, relative to the center of the image. And, since the image contains 360° and 1024px horizontally, then it would seem that the hotspot is located at 1024px / 360° * 40° = 114 px from the center of the image.

And since the camera and the hotspot are both at the same altitude, the relative pitch is zero.

Putting this together, you get the coordinates: 512 + 114, 256 + 0 = coordinates: 626, 256.

If the altitude of the hotspot were not the same as the camera, then you'd have to compute a pitch using some simple trig.:

First let us assume that ground distance = the distance at ground level between the camera location and the hotspot location. This will be the same regardless of the altitude of each.

So, your pitch would be: atan [ (hotspot altitude - camera altitude) / ground distance ].

For example, if you had a ground distance of 100m and the hotspot were at 10.75m with the camera still at 2m altitude, then you'd compute your pitch as:

pitch = atan [ (10.75m - 2m) / 100m ] = atan ( 8.75m / 100m ) = atan (0.0875) = 5°

To plot this on your panorama: 512px / 180° * 5° = 14px higher than the middle. Since the middle is at 256px and the top-left of the image is 0,0, then we'd subtract 14px from 256 to arrive at 242px.

Putting this all together into Javascript as you requested:

// We'll use degrees, but this would be simpler if
// everything were computed in radians, since that
// is how the Math methods work.
function getRelativePitch(cameraAlt, hsAlt, groundDistance)
{
   var degPerRad = 180 / Math.PI;

   if (groundDistance == 0) { return 0.0; } // fringe case

   var rad = Math.atan( ( hsAlt - cameraAlt) / groundDistance );

   // Convert to degress
   return rad * degPerRad;
}

// Pretty simply this one.
function getRelativeHeading(cameraHeading, hsHeading)
{
   return hsHeading - cameraHeading;
}

var cameraHeading = 130; // degrees
var hotspotHeading = 170; // degrees
var cameraAltitude = 2; // meters
var hotspotAltitude = 10.75; // meters
var groundDistance = 100; // meters

var panoWidth = 1024; // pixels
var panoHeight = 512; // pixels

var panoRangeX = 360; // degrees
var panoRangeY = 180; // degrees

var relativeHeading = getRelativeHeading(cameraHeading, hotspotHeading);
var relativePitch   = getRelativePitch(cameraAltitude, hotspotAltitude, groundDistance);

// Now convert to pixels
var hotspotX = Math.round( panoWidth / 2 + panoWidth / panoRangeX * relativeHeading );
var hotspotY = Math.round( panoHeight / 2 - panoHeight / panoRangeY * relativePitch );

// Just in case we endup out of range
while (hotspotX < 0) { hotspotX += panoWidth; }
while (hotspotX > panoWidth) { hotspotX -= panoWidth; }

while (hotspotY < 0) { hotspotY += panoHeight; }
while (hotspotY > panoHeight) { hotspotY -= panoHeight; }

alert("Hotspot is at: " + hotspotX + ", " + hotspotY);

I hope this helps!

mkoistinen