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-2025 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit https://imagingbook.com for additional details. 008 ******************************************************************************/ 009package More_; 010 011import ij.ImagePlus; 012import ij.gui.GenericDialog; 013import ij.gui.Overlay; 014import ij.gui.Roi; 015import ij.plugin.filter.PlugInFilter; 016import ij.process.ImageProcessor; 017import imagingbook.common.ij.DialogUtils; 018import imagingbook.common.image.OutOfBoundsStrategy; 019import imagingbook.common.image.access.ImageAccessor; 020import imagingbook.core.jdoc.JavaDocHelp; 021import imagingbook.core.resource.ImageResource; 022import imagingbook.sampleimages.GeneralSampleImage; 023 024import java.awt.Color; 025 026import static imagingbook.common.ij.IjUtils.noCurrentImage; 027 028/** 029 * This ImageJ plugin demonstrates the effect of different out-of-bounds strategies 030 * for handling pixels that are outside the image. The input image is placed centered inside 031 * a larger canvas and the missing pixels are inserted. The user can select one of the 032 * predefined out-of-bounds strategies and the size factor (min. 1), which specifies how 033 * much larger the output image is compared to the original image. 034 * In the resulting composite image, the original image is outlined by a colored rectangle. 035 * The use of {@link ImageAccessor} makes this plugin work with any type of input image. 036 * If no image is currently open, the user is asked to load a predefined sample image. 037 * 038 * @author WB 039 * @version 2023/04/02 040 * @see OutOfBoundsStrategy 041 * @see ImageAccessor 042 */ 043public class OutOfBoundsStrategy_Demo implements PlugInFilter, JavaDocHelp { 044 045 private static ImageResource SampleImage = GeneralSampleImage.MortarSmall; 046 private static OutOfBoundsStrategy OBS = OutOfBoundsStrategy.NearestBorder; 047 private static double SizeFactor = 5.0; 048 private static Color OutlineColor = Color.green; 049 050 private ImagePlus im = null; 051 052 /** 053 * Constructor, asks to open a predefined sample image if no other image is currently open. 054 */ 055 public OutOfBoundsStrategy_Demo() { 056 if (noCurrentImage()) { 057 DialogUtils.askForSampleImage(SampleImage); 058 } 059 } 060 061 @Override 062 public int setup(String arg, ImagePlus im) { 063 this.im = im; 064 return DOES_ALL + NO_CHANGES; 065 } 066 067 @Override 068 public void run(ImageProcessor ip1) { 069 if (!runDialog()) { 070 return; 071 } 072 073 int w1 = ip1.getWidth(); 074 int h1 = ip1.getHeight(); 075 076 int dw = (int) (0.5 * (SizeFactor - 1) * w1); 077 int dh = (int) (0.5 * (SizeFactor - 1) * h1); 078 079 dw = Math.max(dw, 0); 080 dh = Math.max(dh, 0); 081 082 int w2 = dw + w1 + dw; 083 int h2 = dh + h1 + dh; 084 085 ImageProcessor ip2 = ip1.createProcessor(w2, h2); 086 087 ImageAccessor ia1 = ImageAccessor.create(ip1, OBS, null); 088 ImageAccessor ia2 = ImageAccessor.create(ip2, null, null); 089 090 for (int u = 0; u < w2; u++) { 091 for (int v = 0; v < h2; v++) { 092 float[] val = ia1.getPix(u - dw, v - dh); 093 ia2.setPix(u, v, val); 094 } 095 } 096 097 // mark the embedded original in the composite image 098 Overlay oly = new Overlay(); 099 Roi rect = new Roi(dw, dh, w1, h1); 100 rect.setStrokeWidth(1.0f); 101 rect.setStrokeColor(OutlineColor); 102 oly.add(rect); 103 104 // show the composite image 105 ImagePlus im2 = new ImagePlus("", ip2); 106 im2.setOverlay(oly); 107 ImagePlus im2f = im2.flatten(); 108 im2f.setTitle(im.getShortTitle() + " (" + OBS + ")"); 109 im2f.show(); 110 } 111 112 private boolean runDialog() { 113 GenericDialog gd = new GenericDialog(this.getClass().getSimpleName()); 114 gd.addHelp(getJavaDocUrl()); 115 116 gd.addEnumChoice("Out-of-bounds strategy", OBS); 117 gd.addNumericField("Size factor (>1)", SizeFactor, 1); 118 119 gd.showDialog(); 120 if(gd.wasCanceled()) 121 return false; 122 123 OBS = gd.getNextEnumChoice(OutOfBoundsStrategy.class); 124 SizeFactor = gd.getNextNumber(); 125 SizeFactor = Math.max(1, SizeFactor); 126 127 return true; 128 } 129}