001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image.pixel.sampling; 031 032import java.util.ArrayList; 033import java.util.Iterator; 034import java.util.List; 035import java.util.NoSuchElementException; 036 037import org.openimaj.image.Image; 038import org.openimaj.math.geometry.shape.Rectangle; 039 040/** 041 * A {@link RectangleSampler} provides an easy way to generate a sliding window 042 * of rectangle over an image or other domain. 043 * 044 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 045 * 046 */ 047public class RectangleSampler implements Iterable<Rectangle> { 048 float minx; 049 float maxx; 050 float miny; 051 float maxy; 052 float stepx; 053 float stepy; 054 float width; 055 float height; 056 057 /** 058 * Construct the sampler with the given parameters 059 * 060 * @param minx 061 * starting x-ordinate 062 * @param maxx 063 * finishing x-ordinate 064 * @param miny 065 * starting y-ordinate 066 * @param maxy 067 * finishing y-ordinate 068 * @param stepx 069 * step size in x direction 070 * @param stepy 071 * step size in y direction 072 * @param width 073 * width of sample window 074 * @param height 075 * height of sample window 076 */ 077 public RectangleSampler(float minx, float maxx, float miny, float maxy, float stepx, float stepy, float width, 078 float height) 079 { 080 setBounds(minx, maxx, miny, maxy); 081 this.stepx = stepx; 082 this.stepy = stepy; 083 this.width = width; 084 this.height = height; 085 } 086 087 /** 088 * Construct the sampler with the given parameters 089 * 090 * @param bounds 091 * the bounds in which the window must remain; it will start in 092 * the top-left corner 093 * @param stepx 094 * step size in x direction 095 * @param stepy 096 * step size in y direction 097 * @param width 098 * width of sample window 099 * @param height 100 * height of sample window 101 */ 102 public RectangleSampler(Rectangle bounds, float stepx, float stepy, float width, float height) 103 { 104 setBounds(bounds); 105 this.stepx = stepx; 106 this.stepy = stepy; 107 this.width = width; 108 this.height = height; 109 } 110 111 /** 112 * Construct the sampler with the given parameters 113 * 114 * @param img 115 * the image from which to set the sampler bounds (will be set to 116 * the complete image) 117 * @param stepx 118 * step size in x direction 119 * @param stepy 120 * step size in y direction 121 * @param width 122 * width of sample window 123 * @param height 124 * height of sample window 125 */ 126 public RectangleSampler(Image<?, ?> img, float stepx, float stepy, float width, float height) 127 { 128 setBounds(img); 129 this.stepx = stepx; 130 this.stepy = stepy; 131 this.width = width; 132 this.height = height; 133 } 134 135 /** 136 * Adjust the bounds of the sampler 137 * 138 * @param minx 139 * starting x-ordinate 140 * @param maxx 141 * finishing x-ordinate 142 * @param miny 143 * starting y-ordinate 144 * @param maxy 145 * finishing y-ordinate 146 */ 147 public void setBounds(float minx, float maxx, float miny, float maxy) { 148 this.minx = minx; 149 this.maxx = maxx; 150 this.miny = miny; 151 this.maxy = maxy; 152 } 153 154 /** 155 * Adjust the bounds of the sampler 156 * 157 * @param r 158 * the new bounds rectangle 159 */ 160 public void setBounds(Rectangle r) { 161 if (r == null) 162 return; 163 164 this.minx = r.x; 165 this.maxx = r.x + r.width; 166 this.miny = r.y; 167 this.maxy = r.y + r.height; 168 } 169 170 /** 171 * Adjust the bounds of the sampler 172 * 173 * @param img 174 * the image to determine the bounds from 175 */ 176 public void setBounds(Image<?, ?> img) { 177 if (img == null) 178 return; 179 180 setBounds(img.getBounds()); 181 } 182 183 /** 184 * Get a list of all the rectangles that can be produced by this sampler 185 * 186 * @return all the rectangles 187 */ 188 public List<Rectangle> allRectangles() { 189 final List<Rectangle> list = new ArrayList<Rectangle>(); 190 191 for (final Rectangle r : this) 192 list.add(r); 193 194 return list; 195 } 196 197 @Override 198 public Iterator<Rectangle> iterator() { 199 return new Iterator<Rectangle>() { 200 float x = minx; 201 float y = miny; 202 203 @Override 204 public boolean hasNext() { 205 if (x + width <= maxx && y + height <= maxy) 206 return true; 207 208 return false; 209 } 210 211 @Override 212 public Rectangle next() { 213 if (y + height > maxy) 214 throw new NoSuchElementException(); 215 216 float nextX = x + stepx; 217 float nextY = y; 218 if (nextX + width > maxx) { 219 nextX = minx; 220 nextY += stepy; 221 } 222 223 final Rectangle r = new Rectangle(x, y, width, height); 224 225 x = nextX; 226 y = nextY; 227 228 return r; 229 } 230 231 @Override 232 public void remove() { 233 throw new UnsupportedOperationException("Removal is not supported!"); 234 } 235 }; 236 } 237 238 /** 239 * Create an iterator to extract sub-images from an image based on the 240 * rectangles defined by this sampler. 241 * 242 * @param image 243 * the image to extract from 244 * @return an iterator over the extracted sub-images. 245 */ 246 public <I extends Image<?, I>> Iterator<I> subImageIterator(final I image) { 247 return new Iterator<I>() { 248 Iterator<Rectangle> inner = iterator(); 249 250 @Override 251 public boolean hasNext() { 252 return inner.hasNext(); 253 } 254 255 @Override 256 public I next() { 257 final Rectangle r = inner.next(); 258 259 return image.extractROI(r); 260 } 261 262 @Override 263 public void remove() { 264 throw new UnsupportedOperationException("Removal is not supported!"); 265 } 266 }; 267 } 268}