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.pixel;
31  
32  import java.io.DataInput;
33  import java.io.DataOutput;
34  import java.io.IOException;
35  import java.io.PrintWriter;
36  import java.util.Scanner;
37  
38  import org.openimaj.math.geometry.point.Point2d;
39  
40  import Jama.Matrix;
41  
42  /**
43   * Represents a pixel within an image, storing its coordinates. Provides helper
44   * methods for rounding non-integer values to pixel coordinates.
45   *
46   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
47   */
48  public class Pixel implements Point2d, Cloneable {
49  	/** The x-coordinate of this pixel */
50  	public int x;
51  
52  	/** The y-coordinate of this pixel */
53  	public int y;
54  
55  	/**
56  	 * Construct a pixel with the given coordinates.
57  	 *
58  	 * @param x
59  	 *            The x-coordinate of the pixel
60  	 * @param y
61  	 *            The y-coordinate of the pixel
62  	 */
63  	public Pixel(int x, int y) {
64  		this.x = x;
65  		this.y = y;
66  	}
67  
68  	/**
69  	 * Construct a pixel at the origin
70  	 */
71  	public Pixel() {
72  		this(0, 0);
73  	}
74  
75  	/**
76  	 * {@inheritDoc}
77  	 *
78  	 * @see java.lang.Object#equals(java.lang.Object)
79  	 */
80  	@Override
81  	public boolean equals(Object o) {
82  		if (this == o)
83  			return true;
84  		if (!(o instanceof Pixel))
85  			return false;
86  
87  		if (((Pixel) o).x == x && ((Pixel) o).y == y)
88  			return true;
89  		return false;
90  	}
91  
92  	/**
93  	 * {@inheritDoc}
94  	 *
95  	 * @see java.lang.Object#hashCode()
96  	 */
97  	@Override
98  	public int hashCode() {
99  		int hash = 17;
100 		hash = (31 * hash) + x;
101 		hash = (31 * hash) + y;
102 		return hash;
103 	}
104 
105 	/**
106 	 * {@inheritDoc}
107 	 *
108 	 * @see java.lang.Object#toString()
109 	 */
110 	@Override
111 	public String toString() {
112 		return "(" + x + ", " + y + ")";
113 	}
114 
115 	/**
116 	 * {@inheritDoc}
117 	 *
118 	 * @see org.openimaj.math.geometry.point.Point2d#getX()
119 	 */
120 	@Override
121 	public float getX() {
122 		return x;
123 	}
124 
125 	/**
126 	 * {@inheritDoc}
127 	 *
128 	 * @see org.openimaj.math.geometry.point.Point2d#getY()
129 	 */
130 	@Override
131 	public float getY() {
132 		return y;
133 	}
134 
135 	/**
136 	 * {@inheritDoc}
137 	 *
138 	 * @see org.openimaj.math.geometry.point.Point2d#setX(float)
139 	 */
140 	@Override
141 	public void setX(float x) {
142 		this.x = Math.round(x);
143 	}
144 
145 	/**
146 	 * {@inheritDoc}
147 	 *
148 	 * @see org.openimaj.math.geometry.point.Point2d#setY(float)
149 	 */
150 	@Override
151 	public void setY(float y) {
152 		this.y = Math.round(y);
153 	}
154 
155 	/**
156 	 * {@inheritDoc}
157 	 */
158 	@Override
159 	public Pixel clone() {
160 		return new Pixel(x, y);
161 	}
162 
163 	/**
164 	 * {@inheritDoc}
165 	 *
166 	 * @see org.openimaj.math.geometry.point.Point2d#copyFrom(org.openimaj.math.geometry.point.Point2d)
167 	 */
168 	@Override
169 	public void copyFrom(Point2d p) {
170 		this.setX(p.getX());
171 		this.setY(p.getY());
172 	}
173 
174 	/**
175 	 * {@inheritDoc}
176 	 *
177 	 * @see org.openimaj.math.geometry.point.Coordinate#getOrdinate(int)
178 	 */
179 	@Override
180 	public Integer getOrdinate(int dimension) {
181 		if (dimension == 0)
182 			return x;
183 		return y;
184 	}
185 
186 	/**
187 	 * {@inheritDoc}
188 	 *
189 	 * @see org.openimaj.math.geometry.point.Coordinate#getDimensions()
190 	 */
191 	@Override
192 	public int getDimensions() {
193 		return 2;
194 	}
195 
196 	@Override
197 	public void translate(float x, float y) {
198 		this.x = Math.round(this.x + x);
199 		this.y = Math.round(this.y + y);
200 	}
201 
202 	@Override
203 	public Pixel transform(Matrix transform) {
204 		if (transform.getRowDimension() == 3) {
205 			float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY()
206 					+ (float) transform.get(0, 2);
207 			float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY()
208 					+ (float) transform.get(1, 2);
209 			final float zt = (float) transform.get(2, 0) * getX() + (float) transform.get(2, 1) * getY()
210 					+ (float) transform.get(2, 2);
211 
212 			xt /= zt;
213 			yt /= zt;
214 
215 			return new Pixel(Math.round(xt), Math.round(yt));
216 		} else if (transform.getRowDimension() == 2) {
217 			final float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY();
218 			final float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY();
219 
220 			return new Pixel(Math.round(xt), Math.round(yt));
221 		}
222 		throw new IllegalArgumentException("Transform matrix has unexpected size");
223 	}
224 
225 	/**
226 	 * Inplace transform the point by the given matrix.
227 	 *
228 	 * @param transform
229 	 *            the transform
230 	 * @return this
231 	 */
232 	public Pixel transformInplace(Matrix transform) {
233 		if (transform.getRowDimension() == 3) {
234 			float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY()
235 					+ (float) transform.get(0, 2);
236 			float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY()
237 					+ (float) transform.get(1, 2);
238 			final float zt = (float) transform.get(2, 0) * getX() + (float) transform.get(2, 1) * getY()
239 					+ (float) transform.get(2, 2);
240 
241 			xt /= zt;
242 			yt /= zt;
243 
244 			this.x = Math.round(xt);
245 			this.y = Math.round(yt);
246 			return this;
247 		} else if (transform.getRowDimension() == 2) {
248 			final float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY();
249 			final float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY();
250 
251 			this.x = Math.round(xt);
252 			this.y = Math.round(yt);
253 			return this;
254 		}
255 		throw new IllegalArgumentException("Transform matrix has unexpected size");
256 	}
257 
258 	@Override
259 	public Point2d minus(Point2d a) {
260 		return new Pixel(this.x - (int) a.getX(), this.y - (int) a.getY());
261 	}
262 
263 	@Override
264 	public void readASCII(Scanner in) throws IOException {
265 		x = in.nextInt();
266 		y = in.nextInt();
267 	}
268 
269 	@Override
270 	public String asciiHeader() {
271 		return "Pixel";
272 	}
273 
274 	@Override
275 	public void readBinary(DataInput in) throws IOException {
276 		x = in.readInt();
277 		y = in.readInt();
278 	}
279 
280 	@Override
281 	public byte[] binaryHeader() {
282 		return "PX".getBytes();
283 	}
284 
285 	@Override
286 	public void writeASCII(PrintWriter out) throws IOException {
287 		out.format("%d %d", x, y);
288 	}
289 
290 	@Override
291 	public void writeBinary(DataOutput out) throws IOException {
292 		out.writeInt(x);
293 		out.writeInt(y);
294 	}
295 
296 	@Override
297 	public void translate(Point2d v) {
298 		this.translate(v.getX(), v.getY());
299 	}
300 
301 	@Override
302 	public Pixel copy() {
303 		return clone();
304 	}
305 
306 	@Override
307 	public void setOrdinate(int dimension, Number value) {
308 		if (dimension == 0)
309 			x = value.intValue();
310 		if (dimension == 1)
311 			y = value.intValue();
312 	}
313 }