package fr.unistra.pelican; import java.awt.Point; import java.io.Serializable; import java.util.Arrays; import fr.unistra.pelican.util.Point4D; /** This class represents an Image of boolean values * A boolean pixel is false (black) or true (white). * @author PELICAN team * @version 1.0 */ public class BooleanImage extends Image implements Serializable { /** * Pixel data array */ private boolean[] pixels; /** * Serial version ID */ private static final long serialVersionUID = 3L; /** * Constructs a BooleanImage */ protected BooleanImage(){ super(); } /** * Constructs a BooleanImage identical to the given argument * @param image BooleanImage to copy */ public BooleanImage(BooleanImage image) { super(image); this.pixels = (boolean[])image.pixels.clone(); // deep copy with clone valid only for primitives. } /** * Constructs a BooleanImage identical to the given argument * @param image Image to copy */ public BooleanImage(Image image) { this(image, true); } /** * Constructs a BooleanImage identical to the given argument * @param image Image to copy * @param copyData if and only if it is set to true are the pixels copied */ public BooleanImage(Image image, boolean copyData) { super(image); this.pixels = new boolean[image.getXDim() * image.getYDim() * image.getZDim() * image.getTDim() * image.getBDim()]; if(copyData == true) for(int i = 0; i < pixels.length; i++) setPixelBoolean(i, image.getPixelBoolean(i)); } /** * Constructs a ByteImage from the given argument. The pixels are copied if and only of ''copy'' is set to true. * @param image ByteImage to copy * @param copy if and only if it is set to true are the pixels copied */ public BooleanImage(BooleanImage image, boolean copy) { super(image); if(copy == true) this.pixels = (boolean[])image.pixels.clone(); else this.pixels = new boolean[image.getXDim() * image.getYDim() * image.getZDim() * image.getTDim() * image.getBDim()]; } /** * Constructs a BooleanImage with the given dimensions * @param xdim the horizontal dimension * @param ydim the vertical dimension * @param zdim the depth * @param tdim the frame number * @param bdim the channel number */ public BooleanImage(int xdim,int ydim,int zdim,int tdim,int bdim) { super(xdim,ydim,zdim,tdim,bdim); this.pixels = new boolean[xdim * ydim * zdim * tdim * bdim]; } /** * Creates a copy of this BooleanImage * @return an axact copy of this BooleanImage */ public BooleanImage copyImage(boolean copyData) { return new BooleanImage(this, copyData); } /** * Creates a new instance of BooleanImage * @param xdim the horizontal dimension * @param ydim the vertical dimension * @param zdim the depth * @param tdim the frame number * @param bdim the channel number */ public Image newInstance(int xdim,int ydim,int zdim,int tdim,int bdim) { return new BooleanImage(xdim,ydim,zdim,tdim,bdim); } /** * Sets all the pixel values to the given boolean * @param b Desired value for the pixels */ public void fill(boolean b) { Arrays.fill(pixels,b); } @Override public void fill(double d) { this.fill(doubleToBoolean(d)); } /** * Duplicates the given channel to all the available dimensions * @param band channel to duplicate */ public void duplicateBand(int band) { for(int x = 0; x < this.xdim; x++) for(int y = 0; y < this.ydim; y++) for(int z = 0; z < this.zdim; z++) for(int t = 0; t < this.tdim; t++) for(int b = 0; b < this.bdim; b++) if(b != band) setPixelBoolean(x,y,z,t,b,getPixelBoolean(x,y,z,t,band)); } /** * Checks if the image is empty, i.e. it contains only 0 pixels * @return true if the image is empty */ public boolean isEmpty() { for (int p=0;p<pixels.length;p++) if (pixels[p]) return false; return true; } /** * Computes the total number of pixels in all dimensions * @return the number of pixels */ public int size() { return pixels.length; } /** * Gets a copy of the pixel array * @return a copy of the pixel array */ public boolean[] getPixels() { return (boolean[])pixels.clone(); } /** * Sets the pixels to the copy of the given array * @param values pixel array to copy */ public void setPixels(boolean[] values) { pixels = (boolean[])values.clone(); } /** * Computes the complement image * @return the complement BooleanImage */ public BooleanImage getComplement() { BooleanImage im = new BooleanImage(this); for(int i = 0; i < size(); i++) im.setPixelBoolean(i,!pixels[i]); return im; } /** * Computes the number of "true" pixels * @return the number of true pixels */ public int getSum() { int sum=0; for(int i = 0; i < size(); i++) if ( isPresent(i) && getPixelBoolean(i) ) sum++; return sum; } /** * Extracts the positions of foreground pixels * @return the array of foreground pixels */ public Point4D[] foreground() { int s=getSum(); Point4D tab[]=new Point4D[s]; int k=0; for (int t=0;t<tdim;t++) for (int z=0;z<zdim;z++) for (int y=0;y<ydim;y++) for (int x=0;x<xdim;x++) if ( isPresentXYZT( x,y,z,t ) && getPixelXYZTBoolean( x,y,z,t ) ) tab[k++]=new Point4D(x,y,z,t); return tab; } /** * Extracts the positions of foreground pixels * @return the array of foreground pixels */ public Point[] foreground2D() { int s=getSum(); Point tab[]=new Point[s]; int k=0; for (int y=0;y<ydim;y++) for (int x=0;x<xdim;x++) if ( isPresentXY(x,y) && getPixelXYBoolean(x,y) ) tab[k++]=new Point(x,y); return tab; } /** * Compares with the given BooleanImage * @param im image to compare * @return <code>true</code> if and only if the given image has the same pixel values as this image */ public boolean equals(Image im) { if(im==null || !(im instanceof BooleanImage)) return false; if(!haveSameDimensions(im,this)) return false; int size = size(); boolean impresent,thispresent; for(int i = 0; i < size; i++) { impresent = im.isPresent(i); thispresent = this.isPresent(i); if ( !impresent && thispresent ) return false; if ( impresent && !thispresent ) return false; if ( impresent && thispresent ) if ( im.getPixelBoolean(i) != pixels[i] ) return false; } return true; } @Override public double getPixelDouble(int loc) { return booleanToDouble(pixels[loc]); //return pixels[loc] ? 1.0 : 0.0; } @Override public int getPixelInt(int loc) { return booleanToInt(pixels[loc]); //return pixels[loc] ? Integer.MAX_VALUE : Integer.MIN_VALUE; } @Override public int getPixelByte(int loc) { return booleanToUnsignedByte(pixels[loc]); //return pixels[loc] ? 255 : 0; } @Override public boolean getPixelBoolean(int loc) { return pixels[loc]; } @Override public void setPixelDouble(int loc, double value) { pixels[loc] = doubleToBoolean(value); //pixels[loc] = (value >= 0.5) ? true : false; } @Override public void setPixelInt(int loc, int value) { pixels[loc] =intToBoolean(value); //pixels[loc] = (value >= 0) ? true : false; } @Override public void setPixelByte(int loc, int value) { pixels[loc] = unsignedByteToBoolean(value); //pixels[loc] = (value >= 128) ? true : false; } @Override public void setPixelBoolean(int loc, boolean value) { pixels[loc] = value; } @Override public void setPixel(Image input, int x1, int y1, int z1, int t1, int b1, int x2, int y2, int z2, int t2, int b2) { this.setPixelBoolean(x1, y1, z1, t1, b1, input .getPixelBoolean(x2, y2, z2, t2, b2)); } /** * Convert the BooleanImage to a ByteImage without modifying the values * @return an ByteImage */ public ByteImage copyToByteImage() { ByteImage i=new ByteImage(this,false); for (int p=0;p<i.size();p++) i.setPixelByte(p,getPixelBoolean(p)?1:0); return i; } /** * Convert the BooleanImage to a IntegerImage without modifying the values * @return an IntegerImage */ public IntegerImage copyToIntegerImage() { IntegerImage i=new IntegerImage(this,false); for (int p=0;p<i.size();p++) i.setPixelInt(p,getPixelBoolean(p)?1:0); return i; } /** * Gets the minimum from the whole image. * @return * The minimum as a boolean */ public boolean minimum(){ for (int p = 0; p < size(); p++) if (!getPixelBoolean(p)) return false; return true; } /** * Gets the maximum from the whole image. * @return * The maximum as a boolean */ public boolean maximum(){ for (int p = 0; p < size(); p++) if (getPixelBoolean(p)) return true; return false; } /** * Gets the minimum from a band of the image. * @param band * Band. * @return * The minimum of the selected band as a boolean */ public boolean minimum(int band){ for (int p = band; p < size(); p+=this.getBDim()) if (!getPixelBoolean(p)) return false; return true; } /** * Gets the maximum from a band of the image. * @param band * Band. * @return * The maximum of the selected band as a boolean */ public boolean maximum(int band){ for (int p = band; p < size(); p+=this.getBDim()) if (getPixelBoolean(p)) return true; return false; } @Override public boolean maximumBoolean() { return this.maximum(); } @Override public int maximumByte() { return booleanToUnsignedByte(this.maximum()); } @Override public double maximumDouble() { return booleanToDouble(this.maximum()); } @Override public double maximumDouble(int band) { return booleanToDouble(this.maximum(band)); } @Override public double maximumDoubleIgnoreNonRealValues(int band) { return booleanToDouble(this.maximum(band)); } @Override public int maximumInt() { return booleanToInt(this.maximum()); } @Override public boolean minimumBoolean() { return this.minimum(); } @Override public int minimumByte() { return booleanToUnsignedByte(this.minimum()); } @Override public double minimumDouble() { return booleanToDouble(this.minimum()); } @Override public double minimumDouble(int band) { return booleanToDouble(this.minimum(band)); } @Override public double minimumDoubleIgnoreNonRealValues(int band) { return booleanToDouble(this.minimum(band)); } @Override public int minimumInt() { return booleanToInt(this.minimum()); } }