boofcv.alg.shapes.polygon.RefinePolygonCornersToImage 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-2016, 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.polygon;
import boofcv.alg.shapes.corner.RefineCornerLinesToImage;
import boofcv.alg.shapes.edge.SnapToEdge;
import boofcv.misc.CircularIndex;
import boofcv.struct.distort.PixelTransform_F32;
import boofcv.struct.image.ImageGray;
import georegression.struct.point.Point2D_F64;
import georegression.struct.point.Point2D_I32;
import georegression.struct.shapes.Polygon2D_F64;
import org.ddogleg.struct.GrowQueue_I32;
import java.util.List;
/**
* Given a contour and the index of corner points it will fit the corners individually to sub-pixel precision
* by locally fitting line segments near by each corner. The length of each line segment is specified
* by the number of pixels away it will traverse the contour. It makes sure that the end point does not go
* past the next corner.
*
* @author Peter Abeles
*/
public class RefinePolygonCornersToImage implements RefineBinaryPolygon {
// number of pixels along the contour away should the end point be from the corner
private int pixelsAway;
// used to refine individual corners
protected RefineCornerLinesToImage refineCorner;
// storage for corner points
protected Point2D_F64 cornerPt = new Point2D_F64();
protected Point2D_F64 leftPt = new Point2D_F64();
protected Point2D_F64 rightPt = new Point2D_F64();
// reference ti input contour and corner indexes
protected List contour;
protected GrowQueue_I32 splits;
/**
* Configures all parameters of the detector
*
* @param endPointDistance How many indexes away in the contour list should end points be.
* @param cornerOffset pixels this close to the corner will be ignored. Try 2
* @param maxLineSamples Number of points along the line which will be sampled. try 10
* @param sampleRadius How far away from the line will it sample pixels. ≥ 1
* @param maxIterations Maximum number of iterations it will perform. Try 10
* @param convergeTolPixels When the corner changes less than this amount it will stop iterating. Try 1e-5
* @param maxCornerChangePixels maximum change in corner location allowed from previous iteration in pixels. Try 2.0
* @param imageType Type of input image.
*/
public RefinePolygonCornersToImage(int endPointDistance,
double cornerOffset, int maxLineSamples, int sampleRadius,
int maxIterations, double convergeTolPixels,double maxCornerChangePixels,
Class imageType) {
this.pixelsAway = endPointDistance;
this.refineCorner = new RefineCornerLinesToImage(cornerOffset,maxLineSamples,sampleRadius,maxIterations,
convergeTolPixels,maxCornerChangePixels,imageType);
}
/**
* Provides reasonable default values for all parameters that it can
*
* @param imageType Type of input image.
*/
public RefinePolygonCornersToImage(Class imageType) {
this(12,2,10,1,10,1e-6,2,imageType);
}
/**
* Sets the input image
*
* @param input Input image-
*/
@Override
public void setImage( T input ) {
refineCorner.setImage(input);
}
@Override
public void setLensDistortion(int width, int height, PixelTransform_F32 distToUndist, PixelTransform_F32 undistToDist) {
this.refineCorner.getSnapToEdge().setTransform(undistToDist);
}
/**
* Refines the corner estimates in the contour.
*
* @param contour (Input) Shape's contour
* @param splits (Input) index of corners in the contour
* @param refined (Output) Refined polygon with sub-pixel accurate corners
* @return Number of corners it successfully optimized.
*/
@Override
public boolean refine(Polygon2D_F64 input, List contour , GrowQueue_I32 splits, Polygon2D_F64 refined) {
if( refined.size() != splits.size() )
throw new IllegalArgumentException("Miss match between number of splits and polygon order");
this.contour = contour;
this.splits = splits;
int numGood = 0;
for (int cornerS = 0; cornerS < splits.size(); cornerS++) {
int indexLeft = pickEndIndex(cornerS, 1);
int indexRight = pickEndIndex(cornerS, -1);
Point2D_I32 contourCorner = contour.get(splits.get(cornerS));
Point2D_I32 contourLeft = contour.get(indexLeft);
Point2D_I32 contourRight = contour.get(indexRight);
cornerPt.set(contourCorner.x,contourCorner.y);
leftPt.set(contourLeft.x,contourLeft.y);
rightPt.set(contourRight.x,contourRight.y);
if( refineCorner.refine(cornerPt,leftPt,rightPt)) {
refined.get(cornerS).set( refineCorner.getRefinedCorner());
numGood++;
} else {
// use the original
refined.get(cornerS).set(cornerPt);
}
}
// allow partial success
return numGood >= refined.size()-1;
}
/**
* Selects the index to use as the end point. Makes sure that the index does not go past
* the next corner.
*
* @param cornerS index of corner in split list
* @param dir Specifies which corner is next. can be -1 or 1.
*/
protected int pickEndIndex(int cornerS, int dir)
{
int cornerIndex = splits.get(cornerS);
int endIndex0 = splits.get(CircularIndex.addOffset(cornerS, dir, splits.size));
int endIndex1 = splits.get(CircularIndex.addOffset(cornerS, -dir, splits.size));
// splits being in increasing or decreasing order isn't specified. This make sure the correct
// point is selected
int dist0 = CircularIndex.distanceP(cornerIndex, endIndex0, contour.size());
int dist1 = CircularIndex.distanceP(cornerIndex, endIndex1, contour.size());
if( dir == 1 != dist1 > dist0 )
dir = -dir;
if( dir < 0 ) {
int distance = CircularIndex.distanceP(endIndex0, cornerIndex, contour.size());
distance = Math.min(distance,pixelsAway);
return CircularIndex.addOffset(cornerIndex, -distance, contour.size());
} else {
int distance = CircularIndex.distanceP(cornerIndex, endIndex0, contour.size());
distance = Math.min(distance,pixelsAway);
return CircularIndex.addOffset(cornerIndex, distance, contour.size());
}
}
public int getPixelsAway() {
return pixelsAway;
}
public void setPixelsAway(int pixelsAway) {
this.pixelsAway = pixelsAway;
}
public SnapToEdge getSnapToEdge() {
return refineCorner.getSnapToEdge();
}
}