001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009package imagingbook.common.ransac;
010
011import imagingbook.common.geometry.basic.Pnt2d;
012import imagingbook.common.geometry.circle.GeometricCircle;
013import imagingbook.common.geometry.fitting.circle.algebraic.CircleFit3Points;
014import imagingbook.common.geometry.fitting.circle.algebraic.CircleFitAlgebraic;
015import imagingbook.common.geometry.fitting.circle.algebraic.CircleFitHyperSimple;
016
017/**
018 * <p>
019 * RANSAC detector for circles. See Sec. 12.1.4 of [1] for additional details.
020 * </p>
021 * <p>
022 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing &ndash; An Algorithmic Introduction</em>, 3rd ed, Springer
023 * (2022).
024 * </p>
025 *
026 * @author WB
027 * @version 2022/11/19
028 * @see GeometricCircle
029 * @see RansacDetector
030 */
031public class RansacCircleDetector extends RansacDetector<GeometricCircle>{
032        
033        /**
034         * Nested class extending {@link RansacDetector.RansacParameters} 
035         * to specify additional RANSAC parameters.
036         */
037        public static class Parameters extends RansacDetector.RansacParameters {
038                /**
039                 * Constructor used to define default parameter values.
040                 */
041                public Parameters() {
042                        this.randomPointDraws = 1000;
043                        this.maxInlierDistance = 2.0;
044                        this.minInlierCount = 70;
045                }
046        }
047        
048        // constructors ------------------------------------
049
050        /**
051         * Constructor using specific parameters.
052         * @param params RANSAC parameters
053         */
054        public RansacCircleDetector(Parameters params) {
055                super(3, params);
056        }
057        
058        /**
059         * Constructor using default parameters.
060         */
061        public RansacCircleDetector() {
062                this(new Parameters());
063        }
064        
065        // ----------------------------------------------------------------
066
067        @Override
068        GeometricCircle fitInitial(Pnt2d[] points) {
069                CircleFitAlgebraic fit = new CircleFit3Points(points);
070                return fit.getGeometricCircle();
071        }
072        
073        @Override
074        GeometricCircle fitFinal(Pnt2d[] inliers) {
075//              CircleFitAlgebraic fit2 = new CircleFitPratt(inliers);  // TODO: fails, check why
076                CircleFitAlgebraic fit2 = new CircleFitHyperSimple(inliers);
077                if (fit2.getParameters() == null) 
078                        throw new RuntimeException("circle fitFinal() failed!");
079                return fit2.getGeometricCircle();
080        }
081}