All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.alg.feature.detect.interest.GeneralFeatureDetector Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright (c) 2011-2020, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.feature.detect.interest;

import boofcv.abst.feature.detect.extract.NonMaxSuppression;
import boofcv.abst.feature.detect.intensity.GeneralFeatureIntensity;
import boofcv.alg.feature.detect.selector.FeatureSelectLimit;
import boofcv.struct.QueueCorner;
import boofcv.struct.image.GrayF32;
import boofcv.struct.image.ImageGray;
import georegression.struct.point.Point2D_I16;
import lombok.Getter;
import lombok.Setter;

/**
 * 

* Detects features which are local maximums and/or local minimums in the feature intensity image. * A list of pixels to exclude as candidates can be provided. Image derivatives need to be computed * externally and provided as needed. The passed in {@link GeneralFeatureIntensity} is used to determine if local * maximums or minimums should be detected. *

* *

* If a maximum number of features is specified then the N most intense features are returned. By default all * found features are returned. Set to a value ≤ 0 to detect all features. *

* * @param Input image type. * @param Image derivative type. * * @author Peter Abeles */ public class GeneralFeatureDetector, D extends ImageGray> { // list of feature locations found by the extractor protected QueueCorner foundMaximum = new QueueCorner(10); protected QueueCorner foundMinimum = new QueueCorner(10); // Corners which should be excluded. protected QueueCorner excludeMaximum; protected QueueCorner excludeMinimum; // selects the features with the largest intensity protected @Getter FeatureSelectLimit selectMax; protected QueueCorner selected = new QueueCorner(); /** * Turns on select best features and sets the number it should return. If a list of excluded features * is passed in, then the maximum number of returned features is 'numFeatures' minus the number of * excluded features. A value ≤ 0 means there is no limit */ protected @Getter @Setter int maxFeatures; // extracts corners from the intensity image protected @Getter NonMaxSuppression extractor; // computes the feature intensity image protected GeneralFeatureIntensity intensity; /** * Specifies which algorithms to use and configures the detector. * * @param intensity Computes how much like the feature the region around each pixel is. * @param extractor Extracts the corners from intensity image */ public GeneralFeatureDetector(GeneralFeatureIntensity intensity, NonMaxSuppression extractor , FeatureSelectLimit selectMax) { if( extractor.canDetectMinimums() && !intensity.localMinimums() ) throw new IllegalArgumentException("Extracting local minimums, but intensity has minimums set to false"); if( extractor.canDetectMaximums() && !intensity.localMaximums() ) throw new IllegalArgumentException("Extracting local maximums, but intensity has maximums set to false"); if (extractor.getUsesCandidates() && !intensity.hasCandidates()) throw new IllegalArgumentException("The extractor requires candidate features, which the intensity does not provide."); this.intensity = intensity; this.extractor = extractor; this.selectMax = selectMax; // sanity check ignore borders and increase the size of the extractor's ignore border // if its ignore border is too small then false positive are highly likely if( intensity.getIgnoreBorder() > extractor.getIgnoreBorder() ) extractor.setIgnoreBorder(intensity.getIgnoreBorder()); } protected GeneralFeatureDetector() { } /** * Computes point features from image gradients. * * @param image Original image. * @param derivX image derivative in along the x-axis. Only needed if {@link #getRequiresGradient()} is true. * @param derivY image derivative in along the y-axis. Only needed if {@link #getRequiresGradient()} is true. * @param derivXX Second derivative. Only needed if {@link #getRequiresHessian()} ()} is true. * @param derivXY Second derivative. Only needed if {@link #getRequiresHessian()} ()} is true. * @param derivYY Second derivative. Only needed if {@link #getRequiresHessian()} ()} is true. */ public void process(I image, D derivX, D derivY, D derivXX, D derivYY, D derivXY) { intensity.process(image, derivX, derivY, derivXX, derivYY, derivXY); GrayF32 intensityImage = intensity.getIntensity(); int numSelectMin = -1; int numSelectMax = -1; if( maxFeatures > 0 ) { if( intensity.localMinimums() ) numSelectMin = excludeMinimum == null ? maxFeatures : maxFeatures - excludeMinimum.size; if( intensity.localMaximums() ) numSelectMax = excludeMaximum == null ? maxFeatures : maxFeatures - excludeMaximum.size; // return without processing if there is no room to detect any more features if( numSelectMin <= 0 && numSelectMax <= 0 ) return; } // mark pixels that should be excluded if( excludeMinimum != null ) { for( int i = 0; i < excludeMinimum.size; i++ ) { Point2D_I16 p = excludeMinimum.get(i); intensityImage.set(p.x,p.y,-Float.MAX_VALUE); } } if( excludeMaximum != null ) { for( int i = 0; i < excludeMaximum.size; i++ ) { Point2D_I16 p = excludeMaximum.get(i); intensityImage.set(p.x,p.y,Float.MAX_VALUE); } } foundMinimum.reset(); foundMaximum.reset(); if (intensity.hasCandidates()) { extractor.process(intensityImage, intensity.getCandidatesMin(), intensity.getCandidatesMax(),foundMinimum, foundMaximum); } else { extractor.process(intensityImage, null, null,foundMinimum, foundMaximum); } // optionally select the most intense features only resolveSelectAmbiguity(intensityImage, excludeMaximum, foundMinimum, numSelectMin, false); resolveSelectAmbiguity(intensityImage, excludeMinimum, foundMaximum, numSelectMax, true); } /** * More features were detected than requested. Need to select a subset of them */ private void resolveSelectAmbiguity(GrayF32 intensity, QueueCorner excluded, QueueCorner detected , int numSelect, boolean positive) { if (numSelect > 0) { selectMax.select(intensity,positive,excluded,detected,numSelect,selected); // selected is filled with corners from found, so hopefully implementation details of reset don't change detected.reset(); detected.appendAll(selected); } } /** * If the image gradient is required for calculations. * * @return true if the image gradient is required. */ public boolean getRequiresGradient() { return intensity.getRequiresGradient(); } /** * If the image Hessian is required for calculations. * * @return true if the image Hessian is required. */ public boolean getRequiresHessian() { return intensity.getRequiresHessian(); } public GrayF32 getIntensity() { return intensity.getIntensity(); } /** * Changes feature extraction threshold. * * @param threshold The new feature extraction threshold. */ public void setThreshold(float threshold) { extractor.setThresholdMaximum(threshold); } /** * Returns the current feature extraction threshold. * * @return feature extraction threshold. */ public float getThreshold() { return extractor.getThresholdMaximum(); } /** * Specify points which are excluded when detecting maximums * * @param exclude List of points being excluded */ public void setExcludeMaximum(QueueCorner exclude) { this.excludeMaximum = exclude; } /** * Returns a list of all the found maximums. * @return found point features */ public QueueCorner getMaximums() { return foundMaximum; } /** * Specify points which are excluded when detecting maximums * * @param exclude List of points being excluded */ public void setExcludeMinimum(QueueCorner exclude) { this.excludeMinimum = exclude; } /** * Returns a list of all the found maximums. * @return found point features */ public QueueCorner getMinimums() { return foundMinimum; } /** * true if it will detector local minimums */ public boolean isDetectMinimums() { return intensity.localMinimums(); } /** * true if it will detector local maximums */ public boolean isDetectMaximums() { return intensity.localMaximums(); } /** * Species the search radius for the feature * * @param radius Radius in pixels */ public void setSearchRadius( int radius ) { extractor.setSearchRadius(radius); } public int getSearchRadius() { return extractor.getSearchRadius(); } public Class getImageType() { return intensity.getImageType(); } public Class getDerivType() { return intensity.getDerivType(); } }