View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.image;
31  
32  import java.util.Comparator;
33  
34  import org.apache.log4j.Logger;
35  import org.openimaj.image.analyser.PixelAnalyser;
36  import org.openimaj.image.colour.ColourSpace;
37  import org.openimaj.image.pixel.FValuePixel;
38  import org.openimaj.image.pixel.Pixel;
39  import org.openimaj.image.processor.KernelProcessor;
40  import org.openimaj.image.processor.PixelProcessor;
41  import org.openimaj.image.renderer.FImageRenderer;
42  import org.openimaj.image.renderer.RenderHints;
43  import org.openimaj.math.geometry.shape.Rectangle;
44  import org.openimaj.math.util.Interpolation;
45  
46  import Jama.Matrix;
47  
48  /**
49   * Class representing a single-band floating-point image; that is an image where
50   * each pixel is represented by a floating-point number.
51   * <p>
52   * {@link FImage}s can be created from PGM files or from pixel arrays. If you
53   * wish to read other types of files then use the {@link ImageUtilities} class
54   * that provides read/write functions for {@link Image} objects.
55   *
56   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
57   */
58  public class FImage extends SingleBandImage<Float, FImage>
59  {
60  	private static final long serialVersionUID = 1L;
61  
62  	/** The logging class */
63  	protected static Logger logger = Logger.getLogger(FImage.class);
64  
65  	/**
66  	 * The default number of sigmas at which the Gaussian function is truncated
67  	 * when building a kernel
68  	 */
69  	protected static final float DEFAULT_GAUSS_TRUNCATE = 4.0f;
70  
71  	/** The underlying pixels */
72  	public float pixels[][];
73  
74  	/**
75  	 * Create an {@link FImage} from an array of floating point values with the
76  	 * given width and height. The length of the array must equal the width
77  	 * multiplied by the height.
78  	 *
79  	 * @param array
80  	 *            An array of floating point values.
81  	 * @param width
82  	 *            The width of the resulting image.
83  	 * @param height
84  	 *            The height of th resulting image.
85  	 */
86  	public FImage(final float[] array, final int width, final int height)
87  	{
88  		assert (array.length == width * height);
89  
90  		this.pixels = new float[height][width];
91  		this.height = height;
92  		this.width = width;
93  
94  		for (int y = 0; y < height; y++)
95  			for (int x = 0; x < width; x++)
96  				this.pixels[y][x] = array[y * width + x];
97  	}
98  
99  	/**
100 	 * Create an {@link FImage} from an array of double values with the given
101 	 * width and height. The length of the array must equal the width multiplied
102 	 * by the height. The values will be downcast to floats.
103 	 *
104 	 * @param array
105 	 *            An array of floating point values.
106 	 * @param width
107 	 *            The width of the resulting image.
108 	 * @param height
109 	 *            The height of th resulting image.
110 	 */
111 	public FImage(final double[] array, final int width, final int height)
112 	{
113 		assert (array.length == width * height);
114 
115 		this.pixels = new float[height][width];
116 		this.height = height;
117 		this.width = width;
118 
119 		for (int y = 0; y < height; y++)
120 			for (int x = 0; x < width; x++)
121 				this.pixels[y][x] = (float) array[y * width + x];
122 	}
123 
124 	/**
125 	 * Create an {@link FImage} from an array of double values with the given
126 	 * width and height. The length of the array must equal the width multiplied
127 	 * by the height. The values will be downcast to floats.
128 	 *
129 	 * @param array
130 	 *            An array of floating point values.
131 	 * @param width
132 	 *            The width of the resulting image.
133 	 * @param height
134 	 *            The height of the resulting image.
135 	 * @param offset
136 	 *            The offset in the array to begin reading from
137 	 */
138 	public FImage(final double[] array, final int width, final int height, int offset)
139 	{
140 		assert (array.length == width * height);
141 
142 		this.pixels = new float[height][width];
143 		this.height = height;
144 		this.width = width;
145 
146 		for (int y = 0; y < height; y++)
147 			for (int x = 0; x < width; x++)
148 				this.pixels[y][x] = (float) array[offset + y * width + x];
149 	}
150 
151 	/**
152 	 * Create an {@link FImage} from an array of floating point values.
153 	 *
154 	 * @param array
155 	 *            the array representing pixel values to copy data from.
156 	 */
157 	public FImage(final float[][] array)
158 	{
159 		this.pixels = array;
160 		this.height = array.length;
161 		this.width = array[0].length;
162 	}
163 
164 	/**
165 	 * Create an empty {@link FImage} of the given size.
166 	 *
167 	 * @param width
168 	 *            image width (number of columns)
169 	 * @param height
170 	 *            image height (number of rows)
171 	 */
172 	public FImage(final int width, final int height) {
173 		this.pixels = new float[height][width];
174 
175 		this.height = height;
176 		this.width = width;
177 	}
178 
179 	/**
180 	 * Construct an {@link FImage} from an array of packed ARGB integers.
181 	 *
182 	 * @param data
183 	 *            array of packed ARGB pixels
184 	 * @param width
185 	 *            the image width
186 	 * @param height
187 	 *            the image height
188 	 */
189 	public FImage(final int[] data, final int width, final int height) {
190 		this.internalAssign(data, width, height);
191 	}
192 
193 	/**
194 	 * Construct an {@link FImage} from an array of packed ARGB integers using
195 	 * the specified plane.
196 	 *
197 	 * @param data
198 	 *            array of packed ARGB pixels
199 	 * @param width
200 	 *            the image width
201 	 * @param height
202 	 *            the image height
203 	 * @param plane
204 	 *            The {@link ARGBPlane} to copy data from
205 	 */
206 	public FImage(final int[] data, final int width, final int height, final ARGBPlane plane) {
207 		this.width = width;
208 		this.height = height;
209 		this.pixels = new float[height][width];
210 
211 		for (int y = 0; y < height; y++) {
212 			for (int x = 0; x < width; x++) {
213 				final int rgb = data[x + y * width];
214 
215 				int colour = 0;
216 				switch (plane)
217 				{
218 				case RED:
219 					colour = ((rgb >> 16) & 0xff);
220 					break;
221 				case GREEN:
222 					colour = ((rgb >> 8) & 0xff);
223 					break;
224 				case BLUE:
225 					colour = ((rgb) & 0xff);
226 					break;
227 				default:
228 					break;
229 				}
230 
231 				this.pixels[y][x] = colour;
232 			}
233 		}
234 	}
235 
236 	/**
237 	 * {@inheritDoc}
238 	 *
239 	 * @see org.openimaj.image.Image#abs()
240 	 */
241 	@Override
242 	public FImage abs() {
243 		for (int r = 0; r < this.height; r++)
244 			for (int c = 0; c < this.width; c++)
245 				this.pixels[r][c] = Math.abs(this.pixels[r][c]);
246 		return this;
247 	}
248 
249 	/**
250 	 * Adds the pixel values of the given {@link FImage} to the pixels of this
251 	 * image. Returns a new {@link FImage} and does not affect this image or the
252 	 * given image. This is a version of {@link Image#add(Image)} which takes an
253 	 * {@link FImage}. This method directly accesses the underlying float[][]
254 	 * and is therefore fast. This function returns a new {@link FImage}.
255 	 *
256 	 * @see org.openimaj.image.Image#add(Image)
257 	 * @param im
258 	 *            {@link FImage} to add into this one.
259 	 * @return A new {@link FImage}
260 	 */
261 	public FImage add(final FImage im)
262 	{
263 		if (!ImageUtilities.checkSameSize(this, im))
264 			throw new AssertionError("images must be the same size");
265 
266 		final FImage newImage = new FImage(im.width, im.height);
267 
268 		for (int r = 0; r < im.height; r++)
269 			for (int c = 0; c < im.width; c++)
270 				newImage.pixels[r][c] = this.pixels[r][c] + im.pixels[r][c];
271 
272 		return newImage;
273 	}
274 
275 	/**
276 	 * Returns a new {@link FImage} that contains the pixels of this image
277 	 * increased by the given value. {@inheritDoc}
278 	 *
279 	 * @see org.openimaj.image.Image#add(java.lang.Object)
280 	 */
281 	@Override
282 	public FImage add(final Float num)
283 	{
284 		final FImage newImage = new FImage(this.width, this.height);
285 		final float fnum = num;
286 
287 		for (int r = 0; r < this.height; r++)
288 			for (int c = 0; c < this.width; c++)
289 				newImage.pixels[r][c] = this.pixels[r][c] + fnum;
290 
291 		return newImage;
292 	}
293 
294 	/**
295 	 * {@inheritDoc} This method throws an {@link UnsupportedOperationException}
296 	 * if the given image is not an {@link FImage}.
297 	 *
298 	 * @see org.openimaj.image.Image#add(org.openimaj.image.Image)
299 	 * @exception UnsupportedOperationException
300 	 *                if an unsupported type is added
301 	 * @return a reference to this {@link FImage}
302 	 */
303 	@Override
304 	public FImage add(final Image<?, ?> im)
305 	{
306 		if (im instanceof FImage)
307 			return this.add((FImage) im);
308 		else
309 			throw new UnsupportedOperationException("Unsupported Type");
310 	}
311 
312 	/***
313 	 * Adds the given image pixel values to the pixel values of this image.
314 	 * Version of {@link Image#addInplace(Image)} which takes an {@link FImage}.
315 	 * This directly accesses the underlying float[][] and is therefore fast.
316 	 * This function side-affects the pixels in this {@link FImage}.
317 	 *
318 	 * @see Image#addInplace(Image)
319 	 * @param im
320 	 *            the FImage to add
321 	 * @return a reference to this
322 	 */
323 	public FImage addInplace(final FImage im)
324 	{
325 		if (!ImageUtilities.checkSameSize(this, im))
326 			throw new AssertionError("images must be the same size");
327 
328 		for (int r = 0; r < im.height; r++)
329 			for (int c = 0; c < im.width; c++)
330 				this.pixels[r][c] += im.pixels[r][c];
331 
332 		return this;
333 	}
334 
335 	/**
336 	 * {@inheritDoc}
337 	 *
338 	 * @see org.openimaj.image.Image#addInplace(java.lang.Object)
339 	 */
340 	@Override
341 	public FImage addInplace(final Float num)
342 	{
343 		final float fnum = num;
344 		for (int r = 0; r < this.height; r++)
345 			for (int c = 0; c < this.width; c++)
346 				this.pixels[r][c] += fnum;
347 
348 		return this;
349 	}
350 
351 	/**
352 	 * {@inheritDoc} This method throws an {@link UnsupportedOperationException}
353 	 * if the given image is not an {@link FImage}.
354 	 *
355 	 * @see org.openimaj.image.Image#addInplace(org.openimaj.image.Image)
356 	 * @exception UnsupportedOperationException
357 	 *                if an unsupported type is added
358 	 * @return a reference to this {@link FImage}
359 	 */
360 	@Override
361 	public FImage addInplace(final Image<?, ?> im)
362 	{
363 		if (im instanceof FImage)
364 			return this.addInplace((FImage) im);
365 		else
366 			throw new UnsupportedOperationException("Unsupported Type");
367 	}
368 
369 	/**
370 	 * {@inheritDoc}
371 	 *
372 	 * @see org.openimaj.image.Image#clip(java.lang.Object, java.lang.Object)
373 	 */
374 	@Override
375 	public FImage clip(final Float min, final Float max)
376 	{
377 		int r, c;
378 
379 		for (r = 0; r < this.height; r++)
380 		{
381 			for (c = 0; c < this.width; c++)
382 			{
383 				if (this.pixels[r][c] < min)
384 					this.pixels[r][c] = 0;
385 				if (this.pixels[r][c] > max)
386 					this.pixels[r][c] = 1;
387 			}
388 		}
389 
390 		return this;
391 	}
392 
393 	/**
394 	 * {@inheritDoc}
395 	 *
396 	 * @see org.openimaj.image.Image#clipMax(java.lang.Object)
397 	 */
398 	@Override
399 	public FImage clipMax(final Float thresh)
400 	{
401 		final float fthresh = thresh;
402 		for (int r = 0; r < this.height; r++)
403 		{
404 			for (int c = 0; c < this.width; c++)
405 			{
406 				if (this.pixels[r][c] > fthresh)
407 					this.pixels[r][c] = 1;
408 			}
409 		}
410 		return this;
411 	}
412 
413 	/**
414 	 * {@inheritDoc}
415 	 *
416 	 * @see org.openimaj.image.Image#clipMin(java.lang.Object)
417 	 */
418 	@Override
419 	public FImage clipMin(final Float thresh)
420 	{
421 		final float fthresh = thresh;
422 		for (int r = 0; r < this.height; r++)
423 		{
424 			for (int c = 0; c < this.width; c++)
425 			{
426 				if (this.pixels[r][c] < fthresh)
427 					this.pixels[r][c] = 0;
428 			}
429 		}
430 		return this;
431 	}
432 
433 	/**
434 	 * {@inheritDoc}
435 	 *
436 	 * @see org.openimaj.image.SingleBandImage#clone()
437 	 */
438 	@Override
439 	public FImage clone()
440 	{
441 		final FImage cpy = new FImage(this.width, this.height);
442 		int r;
443 
444 		for (r = 0; r < this.height; r++)
445 			System.arraycopy(this.pixels[r], 0, cpy.pixels[r], 0, this.width);
446 
447 		return cpy;
448 	}
449 
450 	@Override
451 	public FImageRenderer createRenderer() {
452 		return new FImageRenderer(this);
453 	}
454 
455 	@Override
456 	public FImageRenderer createRenderer(final RenderHints options) {
457 		return new FImageRenderer(this, options);
458 	}
459 
460 	/**
461 	 * Divides the pixels values of this image with the values from the given
462 	 * image. This is a version of {@link Image#divide(Image)} which takes an
463 	 * {@link FImage}. This directly accesses the underlying float[][] and is
464 	 * therefore fast. This function returns a new {@link FImage}.
465 	 *
466 	 * @see Image#divide(Image)
467 	 * @param im
468 	 *            the {@link FImage} to be the denominator.
469 	 * @return A new {@link FImage}
470 	 */
471 	public FImage divide(final FImage im)
472 	{
473 		if (!ImageUtilities.checkSameSize(this, im))
474 			throw new AssertionError("images must be the same size");
475 
476 		final FImage newImage = new FImage(im.width, im.height);
477 		int r, c;
478 
479 		for (r = 0; r < im.height; r++)
480 			for (c = 0; c < im.width; c++)
481 				newImage.pixels[r][c] = this.pixels[r][c] / im.pixels[r][c];
482 
483 		return newImage;
484 	}
485 
486 	/**
487 	 * Divides the pixel values of this image with the values from the given
488 	 * image. This is a version of {@link Image#divideInplace(Image)} which
489 	 * takes an {@link FImage}. This directly accesses the underlying float[][]
490 	 * and is therefore fast. This function side-affects this image.
491 	 *
492 	 * @see Image#divideInplace(Image)
493 	 * @param im
494 	 *            the {@link FImage} to be the denominator
495 	 * @return a reference to this {@link FImage}
496 	 */
497 	public FImage divideInplace(final FImage im)
498 	{
499 		if (!ImageUtilities.checkSameSize(this, im))
500 			throw new AssertionError("images must be the same size");
501 
502 		for (int y = 0; y < this.height; y++)
503 		{
504 			for (int x = 0; x < this.width; x++)
505 			{
506 				this.pixels[y][x] /= im.pixels[y][x];
507 			}
508 		}
509 
510 		return this;
511 	}
512 
513 	/**
514 	 * {@inheritDoc}
515 	 *
516 	 * @see org.openimaj.image.Image#divideInplace(java.lang.Object)
517 	 */
518 	@Override
519 	public FImage divideInplace(final Float val)
520 	{
521 		final float fval = val;
522 
523 		for (int y = 0; y < this.height; y++)
524 			for (int x = 0; x < this.width; x++)
525 				this.pixels[y][x] /= fval;
526 
527 		return this;
528 	}
529 
530 	/**
531 	 * Divide all pixels by a given value
532 	 *
533 	 * @param fval
534 	 *            the value
535 	 * @return this image
536 	 * @see org.openimaj.image.Image#divideInplace(java.lang.Object)
537 	 */
538 	public FImage divideInplace(final float fval)
539 	{
540 		for (int y = 0; y < this.height; y++)
541 			for (int x = 0; x < this.width; x++)
542 				this.pixels[y][x] /= fval;
543 
544 		return this;
545 	}
546 
547 	/**
548 	 * {@inheritDoc}
549 	 *
550 	 * @see org.openimaj.image.Image#divideInplace(org.openimaj.image.Image)
551 	 */
552 	@Override
553 	public FImage divideInplace(final Image<?, ?> im)
554 	{
555 		if (im instanceof FImage)
556 			return this.divideInplace((FImage) im);
557 		else
558 			throw new UnsupportedOperationException("Unsupported Type");
559 	}
560 
561 	/**
562 	 * {@inheritDoc}
563 	 *
564 	 * @see org.openimaj.image.Image#extractROI(int, int,
565 	 *      org.openimaj.image.Image)
566 	 */
567 	@Override
568 	public FImage extractROI(final int x, final int y, final FImage out)
569 	{
570 		for (int r = y, rr = 0; rr < out.height; r++, rr++)
571 		{
572 			for (int c = x, cc = 0; cc < out.width; c++, cc++)
573 			{
574 				if (r < 0 || r >= this.height || c < 0 || c >= this.width)
575 					(out).pixels[rr][cc] = 0;
576 				else
577 					(out).pixels[rr][cc] = this.pixels[r][c];
578 			}
579 		}
580 
581 		return out;
582 	}
583 
584 	/**
585 	 * {@inheritDoc}
586 	 *
587 	 * @see org.openimaj.image.Image#extractROI(int, int, int, int)
588 	 */
589 	@Override
590 	public FImage extractROI(final int x, final int y, final int w, final int h)
591 	{
592 		final FImage out = new FImage(w, h);
593 
594 		for (int r = y, rr = 0; rr < h; r++, rr++)
595 		{
596 			for (int c = x, cc = 0; cc < w; c++, cc++)
597 			{
598 				if (r < 0 || r >= this.height || c < 0 || c >= this.width)
599 					out.pixels[rr][cc] = 0;
600 				else
601 					out.pixels[rr][cc] = this.pixels[r][c];
602 			}
603 		}
604 
605 		return out;
606 	}
607 
608 	/**
609 	 * {@inheritDoc}
610 	 *
611 	 * @see org.openimaj.image.SingleBandImage#fill(java.lang.Comparable)
612 	 */
613 	@Override
614 	public FImage fill(final Float colour)
615 	{
616 		for (int r = 0; r < this.height; r++)
617 			for (int c = 0; c < this.width; c++)
618 				this.pixels[r][c] = colour;
619 
620 		return this;
621 	}
622 
623 	/**
624 	 * Fill an image with the given colour
625 	 *
626 	 * @param colour
627 	 *            the colour
628 	 * @return the image
629 	 * @see org.openimaj.image.SingleBandImage#fill(java.lang.Comparable)
630 	 */
631 	public FImage fill(final float colour)
632 	{
633 		for (int r = 0; r < this.height; r++)
634 			for (int c = 0; c < this.width; c++)
635 				this.pixels[r][c] = colour;
636 
637 		return this;
638 	}
639 
640 	/**
641 	 * {@inheritDoc}
642 	 *
643 	 * @see org.openimaj.image.Image#getContentArea()
644 	 */
645 	@Override
646 	public Rectangle getContentArea() {
647 		int minc = this.width, maxc = 0, minr = this.height, maxr = 0;
648 
649 		for (int r = 0; r < this.height; r++) {
650 			for (int c = 0; c < this.width; c++) {
651 				if (this.pixels[r][c] > 0) {
652 					if (c < minc)
653 						minc = c;
654 					if (c > maxc)
655 						maxc = c;
656 					if (r < minr)
657 						minr = r;
658 					if (r > maxr)
659 						maxr = r;
660 				}
661 			}
662 		}
663 
664 		return new Rectangle(minc, minr, maxc - minc + 1, maxr - minr + 1);
665 	}
666 
667 	/**
668 	 * Returns the pixels of the image as a vector (array) of doubles.
669 	 *
670 	 * @return the pixels of the image as a vector (array) of doubles.
671 	 */
672 	public double[] getDoublePixelVector()
673 	{
674 		final double f[] = new double[this.height * this.width];
675 		for (int y = 0; y < this.height; y++)
676 			for (int x = 0; x < this.width; x++)
677 				f[x + y * this.width] = this.pixels[y][x];
678 
679 		return f;
680 	}
681 
682 	/**
683 	 * {@inheritDoc}
684 	 *
685 	 * @see org.openimaj.image.Image#getField(org.openimaj.image.Image.Field)
686 	 */
687 	@Override
688 	public FImage getField(final Field f)
689 	{
690 		final FImage img = new FImage(this.width, this.height / 2);
691 
692 		int r, r2, c;
693 		final int init = (f.equals(Field.ODD) ? 1 : 0);
694 		for (r = init, r2 = 0; r < this.height && r2 < this.height / 2; r += 2, r2++)
695 		{
696 			for (c = 0; c < this.width; c++)
697 			{
698 				img.pixels[r2][c] = this.pixels[r][c];
699 			}
700 		}
701 
702 		return img;
703 	}
704 
705 	/**
706 	 * {@inheritDoc}
707 	 *
708 	 * @see org.openimaj.image.Image#getFieldCopy(org.openimaj.image.Image.Field)
709 	 */
710 	@Override
711 	public FImage getFieldCopy(final Field f)
712 	{
713 		final FImage img = new FImage(this.width, this.height);
714 
715 		int r, c;
716 		for (r = 0; r < this.height; r += 2)
717 		{
718 			for (c = 0; c < this.width; c++)
719 			{
720 				if (f.equals(Field.EVEN))
721 				{
722 					img.pixels[r][c] = this.pixels[r][c];
723 					img.pixels[r + 1][c] = this.pixels[r][c];
724 				}
725 				else
726 				{
727 					img.pixels[r][c] = this.pixels[r + 1][c];
728 					img.pixels[r + 1][c] = this.pixels[r + 1][c];
729 				}
730 			}
731 		}
732 
733 		return img;
734 	}
735 
736 	/**
737 	 * {@inheritDoc}
738 	 *
739 	 * @see org.openimaj.image.Image#getFieldInterpolate(org.openimaj.image.Image.Field)
740 	 */
741 	@Override
742 	public FImage getFieldInterpolate(final Field f)
743 	{
744 		final FImage img = new FImage(this.width, this.height);
745 
746 		int r, c;
747 		for (r = 0; r < this.height; r += 2)
748 		{
749 			for (c = 0; c < this.width; c++)
750 			{
751 				if (f.equals(Field.EVEN))
752 				{
753 					img.pixels[r][c] = this.pixels[r][c];
754 
755 					if (r + 2 == this.height)
756 					{
757 						img.pixels[r + 1][c] = this.pixels[r][c];
758 					}
759 					else
760 					{
761 						img.pixels[r + 1][c] = 0.5F * (this.pixels[r][c] + this.pixels[r + 2][c]);
762 					}
763 				}
764 				else
765 				{
766 					img.pixels[r + 1][c] = this.pixels[r + 1][c];
767 
768 					if (r == 0)
769 					{
770 						img.pixels[r][c] = this.pixels[r + 1][c];
771 					}
772 					else
773 					{
774 						img.pixels[r][c] = 0.5F * (this.pixels[r - 1][c] + this.pixels[r + 1][c]);
775 					}
776 				}
777 			}
778 		}
779 
780 		return img;
781 	}
782 
783 	/**
784 	 * Returns the pixels of the image as a vector (array) of floats.
785 	 *
786 	 * @return the pixels of the image as a vector (array) of floats.
787 	 */
788 	public float[] getFloatPixelVector()
789 	{
790 		final float f[] = new float[this.height * this.width];
791 		for (int y = 0; y < this.height; y++)
792 			for (int x = 0; x < this.width; x++)
793 				f[x + y * this.width] = this.pixels[y][x];
794 
795 		return f;
796 	}
797 
798 	/**
799 	 * {@inheritDoc}
800 	 *
801 	 * @see org.openimaj.image.Image#getPixel(int, int)
802 	 */
803 	@Override
804 	public Float getPixel(final int x, final int y)
805 	{
806 		return this.pixels[y][x];
807 	}
808 
809 	/**
810 	 * {@inheritDoc}
811 	 *
812 	 * @see org.openimaj.image.Image#getPixelComparator()
813 	 */
814 	@Override
815 	public Comparator<? super Float> getPixelComparator() {
816 		return new Comparator<Float>() {
817 
818 			@Override
819 			public int compare(final Float o1, final Float o2) {
820 				return o1.compareTo(o2);
821 			}
822 
823 		};
824 	}
825 
826 	/**
827 	 * {@inheritDoc}
828 	 *
829 	 * @see org.openimaj.image.Image#getPixelInterp(double, double)
830 	 * @see Interpolation#bilerp(double, double, double, double, double, double)
831 	 */
832 	@Override
833 	public Float getPixelInterp(final double x, final double y)
834 	{
835 		int x0 = (int) Math.floor(x);
836 		int x1 = x0 + 1;
837 		int y0 = (int) Math.floor(y);
838 		int y1 = y0 + 1;
839 
840 		if (x0 < 0)
841 			x0 = 0;
842 		if (x0 >= this.width)
843 			x0 = this.width - 1;
844 		if (y0 < 0)
845 			y0 = 0;
846 		if (y0 >= this.height)
847 			y0 = this.height - 1;
848 
849 		if (x1 < 0)
850 			x1 = 0;
851 		if (x1 >= this.width)
852 			x1 = this.width - 1;
853 		if (y1 < 0)
854 			y1 = 0;
855 		if (y1 >= this.height)
856 			y1 = this.height - 1;
857 
858 		final float f00 = this.pixels[y0][x0];
859 		final float f01 = this.pixels[y1][x0];
860 		final float f10 = this.pixels[y0][x1];
861 		final float f11 = this.pixels[y1][x1];
862 		float dx = (float) (x - x0);
863 		float dy = (float) (y - y0);
864 		if (dx < 0)
865 			dx = 1 + dx;
866 		if (dy < 0)
867 			dy = 1 + dy;
868 
869 		return Interpolation.bilerp(dx, dy, f00, f01, f10, f11);
870 	}
871 
872 	/**
873 	 * {@inheritDoc}
874 	 *
875 	 * @see org.openimaj.image.Image#getPixelInterp(double, double)
876 	 * @see Interpolation#bilerp(double, double, double, double, double, double)
877 	 */
878 	@Override
879 	public Float getPixelInterp(final double x, final double y, final Float background)
880 	{
881 		final int x0 = (int) Math.floor(x);
882 		final int x1 = x0 + 1;
883 		final int y0 = (int) Math.floor(y);
884 		final int y1 = y0 + 1;
885 
886 		boolean tx0, tx1, ty0, ty1;
887 		tx0 = ty0 = tx1 = ty1 = true;
888 		if (x0 < 0)
889 			tx0 = false;
890 		if (x0 >= this.width)
891 			tx0 = false;
892 		if (y0 < 0)
893 			ty0 = false;
894 		if (y0 >= this.height)
895 			ty0 = false;
896 
897 		if (x1 < 0)
898 			tx1 = false;
899 		if (x1 >= this.width)
900 			tx1 = false;
901 		if (y1 < 0)
902 			ty1 = false;
903 		if (y1 >= this.height)
904 			ty1 = false;
905 
906 		final double f00 = (ty0 && tx0 ? this.pixels[y0][x0] : background.floatValue()); // this.pixels[y0][x0];
907 		final double f01 = (ty1 && tx0 ? this.pixels[y1][x0] : background.floatValue()); // this.pixels[y1][x0];
908 		final double f10 = (ty0 && tx1 ? this.pixels[y0][x1] : background.floatValue()); // this.pixels[y0][x1];
909 		final double f11 = (ty1 && tx1 ? this.pixels[y1][x1] : background.floatValue()); // this.pixels[y1][x1];
910 
911 		double dx = x - x0;
912 		double dy = y - y0;
913 		if (dx < 0)
914 			dx = 1 + dx;
915 		if (dy < 0)
916 			dy = 1 + dy;
917 
918 		final double interpVal = Interpolation.bilerp(dx, dy, f00, f01, f10, f11);
919 		return (float) interpVal;
920 	}
921 
922 	/**
923 	 * Interpolate the value of a pixel at the given coordinates
924 	 *
925 	 * @param x
926 	 *            the x-ordinate
927 	 * @param y
928 	 *            the y-ordinate
929 	 * @param background
930 	 *            the background colour
931 	 * @return the interpolated pixel value
932 	 * @see org.openimaj.image.Image#getPixelInterp(double, double)
933 	 * @see Interpolation#bilerp(double, double, double, double, double, double)
934 	 */
935 	public float getPixelInterpNative(final float x, final float y, final float background)
936 	{
937 		final int x0 = (int) Math.floor(x);
938 		final int x1 = x0 + 1;
939 		final int y0 = (int) Math.floor(y);
940 		final int y1 = y0 + 1;
941 
942 		boolean tx0, tx1, ty0, ty1;
943 		tx0 = ty0 = tx1 = ty1 = true;
944 		if (x0 < 0)
945 			tx0 = false;
946 		if (x0 >= this.width)
947 			tx0 = false;
948 		if (y0 < 0)
949 			ty0 = false;
950 		if (y0 >= this.height)
951 			ty0 = false;
952 
953 		if (x1 < 0)
954 			tx1 = false;
955 		if (x1 >= this.width)
956 			tx1 = false;
957 		if (y1 < 0)
958 			ty1 = false;
959 		if (y1 >= this.height)
960 			ty1 = false;
961 
962 		final float f00 = (ty0 && tx0 ? this.pixels[y0][x0] : background); // this.pixels[y0][x0];
963 		final float f01 = (ty1 && tx0 ? this.pixels[y1][x0] : background); // this.pixels[y1][x0];
964 		final float f10 = (ty0 && tx1 ? this.pixels[y0][x1] : background); // this.pixels[y0][x1];
965 		final float f11 = (ty1 && tx1 ? this.pixels[y1][x1] : background); // this.pixels[y1][x1];
966 
967 		float dx = x - x0;
968 		float dy = y - y0;
969 		if (dx < 0)
970 			dx = 1 + dx;
971 		if (dy < 0)
972 			dy = 1 + dy;
973 
974 		final float interpVal = Interpolation.bilerpf(dx, dy, f00, f01, f10, f11);
975 		return interpVal;
976 	}
977 
978 	/**
979 	 * {@inheritDoc}
980 	 *
981 	 * @see org.openimaj.image.Image#internalAssign(org.openimaj.image.Image)
982 	 */
983 	@Override
984 	public FImage internalCopy(final FImage im)
985 	{
986 		final int h = im.height;
987 		final int w = im.width;
988 		final float[][] impixels = im.pixels;
989 
990 		for (int r = 0; r < h; r++)
991 			System.arraycopy(impixels[r], 0, this.pixels[r], 0, w);
992 
993 		return this;
994 	}
995 
996 	/**
997 	 * {@inheritDoc}
998 	 *
999 	 * @see org.openimaj.image.Image#internalAssign(org.openimaj.image.Image)
1000 	 */
1001 	@Override
1002 	public FImage internalAssign(final FImage im)
1003 	{
1004 		this.pixels = im.pixels;
1005 		this.height = im.height;
1006 		this.width = im.width;
1007 
1008 		return this;
1009 	}
1010 
1011 	/**
1012 	 * {@inheritDoc}
1013 	 *
1014 	 * @see org.openimaj.image.Image#internalAssign(int [] data, int width, int
1015 	 *      height)
1016 	 */
1017 	@Override
1018 	public FImage internalAssign(final int[] data, final int width, final int height) {
1019 		if (this.height != height || this.width != width) {
1020 			this.height = height;
1021 			this.width = width;
1022 			this.pixels = new float[height][width];
1023 		}
1024 
1025 		for (int y = 0; y < height; y++) {
1026 			for (int x = 0; x < width; x++) {
1027 				final int rgb = data[x + width * y];
1028 
1029 				final int red = ((rgb >> 16) & 0xff);
1030 				final int green = ((rgb >> 8) & 0xff);
1031 				final int blue = ((rgb) & 0xff);
1032 
1033 				// NTSC colour conversion:
1034 				// This improves keypoint detection for some reason!
1035 				final float fpix = 0.299f * red + 0.587f * green + 0.114f * blue;
1036 
1037 				this.pixels[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[(int) fpix];
1038 			}
1039 		}
1040 		return this;
1041 	}
1042 
1043 	/**
1044 	 * {@inheritDoc}
1045 	 *
1046 	 * @see org.openimaj.image.Image#inverse()
1047 	 */
1048 	@Override
1049 	public FImage inverse()
1050 	{
1051 		int r, c;
1052 		final float max = this.max();
1053 
1054 		for (r = 0; r < this.height; r++)
1055 			for (c = 0; c < this.width; c++)
1056 				this.pixels[r][c] = max - this.pixels[r][c];
1057 
1058 		return this;
1059 	}
1060 
1061 	/**
1062 	 * {@inheritDoc}
1063 	 *
1064 	 * @see org.openimaj.image.Image#max()
1065 	 */
1066 	@Override
1067 	public Float max()
1068 	{
1069 		int r, c;
1070 		float max = Float.MIN_VALUE;
1071 
1072 		for (r = 0; r < this.height; r++)
1073 			for (c = 0; c < this.width; c++)
1074 				if (max < this.pixels[r][c])
1075 					max = this.pixels[r][c];
1076 
1077 		return max;
1078 	}
1079 
1080 	/**
1081 	 * Get the pixel with the maximum value. Returns an {@link FValuePixel}
1082 	 * which contains the location and value of the pixel. If there are multiple
1083 	 * pixels with the same value then the first is returned. Note that this
1084 	 * method assumes all pixel values are greater than 0.
1085 	 *
1086 	 * @return the maximum pixel as an {@link FValuePixel}.
1087 	 */
1088 	public FValuePixel maxPixel()
1089 	{
1090 		final FValuePixel max = new FValuePixel(-1, -1);
1091 		max.value = -Float.MAX_VALUE;
1092 
1093 		for (int y = 0; y < this.height; y++) {
1094 			for (int x = 0; x < this.width; x++) {
1095 				if (max.value < this.pixels[y][x]) {
1096 					max.value = this.pixels[y][x];
1097 					max.x = x;
1098 					max.y = y;
1099 				}
1100 			}
1101 		}
1102 
1103 		return max;
1104 	}
1105 
1106 	/**
1107 	 * {@inheritDoc}
1108 	 *
1109 	 * @see org.openimaj.image.Image#min()
1110 	 */
1111 	@Override
1112 	public Float min()
1113 	{
1114 		int r, c;
1115 		float min = Float.MAX_VALUE;
1116 
1117 		for (r = 0; r < this.height; r++)
1118 			for (c = 0; c < this.width; c++)
1119 				if (min > this.pixels[r][c])
1120 					min = this.pixels[r][c];
1121 
1122 		return min;
1123 	}
1124 
1125 	/**
1126 	 * Get the pixel with the minimum value. Returns an {@link FValuePixel}
1127 	 * which contains the location and value of the pixel. If there are multiple
1128 	 * pixels with the same value then the first is returned. Note that this
1129 	 * method assumes all pixel values are greater than 0.
1130 	 *
1131 	 * @return The minimum pixel as an {@link FValuePixel}.
1132 	 */
1133 	public FValuePixel minPixel()
1134 	{
1135 		final FValuePixel min = new FValuePixel(-1, -1);
1136 		min.value = Float.MAX_VALUE;
1137 
1138 		for (int y = 0; y < this.height; y++)
1139 			for (int x = 0; x < this.width; x++)
1140 				if (min.value > this.pixels[y][x]) {
1141 					min.value = this.pixels[y][x];
1142 					min.x = x;
1143 					min.y = y;
1144 				}
1145 
1146 		return min;
1147 	}
1148 
1149 	/**
1150 	 * {@inheritDoc}
1151 	 *
1152 	 * @see org.openimaj.image.Image#multiply(java.lang.Object)
1153 	 */
1154 	@Override
1155 	public FImage multiply(final Float num)
1156 	{
1157 		return super.multiply(num);
1158 	}
1159 
1160 	/**
1161 	 * Multiplies this image's pixel values by the corresponding pixel values in
1162 	 * the given image side-affecting this image. This is a version of
1163 	 * {@link Image#multiplyInplace(Image)} which takes an {@link FImage}. This
1164 	 * directly accesses the underlying float[][] and is therefore fast. This
1165 	 * function works inplace.
1166 	 *
1167 	 * @see Image#multiplyInplace(Image)
1168 	 * @param im
1169 	 *            the {@link FImage} to multiply with this image
1170 	 * @return a reference to this image
1171 	 */
1172 	public FImage multiplyInplace(final FImage im)
1173 	{
1174 		if (!ImageUtilities.checkSameSize(this, im))
1175 			throw new AssertionError("images must be the same size");
1176 
1177 		for (int r = 0; r < this.height; r++)
1178 		{
1179 			for (int c = 0; c < this.width; c++)
1180 			{
1181 				this.pixels[r][c] *= im.pixels[r][c];
1182 			}
1183 		}
1184 
1185 		return this;
1186 	}
1187 
1188 	/**
1189 	 * {@inheritDoc}
1190 	 *
1191 	 * @see org.openimaj.image.Image#multiplyInplace(java.lang.Object)
1192 	 */
1193 	@Override
1194 	public FImage multiplyInplace(final Float num)
1195 	{
1196 		final float fnum = num;
1197 		for (int r = 0; r < this.height; r++)
1198 		{
1199 			for (int c = 0; c < this.width; c++)
1200 			{
1201 				this.pixels[r][c] *= fnum;
1202 			}
1203 		}
1204 
1205 		return this;
1206 	}
1207 
1208 	/**
1209 	 * Multiply all pixel values by the given value
1210 	 *
1211 	 * @param fnum
1212 	 *            the value
1213 	 * @return this image
1214 	 * @see org.openimaj.image.Image#multiplyInplace(java.lang.Object)
1215 	 */
1216 	public FImage multiplyInplace(final float fnum)
1217 	{
1218 		for (int r = 0; r < this.height; r++)
1219 		{
1220 			for (int c = 0; c < this.width; c++)
1221 			{
1222 				this.pixels[r][c] *= fnum;
1223 			}
1224 		}
1225 
1226 		return this;
1227 	}
1228 
1229 	/**
1230 	 * {@inheritDoc} This method will throw an
1231 	 * {@link UnsupportedOperationException} if the input input is not an
1232 	 * {@link FImage}.
1233 	 *
1234 	 * @see org.openimaj.image.Image#multiplyInplace(org.openimaj.image.Image)
1235 	 * @throws UnsupportedOperationException
1236 	 *             if the given image is not an {@link FImage}
1237 	 */
1238 	@Override
1239 	public FImage multiplyInplace(final Image<?, ?> im)
1240 	{
1241 		if (im instanceof FImage)
1242 			return this.multiplyInplace((FImage) im);
1243 		else
1244 			throw new UnsupportedOperationException("Unsupported Type");
1245 	}
1246 
1247 	/**
1248 	 * {@inheritDoc}
1249 	 *
1250 	 * @return A new {@link FImage}
1251 	 * @see org.openimaj.image.Image#newInstance(int, int)
1252 	 */
1253 	@Override
1254 	public FImage newInstance(final int width, final int height)
1255 	{
1256 		return new FImage(width, height);
1257 	}
1258 
1259 	/**
1260 	 * {@inheritDoc}
1261 	 *
1262 	 * @see org.openimaj.image.Image#normalise()
1263 	 */
1264 	@Override
1265 	public FImage normalise()
1266 	{
1267 		final float min = this.min();
1268 		final float max = this.max();
1269 
1270 		if (max == min)
1271 			return this;
1272 
1273 		for (int r = 0; r < this.height; r++)
1274 		{
1275 			for (int c = 0; c < this.width; c++)
1276 			{
1277 				this.pixels[r][c] = (this.pixels[r][c] - min) / (max - min);
1278 			}
1279 		}
1280 
1281 		return this;
1282 	}
1283 
1284 	/**
1285 	 * {@inheritDoc}
1286 	 *
1287 	 * @see org.openimaj.image.SingleBandImage#process(org.openimaj.image.processor.KernelProcessor)
1288 	 */
1289 	@Override
1290 	public FImage process(final KernelProcessor<Float, FImage> p) {
1291 		return this.process(p, false);
1292 	}
1293 
1294 	/**
1295 	 * {@inheritDoc} This method has been overridden in {@link FImage} for
1296 	 * performance.
1297 	 *
1298 	 * @see org.openimaj.image.SingleBandImage#process(org.openimaj.image.processor.KernelProcessor,
1299 	 *      boolean)
1300 	 */
1301 	@Override
1302 	public FImage process(final KernelProcessor<Float, FImage> p, final boolean pad)
1303 	{
1304 		final FImage newImage = new FImage(this.width, this.height);
1305 		final int kh = p.getKernelHeight();
1306 		final int kw = p.getKernelWidth();
1307 
1308 		final FImage tmp = new FImage(kw, kh);
1309 
1310 		final int hh = kh / 2;
1311 		final int hw = kw / 2;
1312 
1313 		if (!pad) {
1314 			for (int y = hh; y < this.height - (kh - hh); y++) {
1315 				for (int x = hw; x < this.width - (kw - hw); x++) {
1316 					newImage.pixels[y][x] = p.processKernel(this.extractROI(x - hw, y - hh, tmp));
1317 				}
1318 			}
1319 		} else {
1320 			for (int y = 0; y < this.height; y++) {
1321 				for (int x = 0; x < this.width; x++) {
1322 					newImage.pixels[y][x] = p.processKernel(this.extractROI(x - hw, y - hh, tmp));
1323 				}
1324 			}
1325 		}
1326 
1327 		return newImage;
1328 	}
1329 
1330 	/**
1331 	 * {@inheritDoc} This method has been overridden in {@link FImage} for
1332 	 * performance.
1333 	 *
1334 	 * @see org.openimaj.image.Image#processInplace(org.openimaj.image.processor.PixelProcessor)
1335 	 */
1336 	@Override
1337 	public FImage processInplace(final PixelProcessor<Float> p)
1338 	{
1339 		for (int y = 0; y < this.height; y++)
1340 		{
1341 			for (int x = 0; x < this.width; x++)
1342 			{
1343 				this.pixels[y][x] = p.processPixel(this.pixels[y][x]);
1344 			}
1345 		}
1346 
1347 		return this;
1348 	}
1349 
1350 	/**
1351 	 * {@inheritDoc} This method has been overridden in {@link FImage} for
1352 	 * performance.
1353 	 *
1354 	 * @see org.openimaj.image.Image#analyseWith(org.openimaj.image.analyser.PixelAnalyser)
1355 	 */
1356 	@Override
1357 	public void analyseWith(final PixelAnalyser<Float> p)
1358 	{
1359 		p.reset();
1360 
1361 		for (int y = 0; y < this.height; y++)
1362 		{
1363 			for (int x = 0; x < this.width; x++)
1364 			{
1365 				p.analysePixel(this.pixels[y][x]);
1366 			}
1367 		}
1368 	}
1369 
1370 	/**
1371 	 * {@inheritDoc}
1372 	 *
1373 	 * @see org.openimaj.image.Image#setPixel(int, int, java.lang.Object)
1374 	 */
1375 	@Override
1376 	public void setPixel(final int x, final int y, final Float val) {
1377 		if (x >= 0 && x < this.width && y >= 0 && y < this.height)
1378 			this.pixels[y][x] = val;
1379 	}
1380 
1381 	/**
1382 	 * Subtracts the given {@link FImage} from this image returning a new image
1383 	 * containing the result.
1384 	 *
1385 	 * @param im
1386 	 *            The image to subtract from this image.
1387 	 * @return A new image containing the result.
1388 	 */
1389 	public FImage subtract(final FImage im)
1390 	{
1391 		if (!ImageUtilities.checkSameSize(this, im))
1392 			throw new AssertionError("images must be the same size");
1393 
1394 		final FImage newImage = new FImage(im.width, im.height);
1395 		int r, c;
1396 
1397 		for (r = 0; r < im.height; r++)
1398 			for (c = 0; c < im.width; c++)
1399 				newImage.pixels[r][c] = this.pixels[r][c] - im.pixels[r][c];
1400 		return newImage;
1401 	}
1402 
1403 	/**
1404 	 * {@inheritDoc}
1405 	 *
1406 	 * @see org.openimaj.image.Image#subtract(java.lang.Object)
1407 	 */
1408 	@Override
1409 	public FImage subtract(final Float num)
1410 	{
1411 		final FImage newImage = new FImage(this.width, this.height);
1412 
1413 		for (int r = 0; r < this.height; r++)
1414 		{
1415 			for (int c = 0; c < this.width; c++)
1416 			{
1417 				newImage.pixels[r][c] = this.pixels[r][c] - num;
1418 			}
1419 		}
1420 		return newImage;
1421 	}
1422 
1423 	/**
1424 	 * {@inheritDoc} Throws an {@link UnsupportedOperationException} if the
1425 	 * given image is not an {@link FImage}.
1426 	 *
1427 	 * @see org.openimaj.image.Image#subtract(org.openimaj.image.Image)
1428 	 * @throws UnsupportedOperationException
1429 	 *             if the given image is not an {@link FImage}.
1430 	 */
1431 	@Override
1432 	public FImage subtract(final Image<?, ?> input)
1433 	{
1434 		if (input instanceof FImage)
1435 			return this.subtract((FImage) input);
1436 		else
1437 			throw new UnsupportedOperationException("Unsupported Type");
1438 	}
1439 
1440 	/**
1441 	 * Subtracts (pixel-by-pixel) the given {@link FImage} from this image.
1442 	 * Side-affects this image.
1443 	 *
1444 	 * @param im
1445 	 *            The {@link FImage} to subtract from this image.
1446 	 * @return A reference to this image containing the result.
1447 	 */
1448 	public FImage subtractInplace(final FImage im)
1449 	{
1450 		if (!ImageUtilities.checkSameSize(this, im))
1451 			throw new AssertionError("images must be the same size");
1452 
1453 		float pix1[][], pix2[][];
1454 		int r, c;
1455 
1456 		pix1 = this.pixels;
1457 		pix2 = im.pixels;
1458 
1459 		for (r = 0; r < this.height; r++)
1460 			for (c = 0; c < this.width; c++)
1461 				pix1[r][c] -= pix2[r][c];
1462 
1463 		return this;
1464 	}
1465 
1466 	/**
1467 	 * {@inheritDoc}
1468 	 *
1469 	 * @see org.openimaj.image.Image#subtractInplace(java.lang.Object)
1470 	 */
1471 	@Override
1472 	public FImage subtractInplace(final Float num)
1473 	{
1474 		final float fnum = num;
1475 		for (int r = 0; r < this.height; r++)
1476 		{
1477 			for (int c = 0; c < this.width; c++)
1478 			{
1479 				this.pixels[r][c] -= fnum;
1480 			}
1481 		}
1482 
1483 		return this;
1484 	}
1485 
1486 	/**
1487 	 * {@inheritDoc}
1488 	 *
1489 	 * @see org.openimaj.image.Image#subtractInplace(org.openimaj.image.Image)
1490 	 */
1491 	@Override
1492 	public FImage subtractInplace(final Image<?, ?> im)
1493 	{
1494 		if (im instanceof FImage)
1495 			return this.subtractInplace((FImage) im);
1496 		else
1497 			throw new UnsupportedOperationException("Unsupported Type");
1498 	}
1499 
1500 	/**
1501 	 * {@inheritDoc}
1502 	 *
1503 	 * @see org.openimaj.image.Image#threshold(java.lang.Object)
1504 	 */
1505 	@Override
1506 	public FImage threshold(final Float thresh)
1507 	{
1508 		final float fthresh = thresh;
1509 		for (int r = 0; r < this.height; r++)
1510 		{
1511 			for (int c = 0; c < this.width; c++)
1512 			{
1513 				if (this.pixels[r][c] <= fthresh)
1514 					this.pixels[r][c] = 0;
1515 				else
1516 					this.pixels[r][c] = 1;
1517 			}
1518 		}
1519 		return this;
1520 	}
1521 
1522 	/**
1523 	 * {@inheritDoc}
1524 	 *
1525 	 * @see org.openimaj.image.Image#toByteImage()
1526 	 */
1527 	@Override
1528 	public byte[] toByteImage()
1529 	{
1530 		final byte[] pgmData = new byte[this.height * this.width];
1531 
1532 		for (int j = 0; j < this.height; j++)
1533 		{
1534 			for (int i = 0; i < this.width; i++)
1535 			{
1536 				int v = (int) (255.0f * this.pixels[j][i]);
1537 
1538 				v = Math.max(0, Math.min(255, v));
1539 
1540 				pgmData[i + j * this.width] = (byte) (v & 0xFF);
1541 			}
1542 		}
1543 		return pgmData;
1544 	}
1545 
1546 	/**
1547 	 * {@inheritDoc}
1548 	 *
1549 	 * @see org.openimaj.image.Image#toPackedARGBPixels()
1550 	 */
1551 	@Override
1552 	public int[] toPackedARGBPixels()
1553 	{
1554 		final int[] bimg = new int[this.width * this.height];
1555 
1556 		for (int r = 0; r < this.height; r++) {
1557 			for (int c = 0; c < this.width; c++) {
1558 				final int v = (Math.max(0, Math.min(255, (int) (this.pixels[r][c] * 255))));
1559 
1560 				final int rgb = 0xff << 24 | v << 16 | v << 8 | v;
1561 				bimg[c + this.width * r] = rgb;
1562 			}
1563 		}
1564 
1565 		return bimg;
1566 	}
1567 
1568 	/**
1569 	 * {@inheritDoc}
1570 	 *
1571 	 * @see java.lang.Object#toString()
1572 	 */
1573 	@Override
1574 	public String toString() {
1575 		String imageString = "";
1576 		for (int y = 0; y < this.height; y++) {
1577 			for (int x = 0; x < this.width; x++) {
1578 				imageString += String.format("%+.3f ", this.pixels[y][x]);
1579 				if (x == 16) {
1580 					if (this.width - 16 <= x)
1581 						continue;
1582 					imageString += "... ";
1583 					x = this.width - 16;
1584 				}
1585 			}
1586 			imageString += "\n";
1587 			if (y == 16) {
1588 				if (this.height - 16 <= y)
1589 					continue;
1590 				y = this.height - 16;
1591 				imageString += "... \n";
1592 			}
1593 
1594 		}
1595 		return imageString;
1596 	}
1597 
1598 	/**
1599 	 * Returns a string representation of every pixel in this image using the
1600 	 * format string (see {@link String#format(String, Object...)}) to format
1601 	 * each pixel value.
1602 	 *
1603 	 * @param format
1604 	 *            The format string to use for each pixel output
1605 	 * @return A string representation of the image
1606 	 * @see String#format(String, Object...)
1607 	 */
1608 	public String toString(final String format) {
1609 		String imageString = "";
1610 		for (int y = 0; y < this.height; y++) {
1611 			for (int x = 0; x < this.width; x++) {
1612 				imageString += String.format(format, this.pixels[y][x]);
1613 			}
1614 			imageString += "\n";
1615 		}
1616 		return imageString;
1617 	}
1618 
1619 	/**
1620 	 * {@inheritDoc}
1621 	 *
1622 	 * @see org.openimaj.image.Image#transform(Jama.Matrix)
1623 	 */
1624 	@Override
1625 	public FImage transform(final Matrix transform) {
1626 		return super.transform(transform);
1627 	}
1628 
1629 	/**
1630 	 * {@inheritDoc}
1631 	 *
1632 	 * @see org.openimaj.image.Image#zero()
1633 	 */
1634 	@Override
1635 	public FImage zero()
1636 	{
1637 		for (int r = 0; r < this.height; r++)
1638 		{
1639 			for (int c = 0; c < this.width; c++)
1640 			{
1641 				this.pixels[r][c] = 0;
1642 			}
1643 		}
1644 		return this;
1645 	}
1646 
1647 	@Override
1648 	public boolean equals(final Object o) {
1649 		if (!(o instanceof FImage)) {
1650 			return false;
1651 		}
1652 		return this.equalsThresh((FImage) o, 0);
1653 	}
1654 
1655 	/**
1656 	 * Compare this image against another using a threshold on the absolute
1657 	 * difference between pixel values in order to determine equality.
1658 	 *
1659 	 * @param o
1660 	 *            the image to compare against
1661 	 * @param thresh
1662 	 *            the threshold for determining equality
1663 	 * @return true images are the same size and if all pixel values have a
1664 	 *         difference less than threshold; false otherwise.
1665 	 */
1666 	public boolean equalsThresh(final FImage o, final float thresh) {
1667 		final FImage that = o;
1668 		if (that.height != this.height || that.width != this.width)
1669 			return false;
1670 		for (int i = 0; i < this.height; i++) {
1671 			for (int j = 0; j < this.width; j++) {
1672 				if (Math.abs(that.pixels[i][j] - this.pixels[i][j]) > thresh) {
1673 					return false;
1674 				}
1675 			}
1676 		}
1677 		return true;
1678 	}
1679 
1680 	/**
1681 	 * Get the value of the pixel at coordinate p
1682 	 *
1683 	 * @param p
1684 	 *            The coordinate to get
1685 	 *
1686 	 * @return The pixel value at (x, y)
1687 	 */
1688 	public float getPixelNative(final Pixel p) {
1689 		return this.getPixelNative(p.x, p.y);
1690 	}
1691 
1692 	/**
1693 	 * Get the value of the pixel at coordinate <code>(x, y)</code>.
1694 	 *
1695 	 * @param x
1696 	 *            The x-coordinate to get
1697 	 * @param y
1698 	 *            The y-coordinate to get
1699 	 *
1700 	 * @return The pixel value at (x, y)
1701 	 */
1702 	public float getPixelNative(final int x, final int y) {
1703 		return this.pixels[y][x];
1704 	}
1705 
1706 	/**
1707 	 * Returns the pixels in this image as a vector (an array of the pixel
1708 	 * type).
1709 	 *
1710 	 * @param f
1711 	 *            The array into which to place the data
1712 	 * @return The pixels in the image as a vector (a reference to the given
1713 	 *         array).
1714 	 */
1715 	public float[] getPixelVectorNative(final float[] f)
1716 	{
1717 		for (int y = 0; y < this.getHeight(); y++)
1718 			for (int x = 0; x < this.getWidth(); x++)
1719 				f[x + y * this.getWidth()] = this.pixels[y][x];
1720 
1721 		return f;
1722 	}
1723 
1724 	/**
1725 	 * Sets the pixel at <code>(x,y)</code> to the given value. Side-affects
1726 	 * this image.
1727 	 *
1728 	 * @param x
1729 	 *            The x-coordinate of the pixel to set
1730 	 * @param y
1731 	 *            The y-coordinate of the pixel to set
1732 	 * @param val
1733 	 *            The value to set the pixel to.
1734 	 */
1735 	public void setPixelNative(final int x, final int y, final float val) {
1736 		this.pixels[y][x] = val;
1737 	}
1738 
1739 	/**
1740 	 * Convenience method to initialise an array of FImages
1741 	 *
1742 	 * @param num
1743 	 *            array length
1744 	 * @param width
1745 	 *            width of images
1746 	 * @param height
1747 	 *            height of images
1748 	 * @return array of newly initialised images
1749 	 */
1750 	public static FImage[] createArray(final int num, final int width, final int height) {
1751 		final FImage[] array = new FImage[num];
1752 
1753 		for (int i = 0; i < num; i++) {
1754 			array[i] = new FImage(width, height);
1755 		}
1756 
1757 		return array;
1758 	}
1759 
1760 	/**
1761 	 * @return The sum of all the pixels in the image
1762 	 */
1763 	public float sum() {
1764 		float sum = 0;
1765 		for (final float[] row : this.pixels) {
1766 			for (int i = 0; i < row.length; i++) {
1767 				sum += row[i];
1768 			}
1769 		}
1770 		return sum;
1771 	}
1772 
1773 	/**
1774 	 * Convert this {@link FImage} to an RGB {@link MBFImage}.
1775 	 *
1776 	 * @return a new RGB colour image.
1777 	 */
1778 	public MBFImage toRGB() {
1779 		return new MBFImage(ColourSpace.RGB, this.clone(), this.clone(), this.clone());
1780 	}
1781 
1782 	@Override
1783 	public FImage flipX() {
1784 		final int hwidth = this.width / 2;
1785 
1786 		for (int y = 0; y < this.height; y++) {
1787 			for (int x = 0; x < hwidth; x++) {
1788 				final int xx = this.width - x - 1;
1789 
1790 				final float tmp = this.pixels[y][x];
1791 
1792 				this.pixels[y][x] = this.pixels[y][xx];
1793 				this.pixels[y][xx] = tmp;
1794 			}
1795 		}
1796 		return this;
1797 	}
1798 
1799 	@Override
1800 	public FImage flipY() {
1801 		final int hheight = this.height / 2;
1802 
1803 		for (int y = 0; y < hheight; y++) {
1804 			final int yy = this.height - y - 1;
1805 
1806 			for (int x = 0; x < this.width; x++) {
1807 				final float tmp = this.pixels[y][x];
1808 
1809 				this.pixels[y][x] = this.pixels[yy][x];
1810 				this.pixels[yy][x] = tmp;
1811 			}
1812 		}
1813 
1814 		return this;
1815 	}
1816 
1817 	/**
1818 	 * Overlay the given image on this image with the given alpha channel at the
1819 	 * given location.
1820 	 *
1821 	 * @param img
1822 	 *            The image to overlay
1823 	 * @param alpha
1824 	 *            The alpha channel to use
1825 	 * @param x
1826 	 *            The location to draw the image
1827 	 * @param y
1828 	 *            The location to draw the image
1829 	 * @return This image with the overlay on it
1830 	 */
1831 	public FImage overlayInplace(final FImage img, final FImage alpha, final int x, final int y)
1832 	{
1833 		final int sx = Math.max(x, 0);
1834 		final int sy = Math.max(y, 0);
1835 		final int ex = Math.min(this.width, x + img.getWidth());
1836 		final int ey = Math.min(this.height, y + img.getHeight());
1837 
1838 		for (int yc = sy; yc < ey; yc++)
1839 		{
1840 			for (int xc = sx; xc < ex; xc++)
1841 			{
1842 				final float a = alpha.pixels[yc - sy][xc - sx];
1843 				this.pixels[yc][xc] = (a * img.pixels[yc - sy][xc - sx] +
1844 						(1 - a) * this.pixels[yc][xc]);
1845 			}
1846 		}
1847 
1848 		return this;
1849 	}
1850 
1851 	/**
1852 	 * {@inheritDoc}
1853 	 * <p>
1854 	 * This method will overlay the given image at the given location with full
1855 	 * opacity.
1856 	 *
1857 	 * @see org.openimaj.image.Image#overlayInplace(org.openimaj.image.Image,
1858 	 *      int, int)
1859 	 */
1860 	@Override
1861 	public FImage overlayInplace(final FImage image, final int x, final int y)
1862 	{
1863 		return this.overlayInplace(image, this.clone().fill(1f), x, y);
1864 	}
1865 
1866 	/**
1867 	 * Create a random image of the given size.
1868 	 *
1869 	 * @param width
1870 	 *            the width
1871 	 * @param height
1872 	 *            the height
1873 	 * @return the image
1874 	 */
1875 	public static FImage randomImage(final int width, final int height) {
1876 		final FImage img = new FImage(width, height);
1877 
1878 		for (int y = 0; y < height; y++)
1879 			for (int x = 0; x < width; x++)
1880 				img.pixels[y][x] = (float) Math.random();
1881 
1882 		return img;
1883 	}
1884 
1885 	@Override
1886 	public FImage replace(Float target, Float replacement) {
1887 		return replace((float) target, (float) replacement);
1888 	}
1889 
1890 	/**
1891 	 * Replace pixels of a certain colour with another colour. Side-affects this
1892 	 * image.
1893 	 *
1894 	 * @param target
1895 	 *            the colour to fill the image with
1896 	 * @param replacement
1897 	 *            the colour to fill the image with
1898 	 * @return A reference to this image.
1899 	 */
1900 	public FImage replace(float target, float replacement) {
1901 		for (int r = 0; r < this.height; r++)
1902 			for (int c = 0; c < this.width; c++)
1903 				if (this.pixels[r][c] == target)
1904 					this.pixels[r][c] = replacement;
1905 
1906 		return this;
1907 	}
1908 
1909 	@Override
1910 	public FImage extractCentreSubPix(float cx, float cy, FImage out) {
1911 		final int width = out.width;
1912 		final int height = out.height;
1913 		for (int y = 0; y < height; y++) {
1914 			for (int x = 0; x < width; x++) {
1915 				final float ix = (float) (x + cx - (width - 1) * 0.5);
1916 				final float iy = (float) (y + cy - (height - 1) * 0.5);
1917 				out.pixels[y][x] = this.getPixelInterpNative(ix, iy, 0f);
1918 			}
1919 		}
1920 		return out;
1921 	}
1922 }