package fr.unistra.pelican.algorithms.morphology.gray;
import java.awt.Point;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.BooleanImage;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.util.morphology.FlatStructuringElement2D;
/**
* This class performs alternating sequential filters (ASF).
*
* @author Erchan Aptoula
*/
public class GrayASF extends Algorithm {
/**
* The input image
*/
public Image input;
/**
* The flat structuring element used in the morphological operation
*/
public BooleanImage se;
/**
* The type of ASF : OPENING_FIRST or CLOSING_FIRST
*/
public int flag;
/**
* The number of iterations
*/
public int times;
/**
* The output image
*/
public Image output;
/**
* Constant representing ASF with opening as first operation
*/
public static final int OPENING_FIRST = 0;
/**
* Constant representing ASF with closing as first operation
*/
public static final int CLOSING_FIRST = 1;
/**
* Default constructor
*/
public GrayASF() {
super.inputs = "input,se,flag,times";
super.outputs = "output";
}
/**
* Performs alternating sequential filters (ASF)
*
* @param input
* The input image
* @param se
* The flat structuring element used in the morphological
* operation
* @param flag
* The type of ASF : OPENING_FIRST or CLOSING_FIRST
* @param times
* The number of iterations
* @return The output image
*/
public static Image exec( Image input, BooleanImage se, int flag, int times ) {
return (Image) new GrayASF().process(input, se, flag, times);
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() {
this.output = this.input.copyImage(true);
if ( this.flag != OPENING_FIRST && this.flag != CLOSING_FIRST )
throw new AlgorithmException( "Invalid flag" );
if ( this.times < 1 )
throw new AlgorithmException( "The number of iterations should be at least one" );
if ( isRectangle( this.se ) ) {
for ( int i = 0; i < this.times; i++ ) {
if ( this.flag == OPENING_FIRST ) {
this.output = GrayOpening.exec( this.output,this.se );
this.output = GrayClosing.exec( this.output,this.se );
} else {
this.output = GrayClosing.exec( this.output,this.se );
this.output = GrayOpening.exec( this.output,this.se );
}
this.se = new BooleanImage( this.se.getXDim()+2,this.se.getYDim()+2,1,1,1 );
}
} else {
// the SE used to dilate the given SE
BooleanImage magnifier = FlatStructuringElement2D.createSquareFlatStructuringElement(3);
// prepare the SE so that it can take the dilation results...
BooleanImage tmp = new BooleanImage( se.getXDim()+2*times,se.getYDim()+2*times,1,1,1);
se.setCenter(new Point( se.getCenter().x + times, se.getCenter().y + times));
tmp.fill(false);
for ( int x = 0 ; x < se.getXDim() ; x++ )
for ( int y = 0 ; y < se.getYDim() ; y++ )
tmp.setPixelXYBoolean( x+times, y+times, this.se.getPixelXYBoolean(x,y) );
se = tmp;
for (int i = 0; i < times; i++) {
if (flag == OPENING_FIRST) {
output = GrayOpening.exec(output, se);
output = GrayClosing.exec(output, se);
} else {
output = GrayClosing.exec(output, se);
output = GrayOpening.exec(output, se);
}
se = (BooleanImage) GrayDilation.exec(se, magnifier);
}
}
}
private static boolean isRectangle( BooleanImage se ) {
return se.getSum() == se.size();
}
}