Example Fiducial Square Hamming

From BoofCV
Jump to navigationJump to search

Demonstration how to detect square fiducials which match targets based on hamming distance, e.g. ArUco and AprilTags.

Example Code:

Concepts:

  • Fiducials
  • Pose estimation

Relevant Examples/Tutorials:

Videos

Example Code

/**
 * Hamming fiducials are an entire family of markers/tags which work by identifying unique ID's by minimizing
 * the hamming distance. This family includes ArUco, ArUco 3, AprilTag, and others. Several prebuilt dictionaries
 * are included with BoofCV and you can specify your own easily. Hamming tags have error correction capabilities
 * can are resiliant to noise. How resilient depends on the dictionary. In general the fewer unique IDs available
 * the better it is at error correction. The recommended dictionary is ARUCO_MIP_25h7.
 *
 * See:
 * Aruco https://www.uco.es/investiga/grupos/ava/node/26
 * AprilTag https://april.eecs.umich.edu/software/apriltag
 *
 * @author Peter Abeles
 */
public class ExampleFiducialHamming {
	public static void main( String[] args ) {
		String directory = UtilIO.pathExample("fiducial/square_hamming/aruco_25h7");

		// load the lens distortion parameters and the input image
		CameraPinholeBrown param = CalibrationIO.load(new File(directory, "intrinsic.yaml"));
		LensDistortionNarrowFOV lensDistortion = new LensDistortionBrown(param);

		// You need to create a different configuration for each dictionary type
		ConfigHammingMarker configMarker = ConfigHammingMarker.loadDictionary(HammingDictionary.ARUCO_MIP_25h7);
		FiducialDetector<GrayF32> detector = FactoryFiducial.squareHamming(configMarker, /*detector*/null, GrayF32.class);

		// Provide it lens parameters so that a 3D pose estimate is possible
		detector.setLensDistortion(lensDistortion, param.width, param.height);

		// Load and process all example images
		ListDisplayPanel gui = new ListDisplayPanel();
		for (int imageID = 1; imageID <= 3; imageID++) {
			String name = String.format("image%02d.jpg", imageID);
			System.out.println("processing: " + name);

			// Load the image
			BufferedImage buffered = UtilImageIO.loadImage(new File(directory, name).getPath());

			// Convert to a BoofCV format
			GrayF32 input = ConvertBufferedImage.convertFrom(buffered, (GrayF32)null);

			// Run the detector
			detector.detect(input);

			// Render a 3D compute on top of all detections
			Graphics2D g2 = buffered.createGraphics();
			Se3_F64 targetToSensor = new Se3_F64();
			Point2D_F64 locationPixel = new Point2D_F64();
			Polygon2D_F64 bounds = new Polygon2D_F64();
			for (int i = 0; i < detector.totalFound(); i++) {
				detector.getCenter(i, locationPixel);
				detector.getBounds(i, bounds);

				g2.setColor(new Color(50, 50, 255));
				g2.setStroke(new BasicStroke(10));
				VisualizeShapes.drawPolygon(bounds, true, 1.0, g2);

				if (detector.hasID())
					System.out.println("Target ID = " + detector.getId(i));
				if (detector.hasMessage())
					System.out.println("Message   = " + detector.getMessage(i));
				System.out.println("2D Image Location = " + locationPixel);

				if (detector.is3D()) {
					detector.getFiducialToCamera(i, targetToSensor);
					System.out.println("3D Location:");
					System.out.println(targetToSensor);
					VisualizeFiducial.drawCube(targetToSensor, param, detector.getWidth(i), 3, g2);
					VisualizeFiducial.drawLabelCenter(targetToSensor, param, "" + detector.getId(i), g2);
				} else {
					VisualizeFiducial.drawLabel(locationPixel, "" + detector.getId(i), g2);
				}
			}
			gui.addImage(buffered, name, ScaleOptions.ALL);
		}
		ShowImages.showWindow(gui, "Example Fiducial Hamming", true);
	}
}