boofcv.alg.shapes.polyline.SplitMergeLineFit Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of feature Show documentation
Show all versions of feature 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.shapes.polyline;
import georegression.struct.line.LineParametric2D_F64;
import georegression.struct.point.Point2D_F64;
import georegression.struct.point.Point2D_I32;
import org.ddogleg.struct.GrowQueue_B;
import org.ddogleg.struct.GrowQueue_I32;
import java.util.List;
/**
* Base class for algorithm which employ a split and merge strategy to fitting a set of line segments onto an
* ordered set of points. The lines are an approximation of the original shape described by the point list.
* This list can either be connected at the end (looped) or not, depending on the implementation. The points
* in the list are assumed to be ordered with each consecutive point connected to its neighbors. The output is
* a set of indexes which correspond to points in the original list that compose the line segments. A minimum
* of two indexes will be returned.
*
* The returned set of line segments is guaranteed to match the original set of points to within a user
* specified tolerance. That is, no point in the list will be more than 'tol' distance away from a line segment.
* A line is split when a point between two end points is greater than the split distance. A corner is removed (two
* lines merged) if the corner is less than the split distance away from two of its adjacent neighbors. The split
* threshold is specified as a fraction of line distance to maximize scale invariance. The minimum split threshold
* is specified in units of pixels because a simple ratio doesn't work well for small objects.
*
* Split and merge is repeated until there is no more change or the maximum number of iterations has been reached.
* @author Peter Abeles
*/
public abstract class SplitMergeLineFit {
// maximum number of split and merge iterations
protected int maxIterations;
// How far away a point is from the line before it is split. In fractions of a line segment's length squared.
protected double toleranceFractionSq;
// The maximum allowed distance a point can be from a line as a function of the overall
// contour length
protected double minimumSideLengthFraction;
protected int minimumSideLengthPixel;
// Reference to the input contour list
protected List contour;
// used to compute distance from line
protected LineParametric2D_F64 line = new LineParametric2D_F64();
protected Point2D_F64 point2D = new Point2D_F64();
// list of vertexes
protected GrowQueue_I32 splits = new GrowQueue_I32();
protected GrowQueue_I32 work = new GrowQueue_I32();
// indicates which line segments need to be checked for splits
protected GrowQueue_B changed = new GrowQueue_B();
// if there are more splits than this amount just give up. It's probably noise
protected int abortSplits = Integer.MAX_VALUE;
/**
* Configures algorithm
* @param splitFraction A line will be split if a point is more than this fraction of its
* length away from the line. Try 0.05
* @param minimumSideLengthFraction The minimum length of a side as a function of contour length
* @param maxIterations Maximum number of split and merge refinements. Set to zero to disable refinement. Try 20
*/
public SplitMergeLineFit(double splitFraction,
double minimumSideLengthFraction,
int maxIterations)
{
setSplitFraction(splitFraction);
setMinimumSideLengthFraction(minimumSideLengthFraction);
setMaxIterations(maxIterations);
}
/**
* Approximates the input list with a set of line segments
*
* @param list Ordered list of connected points.
* @return true if it could fit a polygon to the points or false if not
*/
public abstract boolean process( List list );
/**
* Computes the split threshold from the end point of two lines
*/
protected double splitThresholdSq( Point2D_I32 a , Point2D_I32 b ) {
return Math.max(2,a.distance2(b)* toleranceFractionSq);
}
/**
* List of point indexes in the contour. Each point is the end of a line segment. A minimum of
* two points will be returned.
*
* NOTE: This list is modified the next time process is called.
*
* @return List of indexes
*/
public GrowQueue_I32 getSplits() {
return splits;
}
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
public void setSplitFraction(double toleranceSplit) {
this.toleranceFractionSq = toleranceSplit*toleranceSplit;
}
public int getAbortSplits() {
return abortSplits;
}
public void setAbortSplits(int abortSplits) {
this.abortSplits = abortSplits;
}
public double getMinimumSideLengthFraction() {
return minimumSideLengthFraction;
}
public void setMinimumSideLengthFraction(double minimumSideLengthFraction) {
if( minimumSideLengthFraction >= 1.0 || minimumSideLengthFraction < 0 )
throw new IllegalArgumentException("The minimumSplitFraction must be 0 <= val < 1 ");
this.minimumSideLengthFraction = minimumSideLengthFraction;
}
}