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 Ch21_Geometric_Operations; 010 011import ij.ImagePlus; 012import ij.plugin.filter.PlugInFilter; 013import ij.process.ImageProcessor; 014import imagingbook.common.geometry.basic.Pnt2d; 015import imagingbook.common.geometry.mappings.Mapping2D; 016import imagingbook.common.ij.DialogUtils; 017import imagingbook.common.ij.IjUtils; 018import imagingbook.common.image.ImageMapper; 019import imagingbook.common.image.OutOfBoundsStrategy; 020import imagingbook.common.image.interpolation.InterpolationMethod; 021import imagingbook.core.jdoc.JavaDocHelp; 022import imagingbook.sampleimages.GeneralSampleImage; 023 024/** 025 * <p> 026 * ImageJ plugin, applies a non-linear "ripple" transformation to the current image. See Sec. 21.1.7 of [1] for details. 027 * Optionally opens a sample image if no image is currently open. 028 * </p> 029 * <p> 030 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing – An Algorithmic Introduction</em>, 3rd ed, Springer 031 * (2022). 032 * </p> 033 * 034 * @author WB 035 * @version 2022/11/28 036 * @see ImageMapper 037 * @see Mapping2D 038 */ 039public class Map_Nonlinear_Ripple implements PlugInFilter, JavaDocHelp { 040 041 // transformation parameters: 042 private static double aX = 10; 043 private static double aY = 10; 044 private static double tauX = 120 / (2 * Math.PI); 045 private static double tauY = 250 / (2 * Math.PI); 046 047 /** 048 * Constructor, asks to open a predefined sample image if no other image 049 * is currently open. 050 */ 051 public Map_Nonlinear_Ripple() { 052 if (IjUtils.noCurrentImage()) { 053 DialogUtils.askForSampleImage(GeneralSampleImage.Flower); 054 } 055 } 056 057 @Override 058 public int setup(String arg, ImagePlus imp) { 059 return DOES_ALL; 060 } 061 062 @Override 063 public void run(ImageProcessor ip) { 064 065 Mapping2D imap = new Mapping2D() { 066 @Override 067 public Pnt2d applyTo(Pnt2d uv) { 068 final double u = uv.getX(); 069 final double v = uv.getY(); 070 double x = u + aX * Math.sin(v / tauX); 071 double y = v + aY * Math.sin(u / tauY); 072 return Pnt2d.from(x, y); 073 } 074 }; 075 076 new ImageMapper(imap, OutOfBoundsStrategy.ZeroValues, InterpolationMethod.Bicubic).map(ip); 077 } 078 079}