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.apriltag.jni.AprilTagJNI; 008import edu.wpi.first.math.geometry.Transform3d; 009 010/** Pose estimators for AprilTag tags. */ 011public class AprilTagPoseEstimator { 012 /** Configuration for the pose estimator. */ 013 @SuppressWarnings("MemberName") 014 public static class Config { 015 /** 016 * Creates a pose estimator configuration. 017 * 018 * @param tagSize tag size, in meters 019 * @param fx camera horizontal focal length, in pixels 020 * @param fy camera vertical focal length, in pixels 021 * @param cx camera horizontal focal center, in pixels 022 * @param cy camera vertical focal center, in pixels 023 */ 024 public Config(double tagSize, double fx, double fy, double cx, double cy) { 025 this.tagSize = tagSize; 026 this.fx = fx; 027 this.fy = fy; 028 this.cx = cx; 029 this.cy = cy; 030 } 031 032 public double tagSize; 033 public double fx; 034 public double fy; 035 public double cx; 036 public double cy; 037 038 @Override 039 public int hashCode() { 040 return Double.hashCode(tagSize) 041 + Double.hashCode(fx) 042 + Double.hashCode(fy) 043 + Double.hashCode(cx) 044 + Double.hashCode(cy); 045 } 046 047 @Override 048 public boolean equals(Object obj) { 049 if (!(obj instanceof Config)) { 050 return false; 051 } 052 053 Config other = (Config) obj; 054 return tagSize == other.tagSize 055 && fx == other.fx 056 && fy == other.fy 057 && cx == other.cx 058 && cy == other.cy; 059 } 060 } 061 062 /** 063 * Creates estimator. 064 * 065 * @param config Configuration 066 */ 067 public AprilTagPoseEstimator(Config config) { 068 m_config = new Config(config.tagSize, config.fx, config.fy, config.cx, config.cy); 069 } 070 071 /** 072 * Sets estimator configuration. 073 * 074 * @param config Configuration 075 */ 076 public void setConfig(Config config) { 077 m_config.tagSize = config.tagSize; 078 m_config.fx = config.fx; 079 m_config.fy = config.fy; 080 m_config.cx = config.cx; 081 m_config.cy = config.cy; 082 } 083 084 /** 085 * Gets estimator configuration. 086 * 087 * @return Configuration 088 */ 089 public Config getConfig() { 090 return new Config(m_config.tagSize, m_config.fx, m_config.fy, m_config.cx, m_config.cy); 091 } 092 093 /** 094 * Estimates the pose of the tag using the homography method described in [1]. 095 * 096 * @param detection Tag detection 097 * @return Pose estimate 098 */ 099 public Transform3d estimateHomography(AprilTagDetection detection) { 100 return estimateHomography(detection.getHomography()); 101 } 102 103 /** 104 * Estimates the pose of the tag using the homography method described in [1]. 105 * 106 * @param homography Homography 3x3 matrix data 107 * @return Pose estimate 108 */ 109 public Transform3d estimateHomography(double[] homography) { 110 return AprilTagJNI.estimatePoseHomography( 111 homography, m_config.tagSize, m_config.fx, m_config.fy, m_config.cx, m_config.cy); 112 } 113 114 /** 115 * Estimates the pose of the tag. This returns one or two possible poses for the tag, along with 116 * the object-space error of each. 117 * 118 * <p>This uses the homography method described in [1] for the initial estimate. Then Orthogonal 119 * Iteration [2] is used to refine this estimate. Then [3] is used to find a potential second 120 * local minima and Orthogonal Iteration is used to refine this second estimate. 121 * 122 * <p>[1]: E. Olson, “Apriltag: A robust and flexible visual fiducial system,” in 2011 IEEE 123 * International Conference on Robotics and Automation, May 2011, pp. 3400–3407. 124 * 125 * <p>[2]: Lu, G. D. Hager and E. Mjolsness, "Fast and globally convergent pose estimation from 126 * video images," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 22, no. 127 * 6, pp. 610-622, June 2000. doi: 10.1109/34.862199 128 * 129 * <p>[3]: Schweighofer and A. Pinz, "Robust Pose Estimation from a Planar Target," in IEEE 130 * Transactions on Pattern Analysis and Machine Intelligence, vol. 28, no. 12, pp. 2024-2030, Dec. 131 * 2006. doi: 10.1109/TPAMI.2006.252 132 * 133 * @param detection Tag detection 134 * @param nIters Number of iterations 135 * @return Initial and (possibly) second pose estimates 136 */ 137 public AprilTagPoseEstimate estimateOrthogonalIteration(AprilTagDetection detection, int nIters) { 138 return estimateOrthogonalIteration(detection.getHomography(), detection.getCorners(), nIters); 139 } 140 141 /** 142 * Estimates the pose of the tag. This returns one or two possible poses for the tag, along with 143 * the object-space error of each. 144 * 145 * @param homography Homography 3x3 matrix data 146 * @param corners Corner point array (X and Y for each corner in order) 147 * @param nIters Number of iterations 148 * @return Initial and (possibly) second pose estimates 149 */ 150 public AprilTagPoseEstimate estimateOrthogonalIteration( 151 double[] homography, double[] corners, int nIters) { 152 return AprilTagJNI.estimatePoseOrthogonalIteration( 153 homography, 154 corners, 155 m_config.tagSize, 156 m_config.fx, 157 m_config.fy, 158 m_config.cx, 159 m_config.cy, 160 nIters); 161 } 162 163 /** 164 * Estimates tag pose. This method is an easier to use interface to 165 * EstimatePoseOrthogonalIteration(), running 50 iterations and returning the pose with the lower 166 * object-space error. 167 * 168 * @param detection Tag detection 169 * @return Pose estimate 170 */ 171 public Transform3d estimate(AprilTagDetection detection) { 172 return estimate(detection.getHomography(), detection.getCorners()); 173 } 174 175 /** 176 * Estimates tag pose. This method is an easier to use interface to 177 * EstimatePoseOrthogonalIteration(), running 50 iterations and returning the pose with the lower 178 * object-space error. 179 * 180 * @param homography Homography 3x3 matrix data 181 * @param corners Corner point array (X and Y for each corner in order) 182 * @return Pose estimate 183 */ 184 public Transform3d estimate(double[] homography, double[] corners) { 185 return AprilTagJNI.estimatePose( 186 homography, corners, m_config.tagSize, m_config.fx, m_config.fy, m_config.cx, m_config.cy); 187 } 188 189 private final Config m_config; 190}