Difference between revisions of "Example Detect Black Polygons"

From BoofCV
Jump to navigationJump to search
m
m
 
(3 intermediate revisions by the same user not shown)
Line 5: Line 5:


Example Code:
Example Code:
* [https://github.com/lessthanoptimal/BoofCV/blob/v0.28/examples/src/main/java/boofcv/examples/features/ExampleDetectBlackPolygon.java ExampleDetectBlackPolygon.java]
* [https://github.com/lessthanoptimal/BoofCV/blob/v0.40/examples/src/main/java/boofcv/examples/features/ExampleDetectBlackPolygon.java ExampleDetectBlackPolygon.java]


Concepts:
Concepts:
Line 21: Line 21:
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
/**
/**
  * Example of how to use {@link DetectPolygonFromContour} to find black polygons in an image. This algorithm
  * Example of how to use {@link DetectPolygonFromContour} to find black polygons in an image. This algorithm
  * is the basis for several fiducial detectors in BoofCV and fits the polygon to sub-pixel accuracy and produces
  * is the basis for several fiducial detectors in BoofCV and fits the polygon to sub-pixel accuracy and produces
  * reasonable results on blurred images too. It is highly configurable and can even sparsely fit polygons
  * reasonable results on blurred images too. It is highly configurable and can even sparsely fit polygons
  * in a distorted image. Meaning the expensive step of undistorting the entire image is not needed.
  * in a distorted image. Meaning the expensive step of undistorting the entire image is not needed.
  *
  *
  * @author Peter Abeles
  * @author Peter Abeles
  */
  */
public class ExampleDetectBlackPolygon {
public class ExampleDetectBlackPolygon {
public static void main(String[] args) {
public static void main( String[] args ) {
String imagesConvex[] = new String[]{
String[] imagesConvex = new String[]{
"shapes/polygons01.jpg",
"shapes/polygons01.jpg",
"shapes/shapes02.png",
"shapes/shapes02.png",
"fiducial/image/examples/image01.jpg"};
"fiducial/image/examples/image01.jpg"};


String imagesConcave[] = new String[]{
String[] imagesConcave = new String[]{
"shapes/concave01.jpg"};
"shapes/concave01.jpg"};


Line 41: Line 41:


// first configure the detector to only detect convex shapes with 3 to 7 sides
// first configure the detector to only detect convex shapes with 3 to 7 sides
ConfigPolygonDetector config = new ConfigPolygonDetector(3,7);
ConfigPolygonDetector config = new ConfigPolygonDetector(3, 7);
DetectPolygonBinaryGrayRefine<GrayU8> detector = FactoryShapeDetector.polygon(config, GrayU8.class);
DetectPolygonBinaryGrayRefine<GrayU8> detector = FactoryShapeDetector.polygon(config, GrayU8.class);


Line 47: Line 47:


// now lets detect concave shapes with many sides
// now lets detect concave shapes with many sides
config.detector.maximumSides = 12;
config.detector.contourToPoly.maximumSides = 12;
config.detector.convex = false;
config.detector.contourToPoly.convex = false;
detector = FactoryShapeDetector.polygon(config, GrayU8.class);
detector = FactoryShapeDetector.polygon(config, GrayU8.class);


processImages(imagesConcave, detector, panel);
processImages(imagesConcave, detector, panel);


ShowImages.showWindow(panel,"Found Polygons",true);
ShowImages.showWindow(panel, "Found Polygons", true);
}
}


private static void processImages(String[] files,
private static void processImages( String[] files,
  DetectPolygonBinaryGrayRefine<GrayU8> detector,
  DetectPolygonBinaryGrayRefine<GrayU8> detector,
  ListDisplayPanel panel)
  ListDisplayPanel panel ) {
{
for (String fileName : files) {
for( String fileName : files ) {
BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample(fileName));
BufferedImage image = UtilImageIO.loadImage(UtilIO.pathExample(fileName));


GrayU8 input = ConvertBufferedImage.convertFromSingle(image, null, GrayU8.class);
GrayU8 input = ConvertBufferedImage.convertFromSingle(image, null, GrayU8.class);
GrayU8 binary = new GrayU8(input.width,input.height);
GrayU8 binary = new GrayU8(input.width, input.height);


// Binarization is done outside to allows creative tricks. For example, when applied to a chessboard
// Binarization is done outside to allows creative tricks. For example, when applied to a chessboard
// pattern where square touch each other, the binary image is eroded first so that they don't touch.
// pattern where square touch each other, the binary image is eroded first so that they don't touch.
// The squares are expanded automatically during the subpixel optimization step.
// The squares are expanded automatically during the subpixel optimization step.
int threshold = GThresholdImageOps.computeOtsu(input, 0, 255);
int threshold = (int)GThresholdImageOps.computeOtsu(input, 0, 255);
ThresholdImageOps.threshold(input, binary, threshold, true);
ThresholdImageOps.threshold(input, binary, threshold, true);


Line 78: Line 77:


// visualize results by drawing red polygons
// visualize results by drawing red polygons
java.util.List<Polygon2D_F64> found = detector.getPolygons(null,null);
java.util.List<Polygon2D_F64> found = detector.getPolygons(null, null);
Graphics2D g2 = image.createGraphics();
Graphics2D g2 = image.createGraphics();
g2.setStroke(new BasicStroke(3));
g2.setStroke(new BasicStroke(5));
for (int i = 0; i < found.size(); i++) {
for (int i = 0; i < found.size(); i++) {
g2.setColor(Color.RED);
g2.setColor(Color.RED);
VisualizeShapes.drawPolygon(found.get(i), true, g2, true);
VisualizeShapes.drawPolygon(found.get(i), true, g2, true);
g2.setColor(Color.CYAN);
g2.setColor(Color.CYAN);
VisualizeShapes.drawPolygonCorners(found.get(i), 2, g2, true);
VisualizeShapes.drawPolygonCorners(found.get(i), 3, g2, true);
}
}


panel.addImage(image,new File(fileName).getName());
panel.addImage(image, new File(fileName).getName());
}
}
}
}
}
}
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 12:56, 17 January 2022

Red lines outline detected polygons. Was configured to find objects with 3 to 5 sides.

BinaryPolygonDetector is used by most of the fiducials in BoofCV. What it does is detects black polygons inside the image and then refines that estimate to within subpixel precision. It does this quickly, robustly, and very accurately.

Example Code:

Concepts:

  • Polygons
  • Fiducials

Related Examples

Example Code

/**
 * Example of how to use {@link DetectPolygonFromContour} to find black polygons in an image. This algorithm
 * is the basis for several fiducial detectors in BoofCV and fits the polygon to sub-pixel accuracy and produces
 * reasonable results on blurred images too. It is highly configurable and can even sparsely fit polygons
 * in a distorted image. Meaning the expensive step of undistorting the entire image is not needed.
 *
 * @author Peter Abeles
 */
public class ExampleDetectBlackPolygon {
	public static void main( String[] args ) {
		String[] imagesConvex = new String[]{
				"shapes/polygons01.jpg",
				"shapes/shapes02.png",
				"fiducial/image/examples/image01.jpg"};

		String[] imagesConcave = new String[]{
				"shapes/concave01.jpg"};

		ListDisplayPanel panel = new ListDisplayPanel();

		// first configure the detector to only detect convex shapes with 3 to 7 sides
		ConfigPolygonDetector config = new ConfigPolygonDetector(3, 7);
		DetectPolygonBinaryGrayRefine<GrayU8> detector = FactoryShapeDetector.polygon(config, GrayU8.class);

		processImages(imagesConvex, detector, panel);

		// now lets detect concave shapes with many sides
		config.detector.contourToPoly.maximumSides = 12;
		config.detector.contourToPoly.convex = false;
		detector = FactoryShapeDetector.polygon(config, GrayU8.class);

		processImages(imagesConcave, detector, panel);

		ShowImages.showWindow(panel, "Found Polygons", true);
	}

	private static void processImages( String[] files,
									   DetectPolygonBinaryGrayRefine<GrayU8> detector,
									   ListDisplayPanel panel ) {
		for (String fileName : files) {
			BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample(fileName));

			GrayU8 input = ConvertBufferedImage.convertFromSingle(image, null, GrayU8.class);
			GrayU8 binary = new GrayU8(input.width, input.height);

			// Binarization is done outside to allows creative tricks. For example, when applied to a chessboard
			// pattern where square touch each other, the binary image is eroded first so that they don't touch.
			// The squares are expanded automatically during the subpixel optimization step.
			int threshold = (int)GThresholdImageOps.computeOtsu(input, 0, 255);
			ThresholdImageOps.threshold(input, binary, threshold, true);

			// it takes in a grey scale image and binary image
			// the binary image is used to do a crude polygon fit, then the grey image is used to refine the lines
			// using a sub-pixel algorithm
			detector.process(input, binary);

			// visualize results by drawing red polygons
			java.util.List<Polygon2D_F64> found = detector.getPolygons(null, null);
			Graphics2D g2 = image.createGraphics();
			g2.setStroke(new BasicStroke(5));
			for (int i = 0; i < found.size(); i++) {
				g2.setColor(Color.RED);
				VisualizeShapes.drawPolygon(found.get(i), true, g2, true);
				g2.setColor(Color.CYAN);
				VisualizeShapes.drawPolygonCorners(found.get(i), 3, g2, true);
			}

			panel.addImage(image, new File(fileName).getName());
		}
	}
}