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 *******************************************************************************/ 009package imagingbook.lib.image; 010 011import ij.process.ImageProcessor; 012import imagingbook.pub.geometry.mappings.linear.AffineMapping; 013import imagingbook.pub.geometry.mappings.linear.LinearMapping; 014import imagingbook.pub.geometry.mappings.linear.ProjectiveMapping; 015 016import java.awt.Point; 017import java.awt.geom.Point2D; 018 019/** 020 * Use to exctract warped images for testing the Lucas-Kanade matcher. 021 * @author wilbur 022 * 023 */ 024public class ImageExtractor { 025 026 027// public static ImageProcessor extract(ImageProcessor source, int width, int height, LinearMapping T) { 028// ImageExtractor ie = new ImageExtractor(source); 029// return ie.extractImage(width, height, T); 030// } 031 032 033 private int interpolationMethod = ImageProcessor.BILINEAR; 034 private final ImageProcessor I; 035 036 /** 037 * Creates a new instance of {@link ImageExtractor} for the image {@code I}. 038 * @param I the target image. 039 */ 040 public ImageExtractor(ImageProcessor I) { 041 this.I = I; 042 } 043 044 public void setInterpolationMethod(int interpolationMethod) { 045 this.interpolationMethod = interpolationMethod; 046 } 047 048 /** 049 * Extracts an image {@code R} of size {@code width} x {@code height} from the source image 050 * {@code I} (referenced by {@code this} object). 051 * The image {@code R} is extracted from a quadrilateral patch of the source image, 052 * defined by the transformation of the boundary of {@code R} by {@code T(x)}. 053 * @param width the width of the target image {@code R}. 054 * @param height the height of the target image {@code R}. 055 * @param T a {@link LinearMapping} object. 056 * @return the extracted image {@code R}, which is of the same type as the source image. 057 */ 058 059 public ImageProcessor extractImage(int width, int height, LinearMapping T) { 060 ImageProcessor R = I.createProcessor(width, height); 061 extractImage(R, T); 062 return R; 063 } 064 065 public ImageProcessor extractImage(int width, int height, Point2D[] sourcePnts) { 066 ImageProcessor R = I.createProcessor(width, height); 067 ProjectiveMapping T = getMapping(width, height, sourcePnts); 068 extractImage(R, T); 069 return R; 070 } 071 072 /** 073 * Fills the image {@code R} from the source image 074 * {@code I} (referenced by {@code this} object). 075 * The image {@code R} is extracted from a quadrilateral patch of the source image, 076 * defined by the transformation of the boundary of {@code R} by {@code T(x)}. 077 * Grayscale and color images my not be mixed (i.e., {@code R} must be of the same type as {@code I}). 078 * @param R the image to be filled. 079 * @param T a {@link LinearMapping} object. 080 */ 081 public void extractImage(ImageProcessor R, LinearMapping T) { 082 int prevInterpolationMethod = I.getInterpolationMethod(); 083 // save current interpolation method 084 I.setInterpolationMethod(interpolationMethod); 085 086 ImageAccessor iaI = ImageAccessor.create(I); 087 ImageAccessor iaR = ImageAccessor.create(R); 088 089 int wT = R.getWidth(); 090 int hT = R.getHeight(); 091 for (int u = 0; u < wT; u++) { 092 for (int v = 0; v < hT; v++) { 093 Point2D uv = new Point(u, v); 094 Point2D xy = T.applyTo(uv); 095 float[] val = iaI.getPix(xy.getX(), xy.getY()); 096 iaR.setPix(u, v, val); 097 } 098 } 099 // restore interpolation method 100 I.setInterpolationMethod(prevInterpolationMethod); 101 } 102 103 /** 104 * Extracts a warped sub-image of the associated target image I, 105 * defined by a sequence of 3 or 4 points. In the case of 3 106 * points in sourcePnts, an {@link AffineMapping} is used; with 4 points, 107 * a {@link ProjectiveMapping} is used. The 3 or 4 points map clockwise to 108 * the corner points of the target image R, starting with the top-left corner. 109 * @param R the target image; 110 * @param sourcePnts an array of 3 or 4 {@link Point2D} objects. 111 */ 112 public void extractImage(ImageProcessor R, Point2D[] sourcePnts) { 113 ProjectiveMapping T = getMapping(R.getWidth(), R.getHeight(), sourcePnts); 114 extractImage(R, T); 115 } 116 117 private ProjectiveMapping getMapping(int w, int h, Point2D[] sourcePnts) { 118 Point2D[] targetPnts = { 119 new Point(0, 0), new Point(w - 1, 0), 120 new Point(w - 1, h - 1), new Point(0, h - 1) 121 }; 122 ProjectiveMapping T = null; 123 switch (sourcePnts.length) { 124 case (3) : T = new AffineMapping(targetPnts, sourcePnts); break; 125 case (4) : T = new ProjectiveMapping(targetPnts, sourcePnts); break; 126 default : throw new IllegalArgumentException("wrong number of source points"); 127 } 128 return T; 129 } 130 131}