/* * 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.abst.feature.detect.line; import boofcv.abst.feature.detect.extract.ConfigExtract; import boofcv.abst.feature.detect.extract.NonMaxSuppression; import boofcv.abst.filter.derivative.ImageGradient; import boofcv.alg.feature.detect.edge.GGradientToEdgeFeatures; import boofcv.alg.feature.detect.line.HoughTransformLineFootOfNorm; import boofcv.alg.feature.detect.line.ImageLinePruneMerge; import boofcv.alg.filter.binary.ThresholdImageOps; import boofcv.factory.feature.detect.extract.FactoryFeatureExtractor; import boofcv.struct.image.GrayF32; import boofcv.struct.image.GrayU8; import boofcv.struct.image.ImageGray; import georegression.struct.line.LineParametric2D_F32; import org.ddogleg.struct.FastQueue; import java.util.ArrayList; import java.util.List; /** * <p> * Full processing chain for detecting lines using a foot of norm parametrization inside * a Hough transform. * </p> * * <p> * USAGE NOTES: Blurring the image prior to processing can often improve performance. * Results will not be perfect and to detect all the obvious lines in the image several false * positives might be returned. * </p> * * @see boofcv.alg.feature.detect.line.HoughTransformLineFootOfNorm * * @author Peter Abeles */ public class DetectLineHoughFoot <I extends ImageGray, D extends ImageGray> implements DetectLine<I> { // transform algorithm HoughTransformLineFootOfNorm alg; // computes image gradient ImageGradient<I,D> gradient; // used to create binary edge image float thresholdEdge; // image gradient D derivX; D derivY; // edge intensity image GrayF32 intensity = new GrayF32(1,1); // detected edge image GrayU8 binary = new GrayU8(1,1); // the maximum number of lines it will return int maxLines; // post processing pruning ImageLinePruneMerge post = new ImageLinePruneMerge(); /** * Specifies detection parameters. The suggested parameters should be used as a starting point and will * likely need to be tuned significantly for each different scene. * * @param localMaxRadius Lines in transform space must be a local max in a region with this radius. Try 5; * @param minCounts Minimum number of counts/votes inside the transformed image. Try 5. * @param minDistanceFromOrigin Lines which are this close to the origin of the transformed image are ignored. Try 5. * @param thresholdEdge Threshold for classifying pixels as edge or not. Try 30. * @param gradient Computes the image gradient. */ public DetectLineHoughFoot( int localMaxRadius, int minCounts , int minDistanceFromOrigin , float thresholdEdge , int maxLines , ImageGradient<I,D> gradient ) { this.gradient = gradient; this.thresholdEdge = thresholdEdge; this.maxLines = maxLines; NonMaxSuppression extractor = FactoryFeatureExtractor.nonmaxCandidate( new ConfigExtract(localMaxRadius, minCounts, 0, false)); alg = new HoughTransformLineFootOfNorm(extractor,minDistanceFromOrigin); derivX = gradient.getDerivativeType().createImage(1,1); derivY = gradient.getDerivativeType().createImage(1, 1); } @Override public List<LineParametric2D_F32> detect(I input) { derivX.reshape(input.width,input.height); derivY.reshape(input.width,input.height); intensity.reshape(input.width,input.height); binary.reshape(input.width,input.height); gradient.process(input,derivX,derivY); GGradientToEdgeFeatures.intensityAbs(derivX, derivY, intensity); ThresholdImageOps.threshold(intensity, binary, thresholdEdge, false); alg.transform(derivX,derivY,binary); FastQueue<LineParametric2D_F32> lines = alg.extractLines(); List<LineParametric2D_F32> ret = new ArrayList<>(); for( int i = 0; i < lines.size; i++ ) ret.add(lines.get(i)); ret = pruneLines(input,ret); return ret; } private List<LineParametric2D_F32> pruneLines(I input, List<LineParametric2D_F32> ret) { float intensity[] = alg.getFoundIntensity(); post.reset(); for( int i = 0; i < ret.size(); i++ ) { post.add(ret.get(i),intensity[i]); } // NOTE: angular accuracy is a function of range from sub image center. This pruning // function uses a constant value for range accuracy. A custom algorithm should really // be used here. // NOTE: Thresholds should not be hardcoded... post.pruneSimilar((float) (Math.PI * 0.04), 10, input.width, input.height); post.pruneNBest(maxLines); return post.createList(); } public HoughTransformLineFootOfNorm getTransform() { return alg; } public D getDerivX() { return derivX; } public D getDerivY() { return derivY; } public GrayF32 getEdgeIntensity() { return intensity; } public GrayU8 getBinary() { return binary; } }