DetectorAprilTag

class DetectorAprilTag(*args, **kwargs)

Bases: DetectorBase

Base class for AprilTag detector. This class is a wrapper over AprilTag . There is no need to download and install AprilTag from source code or existing pre-built packages since the source code is embedded in ViSP. Reference papers are AprilTag: A robust and flexible visual fiducial system ( [36] ), AprilTag 2: Efficient and robust fiducial detection ( [46] ) and Flexible Layouts for Fiducial Tags (Under Review) ( [22] ).

The detect() function allows to detect multiple tags in an image. Once detected, for each tag it is possible to retrieve the location of the corners using getPolygon() , the encoded message using getMessage() , the bounding box using getBBox() and the center of gravity using getCog() .

If camera parameters and the size of the tag are provided, you can also estimate the 3D pose of the tag in terms of position and orientation wrt the camera considering 2 cases:

    1. If all the tags have the same size use detect(const vpImage<unsigned char> &, double, const vpCameraParameters &, std::vector<vpHomogeneousMatrix> &, std::vector<vpHomogeneousMatrix> *, std::vector<double> *, std::vector<double> *)

    1. If tag sizes differ, use rather getPose()

The following sample code shows how to use this class to detect the location of 36h11 AprilTag patterns in an image.

#include <visp3/detection/vpDetectorAprilTag.h>
#include <visp3/io/vpImageIo.h>

#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif

int main()
{
#ifdef VISP_HAVE_APRILTAG
  vpImage<unsigned char> I;
  vpImageIo::read(I, "image-tag36h11.pgm");

  vpDetectorAprilTag detector(vpDetectorAprilTag::TAG_36h11);

  bool status = detector.detect(I);
  if (status) {
    for(size_t i=0; i < detector.getNbObjects(); ++i) {
      std::cout << "Tag code " << i << ":" << std::endl;
      std::vector<vpImagePoint> p = detector.getPolygon(i);
      for(size_t j=0; j < p.size(); ++j)
        std::cout << "  Point " << j << ": " << p[j] << std::endl;
      std::cout << "  Message: \"" << detector.getMessage(i) << "\"" << std::endl;
    }
  }
#endif
}

The previous example may produce results like:

Tag code 0:
  Point 0: 124.008, 442.226
  Point 1: 194.614, 441.237
  Point 2: 184.833, 540.386
  Point 3: 111.948, 533.634
  Message: "36h11 id: 0"
Tag code 1:
  Point 0: 245.327, 438.801
  Point 1: 338.116, 437.221
  Point 2: 339.341, 553.539
  Point 3: 238.954, 543.855
  Message: "36h11 id: 1"

<unparsed image <doxmlparser.compound.docImageType object at 0x7f6df13a02b0>>There is the function setZAlignedWithCameraAxis() that allows to choose which tag frame has to be considered.

This other example shows how to estimate the 3D pose of 36h11 AprilTag patterns considering that all the tags have the same size (in our example 0.053 m). Here we consider the default case, when z-camera and z-tag axis are not aligned.

#include <visp3/detection/vpDetectorAprilTag.h>
#include <visp3/io/vpImageIo.h>

#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif

int main()
{
#ifdef VISP_HAVE_APRILTAG
  vpImage<unsigned char> I;
  vpImageIo::read(I, "image-tag36h11.pgm");

  vpDetectorAprilTag detector(vpDetectorAprilTag::TAG_36h11);
  detector.setZAlignedWithCameraAxis(false); // Default configuration
  std::vector<vpHomogeneousMatrix> cMo;
  vpCameraParameters cam;
  cam.initPersProjWithoutDistortion(615.1674805, 615.1675415, 312.1889954, 243.4373779);
  double tagSize = 0.053;

  bool status = detector.detect(I, tagSize, cam, cMo);
  if (status) {
    for(size_t i=0; i < detector.getNbObjects(); ++i) {
      std::cout << "Tag number " << i << ":" << std::endl;
      std::cout << "  Message: \"" << detector.getMessage(i) << "\"" << std::endl;
      std::cout << "  Pose: " << vpPoseVector(cMo[i]).t() << std::endl;
      std::size_t tag_id_pos = detector.getMessage(i).find("id: ");
      if (tag_id_pos != std::string::npos) {
        std::string tag_id = detector.getMessage(i).substr(tag_id_pos + 4);
        std::cout << "  Tag Id: " << tag_id << std::endl;
      }
    }
  }
#endif
}

