![JAR search and dependency download from the Maven repository](/logo.png)
boofcv.alg.tracker.meanshift.LocalWeightedHistogramRotRect Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of recognition Show documentation
Show all versions of recognition Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* Copyright (c) 2011-2015, 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.tracker.meanshift;
import boofcv.alg.interpolate.InterpolatePixelMB;
import boofcv.misc.BoofMiscOps;
import boofcv.struct.RectangleRotate_F32;
import boofcv.struct.image.ImageBase;
import georegression.struct.point.Point2D_F32;
import org.ddogleg.stats.UtilGaussian;
import java.util.ArrayList;
import java.util.List;
/**
* Computes a local histogram weighted using a Gaussian function. The weighting function is shaped using a rotated
* rectangle, where the sigma along each axis is set by the rectangle's width and height. For use with
* {@link TrackerMeanShiftComaniciu2003}.
*
* The histogram is stored in a row major format.
*
* @author Peter Abeles
**/
public class LocalWeightedHistogramRotRect {
// Interpolation function
private InterpolatePixelMB interpolate;
// storage for interpolated pixel
private float value[];
// maximum value of a pixel in any band
protected float maxPixelValue;
// number of binds in the histogram
private int numBins;
// cosine and sine of rotation rectangle angle
protected float c,s;
// output of conversion from region to image coordinates
public float imageX,imageY;
// which element in the histogram does a coordinate in the grid belong to
protected int sampleHistIndex[];
// storage for sample weights and the histogram
protected float weights[];
protected float histogram[];
// list of sample points. in square coordinates. where 0.5 is 1/2 the width or height
protected List samplePts = new ArrayList();
/**
* Configures histogram calculation.
*
* @param numSamples Number of points it samples along each axis of the rectangle.
* @param numSigmas Number of standard deviations away the sides will be from the center. Try 3
* @param numHistogramBins Number of bins in the histogram
* @param numBands Number of bands in the input image
* @param maxPixelValue Maximum value of a pixel across all bands
* @param interpolate Function used to interpolate the image
*/
public LocalWeightedHistogramRotRect(int numSamples, double numSigmas,
int numHistogramBins, int numBands,
float maxPixelValue,
InterpolatePixelMB interpolate) {
this.numBins = numHistogramBins;
this.maxPixelValue = maxPixelValue*1.0001f; // avoid the possibility exceeding the max histogram size
this.interpolate = interpolate;
sampleHistIndex = new int[ numSamples*numSamples ];
histogram = new float[ (int)Math.pow(numHistogramBins,numBands) ];
value = new float[ numBands ];
createSamplePoints(numSamples);
computeWeights(numSamples, numSigmas);
}
/**
* compute the weights by convolving 1D gaussian kernel
*/
protected void computeWeights(int numSamples, double numSigmas) {
weights = new float[ numSamples*numSamples ];
float w[] = new float[ numSamples ];
for( int i = 0; i < numSamples; i++ ) {
float x = i/(float)(numSamples-1);
w[i] = (float) UtilGaussian.computePDF(0, 1, 2f*numSigmas * (x - 0.5f));
}
for( int y = 0; y < numSamples; y++ ) {
for( int x = 0; x < numSamples; x++ ) {
weights[y*numSamples + x] = w[y]*w[x];
}
}
}
/**
* create the list of points in square coordinates that it will sample. values will range
* from -0.5 to 0.5 along each axis.
*/
protected void createSamplePoints(int numSamples) {
for( int y = 0; y < numSamples; y++ ) {
float regionY = (y/(numSamples-1.0f) - 0.5f);
for( int x = 0; x < numSamples; x++ ) {
float regionX = (x/(numSamples-1.0f) - 0.5f);
samplePts.add( new Point2D_F32(regionX,regionY));
}
}
}
/**
* Computes the histogram inside the specified region. Results are returned by calling {@link #getHistogram()}.
*
* @param image Input image
* @param region Region which is to be sampled
*/
public void computeHistogram( T image , RectangleRotate_F32 region ) {
interpolate.setImage(image);
c = (float)Math.cos( region.theta );
s = (float)Math.sin( region.theta );
for( int i = 0; i < histogram.length; i++ ) {
histogram[i] = 0;
}
// if it is entirely inside the image, interpolate using a faster technique
if( isInFastBounds(region) ) {
computeHistogramInside( region);
} else {
computeHistogramBorder(image, region);
}
normalizeHistogram();
}
/**
* Computes the histogram quickly inside the image
*/
protected void computeHistogramInside( RectangleRotate_F32 region) {
for( int i = 0; i < samplePts.size(); i++ ) {
Point2D_F32 p = samplePts.get(i);
squareToImageSample(p.x, p.y, region);
interpolate.get_fast(imageX,imageY,value);
int indexHistogram = computeHistogramBin(value);
sampleHistIndex[ i ] = indexHistogram;
histogram[indexHistogram] += weights[i];
}
}
/**
* Computes the histogram and skips pixels which are outside the image border
*/
protected void computeHistogramBorder(T image, RectangleRotate_F32 region) {
for( int i = 0; i < samplePts.size(); i++ ) {
Point2D_F32 p = samplePts.get(i);
squareToImageSample(p.x, p.y, region);
// make sure its inside the image
if( !BoofMiscOps.checkInside(image, imageX, imageY)) {
sampleHistIndex[ i ] = -1;
} else {
// use the slower interpolation which can handle the border
interpolate.get(imageX, imageY, value);
int indexHistogram = computeHistogramBin(value);
sampleHistIndex[ i ] = indexHistogram;
histogram[indexHistogram] += weights[i];
}
}
}
/**
* Given the value of a pixel, compute which bin in the histogram it belongs in
*/
protected int computeHistogramBin( float value[] ) {
int indexHistogram = 0;
int binStride = 1;
for( int bandIndex = 0; bandIndex < value.length; bandIndex++ ) {
int bin = (int)(numBins*value[bandIndex]/maxPixelValue);
indexHistogram += bin*binStride;
binStride *= numBins;
}
return indexHistogram;
}
/**
* Checks to see if the region can be sampled using the fast algorithm
*/
protected boolean isInFastBounds(RectangleRotate_F32 region) {
squareToImageSample(-0.5f, -0.5f, region);
if( !interpolate.isInFastBounds(imageX, imageY))
return false;
squareToImageSample(-0.5f, 0.5f, region);
if( !interpolate.isInFastBounds(imageX, imageY))
return false;
squareToImageSample(0.5f, 0.5f, region);
if( !interpolate.isInFastBounds(imageX, imageY))
return false;
squareToImageSample(0.5f, -0.5f, region);
if( !interpolate.isInFastBounds(imageX, imageY))
return false;
return true;
}
protected void normalizeHistogram() {
float total = 0;
for( int i = 0; i < histogram.length; i++ ) {
total += histogram[i];
}
for( int i = 0; i < histogram.length; i++ ) {
histogram[i] /= total;
}
}
/**
* Converts a point from square coordinates into image coordinates
*/
protected void squareToImageSample(float x, float y, RectangleRotate_F32 region) {
// -1 because it starts counting at 0. otherwise width+1 samples are made
x *= region.width-1;
y *= region.height-1;
imageX = x*c - y*s + region.cx;
imageY = x*s + y*c + region.cy;
}
public float[] getHistogram() {
return histogram;
}
public int[] getSampleHistIndex() {
return sampleHistIndex;
}
public List getSamplePts() {
return samplePts;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy