Flood Fill Algorithms

前端 未结 7 2215
借酒劲吻你
借酒劲吻你 2020-11-30 08:40

Its the weekend again, and that means I get to play with my hobby project.

I\'ve gotten tired of creating test levels by hand, so I thought I\'d take a break from en

相关标签:
7条回答
  • 2020-11-30 09:06

    We had to program that for school:

    1: stuff the start pixel into a queue, note its color. note it as added.
    2: begin picking a pixel off the queue. If it's similar to the start pixel:
       2: put all its neighbours into the queue
          for each added pixel, note it's added. if already noted for a pixel, don't 
          add it anymore.
       3: color it with the destination color.
    3: nonempty => jump back to 2
    4: empty => we are finished
    

    Depending on whether we do 8-neighbour or 4-neighbour, we check all 8 neighbour pixels, or only pixels left/right or above/below a certain pixel. Here is the code (using ImageJ. I removed some code not relevant). I hope it makes sense, it's Java. Just ask away for questions:

    public class Uebung1_2 implements PlugInFilter, MouseListener {
        private ImageProcessor ip;
        boolean[] state;
        int[] pixels;
        Queue<Integer> nextPixels;
        int threshould;
    
        /**
         * adds one pixel to the next-pixel queue only if it's not
         * already added.
         */
        void addNextPixel(int p) {
            if(!state[p]) {
                nextPixels.add(p);
                state[p] = true;
            }
        }
    
        boolean pixelsSimilar(int color1, int color2) {
            int dr = Math.abs(((color1 >> 16) & 0xff) -
                              ((color2 >> 16) & 0xff));
            int dg = Math.abs(((color1 >>  8) & 0xff) -
                              ((color2 >>  8) & 0xff));
            int db = Math.abs(((color1 >>  0) & 0xff) -
                              ((color2 >>  0) & 0xff));
            return ((double)(dr + dg + db) / 3.0) <= threshould;
        }
    
        /**
         * actually does the hard work :)
         * @param x the x position from which to start filling
         * @param y the y position from which to start filling
         */
        private void doFill(int x, int y, boolean connect8) {
            // first, add the start pixel
            int width = ip.getWidth(),
                height = ip.getHeight();
            /* for 8bit, we just gonna take the median of rgb */
            Color colorC = ij.gui.Toolbar.getForegroundColor();
            int color = colorC.getRGB();
            int firstPixel = ip.get(x, y);
    
            // go on with the mainloop
            addNextPixel(y * width + x);
            while(!nextPixels.isEmpty()) {
                int nextPixel = nextPixels.remove();
                int pixel = pixels[nextPixel];
                if(pixelsSimilar(pixel, firstPixel)) {
                    // yay it matches. put the neighbours.
                    int xN = nextPixel % width,
                        yN = nextPixel / width;
                    /* the three pixels above */
                    if(yN - 1 >= 0) {
                        if(connect8) {
                            if(xN + 1 < width) { 
                                addNextPixel(nextPixel - width + 1);
                            }
                            if(xN - 1 >= 0) {
                                addNextPixel(nextPixel - width - 1);
                            }
                        }
                        addNextPixel(nextPixel - width);
                    }
    
                    /* pixels left and right from the current one */
                    if(xN > 0) {
                        addNextPixel(nextPixel - 1);
                    }
                    if(xN + 1 < width) {
                        addNextPixel(nextPixel + 1);
                    }
    
                    /* three pixels below */
                    if(yN + 1 < height) {
                        if(connect8) {
                            if(xN + 1 < width) { 
                                addNextPixel(nextPixel + width + 1);
                            }
                            if(xN - 1 >= 0) {
                                addNextPixel(nextPixel + width - 1);
                            }
                        }
                        addNextPixel(nextPixel + width);
                    }
    
                    /* color it finally */
                    pixels[nextPixel] = color;
                }
            }
        }
    
        @Override
        public void run(ImageProcessor ip) {
            ij.WindowManager.getCurrentImage().getCanvas().addMouseListener(this);
            this.ip = ip;
            this.pixels = (int[])ip.getPixels();
            this.state = new boolean[ip.getPixelCount()];
            this.nextPixels = new LinkedList<Integer>();
        }
    
        @Override
        public int setup(String arg0, ImagePlus arg1) {
            return DOES_RGB;
        }
    
        @Override
        public void mouseClicked(MouseEvent e) {
            ij.WindowManager.getCurrentWindow().getCanvas().removeMouseListener(this);
            ij.gui.GenericDialog g = new GenericDialog("Please enter parameters");
            g.addChoice("connection", new String[]{"4-connect", "8-connect"}, "8-connect");
            g.addNumericField("Threshould (0..255)", 0.0, 3);
            g.showDialog();
    
            boolean connect8 = g.getNextChoice().equals("8-connect");
            threshould = (int) g.getNextNumber();
            doFill(e.getX(), e.getY(), connect8);
            ij.WindowManager.getCurrentImage().draw();
        }
    }
    
    0 讨论(0)
提交回复
热议问题