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.pixel; 031 032import java.io.DataInput; 033import java.io.DataOutput; 034import java.io.IOException; 035import java.io.PrintWriter; 036import java.util.Scanner; 037 038import org.openimaj.math.geometry.point.Point2d; 039 040import Jama.Matrix; 041 042/** 043 * Represents a pixel within an image, storing its coordinates. Provides helper 044 * methods for rounding non-integer values to pixel coordinates. 045 * 046 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 047 */ 048public class Pixel implements Point2d, Cloneable { 049 /** The x-coordinate of this pixel */ 050 public int x; 051 052 /** The y-coordinate of this pixel */ 053 public int y; 054 055 /** 056 * Construct a pixel with the given coordinates. 057 * 058 * @param x 059 * The x-coordinate of the pixel 060 * @param y 061 * The y-coordinate of the pixel 062 */ 063 public Pixel(int x, int y) { 064 this.x = x; 065 this.y = y; 066 } 067 068 /** 069 * Construct a pixel at the origin 070 */ 071 public Pixel() { 072 this(0, 0); 073 } 074 075 /** 076 * {@inheritDoc} 077 * 078 * @see java.lang.Object#equals(java.lang.Object) 079 */ 080 @Override 081 public boolean equals(Object o) { 082 if (this == o) 083 return true; 084 if (!(o instanceof Pixel)) 085 return false; 086 087 if (((Pixel) o).x == x && ((Pixel) o).y == y) 088 return true; 089 return false; 090 } 091 092 /** 093 * {@inheritDoc} 094 * 095 * @see java.lang.Object#hashCode() 096 */ 097 @Override 098 public int hashCode() { 099 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}