The previous example may produce results like:

Tag number 0:
  Message: "36h11 id: 0"
  Pose: 0.1015061088  -0.05239057228  0.3549037285  1.991474322  2.04143538 -0.9412360063
  Tag Id: 0
Tag number 1:
  Message: "36h11 id: 1"
  Pose: 0.08951250829 0.02243780207  0.306540622  1.998073197  2.061488008  -0.8699567948
  Tag Id: 1

In this other example we estimate the 3D pose of 36h11 AprilTag patterns considering that tag 36h11 with id 0 (in that case the tag message is “36h11 id: 0”) has a size of 0.040 m, while all the others have a size of 0.053m.

#include <visp3/detection/vpDetectorAprilTag.h>
#include <visp3/io/vpImageIo.h>

#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif

int main()
{
#ifdef VISP_HAVE_APRILTAG
  vpImage<unsigned char> I;
  vpImageIo::read(I, "image-tag36h11.pgm");

  vpDetectorAprilTag detector(vpDetectorAprilTag::TAG_36h11);
  vpHomogeneousMatrix cMo;
  vpCameraParameters cam;
  cam.initPersProjWithoutDistortion(615.1674805, 615.1675415, 312.1889954, 243.4373779);
  double tagSize_id_0 = 0.04;
  double tagSize_id_others = 0.053;

  bool status = detector.detect(I);
  if (status) {
    for(size_t i=0; i < detector.getNbObjects(); ++i) {
      std::cout << "Tag code " << i << ":" << std::endl;
      std::cout << "  Message: \"" << detector.getMessage(i) << "\"" << std::endl;
      if (detector.getMessage(i) == std::string("36h11 id: 0")) {
        if (! detector.getPose(i, tagSize_id_0, cam, cMo)) {
          std::cout << "Unable to get tag index " << i << " pose!" << std::endl;
        }
      }
      else {
        if (! detector.getPose(i, tagSize_id_others, cam, cMo)) {
          std::cout << "Unable to get tag index " << i << " pose!" << std::endl;
        }
      }
      std::cout << "  Pose: " << vpPoseVector(cMo).t() << std::endl;
    }
  }
#endif
}

With respect to the previous example, this example may now produce a different pose for tag with id 0:

Tag code 0:
  Message: "36h11 id: 0"
  Pose: 0.07660838403  -0.03954005455  0.2678518706  1.991474322  2.04143538  -0.9412360063
Tag code 1:
  Message: "36h11 id: 1"
  Pose: 0.08951250829  0.02243780207  0.306540622  1.998073197  2.061488008  -0.8699567948

Other examples are also provided in tutorial-apriltag-detector.cpp and tutorial-apriltag-detector-live.cpp

Overloaded function.

  1. __init__(self: visp._visp.detection.DetectorAprilTag, tagFamily: visp._visp.detection.DetectorAprilTag.AprilTagFamily = TAG_36h11, poseEstimationMethod: visp._visp.detection.DetectorAprilTag.PoseEstimationMethod = HOMOGRAPHY_VIRTUAL_VS) -> None

  2. __init__(self: visp._visp.detection.DetectorAprilTag, o: visp._visp.detection.DetectorAprilTag) -> None

Methods

__init__

Overloaded function.

detect

Detect AprilTag tags in the image.

displayFrames

Overloaded function.

displayTags

Overloaded function.

getPoseEstimationMethod

Return the pose estimation method.

getTagsCorners

Return the corners coordinates for the detected tags.

getTagsId

Return the decoded Apriltag id for each detection.

getTagsPoints3D

Return a vector that contains for each tag id the corresponding tag 3D corners coordinates in the tag frame.

isZAlignedWithCameraAxis

return:

When true, z-axis are aligned, false otherwise

setAprilTagDecodeSharpening

setAprilTagFamily

setAprilTagNbThreads

Set the number of threads for April Tag detection (default is 1).

