My team’s robot has a high goal shooter on a turntable. Using our vision system, I need to figure out how far off-target the shooter is in degrees. I’ve been working on this for most of today without much luck.

Pixel displacement should be strictly proportional to angular error, since the camera is effectively a point. To convince yourself of this, draw a picture of the shooter and the target (top view, camera at the origin).

Figure out the lateral FOV of the camera in degrees, and calculate proportional to that using the known width of the image in pixels.

If your camera is mounted solidly then you should be able to interpolate the offset angle of your shooter by using the first option (how many pixels away from the middle the goal is). This isn’t necessarily the best way to solve the problem but it works and it’s really easy. Is that all you’re asking?

No. That function isn’t what I need because it doesn’t return an angle that can be plugged into the turntable. The program I’m supposed to write should be able to look at an image and figure out “Alright, turntable. You need to turn 45 degrees if you want to be on-target.”

If we look at this drawing from an earlier post, both lines (which represent pixel offsets) are 100px long. With the function from before, both would return the same angle offset since the function doesn’t account for distance away from the target.

Distance away from the target doesn’t matter, that’s precisely why you’re measuring in angle (a dimensionless quantity) and not in distance.

Imagine the camera at the origin, pointing in the +y direction. Place your target off to the side somewhere. How far off-center your target will appear in pixels is proportional to the angle between the line from the origin to the target and the y axis, not to the distance from the point to the y axis. To see this, place one target at (1,1). Place another target at (1,2). These are the same distance from the y-axis, which is the centerline of the camera’s FOV, but they will clearly appear at different distances from the center when viewed from the camera, because the camera is a point at the origin and only sees along rays that pass through it.

For an even better demonstration: Cover one of your eyes, align your other (open) eye with the center of your computer screen. Place your finger between your face and your computer screen, so that it overlaps with the edge of the screen in your vision. Notice that your finger is closer to the centerline between your eye and the center of the screen than the edge of the monitor is, despite the fact that they appear the same “distance” away in the 2d image that you see.

The fundamental confusion here is that you’re thinking in terms of rays parallel to the center-line of the camera. But that’s incorrect, because those rays never reach the camera. Think of the camera as a point, not as a screen. All the rays that the camera sees must pass through the point. Thinking this way, it is clear that “distance” in the image the camera sees corresponds to angular distance. To preserve apparent “distance” between two objects from the point of view of the camera, you must preserve their relative angular positions.

If your method described above doesn’t seem to give you quite the right answer, perhaps you really want to know what the proportionality constant (pixels to degrees) is for **small **angles (rather than the full image width). To do this, I suggest:

Position the robot so that the target is reasonably close to the center of the image.

Note exactly where the target center is located.

Rotate by a known small number of degrees (perhaps 5 or 10)

Note where the center of the target is now.

Divide the number of pixels moved from step 2 to 4 by the number of degrees rotated in step 3

This will give you the number of pixels per degree for small angles near the center of the camera image.

If you want to aim to the center of the target than obtain the center x of the target and rotate to it using the formulas postEd.

In the photo posted, the left edge of the target is roughly at x=0 (assuming a graph is overlayed) and the right boundary is at x=x for the “far” target and x=2x for the “near” target, meaning the centers would be at x=1/2x and x=x respectively. The “near” target will request twice as much turning.

It’s fairly simple. It’s (pixels from center) / (camera pixel width) * FOV
For example, your camera has a field of view (FOV) of 45 degrees, your camera width is 320 pixels, and your image is 16 pixels off center. Then the angle to aim is:

You can calibrate your exact camera FOV by pointing your camera at a white board and marking two points on the white board at the left and right edge of the camera image. Then measure the distance between the two points on the white board, and the distance between the white board and the camera. Then a little trig will give you the FOV.