package fr.unistra.pelican.algorithms.morphology.soft;
import java.awt.Point;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.algorithms.io.ImageLoader;
import fr.unistra.pelican.algorithms.visualisation.Viewer2D;
import fr.unistra.pelican.util.SortedBag;
import fr.unistra.pelican.util.morphology.GrayIntStructuringElement;
/**
* Perform a soft erosion with a flat structuring element and a weight map.
* Flat SE and weight map are represented with a GrayIntStructuringElement.
* The flat structuring element is encoded as the value greater than 0.
* Greater value than 0 gives the weight of the pixel.
*
* The threshold is used for rank operation.
*
* Example: consider image {1,5,2} and SE {1,2,3} with threshold 2
* We want to compute the value of pixel at the center:
* We take the 2th lower element of the sorted bag composed of one 1, two 5 and three 2: {1,2,2,2,5,5}
* that is 2!
*
* If all weights are set to 1, this is equivalent to a simple rank filter.
*
* Work on double precision.
* @author Benjamin Perret
*/
public class SoftErosion extends Algorithm {
/**
* Input image
*/
public Image inputImage;
/**
* Rank order
*/
public int threshold;
/**
* Gray Structuring Element, value are treated as integer
*/
public GrayIntStructuringElement se;
/**
* Result
*/
public Image outputImage;
/**
* Default constructor
*/
public SoftErosion()
{
super.inputs="inputImage,se,threshold";
super.outputs="outputImage";
}
/** Return the min value under a flat structuring element.
* @param x
* @param y
* @param z
* @param t
* @param b
* @return
*/
private double getMinGray(int x,int y, int z,int t,int b, Point [] points)
{
double min = 0;
boolean flag = false;
SortedBag sb=new SortedBag();
for (int i = 0; i < points.length; i++) {
int valX = x - se.getCenter().x + points[i].x;
int valY = y - se.getCenter().y + points[i].y;
if( valX>=0 && valX < inputImage.getXDim()
&& valY>=0 && valY < inputImage.getYDim()
&& inputImage.isPresent( valX,valY,z,t,b ) ) {
sb.add( inputImage.getPixelDouble( valX,valY,z,t,b),
se.getPixelXYInt(points[i].x,points[i].y));
flag = true;
}
}
min=sb.getElementAt(Math.max(sb.size()-threshold, 0)).doubleValue();
// FIXME: Strange, if nothing is under the se, what is the right way?
return (flag == true)? min : inputImage.getPixelDouble(x,y,z,t,b);
}
/* (non-Javadoc)
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() throws AlgorithmException {
outputImage = inputImage.copyImage(false);
int xDim = inputImage.getXDim();
int yDim = inputImage.getYDim();
int tDim = inputImage.getTDim();
int bDim = inputImage.getBDim();
int zDim = inputImage.getZDim();
int size = 0;
for(int i = 0; i < se.getXDim(); i++)
for(int j = 0 ; j < se.getYDim(); j++)
if(se.isValue(i,j) == true) size++;
Point[] points = new Point[size];
int k = 0;
for(int i = 0; i < se.getXDim(); i++){
for(int j = 0 ; j < se.getYDim(); j++){
if(se.isValue(i,j) == true) points[k++] = new Point(i,j);
}
}
for ( int b = 0 ; b < bDim ; b++ )
for ( int t = 0 ; t < tDim ; t++ )
for ( int z = 0 ; z < zDim ; z++ )
for ( int x = 0 ; x < xDim ; x++ )
for ( int y = 0 ; y < yDim ; y++ )
if ( inputImage.isPresent( x,y,z,t,b ) )
outputImage.setPixelDouble(x,y,z,t,b,getMinGray(x,y,z,t,b,points));
}
public static void main(String [] args)
{
int size=31;
GrayIntStructuringElement se= new GrayIntStructuringElement(size,size,new Point(size/2,size/2));
se.fill(0.0);
for (int i =0;i<size;i++)
{
se.setPixelXYInt(i,size/2,size/2-Math.abs(size/2-i));
se.setPixelXYInt(size/2,i,size/2-Math.abs(size/2-i));
}
Viewer2D.exec(se,"SE");
Image im=ImageLoader.exec("samples/detection_test.png");
Viewer2D.exec(im,"Original");
Viewer2D.exec(SoftErosion.exec(im, se, 1),"Erosion cross 31*31, threshold=1, normal erosion");
Viewer2D.exec(SoftErosion.exec(im, se, 20),"Erosion cross 31*31, threshold=20");
Viewer2D.exec(SoftErosion.exec(im, se, 80),"Erosion cross 31*31, threshold=40");
}
/**
* Perform a soft erosion with a flat structuring element and a weight map.
* Flat SE and weight map are represented with a GrayIntStructuringElement.
* The flat structuring element is encoded as the value greater than 0.
* Greater value than 0 gives the weight of the pixel.
*
* The threshold is used for rank operation.
*
* Example: consider image {1,5,2} and SE {1,2,3} with threshold 2
* We want to compute the value of pixel at the center:
* We take the 2th lower element of the sorted bag composed of one 1, two 5 and three 2: {1,2,2,2,5,5}
* that is 2!
*
* If all weights are set to 1, this is equivalent to a simple rank filter.
*
* Work on double precision.
* @param image
* The input image
* @param se
* The gray structuring element with weighted position (int precision)
* @param thresold
* Rank order threshold
* @return The output image
*/
public static Image exec(Image image, GrayIntStructuringElement se, int threshold) {
return (Image) new SoftErosion().process(image, se,threshold);
}
}