setAprilTagPoseEstimationMethod

setAprilTagQuadDecimate

From the AprilTag code:detection of quads can be done on a lower-resolution image, improving speed at a cost of pose accuracy and a slight decrease in detection rate.

setAprilTagQuadSigma

From the AprilTag code:What Gaussian blur should be applied to the segmented image (used for quad detection?) Parameter is the standard deviation in pixels.

setAprilTagRefineEdges

From the AprilTag code:When non-zero, the edges of the each quad are adjusted to "snap

setDisplayTag

Allow to enable the display of overlay tag information in the windows ( vpDisplay ) associated to the input image.

setZAlignedWithCameraAxis

Modify the resulting tag pose returned by getPose() or detect(const vpImage<unsigned char> &, double, const vpCameraParameters &, std::vector<vpHomogeneousMatrix> &, std::vector<vpHomogeneousMatrix> *, std::vector<double> *, std::vector<double> *) in order to get a pose where z-axis is aligned when the camera plane is parallel to the tag.

Inherited Methods

getCog

Return the center of gravity location of the ith object.

getMessage

Overloaded function.

getBBox

Return the bounding box of the ith object.

getNbObjects

Return the number of objects that are detected.

getPolygon

Overloaded function.

setTimeout

Set detector timeout in milli-seconds.

Operators

__doc__

__init__

Overloaded function.

__module__

Attributes

BEST_RESIDUAL_VIRTUAL_VS

DEMENTHON_VIRTUAL_VS

HOMOGRAPHY

HOMOGRAPHY_ORTHOGONAL_ITERATION

HOMOGRAPHY_VIRTUAL_VS

LAGRANGE_VIRTUAL_VS

TAG_16h5

TAG_25h7

TAG_25h9

TAG_36ARTOOLKIT

TAG_36h10

TAG_36h11

TAG_CIRCLE21h7

TAG_CIRCLE49h12

TAG_CUSTOM48h12

TAG_STANDARD41h12

TAG_STANDARD52h13

__annotations__

class AprilTagFamily(self, value: int)

Bases: pybind11_object

Values:

  • HOMOGRAPHY: Pose from homography

  • HOMOGRAPHY_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the homography approach

  • DEMENTHON_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the Dementhon approach

  • LAGRANGE_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the Lagrange approach

  • BEST_RESIDUAL_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the approach that gives the lowest residual

  • HOMOGRAPHY_ORTHOGONAL_ITERATION: Pose from homography followed by a refinement by Orthogonal Iteration

__and__(self, other: object) object
__eq__(self, other: object) bool
__ge__(self, other: object) bool
__getstate__(self) int
__gt__(self, other: object) bool
__hash__(self) int
__index__(self) int
__init__(self, value: int)
__int__(self) int
__invert__(self) object
__le__(self, other: object) bool
__lt__(self, other: object) bool
__ne__(self, other: object) bool
__or__(self, other: object) object
__rand__(self, other: object) object
__ror__(self, other: object) object
__rxor__(self, other: object) object
__setstate__(self, state: int) None
__xor__(self, other: object) object
property name : str
class PoseEstimationMethod(self, value: int)

Bases: pybind11_object

Values:

  • HOMOGRAPHY: Pose from homography

  • HOMOGRAPHY_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the homography approach

  • DEMENTHON_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the Dementhon approach

  • LAGRANGE_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the Lagrange approach

  • BEST_RESIDUAL_VIRTUAL_VS: Non linear virtual visual servoing approach initialized by the approach that gives the lowest residual

  • HOMOGRAPHY_ORTHOGONAL_ITERATION: Pose from homography followed by a refinement by Orthogonal Iteration

__and__(self, other: object) object
__eq__(self, other: object) bool
__ge__(self, other: object) bool
__getstate__(self) int
__gt__(self, other: object) bool
__hash__(self) int
__index__(self) int
__init__(self, value: int)
__int__(self) int
__invert__(self) object
__le__(self, other: object) bool
__lt__(self, other: object) bool
__ne__(self, other: object) bool
__or__(self, other: object) object
__rand__(self, other: object) object
__ror__(self, other: object) object
__rxor__(self, other: object) object
__setstate__(self, state: int) None
__xor__(self, other: object) object
property name : str
__init__(*args, **kwargs)

