/*
* This file is part of the JFeatureLib project: https://github.com/locked-fg/JFeatureLib
* JFeatureLib is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* JFeatureLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JFeatureLib; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* You are kindly asked to refer to the papers of the according authors which
* should be mentioned in the Javadocs of the respective classes as well as the
* JFeatureLib project itself.
*
* Hints how to cite the projects can be found at
* https://github.com/locked-fg/JFeatureLib/wiki/Citation
*/
package de.lmu.ifi.dbs.jfeaturelib.features.surf;
import ij.IJ;
import ij.process.ImageProcessor;
import static java.lang.Math.*;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.Logger;
/**
* SURF library for ImageJ. Based on SURF paper (2008) and OpenSURF C++ implementation. See SURF_Test.java for example
* of usage.
*
* @author Eugen Labun
*/
public class IJFacade {
private static final Logger log = Logger.getLogger(IJFacade.class);
private IJFacade() {
}
/**
* Finds interest points using the default parameter.
*/
public static List<InterestPoint> detectAndDescribeInterestPoints(IntegralImage intImg) {
return detectAndDescribeInterestPoints(intImg, new Params());
}
/**
* Finds interest points using the provided parameter.
*/
public static List<InterestPoint> detectAndDescribeInterestPoints(IntegralImage intImg, Params p) {
long begin, end;
// Detect interest points with Fast-Hessian
begin = System.currentTimeMillis();
List<InterestPoint> ipts = Detector.fastHessian(intImg, p);
end = System.currentTimeMillis();
p.getStatistics().timeSURFDetector = end - begin;
p.getStatistics().detectedIPs = ipts.size();
float[] strengthOfIPs = new float[ipts.size()];
for (int i = 0; i < ipts.size(); i++) {
strengthOfIPs[i] = ipts.get(i).strength;
}
Arrays.sort(strengthOfIPs);
p.getStatistics().strengthOfIPs = strengthOfIPs;
// Describe interest points with SURF-descriptor
begin = System.currentTimeMillis();
if (!p.isUpright()) {
for (InterestPoint ipt : ipts) {
Descriptor.computeAndSetOrientation(ipt, intImg);
}
}
for (InterestPoint ipt : ipts) {
Descriptor.computeAndSetDescriptor(ipt, intImg, p);
}
end = System.currentTimeMillis();
p.getStatistics().timeSURFDescriptor = end - begin;
return ipts;
}
/**
* Draws interest points onto suplied
* <code>ImageProcessor</code>.
*/
public static void drawInterestPoints(ImageProcessor img, List<InterestPoint> ipts, Params params) {
for (InterestPoint ipt : ipts) {
drawSingleInterestPoint(img, params, ipt);
}
}
public static void drawSingleInterestPoint(ImageProcessor img, Params p, InterestPoint ipt) {
int x = round(ipt.x);
int y = round(ipt.y);
float w = ipt.scale * 10; // for descriptor window
float ori = ipt.orientation;
float co = (float) cos(ori);
float si = (float) sin(ori);
float s = ipt.strength * 10000; // for orientation vector
// The order of drawing is important:
// 1) descriptor windows
// 2) orientation vectors
// 3) points
// Otherwise some points could be overdrawed by descriptor- or vector-lines.
// Draw descriptor window around the interest point
if (p.isDisplayDescriptorWindows()) {
img.setLineWidth(p.getLineWidth());
img.setColor(p.getDescriptorWindowColor());
float x0 = w * (si + co) + ipt.x;
float y0 = w * (-co + si) + ipt.y;
float x1 = w * (si - co) + ipt.x;
float y1 = w * (-co - si) + ipt.y;
float x2 = w * (-si - co) + ipt.x;
float y2 = w * (co - si) + ipt.y;
float x3 = w * (-si + co) + ipt.x;
float y3 = w * (co + si) + ipt.y;
// normal window
// img.moveTo(round(x0), round(y0));
// img.lineTo(round(x1), round(y1));
// img.lineTo(round(x2), round(y2));
// img.lineTo(round(x3), round(y3));
// img.lineTo(round(x0), round(y0));
// 'envelope'-window
img.moveTo(x, y);
img.lineTo(round(x0), round(y0));
img.lineTo(round(x1), round(y1));
img.lineTo(round(x2), round(y2));
img.lineTo(round(x3), round(y3));
img.lineTo(x, y);
}
// Draw orientation vector
if (p.isDisplayOrientationVectors()) {
img.setLineWidth(p.getLineWidth());
img.setColor(p.getOrientationVectorColor());
img.drawLine(x, y, round(s * co + x), round(s * si + y));
}
// Draw interest point
img.setLineWidth(p.getLineWidth() * 4);
if (ipt.sign) {
img.setColor(p.getDarkPointColor());
} else {
img.setColor(p.getLightPointColor());
}
img.drawDot(x, y);
// TODO: Draw motion (x,y) -> (x+dx, y+dy) ? Or (x-dx, y-dy) -> (x,y) ?
// (OpenSURF uses 'tailSize' parameter to indicate wether to draw the motion.)
}
public static void initializeStatisticsWindow() {
IJ.setColumnHeadings(Statistics.getEmptyHeadersForIJ());
log.info("Program Version:\t" + Params.programVersion);
}
public static void displayStatistics(Params p) {
String out = "";
Statistics stat = p.getStatistics();
out += "Start Time:\t" + stat.startTime + "\n";
out += "Image:\t" + stat.imageTitle + "\n";
out += "\n";
out += "Params\n";
out += "Octaves:\t" + p.getOctaves() + "\n";
out += "Layers:\t" + p.getLayers() + "\n";
out += "Threshold:\t" + IJ.d2s(p.getThreshold(), 5) + "\n";
out += "InitSamplStep:\t" + p.getInitStep() + "\n";
out += "\n";
out += "Detector Statistics\n";
out += Statistics.getHeadersForIJ() + "\n";
String[] rows = stat.getRowsForIJ();
for (String s : rows) {
out += s;
}
out += "\n";
int detectedIPs = p.getStatistics().detectedIPs;
out += "Interest Points:\t" + detectedIPs + "\n";
out += "\n";
out += "Strength of Interest Points\n";
float[] strengthOfIPs = p.getStatistics().strengthOfIPs;
out += "Min:\t" + IJ.d2s(strengthOfIPs[0], 10) + "\n";
out += "Max:\t" + IJ.d2s(strengthOfIPs[detectedIPs - 1], 10) + "\n";
out += "Median:\t" + IJ.d2s(strengthOfIPs[detectedIPs / 2], 10) + "\n";
float sum = 0;
for (float v : strengthOfIPs) {
sum += v;
}
out += "Average:\t" + IJ.d2s(sum / detectedIPs, 10) + "\n";
out += "\n";
out += "Time (ms)\n";
out += "IntegralImage:\t" + stat.timeIntegralImage + "\n";
out += "Detector:\t" + stat.timeSURFDetector + "\n";
out += "Descriptor:\t" + stat.timeSURFDescriptor + "\n";
log.info(out);
}
}