package fr.unistra.pelican.algorithms.applied.remotesensing; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.BooleanImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.InvalidNumberOfParametersException; import fr.unistra.pelican.InvalidTypeOfParameterException; import fr.unistra.pelican.algorithms.arithmetic.AdditionConstantChecked; import fr.unistra.pelican.algorithms.arithmetic.DeleteSmallValues; import fr.unistra.pelican.algorithms.arithmetic.EuclideanNorm; import fr.unistra.pelican.algorithms.morphology.gray.GrayDilation; import fr.unistra.pelican.algorithms.morphology.gray.GrayGradient; import fr.unistra.pelican.algorithms.morphology.gray.geodesic.FastGrayReconstruction; import fr.unistra.pelican.algorithms.segmentation.Watershed; import fr.unistra.pelican.algorithms.segmentation.flatzones.BooleanConnectedComponentsLabeling; import fr.unistra.pelican.algorithms.segmentation.labels.DeleteFrontiers; import fr.unistra.pelican.util.morphology.FlatStructuringElement2D; /** * Create regions using the watershed algorithm on original image. * Settings are : * - hmin : threshold value of the gradient image to limit oversegmentation * - dynamics min dynamics to be taken in account. * - min spatial size to create a bassin. * * @author Sebastien Derivaux */ public class RegionBuilderWatershedClassical extends Algorithm { // Inputs parameters public Image inputImage; public double hmin; public double dynamics; public int spatial; // Outputs parameters public Image outputImage; /** * Constructor * */ public RegionBuilderWatershedClassical() { super(); super.inputs = "inputImage,hmin,dynamics,spatial"; super.outputs = "outputImage"; } /* (non-Javadoc) * @see fr.unistra.pelican.Algorithm#launch() */ public void launch() throws AlgorithmException { BooleanImage se3 = FlatStructuringElement2D.createSquareFlatStructuringElement(3); Image work; try { // Compute the gradient on each band work = (Image) new GrayGradient().process(inputImage, se3); //work = ContrastStretchEachBands.process(work); Image process = (Image) new EuclideanNorm().process(work); // Compute the euclidian distance of the gradient work = process; //Viewer2D.exec(work, "RegionBuilderWatershedClassical"); Object process2 = new AdditionConstantChecked().process(work, 0.0); work = (Image) process2; //work = ContrastStretch.process(work); //Viewer2D.exec(work, "RegionBuilderWatershedClassical"); // Reduce the gradient image with hmin to remove useless local // minima if(hmin > 0.0) work = (Image) new DeleteSmallValues().process(work, hmin); // reduce catchement bassins with low dynamic if(dynamics > 0.0 ) { Image upper = (Image) new AdditionConstantChecked().process(work, dynamics); // work = (Image) new GrayReconstructionByErosion().process(upper, work, se3); work = (Image) new FastGrayReconstruction().process(upper, work , BooleanConnectedComponentsLabeling.CONNEXITY8, true); } // reduce catchement bassins with low surface if(spatial > 0) { BooleanImage sufFilter = FlatStructuringElement2D.createSquareFlatStructuringElement(spatial); Image dil = (Image) new GrayDilation().process(work, sufFilter); work = (Image) new FastGrayReconstruction().process(dil, work , BooleanConnectedComponentsLabeling.CONNEXITY8, true); } // Process a watershed transformation work = (Image) new Watershed().process(work); work = (Image) new DeleteFrontiers().process(work); outputImage = work; } catch (InvalidTypeOfParameterException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidNumberOfParametersException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Create regions using the watershed algorithm on original image. */ public static Image exec(Image image) throws InvalidTypeOfParameterException, AlgorithmException, InvalidNumberOfParametersException { return (Image)new RegionBuilderWatershedClassical().process(image, 0.0, 0.0, 0); } /** * Create regions using the watershed algorithm on original image. * Settings are : * @param hmin threshold value of the gradient image to limit oversegmentation */ public static Image exec(Image image, double hmin) throws InvalidTypeOfParameterException, AlgorithmException, InvalidNumberOfParametersException { return (Image)new RegionBuilderWatershedClassical().process(image, hmin, 0.0, 0); } /** * Create regions using the watershed algorithm on original image. * Settings are : * @param hmin threshold value of the gradient image to limit oversegmentation * @param dynamics min dynamics to be taken in account. */ public static Image exec(Image image, double hmin, double dynamic) throws InvalidTypeOfParameterException, AlgorithmException, InvalidNumberOfParametersException { return (Image)new RegionBuilderWatershedClassical().process(image, hmin, dynamic, 0); } /** * Create regions using the watershed algorithm on original image. * Settings are : * @param dynamics min dynamics to be taken in account. * @param min spatial size to create a bassin. * */ public static Image exec(Image image, double dynamic, int spatial) throws InvalidTypeOfParameterException, AlgorithmException, InvalidNumberOfParametersException { return (Image)new RegionBuilderWatershedClassical().process(image, 0, dynamic, spatial); } /** * Create regions using the watershed algorithm on original image. * Settings are : * @param hmin threshold value of the gradient image to limit oversegmentation * @param dynamics min dynamics to be taken in account. * @param min spatial size to create a bassin. * */ public static Image exec(Image image, double hmin, double dynamic, int spatial) throws InvalidTypeOfParameterException, AlgorithmException, InvalidNumberOfParametersException { return (Image)new RegionBuilderWatershedClassical().process(image, hmin, dynamic, spatial); } // public static void main(String[] args) { // String file = "./samples/remotesensing1"; // // if(args.length > 0) // file = args[0]; // // // try { // // Load the image // Image source = (Image) new ImageLoader().process(file + ".png"); // Image regions = (Image) new RegionsLoader().process(file); // // System.out.println("RegionBuilderWatershedClassical of " + file); // // // Create regions // Image result = (Image) new RegionBuilderWatershedClassical().process(source, 0.0, 0.0, 0); // // // Easy filter // /* FlatStructuringElement labelFilter = FlatStructuringElement.createSquareFlatStructuringElement(5); // result = FilteringLabels.process(result, labelFilter); //*/ // // View it // new Viewer2D().process(new DrawFrontiersOnImage().process(source, new FrontiersFromSegmentation().process(result)), "RegionBuilderWatershedClassical of " + file); // //Viewer2D.exec(LabelsToColorByMeanValue.process(result, source), "RegionBuilderWatershedClassical of " + file); // // System.out.println(EvalSegmentation.process(result, regions)); // // // result = (Image)new RegionBuilderWatershedClassical().process(source, 0.0, 0.15, 0); // // // Easy filter // /* FlatStructuringElement labelFilter = FlatStructuringElement.createSquareFlatStructuringElement(5); // result = FilteringLabels.process(result, labelFilter); //*/ // // View it // new Viewer2D().process(new DrawFrontiersOnImage().process(source,new FrontiersFromSegmentation().process(result)), "RegionBuilderWatershedClassical of " + file); // //Viewer2D.exec(LabelsToColorByMeanValue.process(result, source), "RegionBuilderWatershedClassical of " + file); // // System.out.println(EvalSegmentation.process(result, regions)); // // // } catch (InvalidTypeOfParameterException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (AlgorithmException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (InvalidNumberOfParametersException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } }