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-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.pub.threshold.adaptive;
011
012import ij.plugin.filter.RankFilters;
013import ij.process.ByteProcessor;
014import imagingbook.pub.threshold.BackgroundMode;
015
016/**
017 * This implementation of Bernsen's thresholder uses a circular support region,
018 * implemented with ImageJ's built-in rank-filter methods.
019 */
020public class BernsenThresholder extends AdaptiveThresholder {
021        
022        public static class Parameters {
023                public int radius = 15;
024                public int cmin = 15;
025                public BackgroundMode bgMode = BackgroundMode.DARK;
026        }
027        
028        private final Parameters params;
029        
030        public BernsenThresholder() {
031                this.params = new Parameters();
032        }
033        
034        public BernsenThresholder(Parameters params) {
035                this.params = params;
036        }
037
038        @Override
039        public ByteProcessor getThreshold(ByteProcessor I) {
040                final int M = I.getWidth();
041                final int N = I.getHeight();
042                ByteProcessor Imin = (ByteProcessor) I.duplicate();
043                ByteProcessor Imax = (ByteProcessor) I.duplicate();
044
045                RankFilters rf = new RankFilters();
046                rf.rank(Imin, params.radius, RankFilters.MIN);
047                rf.rank(Imax, params.radius, RankFilters.MAX);
048
049                int q = (params.bgMode == BackgroundMode.DARK) ? 256 : 0;
050                ByteProcessor Q = new ByteProcessor(M, N);
051
052                for (int v = 0; v < N; v++) {
053                        for (int u = 0; u < M; u++) {
054                                int gMin = Imin.get(u, v);
055                                int gMax = Imax.get(u, v);
056                                int c = gMax - gMin;
057                                if (c >= params.cmin)
058                                        Q.set(u, v, (gMin + gMax) / 2);
059                                else
060                                        Q.set(u, v, q);
061                        }
062                }
063                return Q;
064        }
065        
066}