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 ******************************************************************************/ 009 010package imagingbook.common.threshold.adaptive; 011 012import ij.process.ByteProcessor; 013import ij.process.FloatProcessor; 014import imagingbook.common.threshold.Thresholder; 015 016/** 017 * <p> 018 * Common interface to be implemented by all adaptive (i.e., non-global) thresholders. See Sec. 9.2 of [1] for an 019 * overview. 020 * </p> 021 * <p> 022 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing – An Algorithmic Introduction</em>, 3rd ed, Springer 023 * (2022). 024 * </p> 025 * 026 * @author WB 027 * @version 2022/08/01 028 */ 029public interface AdaptiveThresholder extends Thresholder { 030 031 /** 032 * Calculates a adaptive "threshold surface" for the specified {@link ByteProcessor} and returns it as another 033 * {@link ByteProcessor}. 034 * 035 * @param bp the input image 036 * @return the threshold surface 037 */ 038 public FloatProcessor getThreshold(ByteProcessor bp); 039 040 /** 041 * Thresholds a {@link ByteProcessor} image by a threshold surface specified as a {@link ByteProcessor}. 042 * 043 * @param I the input image (gets modified) 044 * @param Q the threshold surface 045 */ 046 public default void threshold(ByteProcessor I, ByteProcessor Q) { 047 final int w = I.getWidth(); 048 final int h = I.getHeight(); 049 final int minVal = 0; 050 final int maxVal = 255; 051 for (int v = 0; v < h; v++) { 052 for (int u = 0; u < w; u++) { 053 int p = I.get(u, v); 054 int q = Q.get(u, v); 055 I.set(u, v, (p <= q) ? minVal : maxVal); 056 } 057 } 058 } 059 060 /** 061 * Thresholds a {@link ByteProcessor} image by a threshold surface specified as a {@link FloatProcessor}. 062 * 063 * @param I the input image (gets modified) 064 * @param Q the threshold surface 065 */ 066 public default void threshold(ByteProcessor I, FloatProcessor Q) { 067 final int w = I.getWidth(); 068 final int h = I.getHeight(); 069 final int minVal = 0; 070 final int maxVal = 255; 071 for (int v = 0; v < h; v++) { 072 for (int u = 0; u < w; u++) { 073 int p = I.get(u, v); 074 float q = Q.getf(u, v); 075 I.set(u, v, (p <= q) ? minVal : maxVal); 076 } 077 } 078 } 079 080 @Override 081 public default boolean threshold(ByteProcessor ip) { 082 FloatProcessor Q = this.getThreshold(ip); 083 if (Q != null) { 084 this.threshold(ip, Q); 085 return true; 086 } 087 else { 088 return false; 089 } 090 } 091 092}