Example Feature Selector Limit

From BoofCV
Jump to navigationJump to search

When detecting interest points and other point features inside an image there's often the need to limit how many you consider. This can be a way to limit the amount of computational resources required. BoofCV provides the NonMaxLimiter as an abstract way to do just that and several different implementations. For some applications you might wish to only select the most intense features, others you might need to select features across the entire image to ensure numeric stability, or maybe random is good enough.

Example File: ExampleCalibrateMonocular.java

Calibration Tutorial: Wikipage


  • Corner detectors
  • Interest point detectors

Related Examples:

Example Code

 * Visualization of feature Select Limit. After non-maximum suppression, select limit decides which detected
 * features should be used when the requested number of features is exceeded by the number of detected features.
 * Typically, you either want the most intense features or you want to ensure that features are selected
 * throughout the image.
 * @author Peter Abeles
public class ExampleFeatureLimit {
	// Radius for non-maximum suppression
	public static final int NON_MAX_RADIUS = 5;

	// Maximum number of features it will return
	public static final int MAX_FEATURES = 200;

	public static BufferedImage renderLimit( GrayF32 intensity, SelectLimitTypes type ) {
		// Configure how it will select features inside the intensity image
		var limit = new ConfigSelectLimit(type, 0xBEEF);
		NonMaxLimiter nonmax = FactoryFeatureExtractor.nonmaxLimiter(new ConfigExtract(NON_MAX_RADIUS, 0), limit, MAX_FEATURES);

		// Detect the features
		FastAccess<LocalExtreme> features = nonmax.getFeatures();

		// Visualize the intensity image
		var output = new BufferedImage(intensity.width, intensity.height, BufferedImage.TYPE_INT_RGB);
		VisualizeImageData.colorizeSign(intensity, output, -1);

		// render each selected maximum with a circle
		Graphics2D g2 = output.createGraphics();
		for (int i = 0; i < features.size(); i++) {
			LocalExtreme c = features.get(i);
			VisualizeFeatures.drawCircle(g2, c.location.x, c.location.y, NON_MAX_RADIUS);
		return output;

	public static void main( String[] args ) {
		BufferedImage buffered = UtilImageIO.loadImageNotNull(UtilIO.pathExample("standard/boat.jpg"));

		GrayF32 input = ConvertBufferedImage.convertFrom(buffered, (GrayF32)null);

		// Compute the image gradient
		GrayF32 derivX = input.createSameShape();
		GrayF32 derivY = input.createSameShape();

		GImageDerivativeOps.gradient(DerivativeType.SOBEL, input, derivX, derivY, BorderType.EXTENDED);

		// From the gradient compute intensity of shi-tomasi features
		GeneralFeatureIntensity<GrayF32, GrayF32> featureIntensity =
				FactoryIntensityPoint.shiTomasi(3, false, GrayF32.class);

		featureIntensity.process(input, derivX, derivY, null, null, null);
		GrayF32 intensity = featureIntensity.getIntensity();

		var panel = new ListDisplayPanel();
		panel.addImage(buffered, "Input Image");

		// Detect maximums with different settings and visualize the results
		for (var type : SelectLimitTypes.values()) {
			panel.addImage(renderLimit(intensity, type), type.name());

		ShowImages.showWindow(panel, "Non-Max with Limiter", true);