Example Fiducial Random Dots

From BoofCV
Jump to navigationJump to search

Uchiya Markers are composed of random dots and work by computing a hashing function based on the relative orientation of neighboring dots. One advantage to these markers is that they are resistant to conclusion. Many of the dots can be covered and the ID and pose of the marker can still be recovered! Square based markers become unrecognizable if the black square is blocked or damaged. BoofCV also provides tools for generating random marker PDF documents that can be printed.

Example File: ExampleFiducialRandomDots.java


  • Fiducial Markers
  • Dots
  • Pose Estimation

Relevant Videos:

Related Tutorials/Example Code:

Example Code

 * Random dot markers are exactly what their name implies. Each marker is a set of random dots that the tracker
 * learns to identify using hash codes computed from geometric invariants which describe the relationships between
 * the dots. These markers are based off of Uchiya Markers.
 * @author Peter Abeles
public class ExampleFiducialRandomDots {
	public static void main( String[] args ) {
		// The definitions file specifies where dots are on each marker and other bits of meta data
		RandomDotDefinition defs = FiducialIO.loadRandomDotYaml(

		// The only parameter that you have to set is markerLength. It's used to compute bounding
		// boxes and similar. If you don't know what the width is just set it to 1.0
		var config = new ConfigUchiyaMarker();
		config.markerWidth = defs.markerWidth;
		config.markerHeight = defs.markerHeight;

		Uchiya_to_FiducialDetector<GrayU8> detector = FactoryFiducial.randomDots(config, GrayU8.class);

		// Load / learn all the markers. This can take a few seconds if there are a lot of markers
		for (List<Point2D_F64> marker : defs.markers) {

		// If you want 3D pose information then the camera need sto be calibrated. If you don't provide
		// this information then just things like the bounding box will be returned
		CameraPinholeBrown intrinsic = CalibrationIO.load(
		detector.setLensDistortion(LensDistortionFactory.narrow(intrinsic), intrinsic.width, intrinsic.height);

		// It's now ready to start processing images. Let's load an image
		BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample("fiducial/random_dots/image02.jpg"));
		GrayU8 gray = ConvertBufferedImage.convertFrom(image, false, ImageType.SB_U8);


		// Time to visualize the results
		Graphics2D g2 = image.createGraphics();
		var targetToSensor = new Se3_F64();
		var bounds = new Polygon2D_F64();
		var center = new Point2D_F64();
		for (int i = 0; i < detector.totalFound(); i++) {
			detector.getBounds(i, bounds);
			detector.getCenter(i, center);

			g2.setColor(new Color(50, 50, 255));
			g2.setStroke(new BasicStroke(10));
			VisualizeShapes.drawPolygon(bounds, true, 1.0, g2);
			VisualizeFiducial.drawLabel(center, "" + detector.getId(i), g2);

			System.out.println("Target ID = " + detector.getId(i));

			if (detector.is3D()) {
				detector.getFiducialToCamera(i, targetToSensor);
				VisualizeFiducial.drawCube(targetToSensor, intrinsic, detector.getWidth(i), 3, g2);
		ShowImages.showWindow(image, "Random Dot Markers", true);