package fr.unistra.pelican.algorithms.statistics; import java.util.Vector; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.BooleanImage; import fr.unistra.pelican.DoubleImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.morphology.gray.GrayClosing; import fr.unistra.pelican.util.morphology.FlatStructuringElement2D; /** * * Given a colour image in a polar colour space, this class allegedly computes the major * hue references. * * In more detail, the input is supposed to be a HSY (or similar: HSV,HSL) colour image. We * first compute the hue histogram..optionally weighted with saturation (+ * luminance) * * optionally an opening is applied * * and the 1D-histogram is clustered..using either meanshift (on 1D???) or * threshold+CC or even a wshed * * and we return the mean of each cluster and its discrete integral. as a vector * containing arrays of doubles to be used with the MultipleHueOrdering class * * 19/12/2006 * * @author Abdullah * */ public class MultipleReferenceHues extends Algorithm { /** * the input image */ public Image input; /** * the computed reference points */ public Vector output; /** * Given a colour image in a polar colour space, this class allegedly computes the major hue references * @param input the input image * @return the reference hues */ public static Vector exec(Image input) { return (Vector) new MultipleReferenceHues().process(input); } /** * Constructor * */ public MultipleReferenceHues() { super(); super.inputs = "input"; super.outputs = "output"; } /* * (non-Javadoc) * * @see fr.unistra.pelican.Algorithm#launch() */ public void launch() throws AlgorithmException { // compute its normalised histogram...over 360 bins double[] histoOriginal = new double[360]; double[] histoTmp = new double[360]; for (int x = 0; x < input.getXDim(); x++) { for (int y = 0; y < input.getYDim(); y++) { double sat = input.getPixelXYBDouble(x, y, 1); double coeff = 1 / (1 + Math.exp(-5.0 * (sat - 0.5))); histoOriginal[(int) Math.floor(360.0 * input.getPixelXYBDouble(x,y,0))] += coeff; } } // normalize for (int i = 0; i < 360; i++) histoOriginal[i] = histoOriginal[i] / input.size(); // Image histoImg = BasicHistogramViewer.exec(histoOriginal); // Viewer2D.exec(histoImg,"asil dagilim"); // set histo as image Image tmp = new DoubleImage(360, 1, 1, 1, 1); for (int x = 0; x < 360; x++) tmp.setPixelXYDouble(x, 0, histoOriginal[x]); BooleanImage se = FlatStructuringElement2D .createHorizontalLineFlatStructuringElement(10); // close it tmp = (Image) new GrayClosing().process(tmp, se); // take back the values for (int x = 0; x < 360; x++) histoTmp[x] = tmp.getPixelXYDouble(x, 0); // get its average double avg = 0.0; for (int x = 0; x < 360; x++) avg += histoTmp[x]; avg = avg / 360.0; System.err.println("Average hue:"+avg); //avg/=2; //avg = 0.00035; // threshold using its average for (int x = 0; x < 360; x++) if (histoTmp[x] < avg) histoTmp[x] = 0.0; // histoImg = BasicHistogramViewer.exec(histoTmp); // Viewer2D.exec(histoImg,"islenmis dagilim"); // get CCs and dont forget to connect the extrema of the hue circle Section[] sections = new Section[180]; // max CC number int j = 0; boolean flag = false; for (int x = 0; x < 360; x++) { if (histoTmp[x] > 0.0) { flag = false; if (sections[j] == null) { sections[j] = new Section(x, x); sections[j].sum += histoOriginal[x]; } else { sections[j].end++; sections[j].sum += histoOriginal[x]; } } else { if (flag == false && sections[j] != null) { j++; flag = true; } } } // index of the last section for (int last = 0; sections[last] != null; last++) // if the first and last sections are connected add them to the last if (sections[0].start == 0 && sections[last].end == 359) { sections[last].end = sections[0].end; sections[last].sum += sections[0].sum; sections[0] = sections[last]; sections[last] = null; } for (int k = 0; sections[k] != null; k++) System.err.println(sections[k].start + " " + sections[k].end + " " + sections[k].sum); // for(int x = 0; x < 360; x++) // System.err.println(histo[x]); output = new Vector(); // return the maximum and integral of each histogram section for (int i = 0; sections[i] != null; i++) { // get the maximum double[] couple = new double[2]; double max = 0.0; int sectorLength = sections[i].end - sections[i].start; if (sectorLength < 0) sectorLength = 360 + sectorLength; for (int syc = 0, k = sections[i].start; syc < sectorLength; k = (++k) % 360, syc++) { if (histoOriginal[k] > max) { couple[0] = k / 360.0; max = histoOriginal[k]; } } couple[1] = sections[i].sum; System.err.println("ref " + couple[0]); output.add(couple); } System.err.println(output.size()); /* * for(int k = 0; sections[k] != null; k++){ double[] d = * (double[])output.get(k); System.err.println(d[0] + " " + d[1]); } */ } private class Section { int start; int end; double sum; Section(int start, int end) { this.start = start; this.end = end; this.sum = 0.0; } } }