Determine relative position from projected angles and distance

31 Views Asked by At

I'm trying to write a computer program that can determine the real-world position of an object based on an image, the position/orientation of the camera, and the distance between the camera and the object.

I am able to easily rotate from the camera's reference frame (with the camera at the origin and with no rotation) to the real-world position and vice-versa. What I am struggling with is how to convert the normalized 2D image coordinates and distance to the object (in 3D space) into a 3D vector coordinates.

What I know:

  1. Camera field of view (along the x axis) in radians
  2. Aspect ratio of the image
  3. The real-world liner distance between the camera and the object
  4. the normalized 2D coordinates of the (center) of the object in the image.
    • I'm not sure what the appropriate convention for this is, but I'm using (-1,-1) to indicate the top-left corner of the image, (1,1) to indicate the bottom-right of the image, and (0,0) to indicate the center.

Let's assume that I do not need to compensate for lens distortion (unless it is easy to do so).

In the following visualization, the camera would be at point H, looking towards point D. The object is at point A (which has some negative x value, and some positive value for both y and z).

enter image description here

1

There are 1 best solutions below

0
On

Figured it out...

I needed to express z, y, and z exclusively in terms of d (the diagonal), h (the projected angle on the x-z plane), and v (the projected angle on the y-z plane):

  • z = Sqrt(d^2 / (tan(v)^2 + tan(h)^2 + 1))
  • x = Sqrt(d^2 / (tan(v)^2 + tan(h)^2 + 1) * tan(v)^2))
  • y = Sqrt(d^2 / (tan(v)^2 + tan(h)^2 + 1) * tan(h)^2))

This could be simplified more, since all three functions share a few common terms, it makes the code easier to work with:

    private static Vector3 CalculateDimensions(double diagonal, double azimuth, double elevation)
    {
        //z = SQRT(SQ(HYP) / (SQ(tan(v)) + SQ(tan(h)) + 1))
        //y = SQRT(SQ(HYP) / (SQ(tan(v)) + SQ(tan(h)) + 1) * SQ(tan(v)))
        //x = SQRT(SQ(HYP) / (SQ(tan(v)) + SQ(tan(h)) + 1) * SQ(tan(h)))
        double diagnalSquared = Math.Pow(diagonal, 2);
        double tanAzimuthSquared = Math.Pow(Math.Tan(azimuth), 2); //h
        double tanElevationSquared = Math.Pow(Math.Tan(elevation), 2); //v
        double magnitude = tanElevationSquared + tanAzimuthSquared + 1;

        double z = Math.Sqrt(diagnalSquared / magnitude);
        double y = Math.Sqrt(diagnalSquared * tanElevationSquared / magnitude);
        double x = Math.Sqrt(diagnalSquared * tanAzimuthSquared / magnitude);

        if (elevation < 0)
        {
            y = -y;
        }
        if (azimuth < 0)
        {
            x = -x;
        }

        return new Vector3(x, y, z);
    }