AprilRobotics / apriltag

AprilTag is a visual fiducial system popular for robotics research.
https://april.eecs.umich.edu/software/apriltag
Other
1.55k stars 532 forks source link

Max measurement distance vs optimal tag size #189

Closed adamanov closed 2 years ago

adamanov commented 2 years ago

Hello,

is there any way to determine optimal tag size for desired distance? As far as I got, the best performance shows the 36h11 family of Apritags. I want to use it, and I need to determine how big it should be , let's say if I place it 10 meters far away from the camera.

I will use Logitech Webcam C920S Pro HD which has resolution 1920x1080 I did a calibration and determined focal length of the camera is app 1400. Below I put distortion and intristic calibration matrix D = [0.016486358093259348, -0.08919904032646075, 0.004494594809368575, 0.0034994745568047016, 0.0] K = [1402.0520961256714, 0.0, 990.98434149758, 0.0, 1393.9198125919136, 565.8528624142899, 0.0, 0.0, 1.0]

Thanks in advance

christian-rauch commented 2 years ago

Generally, the larger the tag in the image and the higher the resolution, the more accurate will the pose estimation be. So just try to make it as big as possible.

adamanov commented 2 years ago

Generally, the larger the tag in the image and the higher the resolution, the more accurate will the pose estimation be. So just try to make it as big as possible.

yes, that is clear. I just wondered if there is any formula to calculate it. I found in optitag block an formula:

Max detection distance

Max detection distance in meters = t /(2 tan( (b f p) / (2 r ) ) ) t = size of your tag in meters - Optitag calls this Edge Length or size b = the number of bits that span the width of the tag (excluding the white border for Apriltag 2). ex: 36h11 = 8, 25h9 = 6, standard41h12 = 9 f = horizontal FOV of your camera r = horizontal resolution of you camera p = the number of pixels required to detect a bit. This is an adjustable constant. We recommend 5. Lowest number we recommend is 2 which is the Nyquist Frequency. We recommend 5 to avoid some of the detection pitfalls mentioned above.

10 = t / (2tan((8 1400 5)/(2 1920)) --> t=5.2m According to above calculation, size of my tag should be 5 meters, which is funny or I did a mistake during calculation

christian-rauch commented 2 years ago

The equation you cite is based on this principle. It gives you a relation between the distance of the tag and the number of pixels that can be detected, assuming the camera parameters and tag size are fixed. You can probably use this to get some overview. But 5 pixel for one of the squares/bits is quite low if you also want to estimate an orientation.

In any case, this will only be the lower bound for the tag size. But "optimal" will be as large as possible, not taking other constraints into account.

According to above calculation, size of my tag should be 5 meters, which is funny or I did a mistake during calculation

You set your horizontal FoV to 1400 rad. That's a bit too large :-) With your values I get to a negative size.

For an Azure Kinect at HD (1280, 90deg) I get to 0.5m which is likely too small for a pose estimation at 10m distance. With UHD (4096, 90deg) the tag size is reduced to 15cm. I highly doubt that anything useful will come out of the pose estimation with such small tags.

adamanov commented 2 years ago

The equation you cite is based on this principle. It gives you a relation between the distance of the tag and the number of pixels that can be detected, assuming the camera parameters and tag size are fixed. You can probably use this to get some overview. But 5 pixel for one of the squares/bits is quite low if you also want to estimate an orientation.

In any case, this will only be the lower bound for the tag size. But "optimal" will be as large as possible, not taking other constraints into account.

According to above calculation, size of my tag should be 5 meters, which is funny or I did a mistake during calculation

You set your horizontal FoV to 1400 rad. That's a bit too large :-) With your values I get to a negative size.

For an Azure Kinect at HD (1280, 90deg) I get to 0.5m which is likely too small for a pose estimation at 10m distance. With UHD (4096, 90deg) the tag size is reduced to 15cm. I highly doubt that anything useful will come out of the pose estimation with such small tags.

Oh, my mistake I took f as focal length which was calculated during calibration. I am still in confuse and not able to verify your number. Could you please write down how did you get them?

For my web cam is Max Resolution: 1080p/30 fp and (dFoV): 78°

christian-rauch commented 2 years ago

Could you please write down how did you get them?

#!/usr/bin/env python3
import numpy as np

# Azure Kinect DK, https://docs.microsoft.com/azure/Kinect-dk/hardware-specification
r = 1280; f = np.deg2rad(90); b = 8; p = 5; d = 10

# minimum tag size, https://optitag.io/blogs/news/designing-your-perfect-apriltag
t = d * (2 * np.tan((b*f*p)/(2*r)))

print("tag size:", t,"m")

For my web cam is Max Resolution: 1080p/30 fp and (dFoV): 78°

That would be r = 1080; f = np.deg2rad(78) and I get to 0.5043.

christian-rauch commented 2 years ago

In case you still need some kind of formula, I would use the relative size to the image:

#!/usr/bin/env python3
import numpy as np

# Azure Kinect vertical size and FoV
r = 720; v = np.deg2rad(59)
b = 8; p = 5; d = 10

# focal length in pixel
# f = r / (2 * np.tan(v/2))
# tag size in meter given relative size s
# s * h/f = t/d
# t = d * s * r / f
t = lambda d, v, s : s * d * 2 * np.tan(v/2)

# tag size by percentag
for s in [1.0, 0.5, 0.1]:
    print("t ({}%): {:.2f} m".format(int(100*s), t(d,v,s)))

which gives:

t (100%): 11.32 m
t (50%): 5.66 m
t (10%): 1.13 m

That means if you want your tag to fill 50% of the image height at d = 10m distance, it should be 5.66m large. This is for the Azure Kinect in the lowest resolution. You have to adapt r (vertical resolution) and v (vertical focal length) accordingly.

adamanov commented 2 years ago

Thank you very much :) btw, with a web camera and 15cm2 Tag, I could detect it from 8-9 meters. By it was during static measurement. When I tested with a moving robot with Tag on it, the detection sometimes didn't happen. Probably I need to increase the tag size