Overloaded function.

  1. __init__(self: visp._visp.detection.DetectorAprilTag, tagFamily: visp._visp.detection.DetectorAprilTag.AprilTagFamily = TAG_36h11, poseEstimationMethod: visp._visp.detection.DetectorAprilTag.PoseEstimationMethod = HOMOGRAPHY_VIRTUAL_VS) -> None

  2. __init__(self: visp._visp.detection.DetectorAprilTag, o: visp._visp.detection.DetectorAprilTag) -> None

detect(self, I: visp._visp.core.ImageGray) bool

Detect AprilTag tags in the image. Return true if at least one tag is detected, false otherwise.

Parameters:
I: visp._visp.core.ImageGray

Input image.

Returns:

true if at least one tag is detected.

displayFrames(*args, **kwargs)

Overloaded function.

  1. displayFrames(self: visp._visp.detection.DetectorAprilTag, I: visp._visp.core.ImageGray, cMo_vec: list[visp._visp.core.HomogeneousMatrix], cam: visp._visp.core.CameraParameters, size: float, color: visp._visp.core.Color, thickness: int = 1) -> None

Display the tag frames on a grayscale image.

Parameters:
I

The image.

cMo_vec

The vector of computed tag poses.

cam

Camera intrinsic parameters.

size

Size of the frame.

color

The desired color, if none the X-axis is red, the Y-axis green and the Z-axis blue.

thickness

The thickness of the lines.

  1. displayFrames(self: visp._visp.detection.DetectorAprilTag, I: visp._visp.core.ImageRGBa, cMo_vec: list[visp._visp.core.HomogeneousMatrix], cam: visp._visp.core.CameraParameters, size: float, color: visp._visp.core.Color, thickness: int = 1) -> None

Display the tag frames on a vpRGBa image.

Parameters:
I

The image.

cMo_vec

The vector of computed tag poses.

cam

Camera intrinsic parameters.

size

Size of the frame.

color

The desired color, if none the X-axis is red, the Y-axis green and the Z-axis blue.

thickness

The thickness of the lines.

displayTags(*args, **kwargs)

Overloaded function.

  1. displayTags(self: visp._visp.detection.DetectorAprilTag, I: visp._visp.core.ImageGray, tagsCorners: list[list[visp._visp.core.ImagePoint]], color: visp._visp.core.Color = vpColor::none, thickness: int = 1) -> None

Display the tag contours on a grayscale image.

Parameters:
I

The image.

tagsCorners

The vector of tag contours.

color

The desired color, if none RGBY colors are used.

thickness

The thickness of the lines.

  1. displayTags(self: visp._visp.detection.DetectorAprilTag, I: visp._visp.core.ImageRGBa, tagsCorners: list[list[visp._visp.core.ImagePoint]], color: visp._visp.core.Color = vpColor::none, thickness: int = 1) -> None

Display the tag contours on a vpRGBa image.

Parameters:
I

The image.

tagsCorners

The vector of tag contours.

color

The desired color, if none RGBY colors are used.

thickness

The thickness of the lines.

getBBox(self, i: int) visp._visp.core.Rect

Return the bounding box of the ith object.

getCog(self, i: int) visp._visp.core.ImagePoint

Return the center of gravity location of the ith object.

getMessage(*args, **kwargs)

Overloaded function.

  1. getMessage(self: visp._visp.detection.DetectorBase) -> list[str]

Returns the contained message of the ith object if there is one.

  1. getMessage(self: visp._visp.detection.DetectorBase, i: int) -> str

Returns the contained message of the ith object if there is one.

getNbObjects(self) int

Return the number of objects that are detected.

getPolygon(*args, **kwargs)

Overloaded function.

  1. getPolygon(self: visp._visp.detection.DetectorBase) -> list[list[visp._visp.core.ImagePoint]]

Returns object container box as a vector of points.

  1. getPolygon(self: visp._visp.detection.DetectorBase, i: int) -> list[visp._visp.core.ImagePoint]

Returns ith object container box as a vector of points.

