Image processing-flood Filling Algorithm (flood fill algorithm)

Source: Internet
Author: User
Tags getcolor

Flood Filling Algorithm (flood fill algorithm)

Flood filling algorithms, also known as flood filling algorithms, are commonly used in many graphic rendering software.

The paint bucket function of Windows paint. The principle of the algorithm is very simple, that is, from a point near the pixel, fill into a new

Until all pixels in the Closed Area are filled with new colors. The most common implementation of extensive red filling is the four adjacent Domains

Pixel filling method, eight-neighbor pixel filling method, and pixel Filling Method Based on scanning line. Based on implementation, it can be divided into recursion and

Non-recursive (stack-based ).

 

Before introducing the three implementation methods of an algorithm, let's first take a look at the UI implementation of this algorithm. The basic idea is to select 1.

The image to be filled. Click the inside of the area to be filled. The algorithm automatically fills the area and the UI is refreshed. End

The whole UI code is as follows:

package com.gloomyfish.paint.fill;import java.awt.Color;import java.awt.Dimension;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.MediaTracker;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;import javax.imageio.ImageIO;import javax.swing.JComponent;import javax.swing.JFileChooser;import javax.swing.JFrame;public class FloodFillUI extends JComponent implements MouseListener{/** *  */private static final long serialVersionUID = 1L;private BufferedImage rawImg;private MediaTracker tracker;private Dimension mySize;FloodFillAlgorithm ffa;public FloodFillUI(File f){try {rawImg = ImageIO.read(f);} catch (IOException e1) {e1.printStackTrace();}tracker = new MediaTracker(this);tracker.addImage(rawImg, 1);// blocked 10 seconds to load the image datatry {if (!tracker.waitForID(1, 10000)) {System.out.println("Load error.");System.exit(1);}// end if} catch (InterruptedException e) {e.printStackTrace();System.exit(1);}// end catchmySize = new Dimension(300, 300);this.addMouseListener(this);ffa = new FloodFillAlgorithm(rawImg);JFrame imageFrame = new JFrame("Flood File Algorithm Demo - Gloomyfish");imageFrame.getContentPane().add(this);imageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);imageFrame.pack();imageFrame.setVisible(true);}public void paint(Graphics g) {Graphics2D g2 = (Graphics2D) g;g2.drawImage(rawImg, 10, 10, rawImg.getWidth(), rawImg.getHeight(), null);}public Dimension getPreferredSize() {return mySize;}public Dimension getMinimumSize() {return mySize;}public Dimension getMaximumSize() {return mySize;}public static void main(String[] args) {JFileChooser chooser = new JFileChooser();chooser.showOpenDialog(null);File f = chooser.getSelectedFile();new FloodFillUI(f);}@Overridepublic void mouseClicked(MouseEvent e) {System.out.println("Mouse Clicked Event!!");int x = (int)e.getPoint().getX();int y = (int)e.getPoint().getY();System.out.println("mouse location x = " + x); // columnSystem.out.println("mouse location y = " + y); // rowSystem.out.println();long startTime = System.nanoTime();// ffa.floodFill4(x, y, Color.GREEN.getRGB(), ffa.getColor(x, y));// ffa.floodFill8(x, y, Color.GREEN.getRGB(), ffa.getColor(x, y));// ffa.floodFillScanLine(x, y, Color.GREEN.getRGB(), ffa.getColor(x, y)); // 13439051ffa.floodFillScanLineWithStack(x, y, Color.GREEN.getRGB(), ffa.getColor(x, y)); // - 16660142long endTime = System.nanoTime() - startTime;System.out.println("run time = " + endTime);ffa.updateResult();this.repaint();}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}}

First, we introduce the flood Filling Algorithm of the four adjacent domains to find the top, bottom, left, and right of the P (x, y) pixel. If no

If it is filled, fill them, and continue to look for the four adjacent domain pixels of them until the closed area is completely filled by the new color.

The blue square shows four neighboring pixels, and p (x, y) indicates the current pixel.

The code based on recursion is simple:

public void floodFill4(int x, int y, int newColor, int oldColor){    if(x >= 0 && x < width && y >= 0 && y < height     && getColor(x, y) == oldColor && getColor(x, y) != newColor)     {     setColor(x, y, newColor); //set color before starting recursion        floodFill4(x + 1, y,     newColor, oldColor);        floodFill4(x - 1, y,     newColor, oldColor);        floodFill4(x,     y + 1, newColor, oldColor);        floodFill4(x,     y - 1, newColor, oldColor);    }   }

The filling Algorithm of the Eight-neighborhood adds four adjacent pixels, namely, top left, bottom left, top right, and bottom right, based on the four adjacent fields.

And recursively look for their eight-neighbor pixel fill until the area is completely filled by the new color.

The blue square shows four neighboring pixels. The yellow is top left, bottom left, top right, and bottom right. The P (x, y) shows the current pixel.

The code based on Recursive Implementation is also very simple:

public void floodFill8(int x, int y, int newColor, int oldColor){    if(x >= 0 && x < width && y >= 0 && y < height &&     getColor(x, y) == oldColor && getColor(x, y) != newColor)     {     setColor(x, y, newColor); //set color before starting recursion        floodFill8(x + 1, y,     newColor, oldColor);        floodFill8(x - 1, y,     newColor, oldColor);        floodFill8(x,     y + 1, newColor, oldColor);        floodFill8(x,     y - 1, newColor, oldColor);        floodFill8(x + 1, y + 1, newColor, oldColor);        floodFill8(x - 1, y - 1, newColor, oldColor);        floodFill8(x - 1, y + 1, newColor, oldColor);        floodFill8(x + 1, y - 1, newColor, oldColor);    }   }

The main idea of the scanning line-based flood filling algorithm is to follow the current input point P (x, y) and follow the y direction up separately.

With downward scan filling, while at the same time to the left p (x-1, Y) and right p (x + 1, Y) recursively look for new scan lines until the recursion ends.

The Code is as follows:

public void floodFillScanLine(int x, int y, int newColor, int oldColor){if(oldColor == newColor) return;    if(getColor(x, y) != oldColor) return;          int y1;        //draw current scanline from start position to the top    y1 = y;    while(y1 < height && getColor(x, y1) == oldColor)    {    setColor(x, y1, newColor);        y1++;    }            //draw current scanline from start position to the bottom    y1 = y - 1;    while(y1 >= 0 && getColor(x, y1) == oldColor)    {    setColor(x, y1, newColor);        y1--;    }        //test for new scanlines to the left    y1 = y;    while(y1 < height && getColor(x, y1) == newColor)    {        if(x > 0 && getColor(x - 1, y1) == oldColor)         {        floodFillScanLine(x - 1, y1, newColor, oldColor);        }         y1++;    }    y1 = y - 1;    while(y1 >= 0 && getColor(x, y1) == newColor)    {        if(x > 0 && getColor(x - 1, y1) == oldColor)         {        floodFillScanLine(x - 1, y1, newColor, oldColor);        }        y1--;    }         //test for new scanlines to the right     y1 = y;    while(y1 < height && getColor(x, y1) == newColor)    {        if(x < width - 1 && getColor(x + 1, y1) == oldColor)         {                   floodFillScanLine(x + 1, y1, newColor, oldColor);        }         y1++;    }    y1 = y - 1;    while(y1 >= 0 && getColor(x, y1) == newColor)    {        if(x < width - 1 && getColor(x + 1, y1) == oldColor)         {        floodFillScanLine(x + 1, y1, newColor, oldColor);        }        y1--;    }}

The recursive flood filling algorithm has a fatal disadvantage, that is, it may cause java stack overflow when filling large areas.

Error: A non-recursive flood Filling Algorithm is implemented for the last scanning line-based algorithm.

public void floodFillScanLineWithStack(int x, int y, int newColor, int oldColor){if(oldColor == newColor) {System.out.println("do nothing !!!, filled area!!");return;}    emptyStack();        int y1;     boolean spanLeft, spanRight;    push(x, y);        while(true)    {        x = popx();    if(x == -1) return;    y = popy();        y1 = y;        while(y1 >= 0 && getColor(x, y1) == oldColor) y1--; // go to line top/bottom        y1++; // start from line starting point pixel        spanLeft = spanRight = false;        while(y1 < height && getColor(x, y1) == oldColor)        {        setColor(x, y1, newColor);            if(!spanLeft && x > 0 && getColor(x - 1, y1) == oldColor)// just keep left line once in the stack            {                push(x - 1, y1);                spanLeft = true;            }            else if(spanLeft && x > 0 && getColor(x - 1, y1) != oldColor)            {                spanLeft = false;            }            if(!spanRight && x < width - 1 && getColor(x + 1, y1) == oldColor) // just keep right line once in the stack            {                push(x + 1, y1);                spanRight = true;            }            else if(spanRight && x < width - 1 && getColor(x + 1, y1) != oldColor)            {                spanRight = false;            }             y1++;        }    }}

Running effect:


The source code of the algorithm class is as follows:

package com.gloomyfish.paint.fill;import java.awt.image.BufferedImage;import com.gloomyfish.filter.study.AbstractBufferedImageOp;public class FloodFillAlgorithm extends AbstractBufferedImageOp {private BufferedImage inputImage;private int[] inPixels;private int width;private int height;// stack data structureprivate int maxStackSize = 500; // will be increased as neededprivate int[] xstack = new int[maxStackSize];private int[] ystack = new int[maxStackSize];private int stackSize;public FloodFillAlgorithm(BufferedImage rawImage) {this.inputImage = rawImage;width = rawImage.getWidth();        height = rawImage.getHeight();        inPixels = new int[width*height];        getRGB(rawImage, 0, 0, width, height, inPixels );}public BufferedImage getInputImage() {return inputImage;}public void setInputImage(BufferedImage inputImage) {this.inputImage = inputImage;}public int getColor(int x, int y){int index = y * width + x;return inPixels[index];}public void setColor(int x, int y, int newColor){int index = y * width + x;inPixels[index] = newColor;}public void updateResult(){setRGB( inputImage, 0, 0, width, height, inPixels );}/** * it is very low calculation speed and cause the stack overflow issue when fill  * some big area and irregular shape. performance is very bad. *  * @param x * @param y * @param newColor * @param oldColor */public void floodFill4(int x, int y, int newColor, int oldColor){    if(x >= 0 && x < width && y >= 0 && y < height     && getColor(x, y) == oldColor && getColor(x, y) != newColor)     {     setColor(x, y, newColor); //set color before starting recursion        floodFill4(x + 1, y,     newColor, oldColor);        floodFill4(x - 1, y,     newColor, oldColor);        floodFill4(x,     y + 1, newColor, oldColor);        floodFill4(x,     y - 1, newColor, oldColor);    }   }/** *  * @param x * @param y * @param newColor * @param oldColor */public void floodFill8(int x, int y, int newColor, int oldColor){    if(x >= 0 && x < width && y >= 0 && y < height &&     getColor(x, y) == oldColor && getColor(x, y) != newColor)     {     setColor(x, y, newColor); //set color before starting recursion        floodFill8(x + 1, y,     newColor, oldColor);        floodFill8(x - 1, y,     newColor, oldColor);        floodFill8(x,     y + 1, newColor, oldColor);        floodFill8(x,     y - 1, newColor, oldColor);        floodFill8(x + 1, y + 1, newColor, oldColor);        floodFill8(x - 1, y - 1, newColor, oldColor);        floodFill8(x - 1, y + 1, newColor, oldColor);        floodFill8(x + 1, y - 1, newColor, oldColor);    }   }/** *  * @param x * @param y * @param newColor * @param oldColor */public void floodFillScanLine(int x, int y, int newColor, int oldColor){if(oldColor == newColor) return;    if(getColor(x, y) != oldColor) return;          int y1;        //draw current scanline from start position to the top    y1 = y;    while(y1 < height && getColor(x, y1) == oldColor)    {    setColor(x, y1, newColor);        y1++;    }            //draw current scanline from start position to the bottom    y1 = y - 1;    while(y1 >= 0 && getColor(x, y1) == oldColor)    {    setColor(x, y1, newColor);        y1--;    }        //test for new scanlines to the left    y1 = y;    while(y1 < height && getColor(x, y1) == newColor)    {        if(x > 0 && getColor(x - 1, y1) == oldColor)         {        floodFillScanLine(x - 1, y1, newColor, oldColor);        }         y1++;    }    y1 = y - 1;    while(y1 >= 0 && getColor(x, y1) == newColor)    {        if(x > 0 && getColor(x - 1, y1) == oldColor)         {        floodFillScanLine(x - 1, y1, newColor, oldColor);        }        y1--;    }         //test for new scanlines to the right     y1 = y;    while(y1 < height && getColor(x, y1) == newColor)    {        if(x < width - 1 && getColor(x + 1, y1) == oldColor)         {                   floodFillScanLine(x + 1, y1, newColor, oldColor);        }         y1++;    }    y1 = y - 1;    while(y1 >= 0 && getColor(x, y1) == newColor)    {        if(x < width - 1 && getColor(x + 1, y1) == oldColor)         {        floodFillScanLine(x + 1, y1, newColor, oldColor);        }        y1--;    }}public void floodFillScanLineWithStack(int x, int y, int newColor, int oldColor){if(oldColor == newColor) {System.out.println("do nothing !!!, filled area!!");return;}    emptyStack();        int y1;     boolean spanLeft, spanRight;    push(x, y);        while(true)    {        x = popx();    if(x == -1) return;    y = popy();        y1 = y;        while(y1 >= 0 && getColor(x, y1) == oldColor) y1--; // go to line top/bottom        y1++; // start from line starting point pixel        spanLeft = spanRight = false;        while(y1 < height && getColor(x, y1) == oldColor)        {        setColor(x, y1, newColor);            if(!spanLeft && x > 0 && getColor(x - 1, y1) == oldColor)// just keep left line once in the stack            {                push(x - 1, y1);                spanLeft = true;            }            else if(spanLeft && x > 0 && getColor(x - 1, y1) != oldColor)            {                spanLeft = false;            }            if(!spanRight && x < width - 1 && getColor(x + 1, y1) == oldColor) // just keep right line once in the stack            {                push(x + 1, y1);                spanRight = true;            }            else if(spanRight && x < width - 1 && getColor(x + 1, y1) != oldColor)            {                spanRight = false;            }             y1++;        }    }}private void emptyStack() {while(popx() != - 1) {popy();}stackSize = 0;}final void push(int x, int y) {stackSize++;if (stackSize==maxStackSize) {int[] newXStack = new int[maxStackSize*2];int[] newYStack = new int[maxStackSize*2];System.arraycopy(xstack, 0, newXStack, 0, maxStackSize);System.arraycopy(ystack, 0, newYStack, 0, maxStackSize);xstack = newXStack;ystack = newYStack;maxStackSize *= 2;}xstack[stackSize-1] = x;ystack[stackSize-1] = y;}final int popx() {if (stackSize==0)return -1;else            return xstack[stackSize-1];}final int popy() {        int value = ystack[stackSize-1];        stackSize--;        return value;}@Overridepublic BufferedImage filter(BufferedImage src, BufferedImage dest) {// TODO Auto-generated method stubreturn null;}}

Reprinted articles must be noted

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.