001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.apriltag; 006 007import edu.wpi.first.math.MatBuilder; 008import edu.wpi.first.math.Matrix; 009import edu.wpi.first.math.Nat; 010import edu.wpi.first.math.numbers.N3; 011import java.util.Arrays; 012 013/** A detection of an AprilTag tag. */ 014public class AprilTagDetection { 015 /** 016 * Gets the decoded tag's family name. 017 * 018 * @return Decoded family name 019 */ 020 public String getFamily() { 021 return m_family; 022 } 023 024 /** 025 * Gets the decoded ID of the tag. 026 * 027 * @return Decoded ID 028 */ 029 public int getId() { 030 return m_id; 031 } 032 033 /** 034 * Gets how many error bits were corrected. Note: accepting large numbers of corrected errors 035 * leads to greatly increased false positive rates. NOTE: As of this implementation, the detector 036 * cannot detect tags with a hamming distance greater than 2. 037 * 038 * @return Hamming distance (number of corrected error bits) 039 */ 040 public int getHamming() { 041 return m_hamming; 042 } 043 044 /** 045 * Gets a measure of the quality of the binary decoding process: the average difference between 046 * the intensity of a data bit versus the decision threshold. Higher numbers roughly indicate 047 * better decodes. This is a reasonable measure of detection accuracy only for very small tags-- 048 * not effective for larger tags (where we could have sampled anywhere within a bit cell and still 049 * gotten a good detection.) 050 * 051 * @return Decision margin 052 */ 053 public float getDecisionMargin() { 054 return m_decisionMargin; 055 } 056 057 /** 058 * Gets the 3x3 homography matrix describing the projection from an "ideal" tag (with corners at 059 * (-1,1), (1,1), (1,-1), and (-1, -1)) to pixels in the image. 060 * 061 * @return Homography matrix data 062 */ 063 @SuppressWarnings("PMD.MethodReturnsInternalArray") 064 public double[] getHomography() { 065 return m_homography; 066 } 067 068 /** 069 * Gets the 3x3 homography matrix describing the projection from an "ideal" tag (with corners at 070 * (-1,1), (1,1), (1,-1), and (-1, -1)) to pixels in the image. 071 * 072 * @return Homography matrix 073 */ 074 public Matrix<N3, N3> getHomographyMatrix() { 075 return new MatBuilder<>(Nat.N3(), Nat.N3()).fill(m_homography); 076 } 077 078 /** 079 * Gets the center of the detection in image pixel coordinates. 080 * 081 * @return Center point X coordinate 082 */ 083 public double getCenterX() { 084 return m_centerX; 085 } 086 087 /** 088 * Gets the center of the detection in image pixel coordinates. 089 * 090 * @return Center point Y coordinate 091 */ 092 public double getCenterY() { 093 return m_centerY; 094 } 095 096 /** 097 * Gets a corner of the tag in image pixel coordinates. These always wrap counter-clock wise 098 * around the tag. 099 * 100 * @param ndx Corner index (range is 0-3, inclusive) 101 * @return Corner point X coordinate 102 */ 103 public double getCornerX(int ndx) { 104 return m_corners[ndx * 2]; 105 } 106 107 /** 108 * Gets a corner of the tag in image pixel coordinates. These always wrap counter-clock wise 109 * around the tag. 110 * 111 * @param ndx Corner index (range is 0-3, inclusive) 112 * @return Corner point Y coordinate 113 */ 114 public double getCornerY(int ndx) { 115 return m_corners[ndx * 2 + 1]; 116 } 117 118 /** 119 * Gets the corners of the tag in image pixel coordinates. These always wrap counter-clock wise 120 * around the tag. 121 * 122 * @return Corner point array (X and Y for each corner in order) 123 */ 124 @SuppressWarnings("PMD.MethodReturnsInternalArray") 125 public double[] getCorners() { 126 return m_corners; 127 } 128 129 private final String m_family; 130 private final int m_id; 131 private final int m_hamming; 132 private final float m_decisionMargin; 133 private final double[] m_homography; 134 private final double m_centerX; 135 private final double m_centerY; 136 private final double[] m_corners; 137 138 /** 139 * Constructs a new detection result. Used from JNI. 140 * 141 * @param family family 142 * @param id id 143 * @param hamming hamming 144 * @param decisionMargin dm 145 * @param homography homography 146 * @param centerX centerX 147 * @param centerY centerY 148 * @param corners corners 149 */ 150 @SuppressWarnings("PMD.ArrayIsStoredDirectly") 151 public AprilTagDetection( 152 String family, 153 int id, 154 int hamming, 155 float decisionMargin, 156 double[] homography, 157 double centerX, 158 double centerY, 159 double[] corners) { 160 m_family = family; 161 m_id = id; 162 m_hamming = hamming; 163 m_decisionMargin = decisionMargin; 164 m_homography = homography; 165 m_centerX = centerX; 166 m_centerY = centerY; 167 m_corners = corners; 168 } 169 170 @Override 171 public String toString() { 172 return "DetectionResult [centerX=" 173 + m_centerX 174 + ", centerY=" 175 + m_centerY 176 + ", corners=" 177 + Arrays.toString(m_corners) 178 + ", decisionMargin=" 179 + m_decisionMargin 180 + ", hamming=" 181 + m_hamming 182 + ", homography=" 183 + Arrays.toString(m_homography) 184 + ", family=" 185 + m_family 186 + ", id=" 187 + m_id 188 + "]"; 189 } 190}