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.renderer;
31  
32  import java.util.Arrays;
33  
34  import org.openimaj.image.FImage;
35  import org.openimaj.image.ImageUtilities;
36  import org.openimaj.image.MBFImage;
37  
38  /**
39   * {@link ImageRenderer} for {@link MBFImage} images.
40   *
41   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
42   *
43   */
44  public class MBFImageRenderer extends MultiBandRenderer<Float, MBFImage, FImage> {
45  
46  	/**
47  	 * Construct with given target image.
48  	 *
49  	 * @param targetImage
50  	 *            the target image.
51  	 */
52  	public MBFImageRenderer(final MBFImage targetImage) {
53  		super(targetImage);
54  	}
55  
56  	/**
57  	 * Construct with given target image and rendering hints.
58  	 *
59  	 * @param targetImage
60  	 *            the target image.
61  	 * @param hints
62  	 *            the render hints
63  	 */
64  	public MBFImageRenderer(final MBFImage targetImage, final RenderHints hints) {
65  		super(targetImage, hints);
66  	}
67  
68  	@Override
69  	public Float[] defaultBackgroundColour() {
70  		return new Float[this.targetImage.numBands()];
71  	}
72  
73  	@Override
74  	public Float[] defaultForegroundColour() {
75  		final Float[] c = new Float[this.targetImage.numBands()];
76  		Arrays.fill(c, 1f);
77  		return c;
78  	}
79  
80  	/**
81  	 * Draw the provided image at the given coordinates. Parts of the image
82  	 * outside the bounds of this image will be ignored
83  	 *
84  	 * @param image
85  	 *            Image to draw.
86  	 * @param x
87  	 *            x-coordinate
88  	 * @param y
89  	 *            y-coordinate
90  	 */
91  	@Override
92  	public void drawImage(final MBFImage image, final int x, final int y) {
93  		final int targetBands = this.targetImage.numBands();
94  		final int imageBands = image.numBands();
95  
96  		if (targetBands == imageBands && targetBands == 3) {
97  			this.drawImage3(image, x, y);
98  			return;
99  		} else if (targetBands < 3 || targetBands > 4 || imageBands < 3 || imageBands > 4) {
100 			super.drawImage(image, x, y);
101 			return;
102 		}
103 
104 		final int stopx = Math.min(this.targetImage.getWidth(), x + image.getWidth());
105 		final int stopy = Math.min(this.targetImage.getHeight(), y + image.getHeight());
106 		final int startx = Math.max(0, x);
107 		final int starty = Math.max(0, y);
108 
109 		final float[][][] thisPixels = new float[targetBands][][];
110 		for (int i = 0; i < thisPixels.length; i++)
111 			thisPixels[i] = this.targetImage.getBand(i).pixels;
112 
113 		final float[][][] thatPixels = new float[imageBands][][];
114 		for (int i = 0; i < thatPixels.length; i++)
115 			thatPixels[i] = image.getBand(i).pixels;
116 
117 		/**
118 		 * If either image is 4 channel then we deal with the alpha channel
119 		 * correctly. Basically you add together the pixel values such that the
120 		 * pixel on top dominates (i.e. the image being added)
121 		 */
122 //		final float thisA = 1.0f, thatA = 1.0f, thisR, thisG, thisB, thatR, thatG, thatB, a, r, g, b;
123 		if(thisPixels.length == 4 && thatPixels.length == 4){
124 			drawBothAlpha(x, y, stopx, stopy, startx, starty, thisPixels, thatPixels);
125 		} else if (thisPixels.length == 4){
126 			drawThisAlpha(x, y, stopx, stopy, startx, starty, thisPixels, thatPixels);
127 		} else{
128 			drawThatAlpha(x, y, stopx, stopy, startx, starty, thisPixels, thatPixels);
129 		}
130 	}
131 
132 	private void drawBothAlpha(final int x, final int y, final int stopx,
133 			final int stopy, final int startx, final int starty,
134 			final float[][][] thisPixels, final float[][][] thatPixels) {
135 		float[] out = new float[4];
136 		for (int yy = starty; yy < stopy; yy++) {
137 			final int thatY = yy - y;
138 
139 			for (int xx = startx; xx < stopx; xx++) {
140 
141 				final int thatX = xx - x;
142 				float thisA = thisPixels[3][yy][xx] ;
143 				float thatA = thatPixels[3][thatY][thatX] ;
144 				ImageUtilities.alphaCompositePixel(out,
145 					thisPixels[0][yy][xx], thisPixels[1][yy][xx], thisPixels[2][yy][xx], thisA,
146 					thatPixels[0][thatY][thatX], thatPixels[1][thatY][thatX], thatPixels[2][thatY][thatX], thatA
147 				);
148 
149 				thisPixels[0][yy][xx] = out[0];
150 				thisPixels[1][yy][xx] = out[1];
151 				thisPixels[2][yy][xx] = out[2];
152 				thisPixels[3][yy][xx] = out[3];
153 			}
154 		}
155 	}
156 	
157 	private void drawThisAlpha(final int x, final int y, final int stopx,
158 			final int stopy, final int startx, final int starty,
159 			final float[][][] thisPixels, final float[][][] thatPixels) {
160 		float[] out = new float[4];
161 		for (int yy = starty; yy < stopy; yy++) {
162 			final int thatY = yy - y;
163 
164 			for (int xx = startx; xx < stopx; xx++) {
165 
166 				final int thatX = xx - x;
167 				float thisA = thisPixels[3][yy][xx] ;
168 				float thatA = 1f ;
169 				ImageUtilities.alphaCompositePixel(out,
170 					thisPixels[0][yy][xx], thisPixels[1][yy][xx], thisPixels[2][yy][xx], thisA,
171 					thatPixels[0][thatY][thatX], thatPixels[1][thatY][thatX], thatPixels[2][thatY][thatX], thatA
172 				);
173 
174 				thisPixels[0][yy][xx] = out[0];
175 				thisPixels[1][yy][xx] = out[1];
176 				thisPixels[2][yy][xx] = out[2];
177 				thisPixels[3][yy][xx] = out[3];
178 			}
179 		}
180 	}
181 	
182 	private void drawThatAlpha(final int x, final int y, final int stopx,
183 			final int stopy, final int startx, final int starty,
184 			final float[][][] thisPixels, final float[][][] thatPixels) {
185 		float[] out = new float[4];
186 		for (int yy = starty; yy < stopy; yy++) {
187 			final int thatY = yy - y;
188 
189 			for (int xx = startx; xx < stopx; xx++) {
190 
191 				final int thatX = xx - x;
192 				float thisA = 1f ;
193 				float thatA = thatPixels[3][thatY][thatX] ;
194 				ImageUtilities.alphaCompositePixel(out,
195 					thisPixels[0][yy][xx], thisPixels[1][yy][xx], thisPixels[2][yy][xx], thisA,
196 					thatPixels[0][thatY][thatX], thatPixels[1][thatY][thatX], thatPixels[2][thatY][thatX], thatA
197 				);
198 
199 				thisPixels[0][yy][xx] = out[0];
200 				thisPixels[1][yy][xx] = out[1];
201 				thisPixels[2][yy][xx] = out[2];
202 			}
203 		}
204 	}
205 
206 	protected void drawImage3(final MBFImage image, final int x, final int y) {
207 		final int stopx = Math.max(0, Math.min(this.targetImage.getWidth(), x + image.getWidth()));
208 		final int stopy = Math.max(0, Math.min(this.targetImage.getHeight(), y + image.getHeight()));
209 		final int startx = Math.max(0, x);
210 		final int starty = Math.max(0, y);
211 
212 		if (startx >= stopx || starty >= stopy)
213 			return;
214 
215 		final float[][][] thisPixels = new float[3][][];
216 		for (int i = 0; i < thisPixels.length; i++)
217 			thisPixels[i] = this.targetImage.getBand(i).pixels;
218 
219 		final float[][][] thatPixels = new float[3][][];
220 		for (int i = 0; i < thatPixels.length; i++)
221 			thatPixels[i] = image.getBand(i).pixels;
222 
223 		for (int yy = starty; yy < stopy; yy++) {
224 			final int thatY = yy - y;
225 
226 			System.arraycopy(thatPixels[0][thatY], startx - x, thisPixels[0][yy], startx, stopx - startx);
227 			System.arraycopy(thatPixels[1][thatY], startx - x, thisPixels[1][yy], startx, stopx - startx);
228 			System.arraycopy(thatPixels[2][thatY], startx - x, thisPixels[2][yy], startx, stopx - startx);
229 
230 			// for (int xx=startx; xx<stopx; xx++)
231 			// {
232 			// int thatX = xx - x;
233 			//
234 			// thisPixels[0][yy][xx] = thatPixels[0][thatY][thatX];
235 			// thisPixels[1][yy][xx] = thatPixels[1][thatY][thatX];
236 			// thisPixels[2][yy][xx] = thatPixels[2][thatY][thatX];
237 			// }
238 		}
239 	}
240 
241 	@Override
242 	protected void drawHorizLine(final int x1, final int x2, final int y, Float[] col) {
243 		col = this.sanitise(col);
244 		if (y < 0 || y > this.targetImage.getHeight() - 1)
245 			return;
246 
247 		final int startx = Math.max(0, Math.min(x1, x2));
248 		final int stopx = Math.min(Math.max(x1, x2), this.targetImage.getWidth() - 1);
249 		final int nbands = Math.min(col.length, this.targetImage.numBands());
250 
251 		for (int b = 0; b < nbands; b++) {
252 			final float[][] img = this.targetImage.getBand(b).pixels;
253 			final float c = col[b];
254 
255 			for (int x = startx; x <= stopx; x++) {
256 				img[y][x] = c;
257 			}
258 		}
259 	}
260 
261 	@Override
262 	protected Float[] sanitise(final Float[] colour)
263 	{
264 		return this.targetImage.colourSpace.sanitise(colour);
265 	}
266 }