5 added files
CDMS/src/CDMS/Partridge/ImageUtils
diff -N ImageData.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ImageData.java 4 Oct 2010 22:49:31 -0000 1.1
@@ -0,0 +1,244 @@
+/*
+ * ImageData.java
+ */
+package CDMS.Partridge.ImageUtils;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * Encapsulate the RGB color information associated with an image.
+ *
+ * @author Richard Partridge
+ */
+public class ImageData {
+
+ private PixelArray _pixarray;
+ private BufferedImage _image;
+ private int[][] _RGB;
+
+ /**
+ * Construct an empty image.
+ *
+ * @param pixarray pixel array descriptor
+ */
+ public ImageData(PixelArray pixarray) {
+ _pixarray = pixarray;
+ _RGB = new int[pixarray.getNRow()][pixarray.getNCol()];
+ }
+
+ /**
+ * Construct an image using the RGB data contained in a BufferedImage
+ *
+ * @param pixarray pixel array descriptor
+ * @param image image
+ */
+ public ImageData(PixelArray pixarray, BufferedImage image) {
+ _pixarray = pixarray;
+ _image = image;
+
+ // Check that the image sizes match
+ if (_pixarray.getNRow() != image.getHeight() || _pixarray.getNCol() != image.getWidth())
+ throw new RuntimeException("Image size does not match pixel array descriptor");
+ }
+
+ /**
+ * Return the pixel array descriptor
+ *
+ * @return pixel array descriptor
+ */
+ public PixelArray getPixelArray() {
+ return _pixarray;
+ }
+
+ /**
+ * Return a BufferedImage associated with this image.
+ *
+ * @return image
+ */
+ public BufferedImage getBufferedImage() {
+
+ // Check if we already have an associated BufferedImage
+ if (_image == null) {
+
+ // Create a new BufferedImage
+ int nrow = _pixarray.getNRow();
+ int ncol = _pixarray.getNCol();
+ _image = new BufferedImage(ncol, nrow, BufferedImage.TYPE_3BYTE_BGR);
+
+ // Copy the image data
+ for (int row=0; row<nrow; row++) {
+ for (int col=0; col<ncol; col++) {
+ _image.setRGB(col, row, _RGB[row][col]);
+ }
+ }
+ }
+
+ return _image;
+ }
+
+ /**
+ * Return the blue color data
+ *
+ * @param RGB packed color data
+ * @return blue color data
+ */
+ public int getBlue(int RGB) {
+ return RGB & 0xff;
+ }
+
+ /**
+ * Return the green color data
+ *
+ * @param RGB packed color data
+ * @return green color data
+ */
+ public int getGreen(int RGB) {
+ return (RGB & 0xff00) >> 8;
+ }
+
+ /**
+ * Return the red color data
+ *
+ * @param RGB packed color data
+ * @return red color data
+ */
+ public int getRed(int RGB) {
+ return (RGB & 0xff0000) >> 16;
+ }
+
+ /**
+ * Return the intensity from the color data
+ *
+ * @param red red color data
+ * @param green green color data
+ * @param blue blue color data
+ * @return intensity
+ */
+ public double getIntensity(int red, int green, int blue) {
+ return Math.sqrt((red * red + green * green + blue * blue) / 3);
+ }
+
+ /**
+ * Return the intensity from the packed color data
+ *
+ * @param RGB packed color data
+ * @return intensity
+ */
+ public double getIntensity(int RGB) {
+ return getIntensity(getRed(RGB), getGreen(RGB), getBlue(RGB));
+ }
+
+ /**
+ * Return the intensity for a given row/col in the pixel array
+ * @param row image row
+ * @param col image col
+ * @return intensity
+ */
+ public double getIntensity(int row, int col) {
+ return getIntensity(getRGB(row, col));
+ }
+
+ /**
+ * Set the packed color data for a pixel
+ * @param row image row
+ * @param col image column
+ * @param RGB packed color data
+ */
+ public void setRGB(int row, int col, int RGB) {
+ if (_image != null) throw new RuntimeException("Attempt to modify static image");
+ _RGB[row][col] = RGB;
+ }
+
+ /**
+ * Set the packed color data for a pixel
+ * @param row image row
+ * @param col image column
+ * @param red red color data
+ * @param green green color data
+ * @param blue blue color data
+ */
+ public void setRGB(int row, int col, int red, int green, int blue) {
+ setRGB(row, col, makeRGB(red, green, blue));
+ }
+
+ /**
+ * Set the packed color data for a pixel
+ *
+ * @param pixel pixel number as specified by the pixel array descriptor
+ * @param RGB packed color data
+ */
+ public void setRGB(long pixel, int RGB) {
+ setRGB(_pixarray.getRow(pixel), _pixarray.getCol(pixel), RGB);
+ }
+
+ /**
+ * Set the packed color data for a pixel
+ *
+ * @param pixel pixel number as specified by the pixel array descriptor
+ * @param red red color data
+ * @param green green color data
+ * @param blue blue color data
+ */
+ public void setRGB(long pixel, int red, int green, int blue) {
+ setRGB(pixel, makeRGB(red, green, blue));
+ }
+
+ /**
+ * Return the packed color data for a given element in the image
+ *
+ * @param row image row
+ * @param col image column
+ * @return packed color data
+ */
+ public int getRGB(int row, int col) {
+ if (_image == null) return _RGB[row][col];
+ int RGB = _image.getRGB(col, row);
+ return translateBufferedImageRGB(RGB);
+ }
+
+ /**
+ * Return the packed color data for a pixel
+ *
+ * @param pixel pixel number as specified by the pixel array descriptor
+ * @return packed color data
+ */
+ public int getRGB(long pixel) {
+ return getRGB(_pixarray.getRow(pixel), _pixarray.getCol(pixel));
+ }
+
+ /**
+ * Translate from the BufferedImage color scheme to the one used here. At
+ * present, it is believe these schemes are the same based on trial and
+ * error techniques. Since it is not entirely clear what format is used
+ * for RGB data in a BufferedImage, keep this simple method as a place
+ * holder for dealing with possible future complications and for now
+ * just mask off the upper 8 bits.
+ *
+ * @param RGB color data for a BufferedImage pixel
+ * @return packed color data
+ */
+ private int translateBufferedImageRGB(int RGB) {
+ // Since the pixel RGB scheme is believed to match the BufferedImage convention,
+ // skip decoding the BufferedImage convention
+ // int blue = pixel & 0x000000ff;
+ // int green = (pixel & 0x0000ff00) >> 8;
+ // int red = (pixel & 0x00ff0000) >> 16;
+ // return makePixel(red, green, blue);
+ return RGB & 0xffffff;
+ }
+
+ /**
+ * Return the packed color given the color components
+ *
+ * @param red red color data
+ * @param green green color data
+ * @param blue blue color data
+ * @return packed color data
+ */
+ private int makeRGB(int red, int green, int blue) {
+ if (red < 0 || red > 0xff) throw new RuntimeException("Invalid RGB data for red: "+red);
+ if (green < 0 || green > 0xff) throw new RuntimeException("Invalid RGB data for green: "+green);
+ if (blue < 0 || blue > 0xff) throw new RuntimeException("Invalid RGB data for blue: "+blue);
+ return (red << 16) + (green << 8) + blue;
+ }
+}
CDMS/src/CDMS/Partridge/ImageUtils
diff -N ImageDescriptor.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ImageDescriptor.java 4 Oct 2010 22:49:31 -0000 1.1
@@ -0,0 +1,180 @@
+/*
+ * ImageDescriptor.java
+ */
+
+package CDMS.Partridge.ImageUtils;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.ImageIO;
+
+/**
+ * Encapsulate the meta-data associated with an image file
+ *
+ * @author Richard Partrdge
+ */
+public class ImageDescriptor {
+
+ private String _filename;
+ private int _id;
+ private double _xc;
+ private double _yc;
+ private double _dx;
+ private double _dy;
+ private int _nrow;
+ private int _ncol;
+
+ /**
+ * Fully qualified constructor.
+ *
+ * @param filename name of image file
+ * @param id unique image identifier
+ * @param xc x coordinate of image center
+ * @param yc y coordinate of image center
+ * @param dx x pixel size
+ * @param dy y pixel size
+ * @param nrow number of rows for image
+ * @param ncol number of columns for image
+ */
+ public ImageDescriptor(String filename, int id, double xc, double yc, double dx,
+ double dy, int nrow, int ncol) {
+ _filename = filename;
+ _id = id;
+ _xc = xc;
+ _yc = yc;
+ _dx = dx;
+ _dy = dy;
+ _nrow = nrow;
+ _ncol = ncol;
+ }
+
+ /**
+ * Constructor that gets image size from the image itself
+ *
+ * @param filename name of image file
+ * @param id unique image identifier
+ * @param xc x coordinate of image center
+ * @param yc y coordinate of image center
+ * @param dx x pixel size
+ * @param dy y pixel size
+ */
+ public ImageDescriptor(String filename, int id, double xc, double yc, double dx, double dy) {
+ _filename = filename;
+ _id = id;
+ _xc = xc;
+ _yc = yc;
+ _dx = dx;
+ _dy = dy;
+ BufferedImage bufimage = getBufferedImage();
+ _nrow = bufimage.getHeight();
+ _ncol = bufimage.getWidth();
+ }
+
+ /**
+ * Return the BufferedImage associated with this image descriptor
+ *
+ * @return image
+ */
+ public BufferedImage getBufferedImage() {
+ File file = new File(_filename);
+ BufferedImage bufimage = null;
+ try {
+ bufimage = ImageIO.read(file);
+ } catch (IOException ex) {
+ System.out.println("Image file not found: "+_filename);
+ }
+ return bufimage;
+ }
+
+ /**
+ * Return the PixelArray associated with this image descriptor
+ *
+ * @return pixel array descriptor
+ */
+ public PixelArray getPixelArray() {
+ return new PixelArray(_nrow, _ncol, _xc, _yc, _dx, _dy);
+ }
+
+ /**
+ * Return the ImageData associated with this image descriptor
+ *
+ * @return image
+ */
+ public ImageData getImageData() {
+ return new ImageData(getPixelArray(), getBufferedImage());
+ }
+
+ /**
+ * Return image identifer
+ *
+ * @return
+ */
+ public int getIdentifer() {
+ return _id;
+ }
+
+ /**
+ * Retrun the x pixel size
+ *
+ * @return x pixel size
+ */
+ public double getXSize() {
+ return _dx;
+ }
+
+ /**
+ * Return the y pixel size
+ *
+ * @return y pixel size
+ */
+ public double getYSize() {
+ return _dy;
+ }
+
+ /**
+ * Return the file name containing the image
+ *
+ * @return image file name
+ */
+ public String getFilename() {
+ return _filename;
+ }
+
+ /**
+ * Return the number of columns for this image
+ *
+ * @return number of columns
+ */
+ public int getNCol() {
+ return _ncol;
+ }
+
+ /**
+ * Return the number of rows for this image
+ *
+ * @return number of rows
+ */
+ public int getNRow() {
+ return _nrow;
+ }
+
+ /**
+ * Return the x coordinate of the image center
+ *
+ * @return x coordinate
+ */
+ public double getXC() {
+ return _xc;
+ }
+
+ /**
+ * Return the y coordinate of the image center
+ *
+ * @return y coordinate
+ */
+ public double getYC() {
+ return _yc;
+ }
+
+}
CDMS/src/CDMS/Partridge/ImageUtils
diff -N InterpolatePixelIntensity.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ InterpolatePixelIntensity.java 4 Oct 2010 22:49:31 -0000 1.1
@@ -0,0 +1,275 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package CDMS.Partridge.ImageUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author richp
+ */
+public class InterpolatePixelIntensity {
+
+ private ImageData _ref;
+ private TransformedPixelArray _refpix;
+ private TransformedPixelArray _testpix;
+ private boolean _rotated;
+ private double _eps = 1.e-10;
+ private int _drow;
+ private int _dcol;
+ private double[] _wrow = new double[3];
+ private double[] _wcol = new double[3];
+
+ public InterpolatePixelIntensity(ImageData ref, TransformedPixelArray refpix, TransformedPixelArray testpix) {
+ _ref = ref;
+ _refpix = refpix;
+ _testpix = testpix;
+ _rotated = refpix.isRotated() || testpix.isRotated();
+ if (!_rotated) {
+ double dx = (testpix.getXC() - refpix.getXC()) / testpix.getSize();
+ double dy = (testpix.getYC() - refpix.getYC()) / testpix.getSize();
+ int dcol = (int) Math.round(dx);
+ int drow = (int) Math.round(dy);
+// System.out.println("dx: " + dx + " dy: " + dy + " dcol: " + dcol + " drow: " + drow);
+ dx -= dcol;
+ dy -= drow;
+ if (dx < 0.) {
+ _wcol[0] = -dx;
+ }
+ if (dx > 0.) {
+ _wcol[2] = dx;
+ }
+ _wcol[1] = 1. - _wcol[0] - _wcol[2];
+ if (dy < 0.) {
+ _wrow[0] = -dy;
+ }
+ if (dy > 0.) {
+ _wrow[2] = dy;
+ }
+ _wrow[1] = 1. - _wrow[0] - _wrow[2];
+// System.out.println("wrow: " + _wrow[0] + " , " + _wrow[1] + " , " + _wrow[2]);
+// System.out.println("wcol: " + _wcol[0] + " , " + _wcol[1] + " , " + _wcol[2]);
+
+ }
+ }
+
+ public double Interpolate(int pixel) {
+
+ // Find the center of the current test pixel
+ double[] testcenter = _testpix.getCenter(pixel);
+
+ // Find the reference pixel containing the center of the test pixel
+ int refcenter = _refpix.getPixel(testcenter[0], testcenter[1]);
+
+// double[] center = _refpix.getCenter(refcenter);
+// if (refcenter == 640 * 40 + 40) {
+// System.out.println("test: " + testcenter[0] + " , " + testcenter[1]);
+// System.out.println("ref: " + center[0] + " , " + center[1]);
+// System.out.println("nbrs: " + _refpix.getNeighbors(refcenter).size());
+// }
+ // Get the list of reference pixels to check for overlaps
+ List<Integer> refnbrs = _refpix.getNeighbors(refcenter);
+
+ // Initialize the pixel area and weighted intensity sums
+ double totarea = 0.;
+ double intensity = 0.;
+
+ if (!_rotated) {
+ int row0 = _refpix.getRow(refcenter);
+ int col0 = _refpix.getCol(refcenter);
+ for (int nbr : refnbrs) {
+ int row = _refpix.getRow(nbr);
+ int col = _refpix.getCol(nbr);
+ double wgt = _wrow[row - row0 + 1] * _wcol[col - col0 + 1];
+ if (wgt > 0.) {
+ intensity += wgt * _ref.getIntensity(row, col);
+ }
+ totarea += Math.abs(wgt);
+// if (refcenter == 640 * 40 + 40) {
+// double[] rcenter = _refpix.getCenter(nbr);
+// System.out.println("ref: " + rcenter[0] + " , " + rcenter[1]);
+// System.out.println("wrow: " + _wrow[row - row0 + 1] + " wcol: " + _wcol[col - col0 + 1]);
+// System.out.println("wgt: " + wgt + " intensity: " + _ref.getIntensity(row, col));
+// }
+ }
+ if (Math.abs(totarea - 1) > _eps) {
+ throw new RuntimeException("Area integral failure");
+ }
+ return intensity;
+ }
+
+ // Loop over the list of reference pixels
+ for (Integer nbr : refnbrs) {
+
+ // Create a list for vertices of the overlap region between this ref pixel and the test pixel
+ List<double[]> vertices = new ArrayList<double[]>();
+
+ // Loop over the reference pixel vertices and see if the reference vertex
+ // is inside the test pixel. If so add it to the list of vertices (don't
+ // worry about duplicate vertices - they contribute no additional polygon area
+ for (int i = 0; i < 4; i++) {
+ double[] vtx = _refpix.getVertex(i, nbr);
+ if (_testpix.Inside(pixel, vtx)) {
+ vertices.add(vtx);
+ }
+ }
+
+ // Now loop over the test pixel vertices
+ for (int i = 0; i < 4; i++) {
+ double[] vtx = _testpix.getVertex(i, pixel);
+ if (_refpix.Inside(nbr, vtx)) {
+ vertices.add(vtx);
+ }
+ }
+
+ // Finally, find any vertices produced by intersections of pixel edges
+ for (int i1 = 0; i1 < 4; i1++) {
+ int i2 = (i1 + 1) % 4;
+ double[] vt1 = _testpix.getVertex(i1, pixel);
+ double[] vt2 = _testpix.getVertex(i2, pixel);
+ for (int j1 = 0; j1 < 4; j1++) {
+ int j2 = (j1 + 1) % 4;
+ double[] vr1 = _refpix.getVertex(j1, nbr);
+ double[] vr2 = _refpix.getVertex(j2, nbr);
+ double[] vtx = findIntersection(vt1, vt2, vr1, vr2);
+ if (vtx != null) {
+ vertices.add(vtx);
+ }
+ }
+ }
+
+ // If there are no vertices, the test pixel and this reference pixel don't overlap
+ if (vertices.size() == 0) {
+ continue;
+ }
+
+ // Find the area of overlap between the test pixel and this reference neighbor pixel
+ double area = getArea(vertices);
+ totarea += area;
+
+ // Take the interpolated intensity to be the sum of the reference neighbor intensities
+ // weighted by the overlap area
+ int refrow = _refpix.getRow(nbr);
+ int refcol = _refpix.getCol(nbr);
+ intensity += area * _ref.getIntensity(refrow, refcol);
+ }
+
+ // Check to make sure the total pixel area is unity
+ if (Math.abs(totarea - 1.) > Math.sqrt(_eps)) {
+ System.out.println(" ***** Grand total area: " + totarea + " *****");
+ throw new RuntimeException("area sum error");
+ }
+
+ return intensity;
+ }
+
+ public double getNormalizionWeight() {
+ double winv = 1.0;
+ for (int row=0; row<2; row++) {
+ for (int col=0; col<2; col++) {
+ winv += Math.pow(_wrow[row]*_wcol[col], 2);
+ }
+ }
+ return 1.0 / winv;
+ }
+
+ private double[] findIntersection(double[] vt1, double[] vt2, double[] vr1, double[] vr2) {
+
+ // Find the variables defining the line between vt1 and vt2
+ double a1 = vt2[1] - vt1[1];
+ double b1 = vt1[0] - vt2[0];
+ double c1 = a1 * vt1[0] + b1 * vt1[1];
+
+ // Find the variables defining the line between vr1 and vr2
+ double a2 = vr2[1] - vr1[1];
+ double b2 = vr1[0] - vr2[0];
+ double c2 = a2 * vr1[0] + b2 * vr1[1];
+
+ // Calculate the determinant, check for parallel lines
+ double det = a1 * b2 - a2 * b1;
+ if (Math.abs(det) < _eps) {
+ return null;
+ }
+
+ // Find the intersection using the determinant method
+ double x = (b2 * c1 - b1 * c2) / det;
+ double y = (a1 * c2 - a2 * c1) / det;
+
+ // Check that the x coordinate of the intersection is on the line segment
+ if (x < Math.min(vt1[0], vt2[0]) - _eps || x > Math.max(vt1[0], vt2[0]) + _eps) {
+ return null;
+ }
+ if (x < Math.min(vr1[0], vr2[0]) - _eps || x > Math.max(vr1[0], vr2[0]) + _eps) {
+ return null;
+ }
+
+ // Also check y in case the line is vertical
+ if (y < Math.min(vt1[1], vt2[1]) - _eps || y > Math.max(vt1[1], vt2[1]) + _eps) {
+ return null;
+ }
+ if (y < Math.min(vr1[1], vr2[1]) - _eps || y > Math.max(vr1[1], vr2[1]) + _eps) {
+ return null;
+ }
+
+ double[] cross = {x, y};
+ return cross;
+ }
+
+ private double getArea(List<double[]> polygon) {
+
+ // Check that we have at least 3 polygon vertices
+ int nv = polygon.size();
+ if (nv < 3) {
+ return 0.;
+ }
+
+ // Order the vertices so that adjacent vertices describe a line segment in the
+ // polygon
+ OrderVertices(polygon);
+
+ // Find the area of the polygon (see, for example, http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/)
+ double area = 0.;
+ for (int i = 0; i < nv; i++) {
+ int j = (i + 1) % nv;
+ double[] p0 = polygon.get(i);
+ double[] p1 = polygon.get(j);
+ double darea = 0.5 * (p0[0] * p1[1] - p1[0] * p0[1]);
+ area += darea;
+ }
+ return Math.abs(area);
+ }
+
+ private double[] PseudoCentroid(List<double[]> polygon) {
+
+ // Find a point within the convex polygon by averaging the coordinates of all vertices
+ double[] pcent = {0., 0.};
+ int nv = polygon.size();
+ for (double[] point : polygon) {
+ pcent[0] += point[0] / nv;
+ pcent[1] += point[1] / nv;
+ }
+ return pcent;
+ }
+
+ private void OrderVertices(List<double[]> polygon) {
+
+ // Take as an origin a point within the polygon and order the polygon vertices according to their azimuthal angle
+ double[] pcent = PseudoCentroid(polygon);
+ int nv = polygon.size();
+ for (int i = 0; i < nv - 1; i++) {
+ for (int j = i + 1; j < nv; j++) {
+ // phi1 calcuation must stay inside loop because of possible re-ordering
+ double phi1 = Math.atan2(polygon.get(i)[1] - pcent[1], polygon.get(i)[0] - pcent[0]);
+ double phi2 = Math.atan2(polygon.get(j)[1] - pcent[1], polygon.get(j)[0] - pcent[0]);
+ if (phi1 > phi2) {
+ double[] temp = polygon.get(j);
+ polygon.set(j, polygon.get(i));
+ polygon.set(i, temp);
+ }
+ }
+ }
+ }
+}
CDMS/src/CDMS/Partridge/ImageUtils
diff -N PixelArray.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ PixelArray.java 4 Oct 2010 22:49:32 -0000 1.1
@@ -0,0 +1,402 @@
+/*
+ * PixelArray.java
+ */
+
+package CDMS.Partridge.ImageUtils;
+
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * This class encapsulates a description of a pixel array associated with a physical
+ * object. Sufficient information is available to provide convert between a pixel
+ * identifier, x/y coordinates, and row/column of the image.
+ *
+ * The pixel array may have associated with it non-overlapping subarrays. This
+ * allows pixel array descriptions to be composed of smaller pixel arrays stitched
+ * together to form a much larger pixel array descriptor.
+ *
+ * @author Richard Partridge
+ */
+public class PixelArray {
+
+ private int _nrow;
+ private int _ncol;
+ private double _xc;
+ private double _yc;
+ private double _dx;
+ private double _dy;
+ private Map<Integer, PixelArray> _subarraymap;
+ private double _eps = 1.e-4; // set tolerance to 0.1 um
+
+ /**
+ * Fully qualified constructor
+ *
+ * @param nrow number of rows for this pixel array
+ * @param ncol number of columns for this pixel array
+ * @param xc x coordinate of the center of the pixel array
+ * @param yc y coordinate of the center of the pixel array
+ * @param dx x pixel size
+ * @param dy y pixel size
+ */
+ public PixelArray(int nrow, int ncol, double xc, double yc, double dx, double dy) {
+ _nrow = nrow;
+ _ncol = ncol;
+ _xc = xc;
+ _yc = yc;
+ _dx = dx;
+ _dy = dy;
+ if (_nrow < 0 || _ncol < 0) throw new RuntimeException("Negative array size - nrow: "+nrow+" ncol: "+ncol);
+ if (_dx <= 0. || _dy <= 0.) throw new RuntimeException("Negative pixel size - dx: "+_dx+" dy: "+dy);
+ _subarraymap = new HashMap<Integer, PixelArray>();
+ }
+
+ /**
+ * Constructor that uses a Buffered Image to specify the number of row/columns in
+ * the pixel array
+ *
+ * @param bufimage BufferedImage represented by this pixel array descriptor
+ * @param xc x coordinate of the center of the pixel array
+ * @param yc y coordinate of the center of the pixel array
+ * @param dx x pixel size
+ * @param dy y pixel size
+ */
+ public PixelArray(BufferedImage bufimage, double xc, double yc, double dx, double dy) {
+ this(bufimage.getHeight(), bufimage.getWidth(), xc, yc, dx, dy);
+ }
+
+ /**
+ * Return the row number for a given pixel
+ *
+ * @param pixel pixel identifier
+ * @return row number
+ */
+ public int getRow(long pixel) {
+ int row = (int) ((pixel >> 32) & 0xffffffffL);
+ if (row < 0 || row >= _nrow) throw new RuntimeException("Invalid pixel number"+pixel);
+ return row;
+ }
+
+ /**
+ * Return the row number for a given y coordinate
+ *
+ * @param y y coordinate
+ * @return row number
+ */
+ public int getRow(double y) {
+ int ipix = (int) Math.floor((y - _yc) / _dy + _nrow / 2.);
+ if (ipix < 0 || ipix >= _nrow) throw new RuntimeException("Row outside pixel array for y = "+y);
+ return ipix;
+ }
+
+ /**
+ * Return the column number for a given pixel
+ * @param pixel pixel identifier
+ * @return column number
+ */
+ public int getCol(long pixel) {
+ int col = (int) (pixel & 0xffffffffL);
+ if (col < 0 || col >= _ncol) throw new RuntimeException("Invalid pixel number"+pixel);
+ return col;
+ }
+
+ /**
+ * Return the column number for a given x coordinate
+ *
+ * @param x x coordinate
+ * @return column number
+ */
+ public int getCol(double x) {
+ int ipix = (int) Math.floor((x - _xc) / _dx + _ncol / 2.);
+ if (ipix < 0 || ipix >= _ncol) throw new RuntimeException("Col outside pixel array for x = "+x);
+ return ipix;
+ }
+
+ /**
+ * Return the pixel identifier for a given row and column
+ * @param row row number
+ * @param col column number
+ * @return pixel identifier
+ */
+ public long getPixel(int row, int col) {
+ if (row < 0 || row >= _nrow) throw new RuntimeException("Invalid row number"+row);
+ if (col < 0 || col >= _ncol) throw new RuntimeException("Invalid col number"+col);
+ long lrow = row;
+ long lcol = col;
+ return (lrow << 32) + lcol;
+ }
+
+ /**
+ * Return the pixel identifier for a given x,y coordinate
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ * @return pixel identifier
+ */
+ public long getPixel(double x, double y) {
+ return getPixel(getRow(y), getCol(x));
+ }
+
+ /**
+ * Return the number of rows associated with this pixel array
+ *
+ * @return number of rows
+ */
+ public int getNRow() {
+ return _nrow;
+ }
+
+ /**
+ * Return the number of columns associated with this pixel array
+ *
+ * @return number of columns
+ */
+ public int getNCol() {
+ return _ncol;
+ }
+
+ /**
+ * Return the x coordinate of a given pixel
+ *
+ * @param pixel pixel identifier
+ * @return x coordinate
+ */
+ public double getX(long pixel) {
+ return _xc + (getCol(pixel) - (_ncol - 1.) / 2.) * _dx;
+ }
+
+ /**
+ * Return the y coordinate of a given pixel
+ *
+ * @param pixel pixel identifier
+ * @return y coordinate
+ */
+ public double getY(long pixel) {
+ return _yc + (getRow(pixel) - (_nrow - 1.) / 2.) * _dy;
+ }
+
+ /**
+ * Return the x coordinate of the center of the pixel array
+ *
+ * @return x center coordinate
+ */
+ public double getXC() {
+ return _xc;
+ }
+
+ /**
+ * Return the y coordinate of the center of the pixel array
+ *
+ * @return y center coordinate
+ */
+ public double getYC() {
+ return _yc;
+ }
+
+ /**
+ * Return the width in x of a pixel
+ *
+ * @return x pixel size
+ */
+ public double getXSize() {
+ return _dx;
+ }
+
+ /**
+ * Return the height in y of a pixel
+ *
+ * @return y pixel size
+ */
+ public double getYSize() {
+ return _dy;
+ }
+
+ /**
+ * Return the minimum x coordinate for the pixel array
+ *
+ * @return minimum x coordinate
+ */
+ public double getXMin() {
+ return _xc - 0.5 * _ncol * _dx;
+ }
+
+ /**
+ * Return the maximum x coordinate for the pixel array
+ *
+ * @return maximum x coordinate
+ */
+ public double getXMax() {
+ return _xc + 0.5 * _ncol * _dx;
+ }
+
+ /**
+ * Return the minimum y coordinate of the pixel array
+ *
+ * @return minimum y coordinate
+ */
+ public double getYMin() {
+ return _yc - 0.5 * _nrow * _dy;
+ }
+
+ /**
+ * Return the maximum y coordinate of the pixel array
+ *
+ * @return maximum y coordinate
+ */
+ public double getYMax() {
+ return _yc + 0.5 * _nrow * _dy;
+ }
+
+ /**
+ * Check whether a given x coordinate is within the pixel array
+ *
+ * @param x x coordinate
+ * @return true if inside
+ */
+ public boolean xInside(double x) {
+ return Math.abs(x -_xc) < 0.5 * _ncol * _dx + _eps;
+ }
+
+ /**
+ * Check whether a given y coordinate is within the pixel array
+ *
+ * @param y y coordinate
+ * @return true if inside
+ */
+ public boolean yInside(double y) {
+ return Math.abs(y -_yc) < 0.5 * _nrow * _dy + _eps;
+ }
+
+ /**
+ * Check whether a given x,y coordinate is within the pixel array
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ * @return true if inside
+ */
+ public boolean Inside(double x, double y) {
+ return xInside(x) && yInside(y);
+ }
+
+ /**
+ * Check whether a given pixel identifier describes a pixel within the pixel array
+ *
+ * @param pixel pixel identifier
+ * @return true if inside
+ */
+ public boolean Inside(long pixel) {
+ return Inside(getX(pixel), getY(pixel));
+ }
+
+ /**
+ * Add a subarray to this pixel array. The subarray must be fully contained
+ * within the pixel array and not overlap any other subarrays that are present.
+ *
+ * @param id identifier for this subarray (must be >=0)
+ * @param sub subarray
+ */
+ public void addSubArray(int id, PixelArray sub) {
+
+ // Check that we have a positive subarray identifer (negative values will be used to
+ // identify error conditions)
+ if (id < 0) throw new RuntimeException("Subarray ID must be non-negative - ID: "+id);
+
+ // Make sure that the identifier is unique
+ if (_subarraymap.containsKey(id)) throw new RuntimeException("Duplicate subarray identifier");
+
+ // Make sure subarray is entirely inside this pixel array
+ if (!Inside(sub.getXMin(), sub.getYMin()) || !Inside(sub.getXMax(), sub.getYMax()))
+ throw new RuntimeException("Subarray is not contained within this pixel array");
+
+ // Loop over the other subarrays and make sure that we don't overlap any of them
+ for (PixelArray check : _subarraymap.values()) {
+ long ll = getPixel(0, 0);
+ long lr = getPixel(0, check.getNCol() -1);
+ long ul = getPixel(check.getNRow() - 1, 0);
+ long ur = getPixel(check.getNRow() - 1, check.getNCol() - 1);
+ if (Inside(ll) || Inside(lr) || Inside(ul) || Inside(ur))
+ throw new RuntimeException("New subarray overlaps an existing subarray");
+ }
+
+ // Put the subarray into the map that contains the subarrays and their identifiers
+ _subarraymap.put(id, sub);
+ }
+
+ /**
+ * Get the subarray identifier associated with a given x,y position. Returns
+ * a value of -1 if there is no subarray containing these coordinates.
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ * @return subarray identifier
+ */
+ public int getSubArrayID(double x, double y) {
+ for (Entry<Integer, PixelArray> sub : _subarraymap.entrySet()) {
+ if (sub.getValue().Inside(x, y)) return sub.getKey();
+ }
+ return -1;
+ }
+
+ /**
+ * Return the subarray descriptor associated with a given x,y position
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ * @return subarray
+ */
+ public PixelArray getSubArray(double x, double y) {
+ int id = getSubArrayID(x, y);
+ return _subarraymap.get(id);
+ }
+
+ /**
+ * Return the subarray descriptor for a given ID
+ *
+ * @param id subarray identifier
+ * @return subarray
+ */
+ public PixelArray getSubArray(int id) {
+ return _subarraymap.get(id);
+ }
+
+ /**
+ * Return a list of neighbors to a given pixel
+ *
+ * @param pixel pixel identifier
+ * @return set of neighbor pixels
+ */
+ public Set<Long> getNeighbors(long pixel) {
+ Set<Long> nbrs = new HashSet<Long>();
+ int row = getRow(pixel);
+ int col = getCol(pixel);
+ for (int irow=row-1; irow<=row+1; irow++) {
+ if (irow < 0 || irow >= _nrow) continue;
+ for (int icol=col-1; icol<=col+1; icol++) {
+ if (icol < 0 || icol >= _ncol) continue;
+ nbrs.add(getPixel(irow, icol));
+ }
+ }
+ return nbrs;
+ }
+
+ public boolean equals(PixelArray test) {
+ if (_ncol != test.getNCol()) return false;
+ if (_nrow != test.getNRow()) return false;
+ if (Math.abs(_xc - test.getXC()) > _eps) return false;
+ if (Math.abs(_yc - test.getYC()) > _eps) return false;
+ if (Math.abs(_dx - test.getXSize()) > _eps / _ncol) return false;
+ if (Math.abs(_dy - test.getYSize()) > _eps / _nrow) return false;
+ for (Entry<Integer, PixelArray> entry : _subarraymap.entrySet()) {
+ int id = entry.getKey();
+ PixelArray subarray = entry.getValue();
+ PixelArray testsub = test._subarraymap.get(id);
+ if (testsub == null) return false;
+ if (!subarray.equals(testsub)) return false;
+ }
+ return true;
+ }
+}
CDMS/src/CDMS/Partridge/ImageUtils
diff -N TransformedPixelArray.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ TransformedPixelArray.java 4 Oct 2010 22:49:32 -0000 1.1
@@ -0,0 +1,162 @@
+/*
+ * TranformedPixelArray.java
+ */
+
+package CDMS.Partridge.ImageUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Richard Partridge
+ */
+public class TransformedPixelArray {
+
+ private double _x0;
+ private double _y0;
+ private double _rotang;
+ private double _size;
+ private int _nx;
+ private int _ny;
+ private double _xc;
+ private double _yc;
+ private double _u[] = new double[2];
+ private double _v[] = new double[2];
+ private double[] _xv = new double[4];
+ private double[] _yv = new double[4];
+ private double _eps = 1.e-6;
+
+ public TransformedPixelArray(double x0, double y0, double rotang, double size, int nx, int ny) {
+
+ // Save the parameters that define the pixel array
+ _x0 = x0;
+ _y0 = y0;
+ _rotang = rotang;
+ _size = size;
+ _nx = nx;
+ _ny = ny;
+
+ // Get unit vectors along the col (u) and row (v) directions
+ double cphi = Math.cos(rotang);
+ double sphi = Math.sin(rotang);
+ _u[0] = cphi;
+ _u[1] = sphi;
+ _v[0] = -sphi;
+ _v[1] = cphi;
+
+ // Find the coordinates of the LL pixel given offsets x0, y0 specified for
+ // the center pixel
+ double xll = _x0 + 0.5 * _size * (_nx * (1 - _u[0]) - _ny * _v[0]);
+ double yll = _y0 + 0.5 * _size * (_ny * (1 - _v[1]) - _nx * _u[1]);
+
+ // Find the vertices of pixel 0 whose LL corner is at the origin
+ // Vertices are stored in a clockwise direction
+ _xv[0] = xll;
+ _yv[0] = yll;
+ _xv[1] = xll + _size * _v[0];
+ _yv[1] = yll + _size * _v[1];
+ _xv[2] = xll + _size * (_u[0] + _v[0]);
+ _yv[2] = yll + _size * (_u[1] + _v[1]);
+ _xv[3] = xll + _size * _u[0];
+ _yv[3] = yll + _size * _u[1];
+
+ // Find the center
+ _xc = (_xv[0] + _xv[2]) / 2.;
+ _yc = (_yv[0] + _yv[2]) / 2.;
+ }
+
+ public double[] getCenter(int pixel) {
+ int row = getRow(pixel);
+ int col = getCol(pixel);
+ double[] center = new double[2];
+ center[0] = _xc + _size * (col * _u[0] + row * _v[0]);
+ center[1] = _yc + _size * (col * _u[1] + row * _v[1]);
+ return center;
+ }
+
+ public boolean Inside(int pixel, double[] vtx0) {
+ for (int i=0; i<4; i++) {
+ int j = (i+1) % 4;
+ double[] vtx1 = getVertex(i, pixel);
+ double[] vtx2 = getVertex(j, pixel);
+ if (twicearea(vtx1[0], vtx1[1], vtx2[0], vtx2[1], vtx0[0], vtx0[1]) < 0.) return false;
+ }
+ return true;
+ }
+
+ public double[] getVertex(int ivtx, int pixel) {
+ int row = getRow(pixel);
+ int col = getCol(pixel);
+ double[] vtx = new double[2];
+ vtx[0] = _xv[ivtx] + _size * (col * _u[0] + row * _v[0]);
+ vtx[1] = _yv[ivtx] + _size * (col * _u[1] + row * _v[1]);
+ return vtx;
+ }
+
+ public int getRow(int pixel) {
+ int row = pixel / _nx;
+ if (row < 0 || row >= _ny) throw new RuntimeException("Invalid pixel number");
+ return row;
+ }
+
+ public int getCol(int pixel) {
+ int col = pixel % _nx;
+ if (col < 0 || col >= _nx) throw new RuntimeException("Invalid pixel number");
+ return col;
+ }
+
+ public int getPixel(int row, int col) {
+ if (row < 0 || row >= _ny) throw new RuntimeException("Invalid row number");
+ if (col < 0 || col >= _nx) throw new RuntimeException("Invalid col number");
+ return row * _nx + col;
+ }
+
+ public int getPixel(double x, double y) {
+ int col = (int) Math.round(((x-_xc)*_u[0] + (y-_yc)*_u[1]) / _size);
+ int row = (int) Math.round(((x-_xc)*_v[0] + (y-_yc)*_v[1]) / _size);
+ return getPixel(row, col);
+ }
+
+ public int getNRow() {
+ return _ny;
+ }
+
+ public int getNCol() {
+ return _nx;
+ }
+
+ public List<Integer> getNeighbors(int pixel) {
+ List<Integer> nbrs = new ArrayList<Integer>();
+ int row = getRow(pixel);
+ int col = getCol(pixel);
+ for (int irow=row-1; irow<row+2; irow++) {
+ if (irow < 0 || irow >= _ny) continue;
+ for (int icol=col-1; icol<col+2; icol++) {
+ if (icol < 0 || icol > _nx) continue;
+ nbrs.add(getPixel(irow, icol));
+ }
+ }
+ return nbrs;
+ }
+
+ public boolean isRotated() {
+ return Math.abs(_rotang) > _eps;
+ }
+
+ public double getXC() {
+ return _xc;
+ }
+
+ public double getYC() {
+ return _yc;
+ }
+
+ public double getSize() {
+ return _size;
+ }
+
+ private double twicearea(double x1, double y1, double x2, double y2, double x3, double y3) {
+ return (x3*y2 - x2*y3) - (x3*y1 - x1*y3) + (x2*y1 - x1*y2);
+ }
+}
CVSspam 0.2.8