Difference between revisions of "Example Fiducial Random Dots"

From BoofCV
Jump to navigationJump to search
m
m
 
(3 intermediate revisions by the same user not shown)
Line 7: Line 7:
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.
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: [https://github.com/lessthanoptimal/BoofCV/blob/v0.36/examples/src/main/java/boofcv/examples/fiducial/ExampleFiducialRandomDots.java ExampleFiducialRandomDots.java]
Example File: [https://github.com/lessthanoptimal/BoofCV/blob/v0.40/examples/src/main/java/boofcv/examples/fiducial/ExampleFiducialRandomDots.java ExampleFiducialRandomDots.java]


Concepts:
Concepts:
Line 15: Line 15:


Relevant Videos:
Relevant Videos:
* Will be added soon
* [https://www.youtube.com/watch?v=8pn9Ebw90uk&t=184s Video Summary]
 
Related Tutorials/Example Code:  
Related Tutorials/Example Code:  
* [[Example_Fiducial_Square_Binary| Square Binary Fiducial]]
* [[Example_Fiducial_Square_Binary| Square Binary Fiducial]]
Line 35: Line 34:
  */
  */
public class ExampleFiducialRandomDots {
public class ExampleFiducialRandomDots {
public static void main(String[] args) {
public static void main( String[] args ) {
// The definitions file specifies where dots are on each marker and other bits of meta data
// The definitions file specifies where dots are on each marker and other bits of meta data
RandomDotDefinition defs = FiducialIO.loadRandomDotYaml(
RandomDotDefinition defs = FiducialIO.loadRandomDotYaml(
Line 42: Line 41:
// The only parameter that you have to set is markerLength. It's used to compute bounding
// 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
// boxes and similar. If you don't know what the width is just set it to 1.0
ConfigUchiyaMarker config = new ConfigUchiyaMarker();
var config = new ConfigUchiyaMarker();
config.markerLength = defs.markerWidth;
config.markerWidth = defs.markerWidth;
config.markerHeight = defs.markerHeight;


Uchiya_to_FiducialDetector<GrayU8> detector = FactoryFiducial.randomDots(config, GrayU8.class);
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
// 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 ) {
for (List<Point2D_F64> marker : defs.markers) {
detector.addMarker(marker);
detector.addMarker(marker);
}
}
Line 56: Line 56:
CameraPinholeBrown intrinsic = CalibrationIO.load(
CameraPinholeBrown intrinsic = CalibrationIO.load(
UtilIO.fileExample("fiducial/random_dots/intrinsic.yaml"));
UtilIO.fileExample("fiducial/random_dots/intrinsic.yaml"));
detector.setLensDistortion(LensDistortionFactory.narrow(intrinsic),intrinsic.width,intrinsic.height);
detector.setLensDistortion(LensDistortionFactory.narrow(intrinsic), intrinsic.width, intrinsic.height);


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


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


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


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


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

Latest revision as of 14:44, 17 January 2022

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

Concepts:

  • 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(
				UtilIO.fileExample("fiducial/random_dots/descriptions.yaml"));

		// 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) {
			detector.addMarker(marker);
		}

		// 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(
				UtilIO.fileExample("fiducial/random_dots/intrinsic.yaml"));
		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);

		detector.detect(gray);

		// 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);
	}
}