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 Ch09_Automatic_Thresholding;
010
011import ij.ImagePlus;
012import ij.gui.GenericDialog;
013import ij.plugin.filter.PlugInFilter;
014import ij.process.ByteProcessor;
015import ij.process.FloatProcessor;
016import ij.process.ImageProcessor;
017import imagingbook.common.threshold.adaptive.SauvolaThresholder;
018import imagingbook.common.threshold.adaptive.SauvolaThresholder.Parameters;
019import imagingbook.core.jdoc.JavaDocHelp;
020import imagingbook.sampleimages.GeneralSampleImage;
021
022import static imagingbook.common.ij.DialogUtils.addToDialog;
023import static imagingbook.common.ij.DialogUtils.askForSampleImage;
024import static imagingbook.common.ij.DialogUtils.getFromDialog;
025import static imagingbook.common.ij.IjUtils.noCurrentImage;
026
027/**
028 * <p>
029 * ImageJ plugin demonstrating the use of the {@link SauvolaThresholder} class.
030 * See Sec. 9.2 of [1] for additional details.
031 * </p>
032 * <p>
033 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing &ndash; An Algorithmic Introduction</em>, 3rd ed, Springer (2022).
034 * </p>
035 *
036 * @author WB
037 * @version 2022/04/01
038 * @see imagingbook.common.threshold.adaptive.SauvolaThresholder
039 */
040public class Adaptive_Sauvola implements PlugInFilter, JavaDocHelp {
041        
042        private static Parameters params = new Parameters();
043        private static boolean ShowThresholdSurface = false;
044        
045        /**
046         * Constructor, asks to open a predefined sample image if no other image
047         * is currently open.
048         */
049        public Adaptive_Sauvola() {
050                if (noCurrentImage()) {
051                        askForSampleImage(GeneralSampleImage.Kepler);
052                }
053        }
054        
055        @Override
056        public int setup(String arg, ImagePlus imp) {
057                return DOES_8G;
058        }
059
060        @Override
061        public void run(ImageProcessor ip) {
062                
063                if (!runDialog(params))
064                        return;
065                
066                ByteProcessor I = (ByteProcessor) ip;
067                SauvolaThresholder thr = new SauvolaThresholder(params);
068                FloatProcessor Q = thr.getThreshold(I);
069                thr.threshold(I, Q);
070                
071                if (ShowThresholdSurface) {
072                        new ImagePlus("Sauvola-Threshold", Q).show();
073                }
074        }
075        
076        boolean runDialog(Parameters params) {
077                GenericDialog gd = new GenericDialog(this.getClass().getSimpleName());
078                gd.addHelp(getJavaDocUrl());
079                addToDialog(params, gd);
080                gd.addCheckbox("Show threshold surface", ShowThresholdSurface);
081                
082                gd.showDialog();
083                if (gd.wasCanceled()) {
084                        return false;
085                }
086
087                getFromDialog(params, gd);
088                ShowThresholdSurface = gd.getNextBoolean();
089                return true;
090        }
091}