package fr.unistra.pelican.algorithms.morphology.binary; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.BooleanImage; import fr.unistra.pelican.util.morphology.FlatStructuringElement2D; /** * Compute a 2D granulometry using rectangular SE and efficient implementation * * @author Jonathan Weber, Lefevre * */ public class Binary2DGranulometry extends Algorithm { /** * Image to be processed */ public BooleanImage inputImage; /** * Limit max of SE's length */ public Integer xMax; /** * Limit max of SE's width */ public Integer yMax; /** * Step for SE's size variation */ public Integer step; /** * SE's angle rotation */ public Double angle = 0.; /** * Flag to compute differential granulometry instead of standard one */ public boolean diff = false; /** * Granulometry array */ public Double[][] outputTab; /** * Constructor * */ public Binary2DGranulometry() { super.inputs = "inputImage,xMax,yMax,step"; super.options = "angle,diff"; super.outputs = "outputTab"; } /* * (non-Javadoc) * * @see fr.unistra.pelican.Algorithm#launch() */ public void launch() throws AlgorithmException { // Initialisation int xCurve, yCurve; if (xMax % 2 == 0) xCurve = xMax / step; else xCurve = xMax / step + 1; if (yMax % 2 == 0) yCurve = yMax / step; else yCurve = yMax / step + 1; outputTab = new Double[xCurve][yCurve]; // Compute the total number of pixels to be used in the ratio measure double total = inputImage.getSum(); boolean calcul; // Computation of the granulometry for (int i = 0; i < xMax; i = i + step) { calcul = true; BooleanImage erosionH = BinaryErosion .exec(inputImage, FlatStructuringElement2D .createLineFlatStructuringElement(i + 1, angle), 2); // BooleanImage erosionH = BinaryErosion.exec(inputImage, // FlatStructuringElement2D.rotate(FlatStructuringElement2D // .createHorizontalLineFlatStructuringElement(i + 1), angle), 2); for (int j = 0; j < yMax; j = j + step) { if (calcul) { // Decompose the 2D opening by a sequence of 1D erosions and // dilations BooleanImage erosionV = BinaryErosion.exec(erosionH, FlatStructuringElement2D.createLineFlatStructuringElement(j + 1, angle + 90), 2); BooleanImage dilationH = BinaryDilation.exec(erosionV, FlatStructuringElement2D.createLineFlatStructuringElement(i + 1, angle), 2); BooleanImage open = BinaryDilation.exec(dilationH, FlatStructuringElement2D.createLineFlatStructuringElement(j + 1, angle + 90), 2); // BooleanImage erosionV = BinaryErosion.exec(erosionH, // FlatStructuringElement2D.rotate(FlatStructuringElement2D // .createVerticalLineFlatStructuringElement(j + 1), angle), 2); // BooleanImage dilationH = BinaryDilation.exec(erosionV, // FlatStructuringElement2D.rotate(FlatStructuringElement2D // .createHorizontalLineFlatStructuringElement(i + 1), angle), 2); // BooleanImage open = BinaryDilation.exec(dilationH, // FlatStructuringElement2D.rotate(FlatStructuringElement2D // .createVerticalLineFlatStructuringElement(j + 1), angle), 2); // Compute the number of pixels after the opening double nb = open.getSum(); outputTab[i / step][j / step] = nb / total; // Check if optimization can be applied if (nb == 0.) calcul = false; } else { // Set all remaining values of the line to 0 int z; for (z = j; z < yMax; z = z + step) outputTab[i / step][z / step] = 0.; j = z; } } } if (diff) { Double outputTab2[][] = new Double[xCurve][yCurve]; for (int i = 0; i < xCurve; i++) for (int j = 0; j < yCurve; j++) { if (i == 0 && j == 0) outputTab2[i][j] = 0.0; else if (i == 0) outputTab2[i][j] = outputTab[i][j - 1] - outputTab[i][j]; else if (j == 0) outputTab2[i][j] = outputTab[i - 1][j] - outputTab[i][j]; else outputTab2[i][j] = 2 * outputTab[i - 1][j - 1] - outputTab[i][j - 1] - outputTab[i - 1][j]; outputTab2[i][j] /= 2; } outputTab = outputTab2; } } /** * This method computes a 2D granulometry using rectangular SE and efficient * implementation. * * @param inputImage * Image to be processed * @param xMax * Limit max of SE's length * @param yMax * Limit max of SE's width * @param step * Step for SE's size variation * @param angle * SE's angle rotation * @return 2D granulometry */ public static Double[][] exec(BooleanImage inputImage, Integer xMax, Integer yMax, Integer step, Double angle) { return (Double[][]) new Binary2DGranulometry().process(inputImage, xMax, yMax, step, angle); } public static Double[][] exec(BooleanImage inputImage, Integer xMax, Integer yMax, Integer step, Double angle, boolean diff) { return (Double[][]) new Binary2DGranulometry().process(inputImage, xMax, yMax, step, angle, diff); } }