www.pudn.com > bsiftC_.rar > LoweDetector.cs
/* LoweDetector.cs
*
* Lowe scale-invariant keypoint feature detector (SIFT) interface.
*
* (C) Copyright 2004 -- Sebastian Nowozin (nowozin@cs.tu-berlin.de)
*
* Implementation of the SIFT algorithm as specified in this research paper by
* David Lowe: http://www.cs.ubc.ca/~lowe/papers/ijcv03-abs.html
*
* "This software is provided for non-commercial use only. The University of
* British Columbia has applied for a patent on the SIFT algorithm in the
* United States. Commercial applications of this software may require a
* license from the University of British Columbia."
* For more information, see the LICENSE file supplied with the distribution.
*/
using System;
using System.Collections;
public class LoweFeatureDetector
{
OctavePyramid pyr;
public OctavePyramid Pyr {
get {
return (pyr);
}
}
// Detection parameters, suggested by Lowe's research paper.
// Initial parameters
double octaveSigma = 1.6;
// Sigma for gaussian filter applied to double-scaled input image.
double preprocSigma = 1.5;
// Once one of the downscaled image's dimension falls below this,
// downscaling is stopped.
int minimumRequiredPixelsize = 32;
// How many DoG levels for each octave.
int scaleSpaceLevels = 3;
// *** Peak related parameters
// Tweak here to reduce/increase keypoint density
// Minimum absolute DoG value of a pixel to be allowed as minimum/maximum
// peak. This control how much general non-differing areas, such as the
// sky is filtered. Higher value = less peaks, lower value = more peaks.
// Good values from 0.005 to 0.01. Note this is related to
// 'dValueLowThresh', which should be a bit larger, factor 1.0 to 1.5.
double dogThresh = 0.0075;
// D-value filter highcap value, higher = less keypoints, lower = more.
// Lower: only keep keypoints with good localization properties, i.e.
// those that are precisely and easily to localize (high contrast, see
// Lowe, page 11. He recommends 0.03, but this seems way too high to
// me.)
double dValueLowThresh = 0.008;
// Required cornerness ratio level, higher = more keypoints, lower = less.
double maximumEdgeRatio = 20.0;
// The exact sub-pixel localization is done on just one DoG plane. Even
// when the scale adjustment exceeds +/- 0.5, the plane is not changed.
// With this value you can discard peaks that are localized to be too far
// from the plane. A high value will allow for peaks to be used that are
// more far away from the plane used for localization, while a low value
// will sort out more peaks, that drifted too far away.
//
// Be very careful with this value, as a too large value will lead to a
// high number of keypoints in hard to localize areas such as in photos of
// the sky.
//
// Good values seem to lie between 0.30 and 0.6.
double scaleAdjustThresh = 0.50;
// Number of maximum steps a single keypoint can make in its space.
int relocationMaximum = 4;
// Results
ArrayList globalKeypoints;
public ArrayList GlobalKeypoints {
get {
return (globalKeypoints);
}
}
// The Integer-normalized version of the globalKeypoints.
ArrayList globalNaturalKeypoints = null;
public ArrayList GlobalNaturalKeypoints {
get {
if (globalNaturalKeypoints != null)
return (globalNaturalKeypoints);
if (globalKeypoints == null)
throw (new ArgumentException ("No keypoints generated yet."));
globalNaturalKeypoints = new ArrayList ();
foreach (Keypoint kp in globalKeypoints)
globalNaturalKeypoints.Add (new KeypointN (kp));
return (globalNaturalKeypoints);
}
}
public LoweFeatureDetector ()
{
}
// Return the number of detected features.
public int DetectFeatures (ImageMap img)
{
return (DetectFeaturesDownscaled (img, -1, 1.0));
}
// Scale down the images down so that both dimensions are smaller than
// 'bothDimHi'. If 'bothDimHi' is < 0, the image is doubled before
// processing, if it is zero, nothing is done to the image.
public int DetectFeaturesDownscaled (ImageMap img, int bothDimHi,
double startScale)
{
globalKeypoints = globalNaturalKeypoints = null;
// Print license restriction
Console.Error.WriteLine ("");
Console.Error.WriteLine ("===============================================================================");
Console.Error.WriteLine ("The use of this software is restricted by certain conditions.");
Console.Error.WriteLine ("See the \"LICENSE\" file distributed with the program for details.");
Console.Error.WriteLine ("");
Console.Error.WriteLine ("This software is provided for non-commercial use only. The University");
Console.Error.WriteLine ("of British Columbia has applied for a patent on the SIFT algorithm in");
Console.Error.WriteLine ("the United States. Commercial applications of this software may");
Console.Error.WriteLine ("require a license from the University of British Columbia.");
Console.Error.WriteLine ("===============================================================================");
Console.Error.WriteLine ("");
// Double the image size, as this way more features are detected. The
// scale is reduced to 0.5.
if (bothDimHi < 0) {
img = img.ScaleDouble ();
startScale *= 0.5;
} else if (bothDimHi > 0) {
while (img.XDim > bothDimHi || img.YDim > bothDimHi) {
img = img.ScaleHalf ();
startScale *= 2.0;
}
}
// XXX: Maybe the blurring has to be before double-sizing?
// better not, if we would lose more information then?
// (Lowe03, p10, "We assume that the original image has a blur of at
// least \sigma = 0.5 ...")
// So, do one initial image smoothing pass.
if (preprocSigma > 0.0) {
GaussianConvolution gaussianPre =
new GaussianConvolution (preprocSigma);
img = gaussianPre.Convolve (img);
}
pyr = new OctavePyramid ();
pyr.BuildOctaves (img, startScale, scaleSpaceLevels,
octaveSigma, minimumRequiredPixelsize);
globalKeypoints = new ArrayList ();
// Generate keypoints from each scalespace.
for (int on = 0 ; on < pyr.Count ; ++on) {
DScaleSpace dsp = pyr[on];
ArrayList peaks = dsp.FindPeaks (dogThresh);
Console.WriteLine ("Octave {0} has {1} raw peaks",
on, peaks.Count);
int oldCount = peaks.Count;
ArrayList peaksFilt = dsp.FilterAndLocalizePeaks (peaks,
maximumEdgeRatio, dValueLowThresh, scaleAdjustThresh,
relocationMaximum);
Console.WriteLine (" filtered: {0} remaining from {1}, thats % {2:N2}",
peaksFilt.Count, oldCount, (100.0 * peaksFilt.Count) / oldCount);
Console.WriteLine ("generating keypoints from peaks");
// Generate the actual keypoint descriptors, using pre-computed
// values for the gradient magnitude and direction.
dsp.GenerateMagnitudeAndDirectionMaps ();
ArrayList keypoints = dsp.GenerateKeypoints (peaksFilt,
scaleSpaceLevels, octaveSigma);
dsp.ClearMagnitudeAndDirectionMaps ();
globalKeypoints.AddRange (keypoints);
}
return (globalKeypoints.Count);
}
}