3 added + 2 modified, total 5 files
CDMS/src/CDMS/Partridge/ImageComparison
diff -N Cluster.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Cluster.java 5 Sep 2010 20:20:10 -0000 1.1
@@ -0,0 +1,129 @@
+/*
+ * Cluster.java
+ */
+
+package CDMS.Partridge.ImageComparison;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Cluster class to hold image pixels that are clustered together and calculate
+ * cluster properties.
+ *
+ * @author Richard Partridge
+ */
+public class Cluster {
+
+ private Map<Long, Double> _pixmap;
+ private PixelArray _pixarray;
+
+ /**
+ * Construct a cluster on a specified pixel array. The pixel array is required
+ * to define the position of the pixels in the cluster.
+ *
+ * @param pixarray pixel array
+ */
+ public Cluster(PixelArray pixarray) {
+ _pixarray = pixarray;
+ _pixmap = new HashMap<Long, Double>();
+ }
+
+ /**
+ * Add a pixel to the cluster with a specified deviation from the reference
+ * pixel.
+ *
+ * @param pixel pixel to be added
+ * @param deviation deviation in intensity from what is expected
+ */
+ public void addPixel(Long pixel, double deviation) {
+ _pixmap.put(pixel, deviation);
+ }
+
+ /**
+ * Return the set of pixels in this cluster.
+ *
+ * @return set of pixels
+ */
+ public Set<Long> getPixelList() {
+ return _pixmap.keySet();
+ }
+
+ /**
+ * Return a map linking the pixels in the cluster to their deviations.
+ *
+ * @return map of pixels to deviations
+ */
+ public Map<Long, Double> getPixelMap() {
+ return _pixmap;
+ }
+
+ /**
+ * Return the pixel array for this cluster.
+ *
+ * @return pixel array
+ */
+ public PixelArray getPixelArray() {
+ return _pixarray;
+ }
+
+ /**
+ * Return the center of gravity for the cluster weighted by the absolute
+ * value of the deviation.
+ *
+ * @return center of gravity coordinates (0 = x, 1 = y)
+ */
+ public double[] getCenterOfGravity() {
+
+ // Initialize the COG sums
+ double xc = 0.;
+ double yc = 0.;
+ double devsum = 0.;
+
+ // Loop over all pixels and calculate position weighted by |deviation|
+ for (Entry<Long, Double> entry : _pixmap.entrySet()) {
+ long pixel = entry.getKey();
+ double deviation = Math.abs(entry.getValue());
+ double x = _pixarray.getX(pixel);
+ double y = _pixarray.getY(pixel);
+ xc += x * deviation;
+ yc += y * deviation;
+ devsum += deviation;
+ }
+
+ // Normalize the weighted position to get the COG
+ if (devsum != 0.) {
+ xc /= devsum;
+ yc /= devsum;
+ }
+
+ // Return the COG as a pair of doubles
+ double[] pos = {xc, yc};
+ return pos;
+ }
+
+ /**
+ * Return the number of pixels in the cluster.
+ *
+ * @return number of pixels
+ */
+ public int getClusterSize() {
+ return _pixmap.size();
+ }
+
+ /**
+ * Return the sum of the absolute value of the deviation for the pixels
+ * in the cluster.
+ *
+ * @return total deviation
+ */
+ public double getTotalDeviation() {
+ double devsum = 0.;
+ for (double dev : _pixmap.values()) {
+ devsum += Math.abs(dev);
+ }
+ return devsum;
+ }
+}
CDMS/src/CDMS/Partridge/ImageComparison
diff -N CompareImages.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ CompareImages.java 5 Sep 2010 20:20:10 -0000 1.1
@@ -0,0 +1,176 @@
+/*
+ * CompareImages.java
+ */
+
+package CDMS.Partridge.ImageComparison;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Compare two sets of images by finding significant deviations in the image and
+ * clustering the regions containing these differences.
+ *
+ * @author Richard Partridge
+ */
+public class CompareImages {
+
+ private double _seed_threshold;
+ private double _neighbor_threshold;
+
+ /**
+ * Constructor for the CompareImages class. The constructor has two
+ * parameters that control the clustering. The seed threshold is the
+ * minimum intensity deviation required to form a new cluster, while
+ * the neighbor threshold is the minimum deviation required to be added
+ * to a cluster.
+ *
+ * @param seed_threshold seed threshold
+ * @param neighbor_threshold neighbor threshold
+ */
+ public CompareImages(double seed_threshold, double neighbor_threshold) {
+ _seed_threshold = seed_threshold;
+ _neighbor_threshold = neighbor_threshold;
+ }
+
+ /**
+ * Finds clusters of significant intensity deviations between two sets
+ * of images. The user provides a map relating pairs of image descriptors
+ * for the images to be compared. The image descriptor serving as the key
+ * is the image being examined, while the image descriptor serving as the
+ * value is the image descriptor for the reference image.
+ *
+ * @param imagemap map giving set of image pairs to be compared
+ * @return list of clusters found
+ */
+ public List<Cluster> FindClusters(Map<ImageDescriptor, ImageDescriptor> imagemap) {
+
+ // Create the list of clusters
+ List<Cluster> clusterlist = new ArrayList<Cluster>();
+
+ // If no images to check, we are done
+ if (imagemap.size() == 0) return clusterlist;
+
+ // Initialize the image bounds and minimum pixel size
+ double xmin = 9999.;
+ double xmax = -9999.;
+ double ymin = 99999.;
+ double ymax = -9999.;
+ double dxmin = 9999.;
+ double dymin = 9999.;
+
+ // Loop over all pairs of test and reference image descriptors
+ for (Entry<ImageDescriptor, ImageDescriptor> entry : imagemap.entrySet()) {
+
+ // Check that the pixel arrays for the reference and test images are identical
+ PixelArray testpix = entry.getKey().getPixelArray();
+ PixelArray refpix = entry.getValue().getPixelArray();
+ if (!testpix.equals(refpix))
+ throw new RuntimeException("Test and Reference pixel arrays are not consistent");
+
+ // Accumulate bounds on the images and the smallest pixel size
+ xmin = Math.min(xmin, refpix.getXMin());
+ xmax = Math.max(xmax, refpix.getXMax());
+ ymin = Math.min(ymin, refpix.getYMin());
+ ymax = Math.max(ymax, refpix.getYMax());
+ dxmin = Math.min(dxmin, refpix.getXSize());
+ dymin = Math.min(dymin, refpix.getYSize());
+ }
+
+ // Create a mother pixelarray to cover the extent given of the images
+ int ncol = (int) Math.floor(2. * Math.max(xmax, -xmin) / dxmin + 0.5);
+ int nrow = (int) Math.floor(2. * Math.max(ymax, -ymin) / dymin + 0.5);
+ PixelArray mother = new PixelArray(nrow, ncol, 0., 0., dxmin, dymin);
+
+ // Add subarrays to the mother array for each image
+ for (ImageDescriptor descriptor : imagemap.keySet()) {
+
+ // Get the pixel array for this image
+ PixelArray pixarray = descriptor.getPixelArray();
+
+ // Get the image ID and check that it is unique
+ int id = descriptor.getIdentifer();
+ if (mother.getSubArray(id)!= null)
+ throw new RuntimeException("Duplicate imaged descriptor ID: "+id);
+
+ // Create a subarray in the mother array for this image
+ mother.addSubArray(id, pixarray);
+ }
+
+ // Create a map relating mother pixels to deviations above the neighbor cut
+ Map<Long, Double> devmap = new HashMap<Long, Double>();
+
+ // Loop over images and find significant deviations
+ for (Entry<ImageDescriptor, ImageDescriptor> entry : imagemap.entrySet()) {
+ ImageDescriptor test = entry.getKey();
+ ImageDescriptor ref = entry.getValue();
+ ImageData testimage = test.getImageData();
+ ImageData refimage = ref.getImageData();
+ PixelArray pixarray = test.getPixelArray();
+ for (int row=0; row<pixarray.getNRow(); row++) {
+ for (int col=0; col<pixarray.getNCol(); col++) {
+ int refrgb = refimage.getRGB(row, col);
+ int testrgb = testimage.getRGB(row, col);
+ int dblue = refimage.getBlue(refrgb) - testimage.getBlue(testrgb);
+ int dgreen = refimage.getGreen(refrgb) - testimage.getGreen(testrgb);
+ int dred = refimage.getRed(refrgb) - testimage.getGreen(testrgb);
+ double deviation = Math.sqrt((dblue*dblue + dgreen*dgreen + dred*dred) / 3.);
+ if (Math.abs(deviation) > _neighbor_threshold) {
+ long pixel = pixarray.getPixel(row, col);
+ double x = pixarray.getX(pixel);
+ double y = pixarray.getY(pixel);
+ long mpixel = mother.getPixel(x, y);
+ devmap.put(pixel, deviation);
+ }
+ }
+ }
+ }
+
+ // Cluster the deviations
+ NearestNeighborClustering clusterer = new NearestNeighborClustering();
+ clusterer.setNeighborThreshold(_neighbor_threshold);
+ clusterer.setSeedThreshold(_seed_threshold);
+ List<Cluster> clusters = clusterer.findClusters(mother, devmap);
+
+ return clusters;
+ }
+
+ /**
+ * Return the neighbor threshold.
+ *
+ * @return neighbor threshold
+ */
+ public double getNeighbor_threshold() {
+ return _neighbor_threshold;
+ }
+
+ /**
+ * Set the neighbor threshold.
+ *
+ * @param neighbor_threshold neighbor threshold
+ */
+ public void setNeighbor_threshold(double neighbor_threshold) {
+ _neighbor_threshold = neighbor_threshold;
+ }
+
+ /**
+ * Return the seed threshold.
+ *
+ * @return seed threshold
+ */
+ public double getSeed_threshold() {
+ return _seed_threshold;
+ }
+
+ /**
+ * Set the seed threshold.
+ *
+ * @param seed_threshold seed threshold
+ */
+ public void setSeed_threshold(double seed_threshold) {
+ _seed_threshold = seed_threshold;
+ }
+}
CDMS/src/CDMS/Partridge/ImageComparison
diff -N ImageDescriptor.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ImageDescriptor.java 5 Sep 2010 20:20:10 -0000 1.1
@@ -0,0 +1,180 @@
+/*
+ * ImageDescriptor.java
+ */
+
+package CDMS.Partridge.ImageComparison;
+
+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/ImageComparison
diff -u -r1.1 -r1.2
--- NearestNeighborClustering.java 4 Sep 2010 01:25:37 -0000 1.1
+++ NearestNeighborClustering.java 5 Sep 2010 20:20:10 -0000 1.2
@@ -47,6 +47,16 @@
}
/**
+ * Minimal constructor - you must set the seed and neighbor thresholds before
+ * calling the findClusters method.
+ */
+ public NearestNeighborClustering() {
+
+ _seed_threshold = -2;
+ _neighbor_threshold = -1;
+ }
+
+ /**
* Set the seed threshold.
*
* @param seed_threshold seed threshold
@@ -90,7 +100,7 @@
* @param pixmap map containing deviations for pixels selected for clustering
* @return list of clusters, with a cluster being a list of pixels
*/
- public List<List<Long>> findClusters(PixelArray pixarray, Map<Long, Double> pixmap) {
+ public List<Cluster> findClusters(PixelArray pixarray, Map<Long, Double> pixmap) {
// Check that the seed threshold is at least as large as the neighbor threshold
if (_seed_threshold < _neighbor_threshold)
@@ -119,7 +129,7 @@
}
// Create a list of clusters
- List<List<Long>> clusterlist = new ArrayList<List<Long>>();
+ List<Cluster> clusterlist = new ArrayList<Cluster>();
// Loop over the cluster seeds
for (Long seed_pixel : cluster_seeds) {
@@ -128,7 +138,7 @@
if (!clusterable.get(seed_pixel)) continue;
// Create a new cluster
- List<Long> cluster = new ArrayList<Long>();
+ Cluster cluster = new Cluster(pixarray);
// Create a queue to hold channels whose neighbors need to be checked for inclusion
LinkedList<Long> unchecked = new LinkedList<Long>();
@@ -142,7 +152,7 @@
// Pull the next pixel off the queue and add it to the cluster
long clustered_pixel = unchecked.removeFirst();
- cluster.add(clustered_pixel);
+ cluster.addPixel(clustered_pixel, pixmap.get(clustered_pixel));
// Get the neigbor channels
Set<Long> neighbor_pixels = pixarray.getNeighbors(clustered_pixel);
CDMS/src/CDMS/Partridge/ImageComparison
diff -u -r1.1 -r1.2
--- PixelArray.java 4 Sep 2010 01:25:38 -0000 1.1
+++ PixelArray.java 5 Sep 2010 20:20:10 -0000 1.2
@@ -383,4 +383,20 @@
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;
+ }
}
CVSspam 0.2.8