首页 文章

用Java实现分水岭分割

提问于
浏览
18

我正在尝试为项目编写自己的Watershed Segmentation实现 . 我有一个版本,返回类似于正确分割的东西给出非常琐碎的图片 . 不幸的是,它超级慢/效率低,它可能会或可能不会在所有情况下终止 .

我一直在使用Woods和Gonzales的“数字图像处理”中的描述,以及Watershed Wikipedia页面 . 一般算法编码并包含在下面,但我有一种感觉,我循环了很多我不需要的东西 . 我非常感谢这里的所有帮助,提前谢谢 .

public static Set<Point> watershed(double[][] im) {

    //Get the Gradient Magnitude to use as our "topographic map."

    double t1 = System.currentTimeMillis();
    double[][] edges = EdgeDetection.sobelMagnitude(im);


    //Only iterate over values in the gradient magnitude to speed up.

    double[] histogram = Image.getHistogram(edges);
    Image.drawHistogram(histogram, Color.red);
    int minPixelValue = 0;
    for (int i = 0; i < histogram.length; i++) {
        if (histogram[i] > 0) {
            minPixelValue = i;
            break;
        }
    }
    int h = im.length;
    int w = im[0].length;

    //SE is a 3x3 structuring element for morphological dilation.
    boolean[][] SE = {{true, true, true}, {true, true, true}, {true, true, true}};

    //Keeping track of last iteration's components to see if two flooded together.
    ArrayList<Set<Point>> lastComponents = connectedComponents(getSet(EdgeDetection.underThreshold(edges, minPixelValue + 1)));
    ArrayList<Set<Point>> components;
    Set<Point> boundary = new HashSet<Point>();

    for (int i = minPixelValue + 1; i < 256; i++) {
        if (histogram[i] != 0) {
            System.out.println("BEHHH " + i);
            t1 = System.currentTimeMillis();
            ArrayList<Integer> damLocations = new ArrayList<Integer>();
            HashMap<Integer, ArrayList<Integer>> correspondingSets = new HashMap<Integer, ArrayList<Integer>>();
            //Figure out which of the old sets the new sets incorporated.
            //Here is where we check if sets flooded into eachother.
            //System.out.println("Checking for flooding");
            components = connectedComponents(getSet(EdgeDetection.underThreshold(edges, i)));
            for (int nc = 0; nc < components.size(); nc++) {
                //System.out.println("Checking component " + nc);
                Set<Point> newComponent = components.get(nc);
                for (int oc = 0; oc < lastComponents.size(); oc++) {
                    //System.out.println("    Against component " + oc);
                    Set<Point> oldComponent = lastComponents.get(oc);
                    if (numberInCommon(newComponent, oldComponent) > 0) {
                        //System.out.println("     In there.");
                        ArrayList<Integer> oldSetsContained;
                        if (correspondingSets.containsKey(nc)) {
                            oldSetsContained = correspondingSets.get(nc);
                            damLocations.add(nc);
                        } else {
                            //System.out.println("     Nope.");
                            oldSetsContained = new ArrayList<Integer>();

                        }
                        oldSetsContained.add(oc);
                        correspondingSets.put(nc, oldSetsContained);
                    }
                }
            }
            System.out.println("Calculating overlapping sets: " + (System.currentTimeMillis() - t1));

            //System.out.println("Check done.");
            for (int key : correspondingSets.keySet()) {
                Integer[] cs = new Integer[correspondingSets.get(key).size()];
                correspondingSets.get(key).toArray(cs);
                if (cs.length == 1) {
                    //System.out.println("Set " + cs[0] + " has grown without flooding.");
                } else {
                    //System.out.println("The following sets have flooded together: " + Arrays.toString(cs));
                }
            }

            //Build Damns to prevent flooding

            for (int c : damLocations) {

                System.out.println("Building dam for component " + c);
                Set<Point> bigComponent = components.get(c);
                System.out.println("Total size: " + bigComponent.size());
                ArrayList<Set<Point>> littleComponent = new ArrayList<Set<Point>>();
                for (int lcindex : correspondingSets.get(c)) {
                    littleComponent.add(lastComponents.get(lcindex));
                }

                Set<Point> unionSet = new HashSet<Point>(boundary);
                for (Set<Point> lc : littleComponent) {
                    unionSet = union(unionSet, lc);

                }
                System.out.println("Building union sets: " + (System.currentTimeMillis() - t1));
                while (intersection(unionSet, bigComponent).size() < bigComponent.size()) {

                    for (int lIndex = 0; lIndex < littleComponent.size(); lIndex++) {
                        Set<Point> lc = littleComponent.get(lIndex);
                        Set<Point> lcBoundary = extractBoundaries(lc, SE, h, w);
                        Set<Point> toAdd = new HashSet<Point>();
                        Set<Point> otherComponents = new HashSet<Point>(unionSet);
                        otherComponents.removeAll(lc);
                        otherComponents.removeAll(boundary);
                        otherComponents = extractBoundaries(otherComponents, SE, h, w);
                        for (Point pt : lcBoundary) {
                            Set<Point> eightNbrs = get8Neighborhood(pt);
                            for (Point nbr : eightNbrs) {
                                if (bigComponent.contains(nbr) & !boundary.contains(nbr)) {
                                    Set<Point> neighborNbr = get8Neighborhood(nbr);
                                    if (intersection(neighborNbr, otherComponents).size() > 0) {
                                        boundary.add(nbr);
                                        edges[nbr.y][nbr.x] = 256;
                                        break;
                                    } else if (!lc.contains(nbr)) {
                                        toAdd.add(nbr);
                                        //if(i==65)System.out.println("Adding point " + nbr.y + " " + nbr.x);
                                    } else {
                                        //if(i==65)System.out.println("Already in here " + nbr.y + " " + nbr.x);
                                    }
                                }
                            }
                        }
                        t1 = System.currentTimeMillis();
                        lc.addAll(toAdd);
                        toAdd.removeAll(toAdd);

                        littleComponent.set(lIndex, lc);
                        unionSet = new HashSet<Point>(boundary);
                        for (Set<Point> ltc : littleComponent) {
                            unionSet = union(unionSet, ltc);
                        }
                        System.out.println("This is a donk " + intersection(unionSet, bigComponent).size());
                        otherComponents = new HashSet<Point>(unionSet);
                        otherComponents.removeAll(lc);
                        otherComponents.removeAll(boundary);
                    }
                }
            }
        }
    }
    boundary = close(boundary,h,w);
    Image.drawSet(boundary, h, w);
    return boundary;
}

