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 Ch03_Point_Operations; 010 011import ij.IJ; 012import ij.ImagePlus; 013import ij.gui.GenericDialog; 014import ij.plugin.filter.PlugInFilter; 015import ij.process.ImageProcessor; 016import imagingbook.common.histogram.HistogramPlot; 017import imagingbook.common.histogram.HistogramUtils; 018import imagingbook.common.ij.DialogUtils; 019import imagingbook.core.jdoc.JavaDocHelp; 020import imagingbook.sampleimages.GeneralSampleImage; 021 022import static imagingbook.common.ij.IjUtils.noCurrentImage; 023import static imagingbook.common.math.Arithmetic.sqr; 024 025/** 026 * <p> 027 * ImageJ plugin, adapts image intensities to match a Gaussian distribution with specified parameters μ, σ 028 * ({@link #Mean}, {@link #StdDev}). The current active image is modified, the histogram and cumulative histogram of the 029 * resulting image are displayed. See Sec. 3.6.4 (Fig. 3.15) of [1] for additional details. 030 * </p> 031 * <p> 032 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing – An Algorithmic Introduction</em>, 3rd ed, Springer 033 * (2022). 034 * </p> 035 * 036 * @author WB 037 * @see HistogramUtils 038 * @see HistogramPlot 039 */ 040public class Match_Gaussian_Histogram implements PlugInFilter, JavaDocHelp { 041 042 // parameters of Gaussian target distribution: 043 private static double Mean = 128; 044 private static double StdDev = 90; 045 046 private static boolean ShowOriginalHistograms = true; 047 private static boolean ShowCumulativeHistograms = true; 048 private static boolean ShowFinalHistogram = true; 049 private static boolean ListMappingFunction = false; 050 051 /** Constructor, asks to open a predefined sample image if no other image is currently open. */ 052 public Match_Gaussian_Histogram() { 053 if (noCurrentImage()) { 054 DialogUtils.askForSampleImage(GeneralSampleImage.IrishManor); 055 } 056 } 057 058 @Override 059 public int setup(String arg0, ImagePlus im) { 060 return DOES_8G; 061 } 062 063 @Override 064 public void run(ImageProcessor ip) { 065 if (!runDialog()) { 066 return; 067 } 068 069 // get histograms 070 int[] hi = ip.getHistogram(); 071 int[] hG = makeGaussianHistogram(Mean, StdDev); 072 073 if (ShowOriginalHistograms) { 074 new HistogramPlot(hi, "Original Histogram").show(); 075 new HistogramPlot(hG, "Gaussian Histogram").show(); 076 } 077 078 double[] chG = HistogramUtils.cdf(hG); 079 int[] F = HistogramUtils.matchHistograms(hi, hG); 080 ip.applyTable(F); 081 int[] hAm = ip.getHistogram(); 082 083 if (ShowFinalHistogram) { 084 new HistogramPlot(hAm, "Final Histogram").show(); 085 } 086 087 if (ShowCumulativeHistograms) { 088 new HistogramPlot(chG, "Gaussian Cumulative Histogram").show(); 089 new HistogramPlot(HistogramUtils.cdf(hAm), "Final Cumulative Histogram").show(); 090 } 091 092 if (ListMappingFunction) { 093 for (int i = 0; i < F.length; i++) { 094 IJ.log(i + " -> " + F[i]); 095 } 096 } 097 } 098 099 private int[] makeGaussianHistogram (double mean, double sigma) { 100 int[] h = new int[256]; 101 double sigma2 = 2 * sqr(sigma); 102 for (int i = 0; i < h.length; i++) { 103 double x = mean - i; 104 double g = Math.exp(-sqr(x) / sigma2) / sigma; 105 h[i] = (int) Math.round(10000 * g); 106 } 107 return h; 108 } 109 110 private boolean runDialog() { 111 GenericDialog gd = new GenericDialog(this.getClass().getSimpleName()); 112 gd.addHelp(getJavaDocUrl()); 113 gd.addNumericField("Mean (μ)", Mean, 2); 114 gd.addNumericField("Std deviation (σ)", StdDev, 2); 115 116 gd.addCheckbox("Show original histograms", ShowOriginalHistograms); 117 gd.addCheckbox("Show cumulative histograms", ShowCumulativeHistograms); 118 gd.addCheckbox("Show final histogram", ShowFinalHistogram); 119 gd.addCheckbox("List mapping function", ListMappingFunction); 120 121 gd.showDialog(); 122 if(gd.wasCanceled()) 123 return false; 124 125 Mean = gd.getNextNumber(); 126 StdDev = gd.getNextNumber(); 127 128 ShowOriginalHistograms = gd.getNextBoolean(); 129 ShowCumulativeHistograms = gd.getNextBoolean(); 130 ShowFinalHistogram = gd.getNextBoolean(); 131 ListMappingFunction = gd.getNextBoolean(); 132 return true; 133 } 134 135} 136