getPoseEstimationMethod(self) visp._visp.detection.DetectorAprilTag.PoseEstimationMethod

Return the pose estimation method.

getTagsCorners(self) list[list[visp._visp.core.ImagePoint]]

Return the corners coordinates for the detected tags.

Note

See getTagsId() , getTagsPoints3D()

getTagsId(self) list[int]

Return the decoded Apriltag id for each detection.

Note

See getTagsCorners() , getTagsPoints3D()

getTagsPoints3D(self, tagsId: list[int], tagsSize: dict[int, float]) list[list[visp._visp.core.Point]]

Return a vector that contains for each tag id the corresponding tag 3D corners coordinates in the tag frame.

Note

See getTagsCorners() , getTagsId()

Parameters:
tagsId: list[int]

A vector containing the id of each tag that is detected. It’s size corresponds to the number of tags that are detected. This vector is returned by getTagsId() .

tagsSize: dict[int, float]

a map that contains as first element a tag id and as second elements its 3D size in meter. When first element of this map is -1, the second element corresponds to the default tag size.

std::map<int, double> tagsSize;
tagsSize[-1] = 0.05; // Default tag size in meter, used when detected tag id is not in this map
tagsSize[10] = 0.1;  // All tags with id 10 are 0.1 meter large
tagsSize[20] = 0.2;  // All tags with id 20 are 0.2 meter large

isZAlignedWithCameraAxis(self) bool
Returns:

When true, z-axis are aligned, false otherwise

setAprilTagDecodeSharpening(self, decodeSharpening: float) None
setAprilTagFamily(self, tagFamily: visp._visp.detection.DetectorAprilTag.AprilTagFamily) None
setAprilTagNbThreads(self, nThreads: int) None

Set the number of threads for April Tag detection (default is 1).

Parameters:
nThreads: int

Number of thread.

setAprilTagPoseEstimationMethod(self, poseEstimationMethod: visp._visp.detection.DetectorAprilTag.PoseEstimationMethod) None
setAprilTagQuadDecimate(self, quadDecimate: float) None

From the AprilTag code:detection of quads can be done on a lower-resolution image, improving speed at a cost of pose accuracy and a slight decrease in detection rate. Decoding the binary payload is still done at full resolution. Default is 1.0, increase this value to reduce the computation time.

Parameters:
quadDecimate: float

Value for quad_decimate.

setAprilTagQuadSigma(self, quadSigma: float) None

From the AprilTag code:What Gaussian blur should be applied to the segmented image (used for quad detection?) Parameter is the standard deviation in pixels. Very noisy images benefit from non-zero values (e.g. 0.8). Default is 0.0.

Parameters:
quadSigma: float

Value for quad_sigma.

setAprilTagRefineEdges(self, refineEdges: bool) None
From the AprilTag code:When non-zero, the edges of the each quad are adjusted to “snap

to” strong gradients nearby. This is useful when decimation is employed, as it can increase the quality of the initial quad estimate substantially. Generally recommended to be on (1). Very computationally inexpensive. Option is ignored if quad_decimate = 1.

Default is 1.

Parameters:
refineEdges: bool

If true, set refine edges parameter.

setDisplayTag(self: visp._visp.detection.DetectorAprilTag, display: bool, color: visp._visp.core.Color = vpColor::none, thickness: int = 2) None

Allow to enable the display of overlay tag information in the windows ( vpDisplay ) associated to the input image.

setTimeout(self, timeout_ms: int) None

Set detector timeout in milli-seconds. When set to 0, there is no timeout.

setZAlignedWithCameraAxis(self, zAlignedWithCameraFrame: bool) None

Modify the resulting tag pose returned by getPose() or detect(const vpImage<unsigned char> &, double, const vpCameraParameters &, std::vector<vpHomogeneousMatrix> &, std::vector<vpHomogeneousMatrix> *, std::vector<double> *, std::vector<double> *) in order to get a pose where z-axis is aligned when the camera plane is parallel to the tag.

<unparsed image <doxmlparser.compound.docImageType object at 0x7f6df1337820>>

Parameters:
zAlignedWithCameraFrame: bool

When set to true, estimated tag pose has a z-axis aligned with the camera frame.