boofcv.alg.feature.describe.DescribeSiftCommon Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of boofcv-feature Show documentation
Show all versions of boofcv-feature Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* Copyright (c) 2011-2017, 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.describe;
import boofcv.alg.descriptor.UtilFeature;
import boofcv.alg.filter.kernel.KernelMath;
import boofcv.factory.filter.kernel.FactoryKernelGaussian;
import boofcv.struct.convolve.Kernel2D_F32;
import boofcv.struct.feature.TupleDesc_F64;
import georegression.metric.UtilAngle;
/**
* Base class for {@link DescribePointSift SIFT} descriptors. Provides common functionality between sparse and
* dense computations.
*
* @author Peter Abeles
*/
public class DescribeSiftCommon {
// width of a subregion, in samples
protected int widthSubregion;
// width of the outer grid, in sub-regions
protected int widthGrid;
// number of bins in the orientation histogram
protected int numHistogramBins;
protected double histogramBinWidth;
// maximum value of an element in the descriptor
protected double maxDescriptorElementValue;
// weight applied across the entire image
protected float gaussianWeight[];
/**
* Configures the descriptor.
*
* @param widthSubregion Width of sub-region in samples. Try 4
* @param widthGrid Width of grid in subregions. Try 4.
* @param numHistogramBins Number of bins in histogram. Try 8
* @param weightingSigmaFraction Sigma for Gaussian weighting function is set to this value * region width. Try 0.5
* @param maxDescriptorElementValue Helps with non-affine changes in lighting. See paper. Try 0.2
*/
public DescribeSiftCommon(int widthSubregion, int widthGrid,
int numHistogramBins , double weightingSigmaFraction , double maxDescriptorElementValue )
{
this.widthSubregion = widthSubregion;
this.widthGrid = widthGrid;
this.numHistogramBins = numHistogramBins;
this.maxDescriptorElementValue = maxDescriptorElementValue;
this.histogramBinWidth = 2.0*Math.PI/numHistogramBins;
// number of samples wide the descriptor window is
int descriptorWindow = widthSubregion*widthGrid;
double weightSigma = descriptorWindow*weightingSigmaFraction;
gaussianWeight = createGaussianWeightKernel(weightSigma,descriptorWindow/2);
}
/**
* Adjusts the descriptor. This adds lighting invariance and reduces the affects of none-affine changes
* in lighting.
*
* 1) Apply L2 normalization
* 2) Clip using max descriptor value
* 3) Apply L2 normalization again
*/
public static void normalizeDescriptor(TupleDesc_F64 descriptor , double maxDescriptorElementValue ) {
// normalize descriptor to unit length
UtilFeature.normalizeL2(descriptor);
// clip the values
for (int i = 0; i < descriptor.size(); i++) {
double value = descriptor.value[i];
if( value > maxDescriptorElementValue ) {
descriptor.value[i] = maxDescriptorElementValue;
}
}
// normalize again
UtilFeature.normalizeL2(descriptor);
}
/**
* Creates a gaussian weighting kernel with an even number of elements along its width
*/
protected static float[] createGaussianWeightKernel( double sigma , int radius ) {
Kernel2D_F32 ker = FactoryKernelGaussian.gaussian2D_F32(sigma,radius,false,false);
float maxValue = KernelMath.maxAbs(ker.data,4*radius*radius);
KernelMath.divide(ker,maxValue);
return ker.data;
}
/**
* Applies trilinear interpolation across the descriptor
*/
protected void trilinearInterpolation( float weight , float sampleX , float sampleY , double angle , TupleDesc_F64 descriptor )
{
for (int i = 0; i < widthGrid; i++) {
double weightGridY = 1.0 - Math.abs(sampleY-i);
if( weightGridY <= 0) continue;
for (int j = 0; j < widthGrid; j++) {
double weightGridX = 1.0 - Math.abs(sampleX-j);
if( weightGridX <= 0 ) continue;
for (int k = 0; k < numHistogramBins; k++) {
double angleBin = k*histogramBinWidth;
double weightHistogram = 1.0 - UtilAngle.dist(angle,angleBin)/histogramBinWidth;
if( weightHistogram <= 0 ) continue;
int descriptorIndex = (i*widthGrid + j)*numHistogramBins + k;
descriptor.value[descriptorIndex] += weight*weightGridX*weightGridY*weightHistogram;
}
}
}
}
/**
* Number of elements in the descriptor.
*/
public int getDescriptorLength() {
return widthGrid*widthGrid*numHistogramBins;
}
/**
* Radius of descriptor in pixels. Width is radius*2
*/
public int getCanonicalRadius() {
return widthGrid*widthSubregion/2;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy