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;
031
032import java.io.Serializable;
033import java.text.AttributedString;
034import java.util.Comparator;
035import java.util.List;
036
037import org.openimaj.image.analyser.ImageAnalyser;
038import org.openimaj.image.analyser.PixelAnalyser;
039import org.openimaj.image.combiner.AccumulatingImageCombiner;
040import org.openimaj.image.combiner.ImageCombiner;
041import org.openimaj.image.pixel.Pixel;
042import org.openimaj.image.processor.GridProcessor;
043import org.openimaj.image.processor.ImageProcessor;
044import org.openimaj.image.processor.KernelProcessor;
045import org.openimaj.image.processor.PixelProcessor;
046import org.openimaj.image.processor.Processor;
047import org.openimaj.image.renderer.ImageRenderer;
048import org.openimaj.image.renderer.RenderHints;
049import org.openimaj.image.typography.Font;
050import org.openimaj.image.typography.FontStyle;
051import org.openimaj.math.geometry.line.Line2d;
052import org.openimaj.math.geometry.point.Point2d;
053import org.openimaj.math.geometry.shape.Polygon;
054import org.openimaj.math.geometry.shape.Rectangle;
055import org.openimaj.math.geometry.shape.Shape;
056
057import Jama.Matrix;
058
059/**
060 * Base class for representing and manipulating images. Images are typed by the
061 * type of pixel at each coordinate and the concrete subclass type.
062 * 
063 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
064 * 
065 * @param <Q>
066 *            the pixel type
067 * @param <I>
068 *            the actual image of the concrete subclass
069 */
070public abstract class Image<Q, I extends Image<Q, I>> implements Cloneable, Serializable, ImageProvider<I> {
071        /**
072         * Enumerator for representing the type of field interlacing operations.
073         * 
074         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
075         */
076        public enum Field {
077                /**
078                 * Odd field
079                 */
080                ODD,
081                /**
082                 * Even field
083                 */
084                EVEN
085        }
086
087        private static final long serialVersionUID = 1L;
088
089        /**
090         * Accumulate this image the the given {@link AccumulatingImageCombiner}.
091         * 
092         * @param combiner
093         *            the combiner
094         * @see AccumulatingImageCombiner#accumulate(Image)
095         */
096        @SuppressWarnings("unchecked")
097        public void accumulateWith(AccumulatingImageCombiner<I, ?> combiner) {
098                combiner.accumulate((I) this);
099        }
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, 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 Line2d 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(Line2d line, int thickness, Q col) {
646                createRenderer().drawLine(line, thickness, col);
647        }
648
649        /**
650         * Draw the given list of lines using {@link #drawLine(Line2d, int, Object)}
651         * with the given colour and thickness. Side-affects this image.
652         * 
653         * <p>
654         * This is a convenience method that calls {@link #createRenderer()} to get
655         * the default renderer to do the actual drawing. Create the renderer
656         * yourself and use it to draw if you need more control.
657         * </p>
658         * 
659         * @param lines
660         *            The list of lines to draw.
661         * @param thickness
662         *            the stroke width
663         * @param col
664         *            The colour to draw each point.
665         */
666        public void drawLines(Iterable<? extends Line2d> lines, int thickness, Q col) {
667                createRenderer().drawLines(lines, thickness, col);
668        }
669
670        /**
671         * Draw a dot centered on the given location (rounded to nearest integer
672         * location) at the given size and with the given color. Side-affects this
673         * image.
674         * 
675         * <p>
676         * This is a convenience method that calls {@link #createRenderer()} to get
677         * the default renderer to do the actual drawing. Create the renderer
678         * yourself and use it to draw if you need more control.
679         * </p>
680         * 
681         * @param p
682         *            The coordinates at which to draw the point
683         * @param col
684         *            The colour to draw the point
685         * @param size
686         *            The size at which to draw the point.
687         */
688        public void drawPoint(Point2d p, Q col, int size) {
689                createRenderer().drawPoint(p, col, size);
690        }
691
692        /**
693         * Draw the given list of points using
694         * {@link #drawPoint(Point2d, Object, int)} with the given colour and size.
695         * Side-affects this image.
696         * 
697         * <p>
698         * This is a convenience method that calls {@link #createRenderer()} to get
699         * the default renderer to do the actual drawing. Create the renderer
700         * yourself and use it to draw if you need more control.
701         * </p>
702         * 
703         * @param pts
704         *            The list of points to draw.
705         * @param col
706         *            The colour to draw each point.
707         * @param size
708         *            The size to draw each point.
709         */
710        public void drawPoints(Iterable<? extends Point2d> pts, Q col, int size) {
711                createRenderer().drawPoints(pts, col, size);
712        }
713
714        /**
715         * Draw the given polygon in the specified colour with the given thickness
716         * lines. Side-affects this image.
717         * 
718         * <p>
719         * This is a convenience method that calls {@link #createRenderer()} to get
720         * the default renderer to do the actual drawing. Create the renderer
721         * yourself and use it to draw if you need more control.
722         * </p>
723         * 
724         * @param p
725         *            The polygon to draw.
726         * @param thickness
727         *            The thickness of the lines to use
728         * @param col
729         *            The colour to draw the lines in
730         */
731        public void drawPolygon(Polygon p, int thickness, Q col) {
732                createRenderer().drawPolygon(p, thickness, col);
733        }
734
735        /**
736         * Draw the given polygon in the specified colour. Uses
737         * {@link #drawPolygon(Polygon, int, Object)} with line thickness 1.
738         * Side-affects this image.
739         * 
740         * <p>
741         * This is a convenience method that calls {@link #createRenderer()} to get
742         * the default renderer to do the actual drawing. Create the renderer
743         * yourself and use it to draw if you need more control.
744         * </p>
745         * 
746         * @param p
747         *            The polygon to draw.
748         * @param col
749         *            The colour to draw the polygon in.
750         */
751        public void drawPolygon(Polygon p, Q col) {
752                createRenderer().drawPolygon(p, col);
753        }
754
755        /**
756         * Draw the given polygon, filled with the specified colour. Side-affects
757         * 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 col
768         *            The colour to fill the polygon with.
769         */
770        public void drawPolygonFilled(Polygon p, Q col) {
771                createRenderer().drawPolygonFilled(p, col);
772        }
773
774        /**
775         * Draw the given shape in the specified colour with the given thickness
776         * lines. Side-affects this image.
777         * 
778         * <p>
779         * This is a convenience method that calls {@link #createRenderer()} to get
780         * the default renderer to do the actual drawing. Create the renderer
781         * yourself and use it to draw if you need more control.
782         * </p>
783         * 
784         * @param s
785         *            The shape to draw.
786         * @param thickness
787         *            The thickness of the lines to use
788         * @param col
789         *            The colour to draw the lines in
790         */
791        public void drawShape(Shape s, int thickness, Q col) {
792                createRenderer().drawShape(s, thickness, col);
793        }
794
795        /**
796         * Draw the given shape in the specified colour. Uses
797         * {@link #drawPolygon(Polygon, int, Object)} with line thickness 1.
798         * Side-affects 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 shape to draw.
808         * @param col
809         *            The colour to draw the polygon in.
810         */
811        public void drawShape(Shape p, Q col) {
812                createRenderer().drawShape(p, col);
813        }
814
815        /**
816         * Draw the given shape, filled with the specified colour. Side-affects this
817         * 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 col
828         *            The colour to fill the polygon with.
829         */
830        public void drawShapeFilled(Shape s, Q col) {
831                createRenderer().drawShapeFilled(s, col);
832        }
833
834        /**
835         * Render the text using its attributes.
836         * 
837         * <p>
838         * This is a convenience method that calls {@link #createRenderer()} to get
839         * the default renderer to do the actual drawing. Create the renderer
840         * yourself and use it to draw if you need more control.
841         * </p>
842         * 
843         * @param text
844         *            the text
845         * @param x
846         *            the x-ordinate
847         * @param y
848         *            the y-ordinate
849         */
850        public void drawText(AttributedString text, int x, int y) {
851                createRenderer().drawText(text, x, y);
852        }
853
854        /**
855         * Render the text using its attributes.
856         * 
857         * <p>
858         * This is a convenience method that calls {@link #createRenderer()} to get
859         * the default renderer to do the actual drawing. Create the renderer
860         * yourself and use it to draw if you need more control.
861         * </p>
862         * 
863         * @param text
864         *            the text
865         * @param pt
866         *            the coordinate to render at
867         */
868        public void drawText(AttributedString text, Point2d pt) {
869                createRenderer().drawText(text, pt);
870        }
871
872        /**
873         * Render the text in the given font with the default style.
874         * 
875         * <p>
876         * This is a convenience method that calls {@link #createRenderer()} to get
877         * the default renderer to do the actual drawing. Create the renderer
878         * yourself and use it to draw if you need more control.
879         * </p>
880         * 
881         * @param <F>
882         *            the font
883         * @param text
884         *            the text
885         * @param x
886         *            the x-ordinate
887         * @param y
888         *            the y-ordinate
889         * @param f
890         *            the font
891         * @param sz
892         *            the size
893         */
894        public <F extends Font<F>> void drawText(String text, int x, int y, F f, int sz) {
895                createRenderer().drawText(text, x, y, f, sz);
896        }
897
898        /**
899         * Render the text in the given font in the given colour with the default
900         * style.
901         * 
902         * <p>
903         * This is a convenience method that calls {@link #createRenderer()} to get
904         * the default renderer to do the actual drawing. Create the renderer
905         * yourself and use it to draw if you need more control.
906         * </p>
907         * 
908         * @param <F>
909         *            the font
910         * @param text
911         *            the text
912         * @param x
913         *            the x-ordinate
914         * @param y
915         *            the y-ordinate
916         * @param f
917         *            the font
918         * @param sz
919         *            the size
920         * @param col
921         *            the font color
922         */
923        public <F extends Font<F>> void drawText(String text, int x, int y, F f, int sz, Q col) {
924                createRenderer().drawText(text, x, y, f, sz, col);
925        }
926
927        /**
928         * Render the text with the given {@link FontStyle}.
929         * 
930         * <p>
931         * This is a convenience method that calls {@link #createRenderer()} to get
932         * the default renderer to do the actual drawing. Create the renderer
933         * yourself and use it to draw if you need more control.
934         * </p>
935         * 
936         * @param text
937         *            the text
938         * @param x
939         *            the x-ordinate
940         * @param y
941         *            the y-ordinate
942         * @param f
943         *            the font style
944         */
945        public void drawText(String text, int x, int y, FontStyle<Q> f) {
946                createRenderer().drawText(text, x, y, f);
947        }
948
949        /**
950         * Render the text in the given font with the default style.
951         * 
952         * <p>
953         * This is a convenience method that calls {@link #createRenderer()} to get
954         * the default renderer to do the actual drawing. Create the renderer
955         * yourself and use it to draw if you need more control.
956         * </p>
957         * 
958         * @param <F>
959         *            the font
960         * @param text
961         *            the text
962         * @param pt
963         *            the coordinate to render at
964         * @param f
965         *            the font
966         * @param sz
967         *            the size
968         */
969        public <F extends Font<F>> void drawText(String text, Point2d pt, F f, int sz) {
970                createRenderer().drawText(text, pt, f, sz);
971        }
972
973        /**
974         * Render the text in the given font in the given colour with the default
975         * style.
976         * 
977         * <p>
978         * This is a convenience method that calls {@link #createRenderer()} to get
979         * the default renderer to do the actual drawing. Create the renderer
980         * yourself and use it to draw if you need more control.
981         * </p>
982         * 
983         * @param <F>
984         *            the font
985         * @param text
986         *            the text
987         * @param pt
988         *            the coordinate to render at
989         * @param f
990         *            the font
991         * @param sz
992         *            the size
993         * @param col
994         *            the font colour
995         */
996        public <F extends Font<F>> void drawText(String text, Point2d pt, F f, int sz, Q col) {
997                createRenderer().drawText(text, pt, f, sz, col);
998        }
999
1000        /**
1001         * Render the text with the given {@link FontStyle}.
1002         * 
1003         * <p>
1004         * This is a convenience method that calls {@link #createRenderer()} to get
1005         * the default renderer to do the actual drawing. Create the renderer
1006         * yourself and use it to draw if you need more control.
1007         * </p>
1008         * 
1009         * @param text
1010         *            the text
1011         * @param pt
1012         *            the coordinate to render at
1013         * @param f
1014         *            the font style
1015         */
1016        public void drawText(String text, Point2d pt, FontStyle<Q> f) {
1017                createRenderer().drawText(text, pt, f);
1018        }
1019
1020        /**
1021         * Extract a rectangular region about the centre of the image with the given
1022         * width and height. The method will return a box that extends
1023         * <code>width/2</code> and <code>height/2</code> from the centre point so
1024         * that the centre point of the extracted box is also the centre point of
1025         * the image.
1026         * 
1027         * @param w
1028         *            The width of the box to extract
1029         * @param h
1030         *            The height of the box to extract
1031         * @return A new image centred around the centre of the image.
1032         */
1033        public I extractCenter(int w, int h) {
1034                final int sw = (int) Math.floor((this.getWidth() - w) / 2);
1035                final int sh = (int) Math.floor((this.getHeight() - h) / 2);
1036
1037                return this.extractROI(sw, sh, w, h);
1038        }
1039
1040        /**
1041         * Extract a rectangular region centred on a given point. The method will
1042         * return a box that extends <code>width/2</code> and <code>height/2</code>
1043         * from the given point <code>(x,y)</code> such that the centre point of the
1044         * extracted box is the same as the point <code>(x,y)</code> in this image.
1045         * 
1046         * @param x
1047         *            Center point of the rectangle to extract
1048         * @param y
1049         *            center point of the rectangle to extract
1050         * @param w
1051         *            The width of the rectangle to extract
1052         * @param h
1053         *            The height of the rectangle to extract
1054         * @return A new image centred around the centre of the image.
1055         */
1056        public I extractCenter(int x, int y, int w, int h) {
1057                final int sw = (int) Math.floor(x - (w / 2));
1058                final int sh = (int) Math.floor(y - (h / 2));
1059
1060                return this.extractROI(sw, sh, w, h);
1061        }
1062
1063        /**
1064         * Extract a rectangular region of interest from this image and put it in
1065         * the given image. Coordinate <code>(0,0)</code> is the top-left corner.
1066         * The width and height of the extracted image should be determined from the
1067         * given image's width and height.
1068         * 
1069         * @param x
1070         *            The leftmost coordinate of the rectangle to extract
1071         * @param y
1072         *            The topmost coordinate of the rectangle to extract
1073         * @param img
1074         *            The destination image
1075         * @return A reference to the destination image containing the result
1076         */
1077        public abstract I extractROI(int x, int y, I img);
1078
1079        /**
1080         * Extract a rectangular region of interest of the given width and height.
1081         * Coordinate <code>(0,0)</code> is the top-left corner. Returns a new
1082         * image.
1083         * 
1084         * @param x
1085         *            The leftmost coordinate of the rectangle to extract
1086         * @param y
1087         *            The topmost coordinate of the rectangle to extract
1088         * @param w
1089         *            The width of the rectangle to extract
1090         * @param h
1091         *            The height of the rectangle to extract
1092         * @return A new image representing the selected region
1093         */
1094        public abstract I extractROI(int x, int y, int w, int h);
1095
1096        /**
1097         * Extract a rectangular region of interest of the given width and height.
1098         * Coordinate <code>(0,0)</code> is the top-left corner. Returns a new
1099         * image.
1100         * 
1101         * @param r
1102         *            the rectangle
1103         * @return A new image representing the selected region
1104         */
1105        public I extractROI(Rectangle r) {
1106                return extractROI((int) r.x, (int) r.y, (int) r.width, (int) r.height);
1107        }
1108
1109        /**
1110         * Fill this image with the given colour. Should overwrite all other data
1111         * stored in this image. Side-affects this image.
1112         * 
1113         * @param colour
1114         *            the colour to fill the image with
1115         * @return A reference to this image.
1116         */
1117        public abstract I fill(Q colour);
1118
1119        /**
1120         * Flips the content horizontally. Side-affects this image.
1121         * 
1122         * @return A reference to this image.
1123         */
1124        public abstract I flipX();
1125
1126        /**
1127         * Flips the content vertically. Side-affects this image.
1128         * 
1129         * @return A reference to this image.
1130         */
1131        public abstract I flipY();
1132
1133        /**
1134         * Get a rectangle representing the image, with the top-left at 0,0 and the
1135         * bottom-right at width,height
1136         * 
1137         * @return the bounding rectangle of the image
1138         */
1139        public Rectangle getBounds() {
1140                return new Rectangle(0, 0, this.getWidth(), this.getHeight());
1141        }
1142
1143        /**
1144         * Get the image width in pixels. This is syntactic sugar for
1145         * {@link #getWidth()};
1146         * 
1147         * @return The image width in pixels.
1148         */
1149        public int getCols() {
1150                return getWidth();
1151        }
1152
1153        /**
1154         * Get bounding box of non-zero-valued pixels around the outside of the
1155         * image. Used by {@link #trim()}.
1156         * 
1157         * @return A rectangle of the boundaries of the non-zero-valued image
1158         */
1159        public abstract Rectangle getContentArea();
1160
1161        /**
1162         * Get the given field of this image. Used for deinterlacing video, this
1163         * should return a new image containing the deinterlaced image. The returned
1164         * image will be half the height of this image.
1165         * 
1166         * @param f
1167         *            The {@link Field} to extract from this image
1168         * @return An image containing only the odd or even fields.
1169         */
1170        public abstract I getField(Field f);
1171
1172        /**
1173         * Get the given field of this image, maintaining the image's aspect ratio
1174         * by doubling the fields. Used for deinterlacing video, this should return
1175         * a new image containing the deinterlaced image. The returned image should
1176         * be the same size as this image.
1177         * 
1178         * @param f
1179         *            The {@link Field} to extract from this image
1180         * @return An image containing the odd or even fields doubled.
1181         */
1182        public abstract I getFieldCopy(Field f);
1183
1184        /**
1185         * Get the given field of this image, maintaining the image's aspect ratio
1186         * by interpolating between the fields. Used for deinterlacing video, this
1187         * should return a new image containing the detinterlaced image. The
1188         * returned image should be the same size as this image.
1189         * 
1190         * @param f
1191         *            The {@link Field} to extract from this image.
1192         * @return An image containing the odd or even fields with interpolated rows
1193         *         between.
1194         */
1195        public abstract I getFieldInterpolate(Field f);
1196
1197        /**
1198         * Returns the image height in pixels.
1199         * 
1200         * @return The image height in pixels.
1201         */
1202        public abstract int getHeight();
1203
1204        /**
1205         * Get the value of the pixel at coordinate <code>(x, y)</code>.
1206         * 
1207         * @param x
1208         *            The x-ordinate to get
1209         * @param y
1210         *            The y-ordinate to get
1211         * 
1212         * @return The pixel value at (x, y)
1213         */
1214        public abstract Q getPixel(int x, int y);
1215
1216        /**
1217         * Get the value of the pixel at coordinate p
1218         * 
1219         * @param p
1220         *            The coordinate to get
1221         * 
1222         * @return The pixel value at (x, y)
1223         */
1224        public Q getPixel(Pixel p) {
1225                return getPixel(p.x, p.y);
1226        }
1227
1228        /**
1229         * Returns a pixel comparator that is able to compare equality of pixels in
1230         * the given image type.
1231         * 
1232         * @return A {@link Comparator} that compares pixels.
1233         */
1234        public abstract Comparator<? super Q> getPixelComparator();
1235
1236        /**
1237         * Get the value of a sub-pixel using linear-interpolation.
1238         * 
1239         * @param x
1240         *            The x-ordinate to get
1241         * @param y
1242         *            The y-ordinate to get
1243         * @return The value of the interpolated point at <code>(x,y)</code>
1244         */
1245        public abstract Q getPixelInterp(double x, double y);
1246
1247        /**
1248         * Get the value of a sub-pixel using linear-interpolation. Also specify the
1249         * colour of the background (for interpolation at the edge)
1250         * 
1251         * @param x
1252         *            The x-ordinate to get.
1253         * @param y
1254         *            The y-ordinate to get.
1255         * @param backgroundColour
1256         *            The colour of the background pixel.
1257         * @return The value of the interpolated point at <code>(x,y)</code>
1258         */
1259        public abstract Q getPixelInterp(double x, double y, Q backgroundColour);
1260
1261        /**
1262         * Returns the pixels in this image as a vector (an array of the pixel
1263         * type).
1264         * 
1265         * @param f
1266         *            The array into which to place the data
1267         * @return The pixels in the image as a vector (a reference to the given
1268         *         array).
1269         */
1270        public Q[] getPixelVector(Q[] f) {
1271                for (int y = 0; y < getHeight(); y++)
1272                        for (int x = 0; x < getWidth(); x++)
1273                                f[x + y * getWidth()] = getPixel(x, y);
1274
1275                return f;
1276        }
1277
1278        /**
1279         * Get the height of this image. This is a syntactic sugar method for
1280         * {@link #getHeight()}.
1281         * 
1282         * @return The image height in pixels.
1283         */
1284        public int getRows() {
1285                return getHeight();
1286        }
1287
1288        /**
1289         * Get the width (number of columns) in this image.
1290         * 
1291         * @return the image width
1292         */
1293        public abstract int getWidth();
1294
1295        /**
1296         * Copy the internal state from another image of the same type. This method
1297         * is designed to be FAST. This means that bounds checking WILL NOT be
1298         * performed, so it is important that the images are the SAME size.
1299         * 
1300         * @param im
1301         *            The source image to make a copy of.
1302         * @return A reference to this image.
1303         */
1304        public abstract I internalCopy(I im);
1305
1306        /**
1307         * Assign the internal state from another image of the same type.
1308         * 
1309         * @param im
1310         *            The source image to make a copy of.
1311         * @return A reference to this image.
1312         */
1313        public abstract I internalAssign(I im);
1314
1315        /**
1316         * Copy pixels from given ARGB buffer image into this image. Side-affects
1317         * this image.
1318         * 
1319         * @param pixelData
1320         *            buffer of ARGB packed integer pixels
1321         * @param width
1322         *            the width of the buffer
1323         * @param height
1324         *            the height of the buffer
1325         * 
1326         * @return A reference to this image.
1327         */
1328        public abstract I internalAssign(int[] pixelData, int width, int height);
1329
1330        /**
1331         * Invert the image pixels by finding the maximum value and subtracting each
1332         * pixel value from that maximum.
1333         * 
1334         * @return A reference to this image.
1335         */
1336        public abstract I inverse();
1337
1338        /**
1339         * Find the maximum pixel value.
1340         * 
1341         * @return The maximum pixel value
1342         */
1343        public abstract Q max();
1344
1345        /**
1346         * Find the minimum pixel value.
1347         * 
1348         * @return The minimum pixel value
1349         */
1350        public abstract Q min();
1351
1352        /**
1353         * Multiply the pixel values in this image with the corresponding pixel
1354         * values in the given image. This method returns a new image.
1355         * 
1356         * @param im
1357         *            The image to multiply with this one
1358         * @return A new image containing the result.
1359         */
1360        public I multiply(Image<?, ?> im) {
1361                final I newImage = this.clone();
1362                newImage.multiplyInplace(im);
1363                return newImage;
1364        }
1365
1366        /**
1367         * Multiply each pixel of this by the given scalar and return new image.
1368         * 
1369         * @param num
1370         *            The scalar which to multiply the image by
1371         * @return A new image containing the result
1372         */
1373        public I multiply(Q num) {
1374                final I newImage = this.clone();
1375                newImage.multiplyInplace(num);
1376                return newImage;
1377        }
1378
1379        /**
1380         * Multiply each pixel in this image by the corresponding pixel in the given
1381         * image. This method side-affects this image.
1382         * 
1383         * @param im
1384         *            The image to multiply with this image.
1385         * @return A reference to this image.
1386         */
1387        public abstract I multiplyInplace(Image<?, ?> im);
1388
1389        /**
1390         * Multiply each pixel of this by the given scalar. This method side-affects
1391         * this image.
1392         * 
1393         * @param num
1394         *            The scalar to multiply this image by.
1395         * @return A reference to this image.
1396         */
1397        public abstract I multiplyInplace(Q num);
1398
1399        /**
1400         * Create a new instance of this image subclass with given dimensions.
1401         * 
1402         * @param width
1403         *            The image width
1404         * @param height
1405         *            The image height
1406         * 
1407         * @return A new instance of an image of type <code>I</code>
1408         */
1409        public abstract I newInstance(int width, int height);
1410
1411        /**
1412         * Normalise all pixel values to fall within the range 0.0 - 1.0. This
1413         * should be scaled by both the maximum and minimum values. This method
1414         * side-affects this image.
1415         * 
1416         * @return A reference to this image.
1417         */
1418        public abstract I normalise();
1419
1420        /**
1421         * Adds padding as in {@link Image#padding(int, int, Object)}. The padding
1422         * colour is the colour of the closest border pixel.
1423         * 
1424         * @param paddingWidth
1425         *            padding in the x direction
1426         * @param paddingHeight
1427         *            padding in the y direction
1428         * @return padded image
1429         */
1430        public I padding(int paddingWidth, int paddingHeight) {
1431                return this.padding(paddingWidth, paddingHeight, null);
1432        }
1433
1434        /**
1435         * Adds this many pixels to both sides of the image such that the new image
1436         * width = padding + width + padding with the original image in the middle
1437         * 
1438         * @param paddingWidth
1439         *            left and right padding width
1440         * @param paddingHeight
1441         *            top and bottom padding width
1442         * @param paddingColour
1443         *            colour of padding, if null the closes border pixel is used
1444         * @return padded image
1445         */
1446        @SuppressWarnings("unchecked")
1447        public I padding(int paddingWidth, int paddingHeight, Q paddingColour) {
1448                final I out = this.newInstance(paddingWidth + this.getWidth() + paddingWidth, paddingHeight + this.getHeight()
1449                                + paddingHeight);
1450
1451                out.createRenderer().drawImage((I) this, paddingWidth, paddingHeight);
1452                final int rightLimit = paddingWidth + this.getWidth();
1453                final int bottomLimit = paddingHeight + this.getHeight();
1454                // Fill the padding with a colour if it isn't null
1455                if (paddingColour != null)
1456                        for (int y = 0; y < out.getHeight(); y++) {
1457                                for (int x = 0; x < out.getWidth(); x++) {
1458                                        if (x >= paddingWidth && x < rightLimit && y >= paddingHeight && y < bottomLimit)
1459                                                continue;
1460                                        out.setPixel(x, y, paddingColour);
1461                                }
1462                        }
1463                else
1464                        for (int y = 0; y < out.getHeight(); y++) {
1465                                for (int x = 0; x < out.getWidth(); x++) {
1466                                        if (x >= paddingWidth && x < rightLimit && y >= paddingHeight && y < bottomLimit)
1467                                                continue;
1468                                        if (x < paddingWidth && y < paddingHeight)
1469                                                out.setPixel(x, y, this.getPixel(0, 0)); // Top Left
1470                                        else if (x < paddingWidth && y >= bottomLimit)
1471                                                out.setPixel(x, y, this.getPixel(0, this.getHeight() - 1)); // Bottom
1472                                                                                                                                                                        // Left
1473                                        else if (x >= rightLimit && y < paddingHeight)
1474                                                out.setPixel(x, y, this.getPixel(this.getWidth() - 1, 0)); // Top
1475                                                                                                                                                                        // Right
1476                                        else if (x >= rightLimit && y >= bottomLimit)
1477                                                out.setPixel(x, y, this.getPixel(this.getWidth() - 1, this.getHeight() - 1)); // Bottom
1478                                                                                                                                                                                                                // Right
1479                                        else {
1480                                                if (x < paddingWidth)
1481                                                        out.setPixel(x, y, this.getPixel(0, y - paddingHeight)); // Left
1482                                                else if (x >= rightLimit)
1483                                                        out.setPixel(x, y, this.getPixel(this.getWidth() - 1, y - paddingHeight)); // Right
1484                                                else if (y < paddingHeight)
1485                                                        out.setPixel(x, y, this.getPixel(x - paddingWidth, 0)); // Top
1486                                                else if (y >= bottomLimit)
1487                                                        out.setPixel(x, y, this.getPixel(x - paddingWidth, this.getHeight() - 1)); // Bottom
1488                                        }
1489                                }
1490                        }
1491
1492                return out;
1493        }
1494
1495        /**
1496         * Adds pixels to around the image such that the new image width =
1497         * paddingLeft + width + paddingRight with the original image in the middle.
1498         * The values of the padding pixels are formed from repeated symmetric
1499         * reflections of the original image.
1500         * 
1501         * @param paddingLeft
1502         *            left padding width
1503         * @param paddingRight
1504         *            right padding width
1505         * @param paddingTop
1506         *            top padding width
1507         * @param paddingBottom
1508         *            bottom padding width
1509         * @return padded image
1510         */
1511        public I paddingSymmetric(int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) {
1512                final I out = this.newInstance(paddingLeft + this.getWidth() + paddingRight, paddingTop + this.getHeight()
1513                                + paddingBottom);
1514                final I clone = this.clone();
1515                final I hflip = clone.clone().flipX();
1516
1517                final ImageRenderer<Q, I> rend = out.createRenderer();
1518                rend.drawImage(clone, paddingLeft, paddingTop);
1519
1520                // left
1521                for (int i = paddingLeft - this.getWidth(), c = 0; i > -this.getWidth(); i -= this.getWidth(), c++) {
1522                        if (c % 2 == 0) {
1523                                rend.drawImage(hflip, i, paddingTop);
1524                        } else {
1525                                rend.drawImage(clone, i, paddingTop);
1526                        }
1527                }
1528
1529                // right
1530                for (int i = paddingLeft + this.getWidth(), c = 0; i < paddingLeft + paddingRight + this.getWidth(); i += this
1531                                .getWidth(), c++)
1532                {
1533                        if (c % 2 == 0) {
1534                                rend.drawImage(hflip, i, paddingTop);
1535                        } else {
1536                                rend.drawImage(clone, i, paddingTop);
1537                        }
1538                }
1539
1540                final I centre = out.extractROI(0, paddingTop, paddingLeft + this.getWidth() + paddingRight, this.getHeight());
1541                final I yflip = centre.clone().flipY();
1542
1543                // up
1544                for (int i = paddingTop - this.getHeight(), c = 0; i > -this.getHeight(); i -= this.getHeight(), c++) {
1545                        if (c % 2 == 0) {
1546                                rend.drawImage(yflip, 0, i);
1547                        } else {
1548                                rend.drawImage(centre, 0, i);
1549                        }
1550                }
1551
1552                // down
1553                for (int i = paddingTop + this.getHeight(), c = 0; i < paddingTop + paddingBottom + this.getHeight(); i += this
1554                                .getHeight(), c++)
1555                {
1556                        if (c % 2 == 0) {
1557                                rend.drawImage(yflip, 0, i);
1558                        } else {
1559                                rend.drawImage(centre, 0, i);
1560                        }
1561                }
1562
1563                return out;
1564        }
1565
1566        /**
1567         * Process this image with the given {@link GridProcessor} and return new
1568         * image containing the result.
1569         * 
1570         * @param p
1571         *            {@link GridProcessor} to apply to this image.
1572         * @return A new image containing the result.
1573         */
1574        public I process(GridProcessor<Q, I> p) {
1575                final int height = p.getVerticalGridElements();
1576                final int width = p.getHorizontalGridElements();
1577                final I newImage = this.newInstance(width, height);
1578                newImage.zero();
1579
1580                final int gridWidth = getWidth() / width;
1581                final int gridHeight = getHeight() / height;
1582                for (int y = 0; y < height; y++)
1583                        for (int x = 0; x < width; x++)
1584                                newImage.setPixel(x, y,
1585                                                p.processGridElement(this.extractROI(gridWidth * x, gridHeight * y, gridWidth, gridHeight)));
1586
1587                return newImage;
1588        }
1589
1590        /**
1591         * Process this image with an {@link ImageProcessor} and return new image
1592         * containing the result.
1593         * 
1594         * @param p
1595         *            The {@link ImageProcessor} to apply to this image.
1596         * @return A new image containing the result.
1597         */
1598        public I process(ImageProcessor<I> p) {
1599                final I newImage = this.clone();
1600                newImage.processInplace(p);
1601                return newImage;
1602        }
1603
1604        /**
1605         * Process this image with the given {@link KernelProcessor} and return new
1606         * image containing the result.
1607         * 
1608         * @param p
1609         *            The {@link KernelProcessor} to apply.
1610         * @return A new image containing the result.
1611         */
1612        public I process(KernelProcessor<Q, I> p) {
1613                return process(p, false);
1614        }
1615
1616        /**
1617         * Process this image with the given {@link KernelProcessor} and return new
1618         * image containing the result.
1619         * 
1620         * @param p
1621         *            The {@link KernelProcessor} to apply.
1622         * @param pad
1623         *            Should the image be zero padded so the kernel reaches the
1624         *            edges of the output
1625         * @return A new image containing the result.
1626         */
1627        public I process(KernelProcessor<Q, I> p, boolean pad) {
1628                final I newImage = this.clone();
1629                newImage.zero();
1630
1631                final int kh = p.getKernelHeight();
1632                final int kw = p.getKernelWidth();
1633
1634                final int hh = p.getKernelHeight() / 2;
1635                final int hw = p.getKernelWidth() / 2;
1636
1637                final I tmp = newInstance(kw, kh);
1638
1639                if (!pad) {
1640                        for (int y = hh; y < getHeight() - (kh - hh); y++) {
1641                                for (int x = hw; x < getWidth() - (kw - hw); x++) {
1642                                        newImage.setPixel(x, y, p.processKernel(this.extractROI(x - hw, y - hh, tmp)));
1643                                }
1644                        }
1645                } else {
1646                        for (int y = 0; y < getHeight(); y++) {
1647                                for (int x = 0; x < getWidth(); x++) {
1648                                        newImage.setPixel(x, y, p.processKernel(this.extractROI(x - hw, y - hh, tmp)));
1649                                }
1650                        }
1651                }
1652
1653                return newImage;
1654        }
1655
1656        /**
1657         * Process this image with the given {@link PixelProcessor} and return a new
1658         * image containing the result.
1659         * 
1660         * @param p
1661         *            The {@link PixelProcessor} to apply.
1662         * @return A new image containing the result.
1663         */
1664        public I process(PixelProcessor<Q> p) {
1665                final I newImage = this.clone();
1666                newImage.processInplace(p);
1667                return newImage;
1668        }
1669
1670        /**
1671         * Process this image with an {@link Processor} and return new image
1672         * containing the result.
1673         * 
1674         * @param p
1675         *            The {@link Processor} to apply to this image.
1676         * @return A new image containing the result.
1677         */
1678        public I process(Processor<I> p) {
1679                final I newImage = this.clone();
1680                newImage.processInplace(p);
1681                return newImage;
1682        }
1683
1684        /**
1685         * Process this image with the given {@link Processor} side-affecting this
1686         * image.
1687         * 
1688         * @param p
1689         *            The {@link Processor} to apply.
1690         * @return A reference to this image containing the result.
1691         */
1692        @SuppressWarnings("unchecked")
1693        public I processInplace(Processor<I> p) {
1694                if (p == null)
1695                        return (I) this;
1696                if (p instanceof ImageProcessor)
1697                        return processInplace((ImageProcessor<I>) p);
1698                if (p instanceof KernelProcessor)
1699                        return processInplace((KernelProcessor<Q, I>) p);
1700                if (p instanceof PixelProcessor)
1701                        return processInplace((PixelProcessor<Q>) p);
1702
1703                throw new UnsupportedOperationException("Unsupported Processor type");
1704        }
1705
1706        /**
1707         * Process this image with the given {@link ImageProcessor} side-affecting
1708         * this image.
1709         * 
1710         * @param p
1711         *            The {@link ImageProcessor} to apply.
1712         * @return A reference to this image containing the result.
1713         */
1714        @SuppressWarnings("unchecked")
1715        public I processInplace(ImageProcessor<I> p) {
1716                p.processImage((I) this);
1717                return (I) this;
1718        }
1719
1720        /**
1721         * Process this image with the given {@link KernelProcessor} side-affecting
1722         * this image.
1723         * 
1724         * @param p
1725         *            The {@link KernelProcessor} to apply.
1726         * @return A reference to this image containing the result.
1727         */
1728        public I processInplace(KernelProcessor<Q, I> p) {
1729                return processInplace(p, false);
1730        }
1731
1732        /**
1733         * Process this image with the given {@link KernelProcessor} side-affecting
1734         * this image.
1735         * 
1736         * @param p
1737         *            The {@link KernelProcessor} to apply.
1738         * @param pad
1739         *            Should the image be zero padded so the kernel reaches the
1740         *            edges of the output
1741         * @return A reference to this image containing the result.
1742         */
1743        @SuppressWarnings("unchecked")
1744        public I processInplace(KernelProcessor<Q, I> p, boolean pad) {
1745                final I newImage = process(p, pad);
1746                this.internalAssign(newImage);
1747                return (I) this;
1748        }
1749
1750        /**
1751         * Process this image with the given {@link PixelProcessor} side-affecting
1752         * this image.
1753         * 
1754         * @param p
1755         *            The {@link PixelProcessor} to apply.
1756         * @return A reference to this image containing the result.
1757         */
1758        @SuppressWarnings("unchecked")
1759        public I processInplace(PixelProcessor<Q> p) {
1760                for (int y = 0; y < getHeight(); y++) {
1761                        for (int x = 0; x < getWidth(); x++) {
1762                                setPixel(x, y, p.processPixel(getPixel(x, y)));
1763                        }
1764                }
1765
1766                return (I) this;
1767        }
1768
1769        /**
1770         * Process this image with the given {@link PixelProcessor} only affecting
1771         * those pixels where the mask is non-zero. Returns a new image.
1772         * 
1773         * @param mask
1774         *            The mask to apply to the processing.
1775         * @param p
1776         *            The {@link PixelProcessor} to apply.
1777         * @return A new image containing the result.
1778         */
1779        public I processMasked(FImage mask, PixelProcessor<Q> p) {
1780                final I newImage = this.clone();
1781                newImage.processMaskedInplace(mask, p);
1782                return newImage;
1783        }
1784
1785        /**
1786         * Process this image with the given {@link PixelProcessor}, only affecting
1787         * those pixels where the mask is non-zero. Side-affects this image.
1788         * 
1789         * @param mask
1790         *            The mask to apply to the processor.
1791         * @param p
1792         *            The {@link PixelProcessor} to apply.
1793         * @return A reference to this image containing the result.
1794         */
1795        @SuppressWarnings("unchecked")
1796        public I processMaskedInplace(FImage mask, PixelProcessor<Q> p) {
1797                for (int y = 0; y < getHeight(); y++) {
1798                        for (int x = 0; x < getWidth(); x++) {
1799                                if (mask.pixels[y][x] == 0)
1800                                        continue;
1801                                setPixel(x, y, p.processPixel(getPixel(x, y)));
1802                        }
1803                }
1804                return (I) this;
1805        }
1806
1807        /**
1808         * Sets the pixel at <code>(x,y)</code> to the given value. Side-affects
1809         * this image.
1810         * 
1811         * @param x
1812         *            The x-ordinate of the pixel to set
1813         * @param y
1814         *            The y-ordinate of the pixel to set
1815         * @param val
1816         *            The value to set the pixel to.
1817         */
1818        public abstract void setPixel(int x, int y, Q val);
1819
1820        /**
1821         * Subtract the corresponding pixel value from the given image from the
1822         * pixel values in this image. Returns a new image.
1823         * 
1824         * @param im
1825         *            The image to subtract from this image.
1826         * @return A new image containing the result.
1827         */
1828        public I subtract(Image<?, ?> im) {
1829                final I newImage = this.clone();
1830                newImage.subtractInplace(im);
1831                return newImage;
1832        }
1833
1834        /**
1835         * Subtract a scalar from every pixel value in this image and return new
1836         * image.
1837         * 
1838         * @param num
1839         *            A value to subtract from each pixel.
1840         * @return A new image containing the result.
1841         */
1842        public I subtract(Q num) {
1843                final I newImage = this.clone();
1844                newImage.subtractInplace(num);
1845                return newImage;
1846        }
1847
1848        /**
1849         * Subtract the corresponding pixel value from the given image from the
1850         * pixel values in this image. Side-affects this image.
1851         * 
1852         * @param im
1853         *            The image to subtract from this image.
1854         * @return A reference to this containing the result.
1855         */
1856        public abstract I subtractInplace(Image<?, ?> im);
1857
1858        /**
1859         * Subtract a scalar from every pixel value in this image. Side-affects this
1860         * image.
1861         * 
1862         * @param num
1863         *            A value to subtract from each pixel.
1864         * @return A reference to this image containing the result.
1865         */
1866        public abstract I subtractInplace(Q num);
1867
1868        /**
1869         * Set all values less than the given threshold to 0 and all others to 1.
1870         * Side-affects this image.
1871         * 
1872         * @param thresh
1873         *            The threshold value
1874         * @return A reference to this image containing the result.
1875         */
1876        public abstract I threshold(Q thresh);
1877
1878        /**
1879         * Convert the image to a byte representation suitable for writing to a pnm
1880         * type format. Each byte should represent a single pixel. Multiband images
1881         * should interleave the data; e.g. [R1,G1,B1,R2,G2,B2...etc.]
1882         * 
1883         * @return This image as a byte array
1884         */
1885        public abstract byte[] toByteImage();
1886
1887        /**
1888         * Returns a 1D array representation of this image with each pixel
1889         * represented as a packed ARGB integer.
1890         * 
1891         * @return An array of ARGB pixels.
1892         */
1893        public abstract int[] toPackedARGBPixels();
1894
1895        /**
1896         * Apply a transform matrix to the image and returns the result as a new
1897         * image.
1898         * 
1899         * @param transform
1900         *            The transform matrix to apply.
1901         * @return A new image containing the result.
1902         */
1903        public I transform(Matrix transform) {
1904                boolean unset = true;
1905                double minX = 0, minY = 0, maxX = 0, maxY = 0;
1906                final double[][][] extrema = new double[][][] {
1907                                { { 0 }, { 0 }, { 1 } },
1908                                { { 0 }, { this.getHeight() }, { 1 } },
1909                                { { this.getWidth() }, { 0 }, { 1 } },
1910                                { { this.getWidth() }, { this.getHeight() }, { 1 } },
1911                };
1912                for (final double[][] ext : extrema) {
1913                        final Matrix tmp = transform.times(Matrix.constructWithCopy(ext));
1914                        if (unset) {
1915                                minX = maxX = tmp.get(0, 0);
1916                                maxY = minY = tmp.get(1, 0);
1917                                unset = false;
1918                        } else {
1919                                if (tmp.get(0, 0) > maxX)
1920                                        maxX = tmp.get(0, 0);
1921                                if (tmp.get(1, 0) > maxY)
1922                                        maxY = tmp.get(1, 0);
1923                                if (tmp.get(0, 0) < minX)
1924                                        minX = tmp.get(0, 0);
1925                                if (tmp.get(1, 0) < minY)
1926                                        minY = tmp.get(1, 0);
1927                        }
1928                }
1929                final I output = this.newInstance((int) (Math.abs(maxX - minX)), (int) (Math.abs(maxY - minY)));
1930                final Matrix invTrans = transform.inverse();
1931                final double[][] invTransData = invTrans.getArray();
1932
1933                for (int x = 0; x < output.getWidth(); x++) {
1934                        for (int y = 0; y < output.getHeight(); y++) {
1935                                double oldx = invTransData[0][0] * x + invTransData[0][1] * y + invTransData[0][2];
1936                                double oldy = invTransData[1][0] * x + invTransData[1][1] * y + invTransData[1][2];
1937                                final double norm = invTransData[2][0] * x + invTransData[2][1] * y + invTransData[2][2];
1938
1939                                oldx /= norm;
1940                                oldy /= norm;
1941
1942                                if (oldx < 0 || oldx >= this.getWidth() || oldy < 0 || oldy >= this.getHeight())
1943                                        continue;
1944
1945                                output.setPixel(x, y, this.getPixelInterp(oldx, oldy));
1946                        }
1947                }
1948                return output;
1949        }
1950
1951        /**
1952         * Removes zero-valued pixels from around the outside of the image.
1953         * Analagous to {@link String#trim()}.
1954         * 
1955         * @return A new image containing the trimmed image.
1956         */
1957        public I trim() {
1958                final Rectangle rect = this.getContentArea();
1959                return this.extractROI((int) rect.minX(), (int) rect.minY(), (int) (rect.getWidth()), (int) (rect.getHeight()));
1960        }
1961
1962        /**
1963         * Set all pixels in the image to zero. Side-affects this image.
1964         * 
1965         * @return A reference to this image containing the result.
1966         */
1967        public abstract I zero();
1968
1969        /**
1970         * Shifts all the pixels to the left by one pixel
1971         * 
1972         * @return A reference to this image.
1973         */
1974        public I shiftLeftInplace() {
1975                return shiftLeftInplace(1);
1976        }
1977
1978        /**
1979         * Shifts all the pixels to the right by one pixel
1980         * 
1981         * @return A reference to this image.
1982         */
1983        public I shiftRightInplace() {
1984                return shiftRightInplace(1);
1985        }
1986
1987        /**
1988         * Shifts all the pixels to the left by count pixel
1989         * 
1990         * @param count
1991         *            The number of pixels
1992         * 
1993         * @return A reference to this image.
1994         */
1995        public I shiftLeftInplace(int count) {
1996                return this.internalAssign(this.shiftLeft(count));
1997        }
1998
1999        /**
2000         * Shifts all the pixels to the right by count pixel
2001         * 
2002         * @param count
2003         *            The number of pixels
2004         * 
2005         * @return A reference to this image.
2006         */
2007        public I shiftRightInplace(int count) {
2008                return this.internalAssign(this.shiftRight(count));
2009        }
2010
2011        /**
2012         * Returns a new image that is it shifted around the x-ordinates by one
2013         * pixel
2014         * 
2015         * @return A new image shifted around to the left by one pixel
2016         */
2017        public I shiftLeft() {
2018                return shiftLeft(1);
2019        }
2020
2021        /**
2022         * Returns a new image that is it shifted around the x-ordinates by the
2023         * number of pixels given.
2024         * 
2025         * @param nPixels
2026         *            The number of pixels
2027         * 
2028         * @return A new image shifted around to the left by the number of pixels
2029         */
2030        public I shiftLeft(int nPixels) {
2031                final I output = this.newInstance(getWidth(), getHeight());
2032                final I img = this.extractROI(0, 0, nPixels, getHeight());
2033                output.createRenderer().drawImage(
2034                                this.extractROI(nPixels, 0, getWidth() - nPixels, getHeight()), 0, 0);
2035                output.createRenderer().drawImage(img, getWidth() - nPixels, 0);
2036                return output;
2037        }
2038
2039        /**
2040         * Returns a new image that is it shifted around the x-ordinates by one
2041         * pixel
2042         * 
2043         * @return A new image shifted around to the right by one pixel
2044         */
2045        public I shiftRight() {
2046                return shiftRight(1);
2047        }
2048
2049        /**
2050         * Returns a new image that is it shifted around the x-ordinates by the
2051         * number of pixels given.
2052         * 
2053         * @param nPixels
2054         *            the number of pixels
2055         * 
2056         * @return A new image shifted around to the right by the number of pixels
2057         */
2058        public I shiftRight(int nPixels) {
2059                final I output = this.newInstance(getWidth(), getHeight());
2060                final I img = this.extractROI(getWidth() - nPixels, 0, nPixels, getHeight());
2061                output.createRenderer().drawImage(
2062                                this.extractROI(0, 0, getWidth() - nPixels, getHeight()), nPixels, 0);
2063                output.createRenderer().drawImage(img, 0, 0);
2064                return output;
2065        }
2066
2067        /**
2068         * Shifts all the pixels up by one pixel
2069         * 
2070         * @return A reference to this image.
2071         */
2072        public I shiftUpInplace() {
2073                return shiftUpInplace(1);
2074        }
2075
2076        /**
2077         * Shifts all the pixels down by one pixels
2078         * 
2079         * @return A reference to this image.
2080         */
2081        public I shiftDownInplace() {
2082                return shiftDownInplace(1);
2083        }
2084
2085        /**
2086         * Shifts all the pixels up by count pixels
2087         * 
2088         * @param count
2089         *            The number of pixels
2090         * 
2091         * @return A reference to this image.
2092         */
2093        public I shiftUpInplace(int count) {
2094                return this.internalAssign(this.shiftUp(count));
2095        }
2096
2097        /**
2098         * Shifts all the pixels down by count pixels
2099         * 
2100         * @param count
2101         *            The number of pixels
2102         * 
2103         * @return A reference to this image.
2104         */
2105        public I shiftDownInplace(int count) {
2106                return this.internalAssign(this.shiftDown(count));
2107        }
2108
2109        /**
2110         * Returns a new image that is it shifted around the x-ordinates by one
2111         * pixel
2112         * 
2113         * @return A new image shifted around up by one pixel
2114         */
2115        public I shiftUp() {
2116                return shiftUp(1);
2117        }
2118
2119        /**
2120         * Returns a new image that is it shifted around the x-ordinates by the
2121         * number of pixels given.
2122         * 
2123         * @param nPixels
2124         *            The number of pixels
2125         * 
2126         * @return A new image shifted around up by the number of pixels
2127         */
2128        public I shiftUp(int nPixels) {
2129                final I output = this.newInstance(getWidth(), getHeight());
2130                final I img = this.extractROI(0, 0, getWidth(), nPixels);
2131                output.createRenderer().drawImage(
2132                                this.extractROI(0, nPixels, getWidth(), getHeight() - nPixels), 0, 0);
2133                output.createRenderer().drawImage(img, 0, getHeight() - nPixels);
2134                return output;
2135        }
2136
2137        /**
2138         * Returns a new image that is it shifted around the x-ordinates by one
2139         * pixel
2140         * 
2141         * @return A new image shifted around down by one pixel
2142         */
2143        public I shiftDown() {
2144                return shiftDown(1);
2145        }
2146
2147        /**
2148         * Returns a new image that is it shifted around the x-ordinates by the
2149         * number of pixels given.
2150         * 
2151         * @param nPixels
2152         *            the number of pixels
2153         * 
2154         * @return A new image shifted around down by the number of pixels
2155         */
2156        public I shiftDown(int nPixels) {
2157                final I output = this.newInstance(getWidth(), getHeight());
2158                final I img = this.extractROI(0, getHeight() - nPixels, getWidth(), nPixels);
2159                output.createRenderer().drawImage(
2160                                this.extractROI(0, 0, getWidth(), getHeight() - nPixels), 0, nPixels);
2161                output.createRenderer().drawImage(img, 0, 0);
2162                return output;
2163        }
2164
2165        /**
2166         * Overlays the given image on this image and returns a new image containing
2167         * the result.
2168         * 
2169         * @param image
2170         *            The image to overlay on this image.
2171         * @param x
2172         *            The location at which to overlay the image
2173         * @param y
2174         *            The location at which to overlay the image
2175         * @return A new image containing the result
2176         */
2177        public I overlay(I image, int x, int y) {
2178                final I img = this.clone();
2179                img.overlayInplace(image, x, y);
2180                return img;
2181        }
2182
2183        /**
2184         * Overlays the given image on this image directly. The method returns this
2185         * image for chaining.
2186         * 
2187         * @param image
2188         *            The image to overlay
2189         * @param x
2190         *            The location at which to overlay the image
2191         * @param y
2192         *            The location at which to overlay the image
2193         * @return Returns this image
2194         */
2195        public abstract I overlayInplace(I image, int x, int y);
2196
2197        @SuppressWarnings("unchecked")
2198        @Override
2199        public I getImage() {
2200                return (I) this;
2201        }
2202
2203        /**
2204         * Replace pixels of a certain colour with another colour. Side-affects this
2205         * image.
2206         * 
2207         * @param target
2208         *            the colour to fill the image with
2209         * @param replacement
2210         *            the colour to fill the image with
2211         * @return A reference to this image.
2212         */
2213        public abstract I replace(Q target, Q replacement);
2214
2215        /**
2216         * Sub-pixel sampling of a centred rectangular region such that
2217         * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2218         * . Sub-pixels values are estimated using bilinear interpolation.
2219         * 
2220         * @see #getPixelInterp(double, double)
2221         * 
2222         * @param centre
2223         *            the centre
2224         * @param width
2225         *            the region width
2226         * @param height
2227         *            the region height
2228         * @return the extracted sub-pixel region
2229         */
2230        public I extractCentreSubPix(Point2d centre, int width, int height) {
2231                return extractCentreSubPix(centre.getX(), centre.getY(), width, height);
2232        }
2233
2234        /**
2235         * Sub-pixel sampling of a centred rectangular region such that
2236         * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2237         * . Sub-pixels values are estimated using bilinear interpolation.
2238         * 
2239         * @see #getPixelInterp(double, double)
2240         * @param cx
2241         *            the x-ordinate of the centre
2242         * @param cy
2243         *            the y-ordinate of the centre
2244         * @param width
2245         *            the region width
2246         * @param height
2247         *            the region height
2248         * @return the extracted sub-pixel region
2249         */
2250        public I extractCentreSubPix(float cx, float cy, int width, int height) {
2251                final I out = newInstance(width, height);
2252                return extractCentreSubPix(cx, cy, out);
2253        }
2254
2255        /**
2256         * Sub-pixel sampling of a centred rectangular region such that
2257         * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2258         * . Sub-pixels values are estimated using bilinear interpolation.
2259         * 
2260         * @see #getPixelInterp(double, double)
2261         * 
2262         * @param centre
2263         *            the centre
2264         * @param out
2265         *            the output image (also defines the size of the extracted
2266         *            region)
2267         * @return <code>out</code>
2268         */
2269        public I extractCentreSubPix(Point2d centre, I out) {
2270                return extractCentreSubPix(centre.getX(), centre.getY(), out);
2271        }
2272
2273        /**
2274         * Sub-pixel sampling of a centred rectangular region such that
2275         * <code>dst(x, y) = src(x + center.x  (width(dst)  1) ⇤ 0.5, y + center.y  (height(dst)  1) ⇤ 0.5)</code>
2276         * . Sub-pixels values are estimated using bilinear interpolation.
2277         * 
2278         * @see #getPixelInterp(double, double)
2279         * @param cx
2280         *            the x-ordinate of the centre
2281         * @param cy
2282         *            the y-ordinate of the centre
2283         * @param out
2284         *            the output image (also defines the size of the extracted
2285         *            region)
2286         * @return <code>out</code>
2287         */
2288        public abstract I extractCentreSubPix(float cx, float cy, I out);
2289}