1 回答

  • 3

    似乎算法最多为O(n ^ 2) . 你有很多嵌套循环..我无法找到伍兹的描述 . Christopher Mei的这段代码实现了算法:它是一个非常简单的实现 .

    WatershedPixel.java

    /*
     * Watershed algorithm
     *
     * Copyright (c) 2003 by Christopher Mei (christopher.mei@sophia.inria.fr)
     *
     * This plugin is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 
     * as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this plugin; if not, write to the Free Software
     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    import java.lang.*;
    import java.util.*;
    import ij.*;
    
    /**
     *  The aim of WatershedPixel is to enable
     *  sorting the pixels of an Image according
     *  to their grayscale value.
     *
     *  This is the first step of the Vincent
     *  and Soille Watershed algorithm (1991)
     *  
     **/
    
    public class WatershedPixel implements Comparable {
        /** Value used to initialise the image */
        final static int INIT = -1;
        /** Value used to indicate the new pixels that
         *  are going to be processed (intial value 
         *  at each level)
         **/
        final static int MASK = -2;
        /** Value indicating that the pixel belongs 
         *  to a watershed.
         **/
        final static int WSHED = 0;
        /** Fictitious pixel **/
        final static int FICTITIOUS = -3;
    
        /** x coordinate of the pixel **/
        private int x;
        /** y coordinate of the pixel **/
        private int y;
        /** grayscale value of the pixel **/
        private byte height; 
        /** Label used in the Watershed immersion algorithm **/
        private int label;
        /** Distance used for working on pixels */
        private int dist;
    
        /** Neighbours **/
        private Vector neighbours;
    
        public WatershedPixel(int x, int y, byte height) {
        this.x = x;
        this.y = y;
        this.height = height;
        label = INIT;
        dist = 0;
        neighbours = new Vector(8);
        }
    
        public WatershedPixel() {
        label = FICTITIOUS;
        }
    
        public void addNeighbour(WatershedPixel neighbour) {
        /*IJ.write("In Pixel, adding :");
          IJ.write(""+neighbour);
          IJ.write("Add done");
        */
        neighbours.add(neighbour);
        }
    
        public Vector getNeighbours() {
        return neighbours;
        }
    
    
    
        public String toString() {
        return new String("("+x+","+y+"), height : "+getIntHeight()+", label : "+label+", distance : "+dist); 
        }
    
    
    
        public final byte getHeight() {
        return height;
        } 
    
        public final int getIntHeight() {
        return (int) height&0xff;
        } 
    
        public final int getX() {
        return x;
        } 
    
        public final int getY() {
        return y;
        }
    
    
        /** Method to be able to use the Collections.sort static method. **/
        public int compareTo(Object o) {
        if(!(o instanceof WatershedPixel))
            throw new ClassCastException();
    
        WatershedPixel obj =  (WatershedPixel) o;
    
        if( obj.getIntHeight() < getIntHeight() ) 
            return 1;
    
        if( obj.getIntHeight() > getIntHeight() )
            return -1;
    
        return 0;
        }
    
        public void setLabel(int label) {
        this.label = label;
        }
    
        public void setLabelToINIT() {
        label = INIT;
        }
    
        public void setLabelToMASK() {
        label = MASK;
        }
    
        public void setLabelToWSHED() {
        label = WSHED;
        }
    
    
        public boolean isLabelINIT() {
        return label == INIT;
        }
        public boolean isLabelMASK() {
        return label == MASK;
        }    
        public boolean isLabelWSHED() {
        return label == WSHED;
        }
    
        public int getLabel() {
        return label;
        }
    
        public void setDistance(int distance) {
        dist = distance;
        }
    
        public int getDistance() {
        return dist;
        }
    
        public boolean isFICTITIOUS() {
        return label == FICTITIOUS;
        }
    
        public boolean allNeighboursAreWSHED() {
        for(int i=0 ; i<neighbours.size() ; i++) {
            WatershedPixel r = (WatershedPixel) neighbours.get(i);
    
            if( !r.isLabelWSHED() ) 
            return false;
        }
        return true;
        }
    }
    

    WatershedFIFO.java

    /*
     * Watershed plugin
     *
     * Copyright (c) 2003 by Christopher Mei (christopher.mei@sophia.inria.fr)
     *
     * This plugin is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 
     * as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this plugin; if not, write to the Free Software
     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    import java.util.*;
    import ij.*;
    
    /** This class implements a FIFO queue that
     *  uses the same formalism as the Vincent
     *  and Soille algorithm (1991)
     **/
    
    public class WatershedFIFO {
        private LinkedList watershedFIFO;
    
        public WatershedFIFO() {
        watershedFIFO = new LinkedList();
        }
    
        public void fifo_add(WatershedPixel p) {
        watershedFIFO.addFirst(p);
        }
    
        public WatershedPixel fifo_remove() {
        return (WatershedPixel) watershedFIFO.removeLast();
        }
    
        public boolean fifo_empty() {
        return watershedFIFO.isEmpty();
        }
    
        public void fifo_add_FICTITIOUS() {
        watershedFIFO.addFirst(new WatershedPixel());
        }
    
        public String toString() {
        StringBuffer ret = new StringBuffer();
        for(int i=0; i<watershedFIFO.size(); i++) {
            ret.append( ((WatershedPixel)watershedFIFO.get(i)).toString() );
            ret.append( "\n" );
        }
    
        return ret.toString();
        }
    }
    

    WatershedStructure.java

    /*
     * Watershed algorithm
     *
     * Copyright (c) 2003 by Christopher Mei (christopher.mei@sophia.inria.fr)
     *
     * This plugin is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 
     * as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this plugin; if not, write to the Free Software
     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    import java.lang.*;
    import java.util.*;
    import ij.process.*;
    import ij.*;
    import java.awt.*;
    
    /**
     *  WatershedStructure contains the pixels
     *  of the image ordered according to their
     *  grayscale value with a direct access to their
     *  neighbours.
     *  
     **/
    
    public class WatershedStructure {
        private Vector watershedStructure;
    
        public WatershedStructure(ImageProcessor ip) {
        byte[] pixels = (byte[])ip.getPixels();
        Rectangle r = ip.getRoi();
        int width = ip.getWidth();
        int offset, topOffset, bottomOffset, i;
    
        watershedStructure = new Vector(r.width*r.height);
    
        /** The structure is filled with the pixels of the image. **/
        for (int y=r.y; y<(r.y+r.height); y++) {
            offset = y*width;
    
            IJ.showProgress(0.1+0.3*(y-r.y)/(r.height));
    
            for (int x=r.x; x<(r.x+r.width); x++) {
            i = offset + x;
    
            int indiceY = y-r.y;
            int indiceX = x-r.x;
    
            watershedStructure.add(new WatershedPixel(indiceX, indiceY, pixels[i]));
            }
        }
    
        /** The WatershedPixels are then filled with the reference to their neighbours. **/
        for (int y=0; y<r.height; y++) {
    
            offset = y*width;
            topOffset = offset+width;
            bottomOffset = offset-width;
    
            IJ.showProgress(0.4+0.3*(y-r.y)/(r.height));
    
            for (int x=0; x<r.width; x++) {     
            WatershedPixel currentPixel = (WatershedPixel)watershedStructure.get(x+offset);
    
            if(x+1<r.width) {
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x+1+offset));
    
                if(y-1>=0)
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x+1+bottomOffset));
    
                if(y+1<r.height)
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x+1+topOffset));
            }
    
            if(x-1>=0) {
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x-1+offset));
    
                if(y-1>=0)
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x-1+bottomOffset));
    
                if(y+1<r.height)
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x-1+topOffset));
            }
    
            if(y-1>=0)
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x+bottomOffset));
    
            if(y+1<r.height)
                currentPixel.addNeighbour((WatershedPixel)watershedStructure.get(x+topOffset));
            }
        } 
    
        Collections.sort(watershedStructure);
        //IJ.showProgress(0.8);
        }
    
        public String toString() {
        StringBuffer ret = new StringBuffer();
    
        for(int i=0; i<watershedStructure.size() ; i++) {
            ret.append( ((WatershedPixel) watershedStructure.get(i)).toString() );
            ret.append( "\n" );
            ret.append( "Neighbours :\n" );
    
            Vector neighbours = ((WatershedPixel) watershedStructure.get(i)).getNeighbours();
    
            for(int j=0 ; j<neighbours.size() ; j++) {
            ret.append( ((WatershedPixel) neighbours.get(j)).toString() );
            ret.append( "\n" );
            }
            ret.append( "\n" );
        }
        return ret.toString();
        }
    
        public int size() {
        return watershedStructure.size();
        }
    
        public WatershedPixel get(int i) {
        return (WatershedPixel) watershedStructure.get(i);
        }
    }
    

    Watershed_Algorithm.java

    /*
     * Watershed algorithm
     *
     * Copyright (c) 2003 by Christopher Mei (christopher.mei@sophia.inria.fr)
     *
     * This plugin is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 
     * as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this plugin; if not, write to the Free Software
     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    import ij.*;
    import ij.plugin.filter.PlugInFilter;
    import ij.process.*;
    import ij.gui.*;
    import ij.plugin.frame.PlugInFrame;
    
    import java.awt.*;
    import java.util.*;
    
    /**
     *  This algorithm is an implementation of the watershed immersion algorithm
     *  written by Vincent and Soille (1991).
     *
     *  @Article{Vincent/Soille:1991,
     *   author =       "Lee Vincent and Pierre Soille",
     *   year =         "1991",
     *   keywords =     "IMAGE-PROC SKELETON SEGMENTATION GIS",
     *   institution =  "Harvard/Paris+Louvain",
     *   title =        "Watersheds in digital spaces: An efficient algorithm
     *                   based on immersion simulations",
     *   journal =      "IEEE PAMI, 1991",
     *   volume =       "13",
     *   number =       "6",
     *   pages =        "583--598",
     *   annote =       "Watershed lines (e.g. the continental divide) mark the
     *                  boundaries of catchment regions in a topographical map.
     *                  The height of a point on this map can have a direct
     *                  correlation to its pixel intensity. WIth this analogy,
     *                  the morphological operations of closing (or opening)
     *                  can be understood as smoothing the ridges (or filling
     *                  in the valleys). Develops a new algorithm for obtaining
     *                  the watershed lines in a graph, and then uses this in
     *                  developing a new segmentation approach based on the
     *                  {"}depth of immersion{"}.",
     *  }
     *
     *  A review of Watershed algorithms can be found at :
     *  http://www.cs.rug.nl/~roe/publications/parwshed.pdf
     *
     *  @Article{RoeMei00,
     *   author =       "Roerdink and Meijster",
     *   title =        "The Watershed Transform: Definitions, Algorithms and
     *                   Parallelization Strategies",
     *   journal =      "FUNDINF: Fundamenta Informatica",
     *   volume =       "41",
     *   publisher =    "IOS Press",
     *   year =         "2000",
     *  }
     **/
    
    public class Watershed_Algorithm implements PlugInFilter {
        private int threshold;
        final static int HMIN = 0;
        final static int HMAX = 256;
    
        public int setup(String arg, ImagePlus imp) {
        if (arg.equals("about"))
            {showAbout(); return DONE;}
        return DOES_8G+DOES_STACKS+SUPPORTS_MASKING+NO_CHANGES;
        }
    
        public void run(ImageProcessor ip) {
        boolean debug = false;
    
        IJ.showStatus("Sorting pixels...");
        IJ.showProgress(0.1);
    
        /** First step : the pixels are sorted according to increasing grey values **/
        WatershedStructure watershedStructure = new WatershedStructure(ip);
        if(debug)
            IJ.write(""+watershedStructure.toString());
    
        IJ.showProgress(0.8);
        IJ.showStatus("Start flooding...");
    
        if(debug)
            IJ.write("Starting algorithm...\n");
    
        /** Start flooding **/
        WatershedFIFO queue = new WatershedFIFO();
        int curlab = 0;
    
        int heightIndex1 = 0;
        int heightIndex2 = 0;
    
        for(int h=HMIN; h<HMAX; h++) /*Geodesic SKIZ of level h-1 inside level h */ {
    
            for(int pixelIndex = heightIndex1 ; pixelIndex<watershedStructure.size() ; pixelIndex++) /*mask all pixels at level h*/ {
            WatershedPixel p = watershedStructure.get(pixelIndex);
    
            if(p.getIntHeight() != h) {
                /** This pixel is at level h+1 **/
                heightIndex1 = pixelIndex;
                break;
            }
    
            p.setLabelToMASK();
    
            Vector neighbours = p.getNeighbours();
            for(int i=0 ; i<neighbours.size() ; i++) {
                WatershedPixel q = (WatershedPixel) neighbours.get(i);
    
                if(q.getLabel()>=0) {/*Initialise queue with neighbours at level h of current basins or watersheds*/
                p.setDistance(1);
                queue.fifo_add(p);
                break;
                } // end if
            } // end for
            } // end for
    
    
            int curdist = 1;
            queue.fifo_add_FICTITIOUS();
    
            while(true) /** extend basins **/{
            WatershedPixel p = queue.fifo_remove();
    
            if(p.isFICTITIOUS())
                if(queue.fifo_empty())
                break;
                else {
                queue.fifo_add_FICTITIOUS();
                curdist++;
                p = queue.fifo_remove();
                }
            if(debug) {
                IJ.write("\nWorking on :");
                IJ.write(""+p);
            }
    
            Vector neighbours = p.getNeighbours();
            for(int i=0 ; i<neighbours.size() ; i++) /* Labelling p by inspecting neighbours */{
                WatershedPixel q = (WatershedPixel) neighbours.get(i);
    
                if(debug)
                IJ.write("Neighbour : "+q);
    
                /* Original algorithm : 
                   if( (q.getDistance() < curdist) &&
                   (q.getLabel()>0 || q.isLabelWSHED()) ) {*/
                if( (q.getDistance() <= curdist) && 
                (q.getLabel()>=0) ) {
                /* q belongs to an existing basin or to a watershed */
    
                if(q.getLabel() > 0) {
                    if( p.isLabelMASK() )
                    // Removed from original algorithm || p.isLabelWSHED() )
                    p.setLabel(q.getLabel());
                    else
                    if(p.getLabel() != q.getLabel())
                        p.setLabelToWSHED();
                } // end if lab>0
                else
                    if(p.isLabelMASK())
                    p.setLabelToWSHED();
                }
                else
                if( q.isLabelMASK() &&
                    (q.getDistance() == 0) ) {
    
                    if(debug)
                    IJ.write("Adding value");
                    q.setDistance( curdist+1 );
                    queue.fifo_add( q );
                }       
            } // end for, end processing neighbours
    
            if(debug) {
                IJ.write("End processing neighbours");
                IJ.write("New val :\n"+p);
                IJ.write("Queue :\n"+queue);
            }
            } // end while (loop)
    
            /* Detect and process new minima at level h */
            for(int pixelIndex = heightIndex2 ; pixelIndex<watershedStructure.size() ; pixelIndex++) {
            WatershedPixel p = watershedStructure.get(pixelIndex);
    
            if(p.getIntHeight() != h) {
                /** This pixel is at level h+1 **/
                heightIndex2 = pixelIndex;
                break;
            }
    
            p.setDistance(0); /* Reset distance to zero */
    
            if(p.isLabelMASK()) { /* the pixel is inside a new minimum */
                curlab++;
                p.setLabel(curlab);         
                queue.fifo_add(p);
    
    
                while(!queue.fifo_empty()) {
                WatershedPixel q = queue.fifo_remove();
    
                Vector neighbours = q.getNeighbours();
    
                for(int i=0 ; i<neighbours.size() ; i++) /* inspect neighbours of p2*/{
                    WatershedPixel r = (WatershedPixel) neighbours.get(i);
    
                    if( r.isLabelMASK() ) {
                    r.setLabel(curlab);
                    queue.fifo_add(r);
                    }
                }
                } // end while
            } // end if
            } // end for
        } /** End of flooding **/
    
        IJ.showProgress(0.9);
        IJ.showStatus("Putting result in a new image...");
    
        /** Put the result in a new image **/
        int width = ip.getWidth();
    
        ImageProcessor outputImage = new ByteProcessor(width, ip.getHeight());
        byte[] newPixels = (byte[]) outputImage.getPixels();
    
        for(int pixelIndex = 0 ; pixelIndex<watershedStructure.size() ; pixelIndex++) {
            WatershedPixel p = watershedStructure.get(pixelIndex);
    
            if(p.isLabelWSHED() && !p.allNeighboursAreWSHED())
            newPixels[p.getX()+p.getY()*width] = (byte)255;
        }
    
        IJ.showProgress(1);
        IJ.showStatus("Displaying result...");
    
        new ImagePlus("Watershed", outputImage).show();
        }
    
        void showAbout() {
        IJ.showMessage("About Watershed_Algorithm...",
                   "This plug-in filter calculates the watershed of a 8-bit images.\n" +
                   "It uses the immersion algorithm written by Vincent and Soille (1991)\n"
                   );
        }
    }
    

相关问题