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-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit http://imagingbook.com for additional details. 008 *******************************************************************************/ 009 010package imagingbook.pub.geometry.mappings; 011 012import ij.process.ImageProcessor; 013import imagingbook.lib.image.ImageAccessor; 014import imagingbook.lib.interpolation.InterpolationMethod; 015 016import java.awt.Point; 017import java.awt.geom.Point2D; 018 019/** 020 * 2013-02-02: changed to use the returned new point of applyTo(Point2D), 021 * not relying on side effect. 022 * 2014-04-19: modified to work with ImageAccessor. 023 * 2015-12-10: added isInverse() method. 024 */ 025public abstract class Mapping implements Cloneable { 026 027 protected boolean isInverseFlag = false; 028 029 // all subclasses must implement this method 030 public abstract double[] applyTo(double[] pnt); 031 032 033 public boolean isInverse() { 034 return isInverseFlag; 035 } 036 037 public Mapping getInverse() { 038 if (isInverseFlag) 039 return this; 040 else { 041 return this.invert(); // only linear mappings invert 042 } 043 } 044 045 protected Mapping invert() { 046 throw new UnsupportedOperationException("mapping cannot be inverted"); 047 } 048 049 public Point2D applyTo(Point2D pnt) { 050 double[] xy = applyTo(new double[] {pnt.getX(), pnt.getY()}); 051 return new Point2D.Double(xy[0], xy[1]); 052 } 053 054 /** 055 * Applies this mapping to all points in the pnts array. 056 * @param pnts array of original points. 057 * @return an array of modified points. 058 */ 059 public Point2D[] applyTo(Point2D[] pnts) { 060 Point2D[] outPnts = new Point2D[pnts.length]; 061 for (int i = 0; i < pnts.length; i++) { 062 outPnts[i] = applyTo(pnts[i]); 063 } 064 return outPnts; 065 } 066 067 /** 068 * Destructively transforms the image in "ip" using this geometric 069 * mapping and the specified pixel interpolation method. 070 * TODO: this should not be here (geometry only)? 071 * 072 * @param ip target image to which THIS mapping is applied. 073 * @param im interpolation method. 074 */ 075 public void applyTo(ImageProcessor ip, InterpolationMethod im) { 076 // make a temporary copy of the image: 077 ImageProcessor source = ip.duplicate(); 078 ImageProcessor target = ip; 079 applyTo(source, target, im); 080 source = null; 081 } 082 083 /** 084 * Transforms the "source" image to the "target" image using this geometric 085 * mapping and the specified pixel interpolation method. Source and target 086 * must be different images! 087 * 088 * @param source input image (not modified). 089 * @param target output image (modified). 090 * @param im interpolation method. 091 */ 092 public void applyTo(ImageProcessor source, ImageProcessor target, InterpolationMethod im) { 093 if (target == source) { 094 throw new IllegalArgumentException("source and target image must not be the same"); 095 } 096 ImageAccessor sourceAcc = ImageAccessor.create(source, null, im); 097 ImageAccessor targetAcc = ImageAccessor.create(target); 098 applyTo(sourceAcc, targetAcc); 099 } 100 101 102 /** 103 * Transforms the source image (contained in "srcInterpol") to the "target" 104 * image using this geometric mapping and the specified pixel interpolator. 105 * 106 * @param sourceAcc accessor to the source image 107 * @param targetAcc accessor to the target image 108 */ 109 public void applyTo(ImageAccessor sourceAcc, ImageAccessor targetAcc) { 110 Mapping invMap = this.getInverse(); // get inverse mapping 111 ImageProcessor target = targetAcc.getProcessor(); 112 final int w = target.getWidth(); 113 final int h = target.getHeight(); 114 for (int v = 0; v < h; v++) { 115 for (int u = 0; u < w; u++) { 116 Point2D sourcePt = invMap.applyTo(new Point(u, v)); 117 float[] val = sourceAcc.getPix(sourcePt.getX(),sourcePt.getY()); 118 targetAcc.setPix(u, v, val); 119 } 120 } 121 } 122 123 public Mapping duplicate() { // duplicates any mapping, overwrite 124 return this.clone(); 125 } 126 127 protected Mapping clone() { 128 Mapping copy = null; 129 try { 130 copy = (Mapping) super.clone(); 131 } 132 catch (CloneNotSupportedException e) { } 133 return copy; 134 } 135 136}