/*
* Copyright (c) 2011-2016, 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.demonstrations.feature.detect.extract;
import boofcv.abst.feature.detect.extract.ConfigExtract;
import boofcv.abst.feature.detect.extract.NonMaxSuppression;
import boofcv.abst.feature.detect.intensity.GeneralFeatureIntensity;
import boofcv.abst.filter.derivative.AnyImageDerivative;
import boofcv.alg.feature.detect.intensity.HessianBlobIntensity;
import boofcv.alg.feature.detect.interest.GeneralFeatureDetector;
import boofcv.alg.filter.derivative.DerivativeType;
import boofcv.alg.filter.derivative.GImageDerivativeOps;
import boofcv.alg.misc.ImageStatistics;
import boofcv.factory.feature.detect.extract.FactoryFeatureExtractor;
import boofcv.factory.feature.detect.intensity.FactoryIntensityPoint;
import boofcv.gui.SelectAlgorithmAndInputPanel;
import boofcv.gui.feature.FancyInterestPointRender;
import boofcv.gui.image.ImagePanel;
import boofcv.gui.image.ShowImages;
import boofcv.gui.image.VisualizeImageData;
import boofcv.io.PathLabel;
import boofcv.io.UtilIO;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.struct.QueueCorner;
import boofcv.struct.image.GrayF32;
import boofcv.struct.image.ImageGray;
import georegression.struct.point.Point2D_I16;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
/**
* Displays a window showing the selected corner-laplace features across different scale spaces.
*
* @author Peter Abeles
*/
public class CompareFeatureExtractorApp
extends SelectAlgorithmAndInputPanel implements GeneralExtractConfigPanel.Listener {
T grayImage;
Class imageType;
GeneralExtractConfigPanel configPanel;
boolean processImage = false;
BufferedImage input;
BufferedImage intensityImage;
BufferedImage workImage;
AnyImageDerivative deriv;
GeneralFeatureIntensity intensityAlg;
int minSeparation = 5;
// which image is being viewed in the GUI
int viewImage = 2;
int radius = 2;
int numFeatures = 200;
float thresholdFraction = 0.1f;
FancyInterestPointRender render = new FancyInterestPointRender();
ImagePanel imagePanel;
public CompareFeatureExtractorApp(Class imageType, Class derivType) {
super(1);
this.imageType = imageType;
addAlgorithm(0, "Harris", FactoryIntensityPoint.harris(radius, 0.04f, false, imageType));
addAlgorithm(0, "KLT", FactoryIntensityPoint.shiTomasi(radius, false, derivType));
addAlgorithm(0, "FAST", FactoryIntensityPoint.fast(5, 11, derivType));
addAlgorithm(0, "KitRos", FactoryIntensityPoint.kitros(derivType));
addAlgorithm(0, "Laplace Det", FactoryIntensityPoint.hessian(HessianBlobIntensity.Type.DETERMINANT, derivType));
addAlgorithm(0, "Laplace Trace", FactoryIntensityPoint.hessian(HessianBlobIntensity.Type.TRACE, derivType));
deriv = GImageDerivativeOps.createAnyDerivatives(DerivativeType.SOBEL,imageType, derivType);
JPanel gui = new JPanel();
gui.setLayout(new BorderLayout());
imagePanel = new ImagePanel();
this.configPanel = new GeneralExtractConfigPanel();
configPanel.setThreshold(thresholdFraction);
configPanel.setFeatureSeparation(minSeparation);
configPanel.setImageIndex(viewImage);
configPanel.setListener(this);
gui.add(configPanel, BorderLayout.WEST);
gui.add(imagePanel, BorderLayout.CENTER);
setMainGUI(gui);
}
public void process(BufferedImage input) {
this.input = input;
grayImage = ConvertBufferedImage.convertFromSingle(input, null, imageType);
workImage = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_BGR);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
doRefreshAll();
}
});
}
@Override
public void loadConfigurationFile(String fileName) {
}
@Override
public void refreshAll(Object[] cookies) {
setActiveAlgorithm(0, null, cookies[0]);
}
@Override
public void setActiveAlgorithm(int indexFamily, String name, Object cookie) {
if (input == null)
return;
intensityAlg = (GeneralFeatureIntensity) cookie;
doProcess();
}
private synchronized void doProcess() {
// System.out.println("radius "+radius+" min separation "+minSeparation+" thresholdFraction "+thresholdFraction+" numFeatures "+numFeatures);
deriv.setInput(grayImage);
D derivX = deriv.getDerivative(true);
D derivY = deriv.getDerivative(false);
D derivXX = deriv.getDerivative(true, true);
D derivYY = deriv.getDerivative(false, false);
D derivXY = deriv.getDerivative(true, false);
// todo modifying buffered images which might be actively being displayed, could mess up swing
intensityAlg.process(grayImage, derivX, derivY, derivXX, derivYY, derivXY);
GrayF32 intensity = intensityAlg.getIntensity();
intensityImage = VisualizeImageData.colorizeSign(
intensityAlg.getIntensity(), null, ImageStatistics.maxAbs(intensity));
float max = ImageStatistics.maxAbs(intensity);
float threshold = max * thresholdFraction;
NonMaxSuppression extractor =
FactoryFeatureExtractor.nonmax(new ConfigExtract(minSeparation, threshold, radius, true));
GeneralFeatureDetector detector = new GeneralFeatureDetector(intensityAlg, extractor);
detector.setMaxFeatures(numFeatures);
detector.process(grayImage, derivX, derivY, derivXX, derivYY, derivXY);
QueueCorner foundCorners = detector.getMaximums();
render.reset();
for (int i = 0; i < foundCorners.size(); i++) {
Point2D_I16 p = foundCorners.get(i);
render.addPoint(p.x, p.y, 3, Color.RED);
}
Graphics2D g2 = workImage.createGraphics();
g2.drawImage(input, 0, 0, grayImage.width, grayImage.height, null);
render.draw(g2);
drawImage();
}
@Override
public void changeInput(String name, int index) {
BufferedImage image = media.openImage(inputRefs.get(index).getPath());
if (image != null) {
process(image);
}
}
@Override
public boolean getHasProcessedImage() {
return processImage;
}
@Override
public void changeImage(int index) {
this.viewImage = index;
drawImage();
}
private void drawImage() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
switch (viewImage) {
case 0:
imagePanel.setBufferedImage(input);
break;
case 1:
imagePanel.setBufferedImage(intensityImage);
break;
case 2:
imagePanel.setBufferedImage(workImage);
break;
}
BufferedImage b = imagePanel.getImage();
imagePanel.setPreferredSize(new Dimension(b.getWidth(), b.getHeight()));
imagePanel.repaint();
processImage = true;
}
});
}
@Override
public synchronized void changeFeatureSeparation(int radius) {
minSeparation = radius;
doProcess();
}
@Override
public synchronized void changeThreshold(double value) {
this.thresholdFraction = (float) value;
doProcess();
}
@Override
public synchronized void changeNumFeatures(int total) {
this.numFeatures = total;
doProcess();
}
public static void main(String args[]) {
CompareFeatureExtractorApp app = new CompareFeatureExtractorApp(GrayF32.class, GrayF32.class);
java.util.List inputs = new ArrayList();
inputs.add(new PathLabel("shapes", UtilIO.pathExample("shapes/shapes01.png")));
inputs.add(new PathLabel("sunflowers", UtilIO.pathExample("sunflowers.jpg")));
inputs.add(new PathLabel("beach", UtilIO.pathExample("scale/beach02.jpg")));
app.setInputList(inputs);
// wait for it to process one image so that the size isn't all screwed up
while (!app.getHasProcessedImage()) {
Thread.yield();
}
ShowImages.showWindow(app, "Feature Extraction", true);
System.out.println("Done");
}
}
Ads help maintain this website.