View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.image;
31  
32  import java.io.Serializable;
33  import java.text.AttributedString;
34  import java.util.Comparator;
35  import java.util.List;
36  
37  import org.openimaj.image.analyser.ImageAnalyser;
38  import org.openimaj.image.analyser.PixelAnalyser;
39  import org.openimaj.image.combiner.AccumulatingImageCombiner;
40  import org.openimaj.image.combiner.ImageCombiner;
41  import org.openimaj.image.pixel.Pixel;
42  import org.openimaj.image.processor.GridProcessor;
43  import org.openimaj.image.processor.ImageProcessor;
44  import org.openimaj.image.processor.KernelProcessor;
45  import org.openimaj.image.processor.PixelProcessor;
46  import org.openimaj.image.processor.Processor;
47  import org.openimaj.image.renderer.ImageRenderer;
48  import org.openimaj.image.renderer.RenderHints;
49  import org.openimaj.image.typography.Font;
50  import org.openimaj.image.typography.FontStyle;
51  import org.openimaj.math.geometry.path.Path2d;
52  import org.openimaj.math.geometry.point.Point2d;
53  import org.openimaj.math.geometry.shape.Polygon;
54  import org.openimaj.math.geometry.shape.Rectangle;
55  import org.openimaj.math.geometry.shape.Shape;
56  
57  import Jama.Matrix;
58  
59  /**
60   * Base class for representing and manipulating images. Images are typed by the
61   * type of pixel at each coordinate and the concrete subclass type.
62   *
63   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
64   *
65   * @param <Q>
66   *            the pixel type
67   * @param <I>
68   *            the actual image of the concrete subclass
69   */
70  public abstract class Image<Q, I extends Image<Q, I>> implements Cloneable, Serializable, ImageProvider<I> {
71  	/**
72  	 * Enumerator for representing the type of field interlacing operations.
73  	 *
74  	 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
75  	 */
76  	public enum Field {
77  		/**
78  		 * Odd field
79  		 */
80  		ODD,
81  		/**
82  		 * Even field
83  		 */
84  		EVEN
85  	}
86  
87  	private static final long serialVersionUID = 1L;
88  
89  	/**
90  	 * Accumulate this image the the given {@link AccumulatingImageCombiner}.
91  	 *
92  	 * @param combiner
93  	 *            the combiner
94  	 * @see AccumulatingImageCombiner#accumulate(Image)
95  	 */
96  	@SuppressWarnings("unchecked")
97  	public void accumulateWith(AccumulatingImageCombiner<I, ?> combiner) {
98  		combiner.accumulate((I) this);
99  	}
100 
101 	/**
102 	 * Set all pixels to their absolute values, so that all pixel values in the
103 	 * image will be greater than zero.
104 	 *
105 	 * @return The image with absolute values
106 	 */
107 	public abstract I abs();
108 
109 	/**
110 	 * Adds the given image to this image and return new image.
111 	 *
112 	 * @param im
113 	 *            The image to add
114 	 * @return A new image that is the sum of this image and the given image.
115 	 */
116 	public I add(Image<?, ?> im) {
117 		final I newImage = this.clone();
118 		newImage.addInplace(im);
119 		return newImage;
120 	}
121 
122 	/**
123 	 * Add a value to each pixel and return new image.
124 	 *
125 	 * @param num
126 	 *            The value to add to each pixel
127 	 * @return A new image that is the sum of this image and the given value.
128 	 */
129 	public I add(Q num) {
130 		final I newImage = this.clone();
131 		newImage.addInplace(num);
132 		return newImage;
133 	}
134 
135 	/**
136 	 * Add the given image to this image (side-affects this image).
137 	 *
138 	 * @param im
139 	 *            The image to add to this image
140 	 * @return A reference to this image.
141 	 */
142 	public abstract I addInplace(Image<?, ?> im);
143 
144 	/**
145 	 * Add a scalar to each pixel in this image (side-affects this image).
146 	 *
147 	 * @param num
148 	 *            The value to add to every pixel in this image.
149 	 * @return A reference to this image.
150 	 */
151 	public abstract I addInplace(Q num);
152 
153 	/**
154 	 * Analyse this image with an {@link ImageAnalyser}.
155 	 *
156 	 * @param analyser
157 	 *            The analyser to analyse with.
158 	 * @see ImageAnalyser#analyseImage(Image)
159 	 */
160 	@SuppressWarnings("unchecked")
161 	public void analyseWith(ImageAnalyser<I> analyser) {
162 		analyser.analyseImage((I) this);
163 	}
164 
165 	/**
166 	 * Analyse this image with a {@link PixelAnalyser}.
167 	 *
168 	 * @param analyser
169 	 *            The analyser to analyse with.
170 	 * @see PixelAnalyser#analysePixel(Object)
171 	 */
172 	public void analyseWith(PixelAnalyser<Q> analyser) {
173 		analyser.reset();
174 
175 		for (int y = 0; y < getHeight(); y++) {
176 			for (int x = 0; x < getWidth(); x++) {
177 				analyser.analysePixel(getPixel(x, y));
178 			}
179 		}
180 	}
181 
182 	/**
183 	 * Analyse this image with the given {@link PixelAnalyser}, only analysing
184 	 * those pixels where the mask is non-zero.
185 	 *
186 	 * @param mask
187 	 *            The mask to apply to the analyser.
188 	 * @param analyser
189 	 *            The {@link PixelProcessor} to apply.
190 	 *
191 	 * @see PixelAnalyser#analysePixel(Object)
192 	 */
193 	public void analyseWithMasked(FImage mask, PixelAnalyser<Q> analyser) {
194 		analyser.reset();
195 
196 		for (int y = 0; y < getHeight(); y++) {
197 			for (int x = 0; x < getWidth(); x++) {
198 				if (mask.pixels[y][x] == 0)
199 					continue;
200 				analyser.analysePixel(getPixel(x, y));
201 			}
202 		}
203 	}
204 
205 	/**
206 	 * Sets any pixels that are below <code>min</code> to zero or above
207 	 * <code>max</code> to the highest normal value that the image allows
208 	 * (usually 1 for floating-point images). This method may side-affect this
209 	 * image.
210 	 *
211 	 * @param min
212 	 *            The minimum value
213 	 * @param max
214 	 *            The maximum value
215 	 * @return The clipped image.
216 	 */
217 	public abstract I clip(Q min, Q max);
218 
219 	/**
220 	 * Set all values greater than the given value to the highest normal value
221 	 * that the image allows (usually 1 for floating-point images). This method
222 	 * may side-affect this image.
223 	 *
224 	 * @param thresh
225 	 *            The value over which pixels are clipped to zero.
226 	 * @return The clipped image.
227 	 */
228 	public abstract I clipMax(Q thresh);
229 
230 	/**
231 	 * Set all values less than the given value to zero. This method may
232 	 * side-affect this image.
233 	 *
234 	 * @param thresh
235 	 *            The value below which pixels are clipped to zero.
236 	 * @return The clipped image.
237 	 */
238 	public abstract I clipMin(Q thresh);
239 
240 	/**
241 	 * Deep copy of an image (internal image buffers copied).
242 	 *
243 	 * @return A copy of this image.
244 	 */
245 	@Override
246 	public abstract I clone();
247 
248 	/**
249 	 * Create a {@link ImageRenderer} capable of drawing into this image.
250 	 *
251 	 * @return the renderer
252 	 */
253 	public abstract ImageRenderer<Q, I> createRenderer();
254 
255 	/**
256 	 * Create a {@link ImageRenderer} capable of drawing into this image.
257 	 *
258 	 * @param options
259 	 *            Options for the renderer
260 	 * @return the renderer
261 	 */
262 	public abstract ImageRenderer<Q, I> createRenderer(RenderHints options);
263 
264 	/**
265 	 * Combine this image with another using an {@link ImageCombiner}.
266 	 *
267 	 * @param <OUT>
268 	 *            The output {@link Image} type.
269 	 * @param <OTHER>
270 	 *            The type of the other {@link Image} being combined.
271 	 * @param combiner
272 	 *            The combiner.
273 	 * @param other
274 	 *            The image to combine with this
275 	 * @return The combined output.
276 	 */
277 	@SuppressWarnings("unchecked")
278 	public <OUT extends Image<?, OUT>, OTHER extends Image<?, OTHER>> OUT combineWith(
279 			ImageCombiner<I, OTHER, OUT> combiner, OTHER other)
280 	{
281 		return combiner.combine((I) this, other);
282 	}
283 
284 	/**
285 	 * Get the default foreground colour.
286 	 *
287 	 * <p>
288 	 * This is a convenience method that calls {@link #createRenderer()} to get
289 	 * the default renderer to do the actual drawing. Create the renderer
290 	 * yourself and use it to draw if you need more control.
291 	 * </p>
292 	 *
293 	 * @return the default foreground colour.
294 	 */
295 	public Q defaultBackgroundColour() {
296 		return createRenderer().defaultBackgroundColour();
297 	}
298 
299 	/**
300 	 * Get the default foreground colour.
301 	 *
302 	 * <p>
303 	 * This is a convenience method that calls {@link #createRenderer()} to get
304 	 * the default renderer to do the actual drawing. Create the renderer
305 	 * yourself and use it to draw if you need more control.
306 	 * </p>
307 	 *
308 	 * @return the default foreground colour.
309 	 */
310 	public Q defaultForegroundColour() {
311 		return createRenderer().defaultForegroundColour();
312 	}
313 
314 	/**
315 	 * Divide each pixel of the image by corresponding pixel in the given image.
316 	 * This method should return a new image.
317 	 *
318 	 * @param im
319 	 *            image The image to divide this image by.
320 	 * @return A new image containing the result.
321 	 */
322 	public I divide(Image<?, ?> im) {
323 		final I newImage = this.clone();
324 		newImage.divideInplace(im);
325 		return newImage;
326 	}
327 
328 	/**
329 	 * Divide each pixel of the image by the given scalar value. This method
330 	 * should return a new image.
331 	 *
332 	 * @param val
333 	 *            The value to divide the pixels in this image by.
334 	 * @return A new image containing the result.
335 	 */
336 	public I divide(Q val) {
337 		final I newImage = this.clone();
338 		newImage.divideInplace(val);
339 		return newImage;
340 	}
341 
342 	/**
343 	 * Divide each pixel in this image by the corresponding pixel value in the
344 	 * given image. This method should side-affect this image.
345 	 *
346 	 * @param im
347 	 *            image The image to divide this image by.
348 	 * @return A reference to this image containing the result.
349 	 */
350 	public abstract I divideInplace(Image<?, ?> im);
351 
352 	/**
353 	 * Divide each pixel of the image by the given scalar value. This method
354 	 * should side-affect this image.
355 	 *
356 	 * @param val
357 	 *            The value to divide each pixel by.
358 	 * @return A reference to this image containing the result.
359 	 */
360 	public abstract I divideInplace(Q val);
361 
362 	/**
363 	 * Draw onto this image lines drawn with the given colour between the points
364 	 * given. No points are drawn. Side-affects this image.
365 	 *
366 	 * <p>
367 	 * This is a convenience method that calls {@link #createRenderer()} to get
368 	 * the default renderer to do the actual drawing. Create the renderer
369 	 * yourself and use it to draw if you need more control.
370 	 * </p>
371 	 *
372 	 * @param pts
373 	 *            The point list to draw onto this image.
374 	 * @param col
375 	 *            The colour to draw the lines
376 	 */
377 	public void drawConnectedPoints(List<? extends Point2d> pts, Q col) {
378 		createRenderer().drawConnectedPoints(pts, col);
379 	}
380 
381 	/**
382 	 * Draw a cubic Bezier curve into the image with 100 point accuracy.
383 	 *
384 	 * <p>
385 	 * This is a convenience method that calls {@link #createRenderer()} to get
386 	 * the default renderer to do the actual drawing. Create the renderer
387 	 * yourself and use it to draw if you need more control.
388 	 * </p>
389 	 *
390 	 * @param p1
391 	 *            One end point of the line
392 	 * @param p2
393 	 *            The other end point of the line
394 	 * @param c1
395 	 *            The control point associated with p1
396 	 * @param c2
397 	 *            The control point associated with p2
398 	 * @param thickness
399 	 *            The thickness to draw the line
400 	 * @param col
401 	 *            The colour to draw the line
402 	 * @return The points along the bezier curve
403 	 */
404 	public Point2d[] drawCubicBezier(Point2d p1, Point2d p2,
405 			Point2d c1, Point2d c2, int thickness, Q col)
406 	{
407 		return createRenderer().drawCubicBezier(p1, p2, c1, c2, thickness, col);
408 	}
409 
410 	/**
411 	 * Draw into this image the provided image at the given coordinates. Parts
412 	 * of the image outside the bounds of this image will be ignored.
413 	 * Side-affects this image.
414 	 *
415 	 * <p>
416 	 * This is a convenience method that calls {@link #createRenderer()} to get
417 	 * the default renderer to do the actual drawing. Create the renderer
418 	 * yourself and use it to draw if you need more control.
419 	 * </p>
420 	 *
421 	 * @param image
422 	 *            The image to draw.
423 	 * @param x
424 	 *            The x-ordinate of the top-left of the image
425 	 * @param y
426 	 *            The y-ordinate of the top-left of the image
427 	 */
428 	public void drawImage(I image, int x, int y) {
429 		createRenderer().drawImage(image, x, y);
430 	}
431 
432 	/**
433 	 * Draw into this image the provided image at the given coordinates. Parts
434 	 * of the image outside the bounds of this image will be ignored.
435 	 * Side-affects this image.
436 	 *
437 	 * <p>
438 	 * This is a convenience method that calls {@link #createRenderer()} to get
439 	 * the default renderer to do the actual drawing. Create the renderer
440 	 * yourself and use it to draw if you need more control.
441 	 * </p>
442 	 *
443 	 * @param image
444 	 *            The image to draw.
445 	 * @param pt
446 	 *            the coordinate at which to draw
447 	 */
448 	public void drawImage(I image, Point2d pt) {
449 		createRenderer().drawImage(image, (int) pt.getX(), (int) pt.getY());
450 	}
451 
452 	/**
453 	 * Draw into this image the provided image at the given coordinates ignoring
454 	 * certain pixels. Parts of the image outside the bounds of this image will
455 	 * be ignored. Side-affects this image. Pixels in the ignore list will be
456 	 * stripped from the image to draw.
457 	 *
458 	 * <p>
459 	 * This is a convenience method that calls {@link #createRenderer()} to get
460 	 * the default renderer to do the actual drawing. Create the renderer
461 	 * yourself and use it to draw if you need more control.
462 	 * </p>
463 	 *
464 	 * @param image
465 	 *            The image to draw.
466 	 * @param x
467 	 *            The x-ordinate of the top-left of the image
468 	 * @param y
469 	 *            The y-ordinate of the top-left of the image
470 	 * @param ignoreList
471 	 *            The list of pixels to ignore when copying the image
472 	 */
473 	public void drawImage(I image, int x, int y, @SuppressWarnings("unchecked") Q... ignoreList) {
474 		createRenderer().drawImage(image, x, y, ignoreList);
475 	}
476 
477 	/**
478 	 * Draw a line from the coordinates specified by <code>(x1,y1)</code> at an
479 	 * angle of <code>theta</code> with the given length, thickness and colour.
480 	 * Side-affects this image.
481 	 *
482 	 * <p>
483 	 * This is a convenience method that calls {@link #createRenderer()} to get
484 	 * the default renderer to do the actual drawing. Create the renderer
485 	 * yourself and use it to draw if you need more control.
486 	 * </p>
487 	 *
488 	 * @param x1
489 	 *            The x-ordinate to start the line.
490 	 * @param y1
491 	 *            The y-ordinate to start the line.
492 	 * @param theta
493 	 *            The angle at which to draw the line.
494 	 * @param length
495 	 *            The length to draw the line.
496 	 * @param thickness
497 	 *            The thickness to draw the line.
498 	 * @param col
499 	 *            The colour to draw the line.
500 	 */
501 	public void drawLine(int x1, int y1, double theta, int length, int thickness, Q col) {
502 		createRenderer().drawLine(x1, y1, theta, length, thickness, col);
503 	}
504 
505 	/**
506 	 * Draw a line from the coordinates specified by <code>(x1,y1)</code> at an
507 	 * angle of <code>theta</code> with the given length and colour.
508 	 * Line-thickness will be 1. Side-affects this image.
509 	 *
510 	 * <p>
511 	 * This is a convenience method that calls {@link #createRenderer()} to get
512 	 * the default renderer to do the actual drawing. Create the renderer
513 	 * yourself and use it to draw if you need more control.
514 	 * </p>
515 	 *
516 	 * @param x1
517 	 *            The x-ordinate to start the line.
518 	 * @param y1
519 	 *            The y-ordinate to start the line.
520 	 * @param theta
521 	 *            The angle at which to draw the line.
522 	 * @param length
523 	 *            The length to draw the line.
524 	 * @param col
525 	 *            The colour to draw the line.
526 	 */
527 	public void drawLine(int x1, int y1, double theta, int length, Q col) {
528 		createRenderer().drawLine(x1, y1, theta, length, 1, col);
529 	}
530 
531 	/**
532 	 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to the
533 	 * coordinates specified by <code>(x1,y1)</code> using the given color and
534 	 * thickness. Side-affects this image.
535 	 *
536 	 * <p>
537 	 * This is a convenience method that calls {@link #createRenderer()} to get
538 	 * the default renderer to do the actual drawing. Create the renderer
539 	 * yourself and use it to draw if you need more control.
540 	 * </p>
541 	 *
542 	 * @param x0
543 	 *            The x-ordinate at the start of the line.
544 	 * @param y0
545 	 *            The y-ordinate at the start of the line.
546 	 * @param x1
547 	 *            The x-ordinate at the end of the line.
548 	 * @param y1
549 	 *            The y-ordinate at the end of the line.
550 	 * @param thickness
551 	 *            The thickness which to draw the line.
552 	 * @param col
553 	 *            The colour in which to draw the line.
554 	 */
555 	public void drawLine(int x0, int y0, int x1, int y1, int thickness, Q col) {
556 		createRenderer().drawLine(x0, y0, x1, y1, thickness, col);
557 	}
558 
559 	/**
560 	 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to
561 	 * <code>(x1,y1)</code> using the given colour. The line thickness will be 1
562 	 * pixel. Side-affects this image.
563 	 *
564 	 * <p>
565 	 * This is a convenience method that calls {@link #createRenderer()} to get
566 	 * the default renderer to do the actual drawing. Create the renderer
567 	 * yourself and use it to draw if you need more control.
568 	 * </p>
569 	 *
570 	 * @param x0
571 	 *            The x-ordinate at the start of the line.
572 	 * @param y0
573 	 *            The y-ordinate at the start of the line.
574 	 * @param x1
575 	 *            The x-ordinate at the end of the line.
576 	 * @param y1
577 	 *            The y-ordinate at the end of the line.
578 	 * @param col
579 	 *            The colour in which to draw the line.
580 	 */
581 	public void drawLine(int x0, int y0, int x1, int y1, Q col) {
582 		createRenderer().drawLine(x0, y0, x1, y1, 1, col);
583 	}
584 
585 	/**
586 	 * Draw a line from the coordinates specified using the given colour. The
587 	 * line thickness will be 1 pixel. Side-affects this image.
588 	 *
589 	 * <p>
590 	 * This is a convenience method that calls {@link #createRenderer()} to get
591 	 * the default renderer to do the actual drawing. Create the renderer
592 	 * yourself and use it to draw if you need more control.
593 	 * </p>
594 	 *
595 	 * @param p1
596 	 *            The coordinate of the start of the line.
597 	 * @param p2
598 	 *            The coordinate of the end of the line.
599 	 * @param col
600 	 *            The colour in which to draw the line.
601 	 */
602 	public void drawLine(Point2d p1, Point2d p2, Q col) {
603 		createRenderer().drawLine(p1, p2, col);
604 	}
605 
606 	/**
607 	 * Draw a line from the coordinates specified using the given colour and
608 	 * thickness. Side-affects this image.
609 	 *
610 	 * <p>
611 	 * This is a convenience method that calls {@link #createRenderer()} to get
612 	 * the default renderer to do the actual drawing. Create the renderer
613 	 * yourself and use it to draw if you need more control.
614 	 * </p>
615 	 *
616 	 * @param p1
617 	 *            The coordinate of the start of the line.
618 	 * @param p2
619 	 *            The coordinate of the end of the line.
620 	 * @param thickness
621 	 *            the stroke width
622 	 * @param col
623 	 *            The colour in which to draw the line.
624 	 */
625 	public void drawLine(Point2d p1, Point2d p2, int thickness, Q col) {
626 		createRenderer().drawLine(p1, p2, thickness, col);
627 	}
628 
629 	/**
630 	 * Draw a line from the specified Path2d object
631 	 *
632 	 * <p>
633 	 * This is a convenience method that calls {@link #createRenderer()} to get
634 	 * the default renderer to do the actual drawing. Create the renderer
635 	 * yourself and use it to draw if you need more control.
636 	 * </p>
637 	 *
638 	 * @param line
639 	 *            the line
640 	 * @param thickness
641 	 *            the stroke width
642 	 * @param col
643 	 *            The colour in which to draw the line.
644 	 */
645 	public void drawLine(Path2d line, int thickness, Q col) {
646 		createRenderer().drawLine(line, thickness, col);
647 	}
648 
649 	/**
650 	 * Draw a line from the specified Path2d object
651 	 *
652 	 * <p>
653 	 * This is a convenience method that calls {@link #createRenderer()} to get
654 	 * the default renderer to do the actual drawing. Create the renderer
655 	 * yourself and use it to draw if you need more control.
656 	 * </p>
657 	 *
658 	 * @param line
659 	 *            the line
660 	 * @param thickness
661 	 *            the stroke width
662 	 * @param col
663 	 *            The colour in which to draw the line.
664 	 */
665 	public void drawPath(Path2d line, int thickness, Q col) {
666 		createRenderer().drawPath(line, thickness, col);
667 	}
668 
669 	/**
670 	 * Draw the given list of lines using {@link #drawLine(Path2d, int, Object)}
671 	 * with the given colour and thickness. Side-affects this image.
672 	 *
673 	 * <p>
674 	 * This is a convenience method that calls {@link #createRenderer()} to get
675 	 * the default renderer to do the actual drawing. Create the renderer
676 	 * yourself and use it to draw if you need more control.
677 	 * </p>
678 	 *
679 	 * @param lines
680 	 *            The list of lines to draw.
681 	 * @param thickness
682 	 *            the stroke width
683 	 * @param col
684 	 *            The colour to draw each point.
685 	 */
686 	public void drawLines(Iterable<? extends Path2d> lines, int thickness, Q col) {
687 		createRenderer().drawLines(lines, thickness, col);
688 	}
689 
690 	/**
691 	 * Draw the given list of paths using {@link #drawLine(Path2d, int, Object)}
692 	 * with the given colour and thickness. Side-affects this image.
693 	 *
694 	 * <p>
695 	 * This is a convenience method that calls {@link #createRenderer()} to get
696 	 * the default renderer to do the actual drawing. Create the renderer
697 	 * yourself and use it to draw if you need more control.
698 	 * </p>
699 	 *
700 	 * @param lines
701 	 *            The list of lines to draw.
702 	 * @param thickness
703 	 *            the stroke width
704 	 * @param col
705 	 *            The colour to draw each point.
706 	 */
707 	public void drawPaths(Iterable<? extends Path2d> lines, int thickness, Q col) {
708 		createRenderer().drawPaths(lines, thickness, col);
709 	}
710 
711 	/**
712 	 * Draw a dot centered on the given location (rounded to nearest integer
713 	 * location) at the given size and with the given color. Side-affects this
714 	 * image.
715 	 *
716 	 * <p>
717 	 * This is a convenience method that calls {@link #createRenderer()} to get
718 	 * the default renderer to do the actual drawing. Create the renderer
719 	 * yourself and use it to draw if you need more control.
720 	 * </p>
721 	 *
722 	 * @param p
723 	 *            The coordinates at which to draw the point
724 	 * @param col
725 	 *            The colour to draw the point
726 	 * @param size
727 	 *            The size at which to draw the point.
728 	 */
729 	public void drawPoint(Point2d p, Q col, int size) {
730 		createRenderer().drawPoint(p, col, size);
731 	}
732 
733 	/**
734 	 * Draw the given list of points using
735 	 * {@link #drawPoint(Point2d, Object, int)} with the given colour and size.
736 	 * Side-affects this image.
737 	 *
738 	 * <p>
739 	 * This is a convenience method that calls {@link #createRenderer()} to get
740 	 * the default renderer to do the actual drawing. Create the renderer
741 	 * yourself and use it to draw if you need more control.
742 	 * </p>
743 	 *
744 	 * @param pts
745 	 *            The list of points to draw.
746 	 * @param col
747 	 *            The colour to draw each point.
748 	 * @param size
749 	 *            The size to draw each point.
750 	 */
751 	public void drawPoints(Iterable<? extends Point2d> pts, Q col, int size) {
752 		createRenderer().drawPoints(pts, col, size);
753 	}
754 
755 	/**
756 	 * Draw the given polygon in the specified colour with the given thickness
757 	 * lines. Side-affects this image.
758 	 *
759 	 * <p>
760 	 * This is a convenience method that calls {@link #createRenderer()} to get
761 	 * the default renderer to do the actual drawing. Create the renderer
762 	 * yourself and use it to draw if you need more control.
763 	 * </p>
764 	 *
765 	 * @param p
766 	 *            The polygon to draw.
767 	 * @param thickness
768 	 *            The thickness of the lines to use
769 	 * @param col
770 	 *            The colour to draw the lines in
771 	 */
772 	public void drawPolygon(Polygon p, int thickness, Q col) {
773 		createRenderer().drawPolygon(p, thickness, col);
774 	}
775 
776 	/**
777 	 * Draw the given polygon in the specified colour. Uses
778 	 * {@link #drawPolygon(Polygon, int, Object)} with line thickness 1.
779 	 * Side-affects this image.
780 	 *
781 	 * <p>
782 	 * This is a convenience method that calls {@link #createRenderer()} to get
783 	 * the default renderer to do the actual drawing. Create the renderer
784 	 * yourself and use it to draw if you need more control.
785 	 * </p>
786 	 *
787 	 * @param p
788 	 *            The polygon to draw.
789 	 * @param col
790 	 *            The colour to draw the polygon in.
791 	 */
792 	public void drawPolygon(Polygon p, Q col) {
793 		createRenderer().drawPolygon(p, col);
794 	}
795 
796 	/**
797 	 * Draw the given polygon, filled with the specified colour. Side-affects
798 	 * this image.
799 	 *
800 	 * <p>
801 	 * This is a convenience method that calls {@link #createRenderer()} to get
802 	 * the default renderer to do the actual drawing. Create the renderer
803 	 * yourself and use it to draw if you need more control.
804 	 * </p>
805 	 *
806 	 * @param p
807 	 *            The polygon to draw.
808 	 * @param col
809 	 *            The colour to fill the polygon with.
810 	 */
811 	public void drawPolygonFilled(Polygon p, Q col) {
812 		createRenderer().drawPolygonFilled(p, col);
813 	}
814 
815 	/**
816 	 * Draw the given shape in the specified colour with the given thickness
817 	 * lines. Side-affects this image.
818 	 *
819 	 * <p>
820 	 * This is a convenience method that calls {@link #createRenderer()} to get
821 	 * the default renderer to do the actual drawing. Create the renderer
822 	 * yourself and use it to draw if you need more control.
823 	 * </p>
824 	 *
825 	 * @param s
826 	 *            The shape to draw.
827 	 * @param thickness
828 	 *            The thickness of the lines to use
829 	 * @param col
830 	 *            The colour to draw the lines in
831 	 */
832 	public void drawShape(Shape s, int thickness, Q col) {
833 		createRenderer().drawShape(s, thickness, col);
834 	}
835 
836 	/**
837 	 * Draw the given shape in the specified colour. Uses
838 	 * {@link #drawPolygon(Polygon, int, Object)} with line thickness 1.
839 	 * Side-affects this image.
840 	 *
841 	 * <p>
842 	 * This is a convenience method that calls {@link #createRenderer()} to get
843 	 * the default renderer to do the actual drawing. Create the renderer
844 	 * yourself and use it to draw if you need more control.
845 	 * </p>
846 	 *
847 	 * @param p
848 	 *            The shape to draw.
849 	 * @param col
850 	 *            The colour to draw the polygon in.
851 	 */
852 	public void drawShape(Shape p, Q col) {
853 		createRenderer().drawShape(p, col);
854 	}
855 
856 	/**
857 	 * Draw the given shape, filled with the specified colour. Side-affects this
858 	 * image.
859 	 *
860 	 * <p>
861 	 * This is a convenience method that calls {@link #createRenderer()} to get
862 	 * the default renderer to do the actual drawing. Create the renderer
863 	 * yourself and use it to draw if you need more control.
864 	 * </p>
865 	 *
866 	 * @param s
867 	 *            The shape to draw.
868 	 * @param col
869 	 *            The colour to fill the polygon with.
870 	 */
871 	public void drawShapeFilled(Shape s, Q col) {
872 		createRenderer().drawShapeFilled(s, col);
873 	}
874 
875 	/**
876 	 * Render the text using its attributes.
877 	 *
878 	 * <p>
879 	 * This is a convenience method that calls {@link #createRenderer()} to get
880 	 * the default renderer to do the actual drawing. Create the renderer
881 	 * yourself and use it to draw if you need more control.
882 	 * </p>
883 	 *
884 	 * @param text
885 	 *            the text
886 	 * @param x
887 	 *            the x-ordinate
888 	 * @param y
889 	 *            the y-ordinate
890 	 */
891 	public void drawText(AttributedString text, int x, int y) {
892 		createRenderer().drawText(text, x, y);
893 	}
894 
895 	/**
896 	 * Render the text using its attributes.
897 	 *
898 	 * <p>
899 	 * This is a convenience method that calls {@link #createRenderer()} to get
900 	 * the default renderer to do the actual drawing. Create the renderer
901 	 * yourself and use it to draw if you need more control.
902 	 * </p>
903 	 *
904 	 * @param text
905 	 *            the text
906 	 * @param pt
907 	 *            the coordinate to render at
908 	 */
909 	public void drawText(AttributedString text, Point2d pt) {
910 		createRenderer().drawText(text, pt);
911 	}
912 
913 	/**
914 	 * Render the text in the given font with the default style.
915 	 *
916 	 * <p>
917 	 * This is a convenience method that calls {@link #createRenderer()} to get
918 	 * the default renderer to do the actual drawing. Create the renderer
919 	 * yourself and use it to draw if you need more control.
920 	 * </p>
921 	 *
922 	 * @param <F>
923 	 *            the font
924 	 * @param text
925 	 *            the text
926 	 * @param x
927 	 *            the x-ordinate
928 	 * @param y
929 	 *            the y-ordinate
930 	 * @param f
931 	 *            the font
932 	 * @param sz
933 	 *            the size
934 	 */
935 	public <F extends Font<F>> void drawText(String text, int x, int y, F f, int sz) {
936 		createRenderer().drawText(text, x, y, f, sz);
937 	}
938 
939 	/**
940 	 * Render the text in the given font in the given colour with the default
941 	 * style.
942 	 *
943 	 * <p>
944 	 * This is a convenience method that calls {@link #createRenderer()} to get
945 	 * the default renderer to do the actual drawing. Create the renderer
946 	 * yourself and use it to draw if you need more control.
947 	 * </p>
948 	 *
949 	 * @param <F>
950 	 *            the font
951 	 * @param text
952 	 *            the text
953 	 * @param x
954 	 *            the x-ordinate
955 	 * @param y
956 	 *            the y-ordinate
957 	 * @param f
958 	 *            the font
959 	 * @param sz
960 	 *            the size
961 	 * @param col
962 	 *            the font color
963 	 */
964 	public <F extends Font<F>> void drawText(String text, int x, int y, F f, int sz, Q col) {
965 		createRenderer().drawText(text, x, y, f, sz, col);
966 	}
967 
968 	/**
969 	 * Render the text with the given {@link FontStyle}.
970 	 *
971 	 * <p>
972 	 * This is a convenience method that calls {@link #createRenderer()} to get
973 	 * the default renderer to do the actual drawing. Create the renderer
974 	 * yourself and use it to draw if you need more control.
975 	 * </p>
976 	 *
977 	 * @param text
978 	 *            the text
979 	 * @param x
980 	 *            the x-ordinate
981 	 * @param y
982 	 *            the y-ordinate
983 	 * @param f
984 	 *            the font style
985 	 */
986 	public void drawText(String text, int x, int y, FontStyle<Q> f) {
987 		createRenderer().drawText(text, x, y, f);
988 	}
989 
990 	/**
991 	 * Render the text in the given font with the default style.
992 	 *
993 	 * <p>
994 	 * This is a convenience method that calls {@link #createRenderer()} to get
995 	 * the default renderer to do the actual drawing. Create the renderer
996 	 * yourself and use it to draw if you need more control.
997 	 * </p>
998 	 *
999 	 * @param <F>
1000 	 *            the font
1001 	 * @param text
1002 	 *            the text
1003 	 * @param pt
1004 	 *            the coordinate to render at
1005 	 * @param f
1006 	 *            the font
1007 	 * @param sz
1008 	 *            the size
1009 	 */
1010 	public <F extends Font<F>> void drawText(String text, Point2d pt, F f, int sz) {
1011 		createRenderer().drawText(text, pt, f, sz);
1012 	}
1013 
1014 	/**
1015 	 * Render the text in the given font in the given colour with the default
1016 	 * style.
1017 	 *
1018 	 * <p>
1019 	 * This is a convenience method that calls {@link #createRenderer()} to get
1020 	 * the default renderer to do the actual drawing. Create the renderer
1021 	 * yourself and use it to draw if you need more control.
1022 	 * </p>
1023 	 *
1024 	 * @param <F>
1025 	 *            the font
1026 	 * @param text
1027 	 *            the text
1028 	 * @param pt
1029 	 *            the coordinate to render at
1030 	 * @param f
1031 	 *            the font
1032 	 * @param sz
1033 	 *            the size
1034 	 * @param col
1035 	 *            the font colour
1036 	 */
1037 	public <F extends Font<F>> void drawText(String text, Point2d pt, F f, int sz, Q col) {
1038 		createRenderer().drawText(text, pt, f, sz, col);
1039 	}
1040 
1041 	/**
1042 	 * Render the text with the given {@link FontStyle}.
1043 	 *
1044 	 * <p>
1045 	 * This is a convenience method that calls {@link #createRenderer()} to get
1046 	 * the default renderer to do the actual drawing. Create the renderer
1047 	 * yourself and use it to draw if you need more control.
1048 	 * </p>
1049 	 *
1050 	 * @param text
1051 	 *            the text
1052 	 * @param pt
1053 	 *            the coordinate to render at
1054 	 * @param f
1055 	 *            the font style
1056 	 */
1057 	public void drawText(String text, Point2d pt, FontStyle<Q> f) {
1058 		createRenderer().drawText(text, pt, f);
1059 	}
1060 
1061 	/**
1062 	 * Extract a rectangular region about the centre of the image with the given
1063 	 * width and height. The method will return a box that extends
1064 	 * <code>width/2</code> and <code>height/2</code> from the centre point so
1065 	 * that the centre point of the extracted box is also the centre point of
1066 	 * the image.
1067 	 *
1068 	 * @param w
1069 	 *            The width of the box to extract
1070 	 * @param h
1071 	 *            The height of the box to extract
1072 	 * @return A new image centred around the centre of the image.
1073 	 */
1074 	public I extractCenter(int w, int h) {
1075 		final int sw = (int) Math.floor((this.getWidth() - w) / 2);
1076 		final int sh = (int) Math.floor((this.getHeight() - h) / 2);
1077 
1078 		return this.extractROI(sw, sh, w, h);
1079 	}
1080 
1081 	/**
1082 	 * Extract a rectangular region centred on a given point. The method will
1083 	 * return a box that extends <code>width/2</code> and <code>height/2</code>
1084 	 * from the given point <code>(x,y)</code> such that the centre point of the
1085 	 * extracted box is the same as the point <code>(x,y)</code> in this image.
1086 	 *
1087 	 * @param x
1088 	 *            Center point of the rectangle to extract
1089 	 * @param y
1090 	 *            center point of the rectangle to extract
1091 	 * @param w
1092 	 *            The width of the rectangle to extract
1093 	 * @param h
1094 	 *            The height of the rectangle to extract
1095 	 * @return A new image centred around the centre of the image.
1096 	 */
1097 	public I extractCenter(int x, int y, int w, int h) {
1098 		final int sw = (int) Math.floor(x - (w / 2));
1099 		final int sh = (int) Math.floor(y - (h / 2));
1100 
1101 		return this.extractROI(sw, sh, w, h);
1102 	}
1103 
1104 	/**
1105 	 * Extract a rectangular region of interest from this image and put it in
1106 	 * the given image. Coordinate <code>(0,0)</code> is the top-left corner.
1107 	 * The width and height of the extracted image should be determined from the
1108 	 * given image's width and height.
1109 	 *
1110 	 * @param x
1111 	 *            The leftmost coordinate of the rectangle to extract
1112 	 * @param y
1113 	 *            The topmost coordinate of the rectangle to extract
1114 	 * @param img
1115 	 *            The destination image
1116 	 * @return A reference to the destination image containing the result
1117 	 */
1118 	public abstract I extractROI(int x, int y, I img);
1119 
1120 	/**
1121 	 * Extract a rectangular region of interest of the given width and height.
1122 	 * Coordinate <code>(0,0)</code> is the top-left corner. Returns a new
1123 	 * image.
1124 	 *
1125 	 * @param x
1126 	 *            The leftmost coordinate of the rectangle to extract
1127 	 * @param y
1128 	 *            The topmost coordinate of the rectangle to extract
1129 	 * @param w
1130 	 *            The width of the rectangle to extract
1131 	 * @param h
1132 	 *            The height of the rectangle to extract
1133 	 * @return A new image representing the selected region
1134 	 */
1135 	public abstract I extractROI(int x, int y, int w, int h);
1136 
1137 	/**
1138 	 * Extract a rectangular region of interest of the given width and height.
1139 	 * Coordinate <code>(0,0)</code> is the top-left corner. Returns a new
1140 	 * image.
1141 	 *
1142 	 * @param r
1143 	 *            the rectangle
1144 	 * @return A new image representing the selected region
1145 	 */
1146 	public I extractROI(Rectangle r) {
1147 		return extractROI((int) r.x, (int) r.y, (int) r.width, (int) r.height);
1148 	}
1149 
1150 	/**
1151 	 * Fill this image with the given colour. Should overwrite all other data
1152 	 * stored in this image. Side-affects this image.
1153 	 *
1154 	 * @param colour
1155 	 *            the colour to fill the image with
1156 	 * @return A reference to this image.
1157 	 */
1158 	public abstract I fill(Q colour);
1159 
1160 	/**
1161 	 * Flips the content horizontally. Side-affects this image.
1162 	 *
1163 	 * @return A reference to this image.
1164 	 */
1165 	public abstract I flipX();
1166 
1167 	/**
1168 	 * Flips the content vertically. Side-affects this image.
1169 	 *
1170 	 * @return A reference to this image.
1171 	 */
1172 	public abstract I flipY();
1173 
1174 	/**
1175 	 * Get a rectangle representing the image, with the top-left at 0,0 and the
1176 	 * bottom-right at width,height
1177 	 *
1178 	 * @return the bounding rectangle of the image
1179 	 */
1180 	public Rectangle getBounds() {
1181 		return new Rectangle(0, 0, this.getWidth(), this.getHeight());
1182 	}
1183 
1184 	/**
1185 	 * Get the image width in pixels. This is syntactic sugar for
1186 	 * {@link #getWidth()};
1187 	 *
1188 	 * @return The image width in pixels.
1189 	 */
1190 	public int getCols() {
1191 		return getWidth();
1192 	}
1193 
1194 	/**
1195 	 * Get bounding box of non-zero-valued pixels around the outside of the
1196 	 * image. Used by {@link #trim()}.
1197 	 *
1198 	 * @return A rectangle of the boundaries of the non-zero-valued image
1199 	 */
1200 	public abstract Rectangle getContentArea();
1201 
1202 	/**
1203 	 * Get the given field of this image. Used for deinterlacing video, this
1204 	 * should return a new image containing the deinterlaced image. The returned
1205 	 * image will be half the height of this image.
1206 	 *
1207 	 * @param f
1208 	 *            The {@link Field} to extract from this image
1209 	 * @return An image containing only the odd or even fields.
1210 	 */
1211 	public abstract I getField(Field f);
1212 
1213 	/**
1214 	 * Get the given field of this image, maintaining the image's aspect ratio
1215 	 * by doubling the fields. Used for deinterlacing video, this should return
1216 	 * a new image containing the deinterlaced image. The returned image should
1217 	 * be the same size as this image.
1218 	 *
1219 	 * @param f
1220 	 *            The {@link Field} to extract from this image
1221 	 * @return An image containing the odd or even fields doubled.
1222 	 */
1223 	public abstract I getFieldCopy(Field f);
1224 
1225 	/**
1226 	 * Get the given field of this image, maintaining the image's aspect ratio
1227 	 * by interpolating between the fields. Used for deinterlacing video, this
1228 	 * should return a new image containing the detinterlaced image. The
1229 	 * returned image should be the same size as this image.
1230 	 *
1231 	 * @param f
1232 	 *            The {@link Field} to extract from this image.
1233 	 * @return An image containing the odd or even fields with interpolated rows
1234 	 *         between.
1235 	 */
1236 	public abstract I getFieldInterpolate(Field f);
1237 
1238 	/**
1239 	 * Returns the image height in pixels.
1240 	 *
1241 	 * @return The image height in pixels.
1242 	 */
1243 	public abstract int getHeight();
1244 
1245 	/**
1246 	 * Get the value of the pixel at coordinate <code>(x, y)</code>.
1247 	 *
1248 	 * @param x
1249 	 *            The x-ordinate to get
1250 	 * @param y
1251 	 *            The y-ordinate to get
1252 	 *
1253 	 * @return The pixel value at (x, y)
1254 	 */
1255 	public abstract Q getPixel(int x, int y);
1256 
1257 	/**
1258 	 * Get the value of the pixel at coordinate p
1259 	 *
1260 	 * @param p
1261 	 *            The coordinate to get
1262 	 *
1263 	 * @return The pixel value at (x, y)
1264 	 */
1265 	public Q getPixel(Pixel p) {
1266 		return getPixel(p.x, p.y);
1267 	}
1268 
1269 	/**
1270 	 * Returns a pixel comparator that is able to compare equality of pixels in
1271 	 * the given image type.
1272 	 *
1273 	 * @return A {@link Comparator} that compares pixels.
1274 	 */
1275 	public abstract Comparator<? super Q> getPixelComparator();
1276 
1277 	/**
1278 	 * Get the value of a sub-pixel using linear-interpolation.
1279 	 *
1280 	 * @param x
1281 	 *            The x-ordinate to get
1282 	 * @param y
1283 	 *            The y-ordinate to get
1284 	 * @return The value of the interpolated point at <code>(x,y)</code>
1285 	 */
1286 	public abstract Q getPixelInterp(double x, double y);
1287 
1288 	/**
1289 	 * Get the value of a sub-pixel using linear-interpolation. Also specify the
1290 	 * colour of the background (for interpolation at the edge)
1291 	 *
1292 	 * @param x
1293 	 *            The x-ordinate to get.
1294 	 * @param y
1295 	 *            The y-ordinate to get.
1296 	 * @param backgroundColour
1297 	 *            The colour of the background pixel.
1298 	 * @return The value of the interpolated point at <code>(x,y)</code>
1299 	 */
1300 	public abstract Q getPixelInterp(double x, double y, Q backgroundColour);
1301 
1302 	/**
1303 	 * Returns the pixels in this image as a vector (an array of the pixel
1304 	 * type).
1305 	 *
1306 	 * @param f
1307 	 *            The array into which to place the data
1308 	 * @return The pixels in the image as a vector (a reference to the given
1309 	 *         array).
1310 	 */
1311 	public Q[] getPixelVector(Q[] f) {
1312 		for (int y = 0; y < getHeight(); y++)
1313 			for (int x = 0; x < getWidth(); x++)
1314 				f[x + y * getWidth()] = getPixel(x, y);
1315 
1316 		return f;
1317 	}
1318 
1319 	/**
1320 	 * Get the height of this image. This is a syntactic sugar method for
1321 	 * {@link #getHeight()}.
1322 	 *
1323 	 * @return The image height in pixels.
1324 	 */
1325 	public int getRows() {
1326 		return getHeight();
1327 	}
1328 
1329 	/**
1330 	 * Get the width (number of columns) in this image.
1331 	 *
1332 	 * @return the image width
1333 	 */
1334 	public abstract int getWidth();
1335 
1336 	/**
1337 	 * Copy the internal state from another image of the same type. This method
1338 	 * is designed to be FAST. This means that bounds checking WILL NOT be
1339 	 * performed, so it is important that the images are the SAME size.
1340 	 *
1341 	 * @param im
1342 	 *            The source image to make a copy of.
1343 	 * @return A reference to this image.
1344 	 */
1345 	public abstract I internalCopy(I im);
1346 
1347 	/**
1348 	 * Assign the internal state from another image of the same type.
1349 	 *
1350 	 * @param im
1351 	 *            The source image to make a copy of.
1352 	 * @return A reference to this image.
1353 	 */
1354 	public abstract I internalAssign(I im);
1355 
1356 	/**
1357 	 * Copy pixels from given ARGB buffer image into this image. Side-affects
1358 	 * this image.
1359 	 *
1360 	 * @param pixelData
1361 	 *            buffer of ARGB packed integer pixels
1362 	 * @param width
1363 	 *            the width of the buffer
1364 	 * @param height
1365 	 *            the height of the buffer
1366 	 *
1367 	 * @return A reference to this image.
1368 	 */
1369 	public abstract I internalAssign(int[] pixelData, int width, int height);
1370 
1371 	/**
1372 	 * Invert the image pixels by finding the maximum value and subtracting each
1373 	 * pixel value from that maximum.
1374 	 *
1375 	 * @return A reference to this image.
1376 	 */
1377 	public abstract I inverse();
1378 
1379 	/**
1380 	 * Find the maximum pixel value.
1381 	 *
1382 	 * @return The maximum pixel value
1383 	 */
1384 	public abstract Q max();
1385 
1386 	/**
1387 	 * Find the minimum pixel value.
1388 	 *
1389 	 * @return The minimum pixel value
1390 	 */
1391 	public abstract Q min();
1392 
1393 	/**
1394 	 * Multiply the pixel values in this image with the corresponding pixel
1395 	 * values in the given image. This method returns a new image.
1396 	 *
1397 	 * @param im
1398 	 *            The image to multiply with this one
1399 	 * @return A new image containing the result.
1400 	 */
1401 	public I multiply(Image<?, ?> im) {
1402 		final I newImage = this.clone();
1403 		newImage.multiplyInplace(im);
1404 		return newImage;
1405 	}
1406 
1407 	/**
1408 	 * Multiply each pixel of this by the given scalar and return new image.
1409 	 *
1410 	 * @param num
1411 	 *            The scalar which to multiply the image by
1412 	 * @return A new image containing the result
1413 	 */
1414 	public I multiply(Q num) {
1415 		final I newImage = this.clone();
1416 		newImage.multiplyInplace(num);
1417 		return newImage;
1418 	}
1419 
1420 	/**
1421 	 * Multiply each pixel in this image by the corresponding pixel in the given
1422 	 * image. This method side-affects this image.
1423 	 *
1424 	 * @param im
1425 	 *            The image to multiply with this image.
1426 	 * @return A reference to this image.
1427 	 */
1428 	public abstract I multiplyInplace(Image<?, ?> im);
1429 
1430 	/**
1431 	 * Multiply each pixel of this by the given scalar. This method side-affects
1432 	 * this image.
1433 	 *
1434 	 * @param num
1435 	 *            The scalar to multiply this image by.
1436 	 * @return A reference to this image.
1437 	 */
1438 	public abstract I multiplyInplace(Q num);
1439 
1440 	/**
1441 	 * Create a new instance of this image subclass with given dimensions.
1442 	 *
1443 	 * @param width
1444 	 *            The image width
1445 	 * @param height
1446 	 *            The image height
1447 	 *
1448 	 * @return A new instance of an image of type <code>I</code>
1449 	 */
1450 	public abstract I newInstance(int width, int height);
1451 
1452 	/**
1453 	 * Normalise all pixel values to fall within the range 0.0 - 1.0. This
1454 	 * should be scaled by both the maximum and minimum values. This method
1455 	 * side-affects this image.
1456 	 *
1457 	 * @return A reference to this image.
1458 	 */
1459 	public abstract I normalise();
1460 
1461 	/**
1462 	 * Adds padding as in {@link Image#padding(int, int, Object)}. The padding
1463 	 * colour is the colour of the closest border pixel.
1464 	 *
1465 	 * @param paddingWidth
1466 	 *            padding in the x direction
1467 	 * @param paddingHeight
1468 	 *            padding in the y direction
1469 	 * @return padded image
1470 	 */
1471 	public I padding(int paddingWidth, int paddingHeight) {
1472 		return this.padding(paddingWidth, paddingHeight, null);
1473 	}
1474 
1475 	/**
1476 	 * Adds this many pixels to both sides of the image such that the new image
1477 	 * width = padding + width + padding with the original image in the middle
1478 	 *
1479 	 * @param paddingWidth
1480 	 *            left and right padding width
1481 	 * @param paddingHeight
1482 	 *            top and bottom padding width
1483 	 * @param paddingColour
1484 	 *            colour of padding, if null the closes border pixel is used
1485 	 * @return padded image
1486 	 */
1487 	@SuppressWarnings("unchecked")
1488 	public I padding(int paddingWidth, int paddingHeight, Q paddingColour) {
1489 		final I out = this.newInstance(paddingWidth + this.getWidth() + paddingWidth, paddingHeight + this.getHeight()
1490 				+ paddingHeight);
1491 
1492 		out.createRenderer().drawImage((I) this, paddingWidth, paddingHeight);
1493 		final int rightLimit = paddingWidth + this.getWidth();
1494 		final int bottomLimit = paddingHeight + this.getHeight();
1495 		// Fill the padding with a colour if it isn't null
1496 		if (paddingColour != null)
1497 			for (int y = 0; y < out.getHeight(); y++) {
1498 				for (int x = 0; x < out.getWidth(); x++) {
1499 					if (x >= paddingWidth && x < rightLimit && y >= paddingHeight && y < bottomLimit)
1500 						continue;
1501 					out.setPixel(x, y, paddingColour);
1502 				}
1503 			}
1504 		else
1505 			for (int y = 0; y < out.getHeight(); y++) {
1506 				for (int x = 0; x < out.getWidth(); x++) {
1507 					if (x >= paddingWidth && x < rightLimit && y >= paddingHeight && y < bottomLimit)
1508 						continue;
1509 					if (x < paddingWidth && y < paddingHeight)
1510 						out.setPixel(x, y, this.getPixel(0, 0)); // Top Left
1511 					else if (x < paddingWidth && y >= bottomLimit)
1512 						out.setPixel(x, y, this.getPixel(0, this.getHeight() - 1)); // Bottom
1513 					// Left
1514 					else if (x >= rightLimit && y < paddingHeight)
1515 						out.setPixel(x, y, this.getPixel(this.getWidth() - 1, 0)); // Top
1516 					// Right
1517 					else if (x >= rightLimit && y >= bottomLimit)
1518 						out.setPixel(x, y, this.getPixel(this.getWidth() - 1, this.getHeight() - 1)); // Bottom
1519 					// Right
1520 					else {
1521 						if (x < paddingWidth)
1522 							out.setPixel(x, y, this.getPixel(0, y - paddingHeight)); // Left
1523 						else if (x >= rightLimit)
1524 							out.setPixel(x, y, this.getPixel(this.getWidth() - 1, y - paddingHeight)); // Right
1525 						else if (y < paddingHeight)
1526 							out.setPixel(x, y, this.getPixel(x - paddingWidth, 0)); // Top
1527 						else if (y >= bottomLimit)
1528 							out.setPixel(x, y, this.getPixel(x - paddingWidth, this.getHeight() - 1)); // Bottom
1529 					}
1530 				}
1531 			}
1532 
1533 		return out;
1534 	}
1535 
1536 	/**
1537 	 * Adds pixels to around the image such that the new image width =
1538 	 * paddingLeft + width + paddingRight with the original image in the middle.
1539 	 * The values of the padding pixels are formed from repeated symmetric
1540 	 * reflections of the original image.
1541 	 *
1542 	 * @param paddingLeft
1543 	 *            left padding width
1544 	 * @param paddingRight
1545 	 *            right padding width
1546 	 * @param paddingTop
1547 	 *            top padding width
1548 	 * @param paddingBottom
1549 	 *            bottom padding width
1550 	 * @return padded image
1551 	 */
1552 	public I paddingSymmetric(int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) {
1553 		final I out = this.newInstance(paddingLeft + this.getWidth() + paddingRight, paddingTop + this.getHeight()
1554 				+ paddingBottom);
1555 		final I clone = this.clone();
1556 		final I hflip = clone.clone().flipX();
1557 
1558 		final ImageRenderer<Q, I> rend = out.createRenderer();
1559 		rend.drawImage(clone, paddingLeft, paddingTop);
1560 
1561 		// left
1562 		for (int i = paddingLeft - this.getWidth(), c = 0; i > -this.getWidth(); i -= this.getWidth(), c++) {
1563 			if (c % 2 == 0) {
1564 				rend.drawImage(hflip, i, paddingTop);
1565 			} else {
1566 				rend.drawImage(clone, i, paddingTop);
1567 			}
1568 		}
1569 
1570 		// right
1571 		for (int i = paddingLeft + this.getWidth(), c = 0; i < paddingLeft + paddingRight + this.getWidth(); i += this
1572 				.getWidth(), c++)
1573 		{
1574 			if (c % 2 == 0) {
1575 				rend.drawImage(hflip, i, paddingTop);
1576 			} else {
1577 				rend.drawImage(clone, i, paddingTop);
1578 			}
1579 		}
1580 
1581 		final I centre = out.extractROI(0, paddingTop, paddingLeft + this.getWidth() + paddingRight, this.getHeight());
1582 		final I yflip = centre.clone().flipY();
1583 
1584 		// up
1585 		for (int i = paddingTop - this.getHeight(), c = 0; i > -this.getHeight(); i -= this.getHeight(), c++) {
1586 			if (c % 2 == 0) {
1587 				rend.drawImage(yflip, 0, i);
1588 			} else {
1589 				rend.drawImage(centre, 0, i);
1590 			}
1591 		}
1592 
1593 		// down
1594 		for (int i = paddingTop + this.getHeight(), c = 0; i < paddingTop + paddingBottom + this.getHeight(); i += this
1595 				.getHeight(), c++)
1596 		{
1597 			if (c % 2 == 0) {
1598 				rend.drawImage(yflip, 0, i);
1599 			} else {
1600 				rend.drawImage(centre, 0, i);
1601 			}
1602 		}
1603 
1604 		return out;
1605 	}
1606 
1607 	/**
1608 	 * Process this image with the given {@link GridProcessor} and return new
1609 	 * image containing the result.
1610 	 *
1611 	 * @param p
1612 	 *            {@link GridProcessor} to apply to this image.
1613 	 * @return A new image containing the result.
1614 	 */
1615 	public I process(GridProcessor<Q, I> p) {
1616 		final int height = p.getVerticalGridElements();
1617 		final int width = p.getHorizontalGridElements();
1618 		final I newImage = this.newInstance(width, height);
1619 		newImage.zero();
1620 
1621 		final int gridWidth = getWidth() / width;
1622 		final int gridHeight = getHeight() / height;
1623 		for (int y = 0; y < height; y++)
1624 			for (int x = 0; x < width; x++)
1625 				newImage.setPixel(x, y,
1626 						p.processGridElement(this.extractROI(gridWidth * x, gridHeight * y, gridWidth, gridHeight)));
1627 
1628 		return newImage;
1629 	}
1630 
1631 	/**
1632 	 * Process this image with an {@link ImageProcessor} and return new image
1633 	 * containing the result.
1634 	 *
1635 	 * @param p
1636 	 *            The {@link ImageProcessor} to apply to this image.
1637 	 * @return A new image containing the result.
1638 	 */
1639 	public I process(ImageProcessor<I> p) {
1640 		final I newImage = this.clone();
1641 		newImage.processInplace(p);
1642 		return newImage;
1643 	}
1644 
1645 	/**
1646 	 * Process this image with the given {@link KernelProcessor} and return new
1647 	 * image containing the result.
1648 	 *
1649 	 * @param p
1650 	 *            The {@link KernelProcessor} to apply.
1651 	 * @return A new image containing the result.
1652 	 */
1653 	public I process(KernelProcessor<Q, I> p) {
1654 		return process(p, false);
1655 	}
1656 
1657 	/**
1658 	 * Process this image with the given {@link KernelProcessor} and return new
1659 	 * image containing the result.
1660 	 *
1661 	 * @param p
1662 	 *            The {@link KernelProcessor} to apply.
1663 	 * @param pad
1664 	 *            Should the image be zero padded so the kernel reaches the
1665 	 *            edges of the output
1666 	 * @return A new image containing the result.
1667 	 */
1668 	public I process(KernelProcessor<Q, I> p, boolean pad) {
1669 		final I newImage = this.clone();
1670 		newImage.zero();
1671 
1672 		final int kh = p.getKernelHeight();
1673 		final int kw = p.getKernelWidth();
1674 
1675 		final int hh = p.getKernelHeight() / 2;
1676 		final int hw = p.getKernelWidth() / 2;
1677 
1678 		final I tmp = newInstance(kw, kh);
1679 
1680 		if (!pad) {
1681 			for (int y = hh; y < getHeight() - (kh - hh); y++) {
1682 				for (int x = hw; x < getWidth() - (kw - hw); x++) {
1683 					newImage.setPixel(x, y, p.processKernel(this.extractROI(x - hw, y - hh, tmp)));
1684 				}
1685 			}
1686 		} else {
1687 			for (int y = 0; y < getHeight(); y++) {
1688 				for (int x = 0; x < getWidth(); x++) {
1689 					newImage.setPixel(x, y, p.processKernel(this.extractROI(x - hw, y - hh, tmp)));
1690 				}
1691 			}
1692 		}
1693 
1694 		return newImage;
1695 	}
1696 
1697 	/**
1698 	 * Process this image with the given {@link PixelProcessor} and return a new
1699 	 * image containing the result.
1700 	 *
1701 	 * @param p
1702 	 *            The {@link PixelProcessor} to apply.
1703 	 * @return A new image containing the result.
1704 	 */
1705 	public I process(PixelProcessor<Q> p) {
1706 		final I newImage = this.clone();
1707 		newImage.processInplace(p);
1708 		return newImage;
1709 	}
1710 
1711 	/**
1712 	 * Process this image with an {@link Processor} and return new image
1713 	 * containing the result.
1714 	 *
1715 	 * @param p
1716 	 *            The {@link Processor} to apply to this image.
1717 	 * @return A new image containing the result.
1718 	 */
1719 	public I process(Processor<I> p) {
1720 		final I newImage = this.clone();
1721 		newImage.processInplace(p);
1722 		return newImage;
1723 	}
1724 
1725 	/**
1726 	 * Process this image with the given {@link Processor} side-affecting this
1727 	 * image.
1728 	 *
1729 	 * @param p
1730 	 *            The {@link Processor} to apply.
1731 	 * @return A reference to this image containing the result.
1732 	 */
1733 	@SuppressWarnings("unchecked")
1734 	public I processInplace(Processor<I> p) {
1735 		if (p == null)
1736 			return (I) this;
1737 		if (p instanceof ImageProcessor)
1738 			return processInplace((ImageProcessor<I>) p);
1739 		if (p instanceof KernelProcessor)
1740 			return processInplace((KernelProcessor<Q, I>) p);
1741 		if (p instanceof PixelProcessor)
1742 			return processInplace((PixelProcessor<Q>) p);
1743 
1744 		throw new UnsupportedOperationException("Unsupported Processor type");
1745 	}
1746 
1747 	/**
1748 	 * Process this image with the given {@link ImageProcessor} side-affecting
1749 	 * this image.
1750 	 *
1751 	 * @param p
1752 	 *            The {@link ImageProcessor} to apply.
1753 	 * @return A reference to this image containing the result.
1754 	 */
1755 	@SuppressWarnings("unchecked")
1756 	public I processInplace(ImageProcessor<I> p) {
1757 		p.processImage((I) this);
1758 		return (I) this;
1759 	}
1760 
1761 	/**
1762 	 * Process this image with the given {@link KernelProcessor} side-affecting
1763 	 * this image.
1764 	 *
1765 	 * @param p
1766 	 *            The {@link KernelProcessor} to apply.
1767 	 * @return A reference to this image containing the result.
1768 	 */
1769 	public I processInplace(KernelProcessor<Q, I> p) {
1770 		return processInplace(p, false);
1771 	}
1772 
1773 	/**
1774 	 * Process this image with the given {@link KernelProcessor} side-affecting
1775 	 * this image.
1776 	 *
1777 	 * @param p
1778 	 *            The {@link KernelProcessor} to apply.
1779 	 * @param pad
1780 	 *            Should the image be zero padded so the kernel reaches the
1781 	 *            edges of the output
1782 	 * @return A reference to this image containing the result.
1783 	 */
1784 	@SuppressWarnings("unchecked")
1785 	public I processInplace(KernelProcessor<Q, I> p, boolean pad) {
1786 		final I newImage = process(p, pad);
1787 		this.internalAssign(newImage);
1788 		return (I) this;
1789 	}
1790 
1791 	/**
1792 	 * Process this image with the given {@link PixelProcessor} side-affecting
1793 	 * this image.
1794 	 *
1795 	 * @param p
1796 	 *            The {@link PixelProcessor} to apply.
1797 	 * @return A reference to this image containing the result.
1798 	 */
1799 	@SuppressWarnings("unchecked")
1800 	public I processInplace(PixelProcessor<Q> p) {
1801 		for (int y = 0; y < getHeight(); y++) {
1802 			for (int x = 0; x < getWidth(); x++) {
1803 				setPixel(x, y, p.processPixel(getPixel(x, y)));
1804 			}
1805 		}
1806 
1807 		return (I) this;
1808 	}
1809 
1810 	/**
1811 	 * Process this image with the given {@link PixelProcessor} only affecting
1812 	 * those pixels where the mask is non-zero. Returns a new image.
1813 	 *
1814 	 * @param mask
1815 	 *            The mask to apply to the processing.
1816 	 * @param p
1817 	 *            The {@link PixelProcessor} to apply.
1818 	 * @return A new image containing the result.
1819 	 */
1820 	public I processMasked(FImage mask, PixelProcessor<Q> p) {
1821 		final I newImage = this.clone();
1822 		newImage.processMaskedInplace(mask, p);
1823 		return newImage;
1824 	}
1825 
1826 	/**
1827 	 * Process this image with the given {@link PixelProcessor}, only affecting
1828 	 * those pixels where the mask is non-zero. Side-affects this image.
1829 	 *
1830 	 * @param mask
1831 	 *            The mask to apply to the processor.
1832 	 * @param p
1833 	 *            The {@link PixelProcessor} to apply.
1834 	 * @return A reference to this image containing the result.
1835 	 */
1836 	@SuppressWarnings("unchecked")
1837 	public I processMaskedInplace(FImage mask, PixelProcessor<Q> p) {
1838 		for (int y = 0; y < getHeight(); y++) {
1839 			for (int x = 0; x < getWidth(); x++) {
1840 				if (mask.pixels[y][x] == 0)
1841 					continue;
1842 				setPixel(x, y, p.processPixel(getPixel(x, y)));
1843 			}
1844 		}
1845 		return (I) this;
1846 	}
1847 
1848 	/**
1849 	 * Sets the pixel at <code>(x,y)</code> to the given value. Side-affects
1850 	 * this image.
1851 	 *
1852 	 * @param x
1853 	 *            The x-ordinate of the pixel to set
1854 	 * @param y
1855 	 *            The y-ordinate of the pixel to set
1856 	 * @param val
1857 	 *            The value to set the pixel to.
1858 	 */
1859 	public abstract void setPixel(int x, int y, Q val);
1860 
1861 	/**
1862 	 * Subtract the corresponding pixel value from the given image from the
1863 	 * pixel values in this image. Returns a new image.
1864 	 *
1865 	 * @param im
1866 	 *            The image to subtract from this image.
1867 	 * @return A new image containing the result.
1868 	 */
1869 	public I subtract(Image<?, ?> im) {
1870 		final I newImage = this.clone();
1871 		newImage.subtractInplace(im);
1872 		return newImage;
1873 	}
1874 
1875 	/**
1876 	 * Subtract a scalar from every pixel value in this image and return new
1877 	 * image.
1878 	 *
1879 	 * @param num
1880 	 *            A value to subtract from each pixel.
1881 	 * @return A new image containing the result.
1882 	 */
1883 	public I subtract(Q num) {
1884 		final I newImage = this.clone();
1885 		newImage.subtractInplace(num);
1886 		return newImage;
1887 	}
1888 
1889 	/**
1890 	 * Subtract the corresponding pixel value from the given image from the
1891 	 * pixel values in this image. Side-affects this image.
1892 	 *
1893 	 * @param im
1894 	 *            The image to subtract from this image.
1895 	 * @return A reference to this containing the result.
1896 	 */
1897 	public abstract I subtractInplace(Image<?, ?> im);
1898 
1899 	/**
1900 	 * Subtract a scalar from every pixel value in this image. Side-affects this
1901 	 * image.
1902 	 *
1903 	 * @param num
1904 	 *            A value to subtract from each pixel.
1905 	 * @return A reference to this image containing the result.
1906 	 */
1907 	public abstract I subtractInplace(Q num);
1908 
1909 	/**
1910 	 * Set all values less than the given threshold to 0 and all others to 1.
1911 	 * Side-affects this image.
1912 	 *
1913 	 * @param thresh
1914 	 *            The threshold value
1915 	 * @return A reference to this image containing the result.
1916 	 */
1917 	public abstract I threshold(Q thresh);
1918 
1919 	/**
1920 	 * Convert the image to a byte representation suitable for writing to a pnm
1921 	 * type format. Each byte should represent a single pixel. Multiband images
1922 	 * should interleave the data; e.g. [R1,G1,B1,R2,G2,B2...etc.]
1923 	 *
1924 	 * @return This image as a byte array
1925 	 */
1926 	public abstract byte[] toByteImage();
1927 
1928 	/**
1929 	 * Returns a 1D array representation of this image with each pixel
1930 	 * represented as a packed ARGB integer.
1931 	 *
1932 	 * @return An array of ARGB pixels.
1933 	 */
1934 	public abstract int[] toPackedARGBPixels();
1935 
1936 	/**
1937 	 * Apply a transform matrix to the image and returns the result as a new
1938 	 * image.
1939 	 *
1940 	 * @param transform
1941 	 *            The transform matrix to apply.
1942 	 * @return A new image containing the result.
1943 	 */
1944 	public I transform(Matrix transform) {
1945 		boolean unset = true;
1946 		double minX = 0, minY = 0, maxX = 0, maxY = 0;
1947 		final double[][][] extrema = new double[][][] {
1948 				{ { 0 }, { 0 }, { 1 } },
1949 				{ { 0 }, { this.getHeight() }, { 1 } },
1950 				{ { this.getWidth() }, { 0 }, { 1 } },
1951 				{ { this.getWidth() }, { this.getHeight() }, { 1 } },
1952 		};
1953 		for (final double[][] ext : extrema) {
1954 			final Matrix tmp = transform.times(Matrix.constructWithCopy(ext));
1955 			if (unset) {
1956 				minX = maxX = tmp.get(0, 0);
1957 				maxY = minY = tmp.get(1, 0);
1958 				unset = false;
1959 			} else {
1960 				if (tmp.get(0, 0) > maxX)
1961 					maxX = tmp.get(0, 0);
1962 				if (tmp.get(1, 0) > maxY)
1963 					maxY = tmp.get(1, 0);
1964 				if (tmp.get(0, 0) < minX)
1965 					minX = tmp.get(0, 0);
1966 				if (tmp.get(1, 0) < minY)
1967 					minY = tmp.get(1, 0);
1968 			}
1969 		}
1970 		final I output = this.newInstance((int) (Math.abs(maxX - minX)), (int) (Math.abs(maxY - minY)));
1971 		final Matrix invTrans = transform.inverse();
1972 		final double[][] invTransData = invTrans.getArray();
1973 
1974 		for (int x = 0; x < output.getWidth(); x++) {
1975 			for (int y = 0; y < output.getHeight(); y++) {
1976 				double oldx = invTransData[0][0] * x + invTransData[0][1] * y + invTransData[0][2];
1977 				double oldy = invTransData[1][0] * x + invTransData[1][1] * y + invTransData[1][2];
1978 				final double norm = invTransData[2][0] * x + invTransData[2][1] * y + invTransData[2][2];
1979 
1980 				oldx /= norm;
1981 				oldy /= norm;
1982 
1983 				if (oldx < 0 || oldx >= this.getWidth() || oldy < 0 || oldy >= this.getHeight())
1984 					continue;
1985 
1986 				output.setPixel(x, y, this.getPixelInterp(oldx, oldy));
1987 			}
1988 		}
1989 		return output;
1990 	}
1991 
1992 	/**
1993 	 * Removes zero-valued pixels from around the outside of the image.
1994 	 * Analagous to {@link String#trim()}.
1995 	 *
1996 	 * @return A new image containing the trimmed image.
1997 	 */
1998 	public I trim() {
1999 		final Rectangle rect = this.getContentArea();
2000 		return this.extractROI((int) rect.minX(), (int) rect.minY(), (int) (rect.getWidth()), (int) (rect.getHeight()));
2001 	}
2002 
2003 	/**
2004 	 * Set all pixels in the image to zero. Side-affects this image.
2005 	 *
2006 	 * @return A reference to this image containing the result.
2007 	 */
2008 	public abstract I zero();
2009 
2010 	/**
2011 	 * Shifts all the pixels to the left by one pixel
2012 	 *
2013 	 * @return A reference to this image.
2014 	 */
2015 	public I shiftLeftInplace() {
2016 		return shiftLeftInplace(1);
2017 	}
2018 
2019 	/**
2020 	 * Shifts all the pixels to the right by one pixel
2021 	 *
2022 	 * @return A reference to this image.
2023 	 */
2024 	public I shiftRightInplace() {
2025 		return shiftRightInplace(1);
2026 	}
2027 
2028 	/**
2029 	 * Shifts all the pixels to the left by count pixel
2030 	 *
2031 	 * @param count
2032 	 *            The number of pixels
2033 	 *
2034 	 * @return A reference to this image.
2035 	 */
2036 	public I shiftLeftInplace(int count) {
2037 		return this.internalAssign(this.shiftLeft(count));
2038 	}
2039 
2040 	/**
2041 	 * Shifts all the pixels to the right by count pixel
2042 	 *
2043 	 * @param count
2044 	 *            The number of pixels
2045 	 *
2046 	 * @return A reference to this image.
2047 	 */
2048 	public I shiftRightInplace(int count) {
2049 		return this.internalAssign(this.shiftRight(count));
2050 	}
2051 
2052 	/**
2053 	 * Returns a new image that is it shifted around the x-ordinates by one
2054 	 * pixel
2055 	 *
2056 	 * @return A new image shifted around to the left by one pixel
2057 	 */
2058 	public I shiftLeft() {
2059 		return shiftLeft(1);
2060 	}
2061 
2062 	/**
2063 	 * Returns a new image that is it shifted around the x-ordinates by the
2064 	 * number of pixels given.
2065 	 *
2066 	 * @param nPixels
2067 	 *            The number of pixels
2068 	 *
2069 	 * @return A new image shifted around to the left by the number of pixels
2070 	 */
2071 	public I shiftLeft(int nPixels) {
2072 		final I output = this.newInstance(getWidth(), getHeight());
2073 		final I img = this.extractROI(0, 0, nPixels, getHeight());
2074 		output.createRenderer().drawImage(
2075 				this.extractROI(nPixels, 0, getWidth() - nPixels, getHeight()), 0, 0);
2076 		output.createRenderer().drawImage(img, getWidth() - nPixels, 0);
2077 		return output;
2078 	}
2079 
2080 	/**
2081 	 * Returns a new image that is it shifted around the x-ordinates by one
2082 	 * pixel
2083 	 *
2084 	 * @return A new image shifted around to the right by one pixel
2085 	 */
2086 	public I shiftRight() {
2087 		return shiftRight(1);
2088 	}
2089 
2090 	/**
2091 	 * Returns a new image that is it shifted around the x-ordinates by the
2092 	 * number of pixels given.
2093 	 *
2094 	 * @param nPixels
2095 	 *            the number of pixels
2096 	 *
2097 	 * @return A new image shifted around to the right by the number of pixels
2098 	 */
2099 	public I shiftRight(int nPixels) {
2100 		final I output = this.newInstance(getWidth(), getHeight());
2101 		final I img = this.extractROI(getWidth() - nPixels, 0, nPixels, getHeight());
2102 		output.createRenderer().drawImage(
2103 				this.extractROI(0, 0, getWidth() - nPixels, getHeight()), nPixels, 0);
2104 		output.createRenderer().drawImage(img, 0, 0);
2105 		return output;
2106 	}
2107 
2108 	/**
2109 	 * Shifts all the pixels up by one pixel
2110 	 *
2111 	 * @return A reference to this image.
2112 	 */
2113 	public I shiftUpInplace() {
2114 		return shiftUpInplace(1);
2115 	}
2116 
2117 	/**
2118 	 * Shifts all the pixels down by one pixels
2119 	 *
2120 	 * @return A reference to this image.
2121 	 */
2122 	public I shiftDownInplace() {
2123 		return shiftDownInplace(1);
2124 	}
2125 
2126 	/**
2127 	 * Shifts all the pixels up by count pixels
2128 	 *
2129 	 * @param count
2130 	 *            The number of pixels
2131 	 *
2132 	 * @return A reference to this image.
2133 	 */
2134 	public I shiftUpInplace(int count) {
2135 		return this.internalAssign(this.shiftUp(count));
2136 	}
2137 
2138 	/**
2139 	 * Shifts all the pixels down by count pixels
2140 	 *
2141 	 * @param count
2142 	 *            The number of pixels
2143 	 *
2144 	 * @return A reference to this image.
2145 	 */
2146 	public I shiftDownInplace(int count) {
2147 		return this.internalAssign(this.shiftDown(count));
2148 	}
2149 
2150 	/**
2151 	 * Returns a new image that is it shifted around the x-ordinates by one
2152 	 * pixel
2153 	 *
2154 	 * @return A new image shifted around up by one pixel
2155 	 */
2156 	public I shiftUp() {
2157 		return shiftUp(1);
2158 	}
2159 
2160 	/**
2161 	 * Returns a new image that is it shifted around the x-ordinates by the
2162 	 * number of pixels given.
2163 	 *
2164 	 * @param nPixels
2165 	 *            The number of pixels
2166 	 *
2167 	 * @return A new image shifted around up by the number of pixels
2168 	 */
2169 	public I shiftUp(int nPixels) {
2170 		final I output = this.newInstance(getWidth(), getHeight());
2171 		final I img = this.extractROI(0, 0, getWidth(), nPixels);
2172 		output.createRenderer().drawImage(
2173 				this.extractROI(0, nPixels, getWidth(), getHeight() - nPixels), 0, 0);
2174 		output.createRenderer().drawImage(img, 0, getHeight() - nPixels);
2175 		return output;
2176 	}
2177 
2178 	/**
2179 	 * Returns a new image that is it shifted around the x-ordinates by one
2180 	 * pixel
2181 	 *
2182 	 * @return A new image shifted around down by one pixel
2183 	 */
2184 	public I shiftDown() {
2185 		return shiftDown(1);
2186 	}
2187 
2188 	/**
2189 	 * Returns a new image that is it shifted around the x-ordinates by the
2190 	 * number of pixels given.
2191 	 *
2192 	 * @param nPixels
2193 	 *            the number of pixels
2194 	 *
2195 	 * @return A new image shifted around down by the number of pixels
2196 	 */
2197 	public I shiftDown(int nPixels) {
2198 		final I output = this.newInstance(getWidth(), getHeight());
2199 		final I img = this.extractROI(0, getHeight() - nPixels, getWidth(), nPixels);
2200 		output.createRenderer().drawImage(
2201 				this.extractROI(0, 0, getWidth(), getHeight() - nPixels), 0, nPixels);
2202 		output.createRenderer().drawImage(img, 0, 0);
2203 		return output;
2204 	}
2205 
2206 	/**
2207 	 * Overlays the given image on this image and returns a new image containing
2208 	 * the result.
2209 	 *
2210 	 * @param image
2211 	 *            The image to overlay on this image.
2212 	 * @param x
2213 	 *            The location at which to overlay the image
2214 	 * @param y
2215 	 *            The location at which to overlay the image
2216 	 * @return A new image containing the result
2217 	 */
2218 	public I overlay(I image, int x, int y) {
2219 		final I img = this.clone();
2220 		img.overlayInplace(image, x, y);
2221 		return img;
2222 	}
2223 
2224 	/**
2225 	 * Overlays the given image on this image directly. The method returns this
2226 	 * image for chaining.
2227 	 *
2228 	 * @param image
2229 	 *            The image to overlay
2230 	 * @param x
2231 	 *            The location at which to overlay the image
2232 	 * @param y
2233 	 *            The location at which to overlay the image
2234 	 * @return Returns this image
2235 	 */
2236 	public abstract I overlayInplace(I image, int x, int y);
2237 
2238 	@SuppressWarnings("unchecked")
2239 	@Override
2240 	public I getImage() {
2241 		return (I) this;
2242 	}
2243 
2244 	/**
2245 	 * Replace pixels of a certain colour with another colour. Side-affects this
2246 	 * image.
2247 	 *
2248 	 * @param target
2249 	 *            the colour to fill the image with
2250 	 * @param replacement
2251 	 *            the colour to fill the image with
2252 	 * @return A reference to this image.
2253 	 */
2254 	public abstract I replace(Q target, Q replacement);
2255 
2256 	/**
2257 	 * Sub-pixel sampling of a centred rectangular region such that
2258 	 * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2259 	 * . Sub-pixels values are estimated using bilinear interpolation.
2260 	 *
2261 	 * @see #getPixelInterp(double, double)
2262 	 *
2263 	 * @param centre
2264 	 *            the centre
2265 	 * @param width
2266 	 *            the region width
2267 	 * @param height
2268 	 *            the region height
2269 	 * @return the extracted sub-pixel region
2270 	 */
2271 	public I extractCentreSubPix(Point2d centre, int width, int height) {
2272 		return extractCentreSubPix(centre.getX(), centre.getY(), width, height);
2273 	}
2274 
2275 	/**
2276 	 * Sub-pixel sampling of a centred rectangular region such that
2277 	 * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2278 	 * . Sub-pixels values are estimated using bilinear interpolation.
2279 	 *
2280 	 * @see #getPixelInterp(double, double)
2281 	 * @param cx
2282 	 *            the x-ordinate of the centre
2283 	 * @param cy
2284 	 *            the y-ordinate of the centre
2285 	 * @param width
2286 	 *            the region width
2287 	 * @param height
2288 	 *            the region height
2289 	 * @return the extracted sub-pixel region
2290 	 */
2291 	public I extractCentreSubPix(float cx, float cy, int width, int height) {
2292 		final I out = newInstance(width, height);
2293 		return extractCentreSubPix(cx, cy, out);
2294 	}
2295 
2296 	/**
2297 	 * Sub-pixel sampling of a centred rectangular region such that
2298 	 * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2299 	 * . Sub-pixels values are estimated using bilinear interpolation.
2300 	 *
2301 	 * @see #getPixelInterp(double, double)
2302 	 *
2303 	 * @param centre
2304 	 *            the centre
2305 	 * @param out
2306 	 *            the output image (also defines the size of the extracted
2307 	 *            region)
2308 	 * @return <code>out</code>
2309 	 */
2310 	public I extractCentreSubPix(Point2d centre, I out) {
2311 		return extractCentreSubPix(centre.getX(), centre.getY(), out);
2312 	}
2313 
2314 	/**
2315 	 * Sub-pixel sampling of a centred rectangular region such that
2316 	 * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2317 	 * . Sub-pixels values are estimated using bilinear interpolation.
2318 	 *
2319 	 * @see #getPixelInterp(double, double)
2320 	 * @param cx
2321 	 *            the x-ordinate of the centre
2322 	 * @param cy
2323 	 *            the y-ordinate of the centre
2324 	 * @param out
2325 	 *            the output image (also defines the size of the extracted
2326 	 *            region)
2327 	 * @return <code>out</code>
2328 	 */
2329 	public abstract I extractCentreSubPix(float cx, float cy, I out);
2330 }