package fr.unistra.pelican.algorithms.segmentation; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.Image; import fr.unistra.pelican.IntegerImage; /** * This class performs a watershed segmentation using Multi-Degree Immersion Simulation * described in S. Peng and L. Gu. A novel implementation of watershed transform using * multi-degree immersion simulation. In 27th Annual International Conference * of the Engineering in Medicine and Biology Society, pages 1754-1757,2005. * * It works by default on Byte resolution. The maximum number of created segment * is 2^31-1. It return an IntegerImage, the first segment as label * Integer.MIN_VALUE. * * XY : 8-connectivity * XYT : 26-connectivity * XYZ : 26-connectivity * XYZTB : 80-connectivity, each band processed independantly * * @author Jonathan Weber */ public class WatershedUsingMultiDegreeImmersion extends Algorithm { /** * The input image */ public Image inputImage; /** * The output image */ public Image outputImage; private int xDim; private int yDim; private int zDim; private int tDim; private int bDim; /** * Constructor */ public WatershedUsingMultiDegreeImmersion() { super.inputs = "inputImage"; super.options = ""; super.outputs = "outputImage"; } /** * Performs a watershed segmentation Multi-Degree Immersion Simulation * * @param inputImage The input image * @return outputImage The output image */ public static IntegerImage exec(Image inputImage) { return (IntegerImage) new WatershedUsingMultiDegreeImmersion().process(inputImage); } @Override public void launch() throws AlgorithmException { Image newValues = inputImage.copyImage(false); xDim = inputImage.getXDim(); yDim = inputImage.getYDim(); zDim = inputImage.getZDim(); tDim = inputImage.getTDim(); bDim = inputImage.getBDim(); if(xDim>1&&yDim>1&&zDim==1&&tDim==1&&bDim==1)//Spatial 2D case { for(int y=0;y<yDim;y++) for(int x=0;x<xDim;x++) { newValues.setPixelXYByte(x, y, Math.max(0, calculateDiffXY(x,y))); } outputImage = Watershed2.exec(newValues,Watershed2.CLOSESTVALUE); } else if (xDim>1&&yDim>1&&zDim==1&&tDim>1&&bDim==1) //Video case { for(int t=0;t<tDim;t++) for(int y=0;y<yDim;y++) for(int x=0;x<xDim;x++) { newValues.setPixelXYTByte(x, y, t, Math.max(0, calculateDiffXYT(x,y,t))); } outputImage = WatershedND.exec(newValues); } else if (xDim>1&&yDim>1&&zDim==1&&tDim>1&&bDim==1) //Spatial 3D case { for(int z=0;z<zDim;z++) for(int y=0;y<yDim;y++) for(int x=0;x<xDim;x++) { newValues.setPixelXYTByte(x, y, z, Math.max(0, calculateDiffXYZ(x,y,z))); } outputImage = WatershedND.exec(newValues); } else //All the others cases but not optimized... { 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++) for(int b=0;b<bDim;b++) { newValues.setPixelXYZTBByte(x, y, z, t, b, Math.max(0, calculateDiffXYZTB(x,y,z,t,b))); } outputImage = WatershedND.exec(newValues); } } private int calculateDiffXY(int x, int y) { int diff=0; int pixelValue = inputImage.getPixelXYByte(x, y); for(int yNeighbour=-1;yNeighbour<=1;yNeighbour++) for(int xNeighbour=-1;xNeighbour<=1;xNeighbour++) { if(!(xNeighbour==0&&yNeighbour==0)) { int _x=x+xNeighbour; int _y=y+yNeighbour; if(_x>=0&&_y>=0&&_x<xDim&&_y<yDim) { diff+= Math.abs(pixelValue - inputImage.getPixelXYByte(_x, _y)); } } } diff/=8; // We take 8-connectivity into account return diff; } private int calculateDiffXYT(int x, int y, int t) { int diff=0; int pixelValue = inputImage.getPixelXYTByte(x, y, t); for(int tNeighbour=-1;tNeighbour<=1;tNeighbour++) for(int yNeighbour=-1;yNeighbour<=1;yNeighbour++) for(int xNeighbour=-1;xNeighbour<=1;xNeighbour++) { if(!(xNeighbour==0&&yNeighbour==0&&tNeighbour==0)) { int _x=x+xNeighbour; int _y=y+yNeighbour; int _t=t+tNeighbour; if(_x>=0&&_y>=0&&_t>=0&&_x<xDim&&_y<yDim&&_t<tDim) { diff+= Math.abs(pixelValue - inputImage.getPixelXYTByte(_x, _y, _t)); } } } diff/=26; // We take 26-connectivity into account return diff; } private int calculateDiffXYZ(int x, int y, int z) { int diff=0; int pixelValue = inputImage.getPixelXYTByte(x, y, z); for(int zNeighbour=-1;zNeighbour<=1;zNeighbour++) for(int yNeighbour=-1;yNeighbour<=1;yNeighbour++) for(int xNeighbour=-1;xNeighbour<=1;xNeighbour++) { if(!(xNeighbour==0&&yNeighbour==0&&zNeighbour==0)) { int _x=x+xNeighbour; int _y=y+yNeighbour; int _z=z+zNeighbour; if(_x>=0&&_y>=0&&_z>=0&&_x<xDim&&_y<yDim&&_z<zDim) { diff+= Math.abs(pixelValue - inputImage.getPixelXYZByte(_x, _y, _z)); } } } diff/=26; // We take 26-connectivity into account return diff; } private int calculateDiffXYZTB(int x, int y, int z, int t, int b) { int diff=0; int pixelValue = inputImage.getPixelXYTByte(x, y, z); for(int tNeighbour=-1;tNeighbour<=1;tNeighbour++) for(int zNeighbour=-1;zNeighbour<=1;zNeighbour++) for(int yNeighbour=-1;yNeighbour<=1;yNeighbour++) for(int xNeighbour=-1;xNeighbour<=1;xNeighbour++) { if(!(xNeighbour==0&&yNeighbour==0&&zNeighbour==0)) { int _x=x+xNeighbour; int _y=y+yNeighbour; int _z=z+zNeighbour; int _t=t=t+tNeighbour; if(_x>=0&&_y>=0&&_z>=0&&_t>=0&&_x<xDim&&_y<yDim&&_z<zDim&&_t<tDim) { diff+= Math.abs(pixelValue - inputImage.getPixelXYZTBByte(_x, _y, _z, _t, b)); } } } diff/=80; // We take 80-connectivity into account return diff; } }