package fr.unistra.pelican.algorithms.histogram;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.BooleanImage;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.algorithms.morphology.gray.GrayASF;
import fr.unistra.pelican.algorithms.morphology.gray.GrayLeveling;
import fr.unistra.pelican.algorithms.morphology.gray.GrayOpening;
import fr.unistra.pelican.algorithms.morphology.gray.geodesic.GrayOpeningByReconstruction;
import fr.unistra.pelican.util.morphology.FlatStructuringElement2D;
/**
*
* Produces normalized histograms with a custom number of bins using a custom
* scale-space.
*
* @author Erchan Aptoula
*
*/
public class CustomMultiscaleHistogram extends Algorithm {
/**
* first input parameter.
*/
public Image input;
/**
* Output parameter.
*/
public double[] output;
/**
* Second input parameter which is the number of bins of each band.
*/
public int size;
/**
* Third input parameter which is the number of scales.
*/
public int scales;
/**
* Fourth input parameter which is the type of scale.
*/
public int type;
private static final int Opening = 0;
private static final int OpeningByRecon = 1;
private static final int ASF = 2;
private static final int Leveling = 3;
/**
* Constructor
*
*/
public CustomMultiscaleHistogram() {
super();
super.inputs = "input,size,scales,type";
super.outputs = "output";
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() throws AlgorithmException {
int totalHistoSizePerScale = size * size * size;
output = new double[scales * totalHistoSizePerScale];
for (int s = 0; s < scales; s++) {
// prepare this scale
Image tmp = null;
if (type == Opening) {
BooleanImage se = FlatStructuringElement2D
.createSquareFlatStructuringElement(s * 2 + 1);
tmp = (Image) new GrayOpening().process(input, se);
} else if (type == OpeningByRecon) {
BooleanImage se = FlatStructuringElement2D
.createSquareFlatStructuringElement(s * 2 + 1);
tmp = (Image) new GrayOpeningByReconstruction().process(input,
se);
} else if (type == ASF) {
BooleanImage se = FlatStructuringElement2D
.createSquareFlatStructuringElement(5);
tmp = (Image) new GrayASF().process(input, se,
GrayASF.OPENING_FIRST, new Integer(s + 1));
} else if (type == Leveling) {
BooleanImage se = FlatStructuringElement2D
.createSquareFlatStructuringElement(5);
Image marker = (Image) new GrayASF().process(input, se,
GrayASF.OPENING_FIRST, new Integer(s * 2 + 1));
tmp = (Image) new GrayLeveling().process(input, marker,
new Integer(0));
} else
throw new AlgorithmException("Unsupported scale space type");
// extract the histogram
for (int x = 0; x < input.getXDim(); x++) {
for (int y = 0; y < input.getYDim(); y++) {
int[] p = tmp.getVectorPixelXYZTByte(x, y, 0, 0);
output[s * totalHistoSizePerScale + p[0] * size * size
+ p[1] * size + p[2]]++;
}
}
}
// normalize
for (int i = 0; i < output.length; i++)
output[i] = output[i] / (input.getXDim() * input.getYDim());
}
/**
* Produces normalized histograms with a custom number of bins using a
* custom scale-space.
*
* @param inputImage
* Image to be converted in a histogram.
* @return The normalized histogram.
*/
public static Image exec(Image input) {
return (Image) new CustomMultiscaleHistogram().process(input);
}
/**
* Produces normalized histograms with a custom number of bins using a
* custom scale-space.
*
* @param inputImage
* Image to be converted in a histogram.
* @param size
* The number of bins of each band.
* @param scales
* The number of scales.
* @param type
* The type of scale.
* @return The normalized histogram.
*/
public static Image exec(Image input, int size, int scales, int type) {
return (Image) new CustomMultiscaleHistogram().process(input, size, scales, type);
}
}