boofcv.alg.interpolate.array.Interpolate1D_F32 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of boofcv-ip Show documentation
Show all versions of boofcv-ip Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* Copyright (c) 2021, 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.interpolate.array;
/**
* Provides much of the basic house keeping needed for interpolating 1D data. Interpolation
* is done using sample points y[i] = f(x[i]) where x is a monotonically increasing or decreasing
* function.
*
* @author Peter Abeles
*/
@SuppressWarnings({"NullAway.Init"})
public abstract class Interpolate1D_F32 {
// the sample data
// both axises must be monotonic increasing or decreasing
protected int size;
protected float[] x;
protected float[] y;
// how many points should the interpolation use
// this is equal to the degree + 1
protected int M;
// this is an index that the sample point is between
private int center;
// this is the first index that the interpolation algorithm will use
// 0 <= index0 <= size - M
protected int index0;
// should it hunt next time instead of searching?
private boolean doHunt;
// used to help it decide to hunt or search
private int dj;
// true if the data is increasing
protected boolean ascend;
/**
* @param degree The number of points used in the interpolation minus one
*/
protected Interpolate1D_F32( int degree ) {
changeDegree(degree);
}
/**
* @param degree The number of points used in the interpolation minus one
* @param x Where the points are sample at. Not modifed. Reference saved.
* @param y The value at the sample points. Not modifed. Reference saved.
* @param size The number of points used.
*/
protected Interpolate1D_F32( int degree, float[] x, float[] y, int size ) {
this(degree);
setInput(x, y, size);
}
/**
* Sets the data that is being interpolated.
*
* @param x Where the points are sample at. Not modifed. Reference saved.
* @param y The value at the sample points. Not modifed. Reference saved.
* @param size The number of points used.
*/
public void setInput( float[] x, float[] y, int size ) {
if (x.length < size || y.length < size) {
throw new IllegalArgumentException("Arrays too small for size.");
}
if (size < M) {
throw new IllegalArgumentException("Not enough data points for M");
}
this.x = x;
this.y = y;
this.size = size;
this.dj = Math.min(1, (int)Math.pow(size, 0.25));
ascend = x[size - 1] >= x[0];
}
/**
* Performs interpolation at the sample point.
*
* @param testX Where the interpolated value is done at.
* @return The interpolated value at sampleX.
*/
public float process( float testX ) {
if (doHunt) {
hunt(testX);
} else {
bisectionSearch(testX, 0, size - 1);
}
return compute(testX);
}
/**
* Performs an interpolation using sample data starting at index0. Little checking
* is done and it is assumed the user knows what he is doing. Interpolation is done
* using points from index0 to index0 + M - 1
*
* @param index0 first sample point used in the interpolation.
* @param testX Where the interpolated value is done at.
* @return The interpolated value at sampleX.
*/
public float process( int index0, float testX ) {
this.index0 = index0;
return compute(testX);
}
/**
* This is where the specific implementation of the interpolation is done. It should
* use points index0 to index0 + M - 1 in its interpolation
*
* @param testX Where the interpolated value is done at.
* @return The interpolated value at sampleX.
*/
protected abstract float compute( float testX );
/**
* Changes the number of points used in the interpolation.
*
* @param degree Number of points used minus one.
*/
public void changeDegree( int degree ) {
this.M = degree + 1;
doHunt = false;
}
/**
* To speed up finding the appropriate indexes to use in the interpolation it can use its
* previous results to search a smaller region than it would otherwise.
*
* @param val The value that is to be interpolated.
*/
protected void hunt( float val ) {
int lowerLimit = center;
int upperLimit;
int inc = 1;
if (val >= x[lowerLimit] && ascend) {
// hunt up
for (; ; ) {
upperLimit = lowerLimit + inc;
// see if it is outside the table
if (upperLimit >= size - 1) {
upperLimit = size - 1;
break;
} else if (val < x[upperLimit] && ascend) {
break;
} else {
lowerLimit = upperLimit;
inc += inc;
}
}
} else {
// hunt down
upperLimit = lowerLimit;
for (; ; ) {
lowerLimit = lowerLimit - inc;
if (lowerLimit <= 0) {
lowerLimit = 0;
break;
} else if (val >= x[lowerLimit] && ascend) {
break;
} else {
upperLimit = lowerLimit;
inc += inc;
}
}
}
bisectionSearch(val, lowerLimit, upperLimit);
}
/**
* Searches the x array by bisecting it. This takes advantage of the data being
* monotonic. This finds a center index which has the following property:
* x[center] ≤ val < x[center+1]
* From that it selects index0 which is center - M/2.
*
* @param val The value that is to be interpolated.
* @param lowerLimit Lower limit for x index.
* @param upperLimit The largest possible index of x
*/
protected void bisectionSearch( float val, int lowerLimit, int upperLimit ) {
while (upperLimit - lowerLimit > 1) {
int middle = (upperLimit + lowerLimit)/2;
if (val >= x[middle] && ascend) {
lowerLimit = middle;
} else {
upperLimit = middle;
}
}
// decide if it should hunt or locate next time
doHunt = Math.abs(lowerLimit - center) > dj;
// make sure the points sampled for the polynomial are all within bounds
center = lowerLimit;
index0 = center - M/2;
if (index0 + M > size) {
index0 = size - M;
} else if (index0 < 0) {
index0 = 0;
}
}
}