package fr.unistra.pelican.util.morphology; import java.awt.Point; import java.util.ArrayList; import fr.unistra.pelican.BooleanImage; import fr.unistra.pelican.DoubleImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.visualisation.MViewer; import fr.unistra.pelican.algorithms.visualisation.Viewer2D; import fr.unistra.pelican.util.Point4D; /** * A grayscale structuring element; * to be used in conjunction with grayscale morphology * * @author Abdullah * @deprecated */ public class GrayStructuringElement extends DoubleImage implements StructuringElement { /** * */ public static final long serialVersionUID = 234524; // x.y as in image coordinates. // no more rows & columns confusion, enough is enough! protected Point center; protected ArrayList<Point[]> points = null; /* * the value considered to be background.. */ private static double INF = Double.NEGATIVE_INFINITY; /** * copy constructor with no pixel cloning * @param e the structuring element to clone. */ public GrayStructuringElement(GrayStructuringElement e) { super(e.getXDim(),e.getYDim(),1,1,1); this.center = (Point) e.getCenter().clone(); } /** * */ public GrayStructuringElement copyImage(boolean copy) { return new GrayStructuringElement(this,copy); } /** * * @param se * @param copy */ public GrayStructuringElement(GrayStructuringElement se, boolean copy) { super(se); this.center = se.center; if(copy == true) this.setPixels((double[])se.getPixels().clone()); else this.setPixels(new double[se.getXDim() * se.getYDim() * 1 * 1 * 1]); } /** * @param xdim number of columns * @param ydim number of rows */ public GrayStructuringElement(int xdim, int ydim) { super(xdim,ydim,1,1,1); } /** * @param xdim number of columns * @param ydim number of rows * @param bdim number of channels */ public GrayStructuringElement(int xdim, int ydim,int bdim) { super(xdim,ydim,1,1,bdim); } /** * @param xdim horizontal dimension * @param ydim vertical dimension * @param centre center of the structuring element. */ public GrayStructuringElement(int xdim, int ydim, Point centre) { super(xdim,ydim,1,1,1); this.center = (Point) centre.clone(); this.setCenter(new Point4D(centre.x,centre.y,0,0)); } /** * @param xdim horizontal dimension * @param ydim vertical dimension * @param bdim number of channels * @param centre center of the structuring element. */ public GrayStructuringElement(int xdim, int ydim, int bdim, Point centre) { super(xdim,ydim,1,1,bdim); this.center = (Point) centre.clone(); } /** * * @param img input image * @param center center */ public GrayStructuringElement(Image img, Point center) { super(img); this.center = (Point) center.clone(); } /** * @param x * @param y * @return whether the pixel at the given location is non zero */ public boolean isValue(int x, int y) { return getPixelXYBDouble(x,y,0) > INF; } /** * @param x * @param y * @param b * @return whether the pixel at the given location is non zero */ public boolean isValue(int x, int y,int b) { return getPixelXYBDouble(x,y,b) > INF; } /** * Get pixel value with respect to center translation * @param x * @param y * @return */ public double getCenteredValue(int x, int y) { return getPixelXYDouble(x+center.x, y+center.y); } /** * Get pixel value * @param x * @param y * @return */ public double getValue(int x, int y) { return getPixelXYDouble(x, y); } /** * Get pixel value with respect to center translation * @param x * @param y * @return */ public double getCenteredValue(int x, int y, int b) { return getPixelXYBDouble(x+center.x, y+center.y,b); } /** * * @return the maximum value of this se */ public double getMaxValue() { double max = 0.0; for(int i = 0; i < size(); i++){ double d = getPixelDouble(i); if (d > max) max = d; } return max; } /** * @param center */ public void setCenter(Point center) { this.center = center; } /** * @return the center */ //public Point getCenter() //{ // return center; //} /** * Create a circle of radius radius (plus the pixel at the cross). * * @param radius * @return */ public static GrayStructuringElement createCircleStructuringElement(int radius) { GrayStructuringElement se = new GrayStructuringElement(2 * radius + 1, 2 * radius + 1); se.resetCenter(); se.center = new Point(radius,radius); se.fill(INF); for (int i = 0; i < 2 * radius + 1; i++) { for (int j = 0; j < 2 * radius + 1; j++) { if (Math.sqrt(Math.pow(i - radius, 2) + Math.pow(j - radius, 2)) <= radius + 0.000001) se.setPixelXYDouble(i, j, 1.0); } } return se; } /** * Create a cone of radius radius (plus the pixel at the cross) and height height. * * @param radius * @return */ public static GrayStructuringElement createConeStructuringElement(int radius, int height) { GrayStructuringElement se = new GrayStructuringElement(2 * radius + 1, 2 * radius + 1); se.resetCenter(); se.fill(INF); for (int i = 0; i < 2 * radius + 1; i++) { for (int j = 0; j < 2 * radius + 1; j++) { double distFromCenter = Math.sqrt(Math.pow(i - radius, 2) + Math.pow(j - radius, 2)); if (distFromCenter <= radius + 0.000001) { se.setPixelXYByte(i, j, (int) ((1-(distFromCenter/radius))*height)); } } } return se; } /** * Create a cone of radius radius (plus the pixel at the cross) and height height. * * @param radius * @return */ public static GrayStructuringElement createConeToZeroStructuringElement(int radius, double slope) { GrayStructuringElement se = new GrayStructuringElement(2 * radius + 1, 2 * radius + 1); se.resetCenter(); se.fill(INF); for (int i = 0; i < 2 * radius + 1; i++) { for (int j = 0; j < 2 * radius + 1; j++) { double distFromCenter = Math.sqrt(Math.pow(i - radius, 2) + Math.pow(j - radius, 2)); if (distFromCenter <= radius + 0.000001) { se.setPixelXYDouble(i, j, -distFromCenter*slope); } } } //MViewer.exec(se); return se; } /** * Create a vertical line of length length. The center is at length/2 * @param length length of se * @return the resulting se */ public static GrayStructuringElement createVerticalLineFlatStructuringElement(int length) { GrayStructuringElement se = new GrayStructuringElement(1,length,new Point(0,length/2)); se.fill(1.0); return se; } /** * Create a horizontal line of length length. The center is at length/2. * @param length * @return the resulting SE */ public static GrayStructuringElement createHorizontalLineGrayStructuringElement(int length) { GrayStructuringElement se = new GrayStructuringElement(length,1,new Point(length/2,0)); se.resetCenter(); se.fill(1.0); return se; } /** * Create a horizontal line of length length. The center is at center. * @param length * @param center * @return the resulting SE */ public static GrayStructuringElement createHorizontalLineFlatStructuringElement(int length, Point center) { GrayStructuringElement se = new GrayStructuringElement(length,1,center); se.fill(1.0); return se; } /** * Create a cross line of radius radius (plus the pixel at the cross). * @param radius * @return the resulting SE */ public static GrayStructuringElement createCrossFlatStructuringElement(int radius) { GrayStructuringElement se = new GrayStructuringElement(2 * radius + 1,2 * radius + 1, new Point(radius, radius)); for (int i = 0; i < 2 * radius + 1; i++){ se.setPixelXYDouble(i, radius,1.0); se.setPixelXYDouble(radius, i,1.0); } return se; } /** Create a square of edge's length size. Center is at (size/2, size/2). * * @param size * @return se */ public static GrayStructuringElement createSquareFlatStructuringElement(int size) { GrayStructuringElement se = new GrayStructuringElement(size,size,new Point(size/2,size/2)); se.fill(1.0); return se; } /** * Create a rectangle. Center is at (height/2, width/2). * * @param xdim * @param ydim * * @return se the resulting se */ public static GrayStructuringElement createRectangularFlatStructuringElement(int xdim, int ydim) { GrayStructuringElement se = new GrayStructuringElement(xdim,ydim,new Point(xdim/2,ydim/2)); se.fill(1.0); return se; } /** * * @param se1 * @param se2 * @return whether the two SEs have the same centre. */ public static boolean haveSameCentre(GrayStructuringElement se1,GrayStructuringElement se2){ return se1.getCenter().equals(se2.getCenter()); } /** * * @return the number of pixels strictement superior to INF */ public int[] numberOfActivePixels() { int[] tmp = new int[getBDim()]; for(int b = 0; b < getBDim(); b++){ for(int x = 0; x < getXDim(); x++){ for(int y = 0 ; y < getYDim(); y++){ if(isValue(x,y,b) == true) tmp[b]++; } } } return tmp; } /** * Apply a central symmetry on SE * SE(p)=SE(-p) * @return reflected SE */ public GrayStructuringElement getReflection() { GrayStructuringElement se = new GrayStructuringElement(this,false); int xd=this.getXDim()-1; int yd=this.getYDim()-1; se.setCenter(new Point(xd-this.getCenter().x,yd-this.getCenter().y) ); for(int j=0;j<=yd;j++) for(int i=0;i<=xd;i++) { se.setPixelXYDouble(xd-i,yd-j,this.getPixelXYDouble(i, j)); } return se; } /** * Get dual SE* from SE defined as * SE*(p) = -SE(p) * * Support is also inverted * * Caution: this definition differs from usual one : SE*(p)=-SE*(-p) * @return dual from SE */ public GrayStructuringElement dual() { GrayStructuringElement se = new GrayStructuringElement(this,true); for(int i = 0; i < size(); i++) se.setPixelDouble(i,-1.0 * se.getPixelDouble(i)); GrayStructuringElement.INF = -1.0; return se; } /** * If the centre of the SE is set (=true) then it must be placed first! * * @return an array of Points containing the coordinates of pixels set to true */ public ArrayList<Point[]> getPoints() { if(points != null) return points; int[] tmp = numberOfActivePixels(); points = new ArrayList<Point[]>(getBDim()); for(int b = 0; b < getBDim(); b++){ Point[] p = new Point[tmp[b]]; int k = 0; if(isValue(center.x,center.y,b) == true) p[k++] = new Point(center.x,center.y); for(int x = 0; x < getXDim(); x++){ for(int y = 0 ; y < getYDim(); y++){ if(isValue(x,y,b) == true && !(x == center.x && y == center.y)) p[k++] = new Point(x,y); } } points.add(p); } return points; } /** * Get the actual value representing the background (default value is 0) * @return the iNF */ public static double getINF() { return GrayStructuringElement.INF; } /** * Set the value representing the background * @param inf the iNF to set */ public static void setINF(double inf) { GrayStructuringElement.INF = inf; } public GrayStructuringElement rotate(double degree) { double angleradian = Math.toRadians(degree); double xinput = this.getXDim(); double yinput = this.getYDim(); double tcos = Math.cos(-angleradian); double tsin = Math.sin(-angleradian); double atcos = Math.cos(angleradian); double atsin = Math.sin(angleradian); int xoutput = (int) Math.round(xinput * Math.abs(tcos) + yinput * Math.abs(tsin)); int youtput = (int) Math.round(xinput * Math.abs(tsin) + yinput * Math.abs(tcos)); // System.out.println(xoutput + " " + youtput + " ... " // + (xinput * Math.abs(tcos) + yinput * Math.abs(tsin)) + " " // + (xinput * Math.abs(tsin) + yinput * Math.abs(tcos))); int xm = this.getXDim() / 2; int ym = this.getYDim() / 2; int xmprime = xoutput / 2; int ymprime = youtput / 2; GrayStructuringElement se = new GrayStructuringElement(xoutput, youtput, new Point(xoutput / 2, youtput / 2)); se.fill(INF); for (int x = 0; x < this.getXDim(); x++) for (int y = 0; y < this.getYDim(); y++) { int xprime = (int) Math.round((x - xm) * atcos - (y - ym) * atsin + xmprime); int yprime = (int) Math.round((x - xm) * atsin + (y - ym) * atcos + ymprime); if (xprime < 0) { xprime = 0; } if (xprime >= xoutput) { xprime = xoutput - 1; } if (yprime < 0) { yprime = 0; } if (yprime >= youtput) { yprime = youtput - 1; } se.setPixelXYDouble(xprime, yprime, this.getValue(x, y)); } int centreX = (int) this.getCenter().getX(); int centreY = (int) this.getCenter().getY(); int centreXprime = (int) Math.round((centreX - xm) * atcos - (centreY - ym) * atsin + xmprime); int centreYprime = (int) Math.round((centreX - xm) * atsin + (centreY - ym) * atcos + ymprime); if (centreXprime < 0) { centreXprime = 0; } if (centreXprime >= xoutput) { centreXprime = xoutput - 1; } if (centreYprime < 0) { centreYprime = 0; } if (centreYprime >= youtput) { centreYprime = youtput - 1; } se.setCenter(new Point(centreXprime, centreYprime)); se.setCenter(new Point4D(centreXprime,centreYprime,0,0)); return se; } /** * Reset the center of the gse to the central position */ public void resetCenter() { super.resetCenter(); this.center=new Point(xdim/2,ydim/2); } }