图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能
泛洪填充算法(Flood Fill Algorithm)
泛洪填充算法又称洪水填充算法是在很多图形绘制软件中常用的填充算法,最熟悉不过就是
windows paint的油漆桶功能。算法的原理很简单,就是从一个点开始附近像素点,填充成新
的颜色,直到封闭区域内的所有像素点都被填充新颜色为止。泛红填充实现最常见有四邻域
像素填充法,八邻域像素填充法,基于扫描线的像素填充方法。根据实现又可以分为递归与
非递归(基于栈)。
在介绍算法的三种实现方式之前,首先来看一下测试该算法的UI实现。基本思路是选择一
张要填充的图片,鼠标点击待填充的区域内部,算法会自动填充该区域,然后UI刷新。完
整的UI代码如下:
- 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 data
- try {
- if (!tracker.waitForID(1, 10000)) {
- System.out.println("Load error.");
- System.exit(1);
- }// end if
- } catch (InterruptedException e) {
- e.printStackTrace();
- System.exit(1);
- }// end catch
- mySize = 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);
- }
- @Override
- public 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); // column
- System.out.println("mouse location y = " + y); // row
- System.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)); // 13439051
- ffa.floodFillScanLineWithStack(x, y, Color.GREEN.getRGB(), ffa.getColor(x, y)); // - 16660142
- long endTime = System.nanoTime() - startTime;
- System.out.println("run time = " + endTime);
- ffa.updateResult();
- this.repaint();
- }
- @Override
- public void mousePressed(MouseEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void mouseReleased(MouseEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void mouseEntered(MouseEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void mouseExited(MouseEvent e) {
- // TODO Auto-generated method stub
- }
- }
首先介绍四邻域的泛洪填充算法,寻找像素点p(x, y)的上下左右四个临近像素点,如果没有
被填充,则填充它们,并且继续寻找它们的四邻域像素,直到封闭区域完全被新颜色填充。
蓝色方格为四个邻域像素, p(x, y)为当前像素点。
基于递归实现代码很简单:
- 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);
- }
- }
八邻域的填充算法,则是在四邻域的基础上增加了左上,左下,右上,右下四个相邻像素。
并递归寻找它们的八邻域像素填充,直到区域完全被新颜色填充。
蓝色方格为四个邻域像素,黄色为左上,左下,右上,右下四个像素, p(x, y)为当前像素点。
基于递归实现的代码也很简单:
- 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);
- }
- }
基于扫描线实现的泛洪填充算法的主要思想是根据当前输入的点p(x, y),沿y方向分别向上
与向下扫描填充,同时向左p(x-1, y)与向右p(x+1, y)递归寻找新的扫描线,直到递归结束。
代码如下:
- 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--;
- }
- }
基于递归实现的泛洪填充算法有个致命的缺点,就是对于大的区域填充时可能导致JAVA栈溢出
错误,对最后一种基于扫描线的算法,实现了一种非递归的泛洪填充算法。
- 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++;
- }
- }
- }
; // will be increased as needed
图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能的更多相关文章
- 图像处理之泛洪填充算法(Flood Fill Algorithm)
泛洪填充算法(Flood Fill Algorithm) 泛洪填充算法又称洪水填充算法是在很多图形绘制软件中常用的填充算法,最熟悉不过就是 windows paint的油漆桶功能.算法的原理很简单,就 ...
- OpenCV---ROI(region of interest)和泛洪填充
一:ROI 感兴趣区(Region of Interest,ROIs) 是图像的一部分,它通过在图像上选择或使用诸如设定阈值(thresholding) 或者从其他文件(如矢量> 转换获得等方法 ...
- 八 ROI(region of interest)和泛洪填充
一.ROI 感兴趣区(Region of Interest,ROIs) 是图像的一部分,它通过在图像上选择或使用诸如设定阈值(thresholding) 或者从其他文件(如矢量> 转换获得等方法 ...
- Python+OpenCV图像处理(六)—— ROI与泛洪填充
一.ROI ROI(region of interest),感兴趣区域.机器视觉.图像处理中,从被处理的图像以方框.圆.椭圆.不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI. 代码如下 ...
- CGA填充算法之种子填充算法
CGA填充算法之种子填充算法 平面区域填充算法是计算机图形学领域的一个很重要的算法,区域填充即给出一个区域的边界 (也可以是没有边界,只是给出指定颜色),要求将边界范围内的所有象素单元都修改成指定的颜 ...
- 【Leetcode_easy】733. Flood Fill
problem 733. Flood Fill 题意:图像处理中的泛洪填充算法,常见的有四邻域像素填充法.八邻域像素填充法.基于扫描线的像素填充法,实现方法分为递归与非递归(基于栈). 泛洪填充算法原 ...
- 和同事谈谈Flood Fill 算法
前言 今天忙完了公司的工作后,发现同事在做LeeCode的算法题,顿时来了兴趣,于是王子与同事一起探讨如何能做好算法题,今天在此文章中和大家分享一下. 什么是Flood Fill 算法 我们今天谈论的 ...
- 带你学习Flood Fill算法与最短路模型
一.Flood Fill(连通块问题) 0.简介 Flood Fill(洪水覆盖) 可以在线性的时间复杂内,找到某个点所在的连通块! 注:基于宽搜的思想,深搜也可以做但可能会爆栈 flood fill ...
- LeetCode算法题-Flood Fill(Java实现)
这是悦乐书的第306次更新,第325篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第173题(顺位题号是733).图像由二维整数数组表示,每个整数表示图像的像素值(从0到 ...
随机推荐
- VBA小技巧
运用VBA时,可以构造一些函数去实现诸如printf的方便函数. Public Function printf(mask As String, ParamArray tokens()) As Stri ...
- 怎么改变title属性的样式?
我们经常会设置title属性来显示提示的内容,最常见的一种就是超过文本框的内容显示省略号,鼠标移上去显示完整的内容,这里顺便说下显示省略号的设置,如 div{text-overflow:ellipsi ...
- FluorineFx.IO.AMFMessage
近日玩网页游戏七雄争霸,觉得还可以,但是玩起来太累,所以想自己开发个辅助试试 从网上找到了个<流年网页游戏辅助VIP系列教程>,看了下,遇到了一个问题 特来请高手指点...... 代码如下 ...
- Linux系统zookeeper环境搭建(单机、伪分布式、分布式)
本人现在对zookeeper的环境搭建做一个总结,一般zookeeper的安装部署可以有三种模式,单机模式.伪分布式和分布式,这三种模式在什么时候应用具体看大家的使用场景,如果你只有一台机器且只是想自 ...
- CF487 E. Tourists [点双连通分量 树链剖分 割点]
E. Tourists 题意: 无向连通图 C a w: 表示 a 城市的纪念品售价变成 w. A a b: 表示有一个游客要从 a 城市到 b 城市,你要回答在所有他的旅行路径中最低售价的最低可能值 ...
- BZOJ 1042: [HAOI2008]硬币购物 [容斥原理]
1042: [HAOI2008]硬币购物 题意:4种硬币.面值分别为c1,c2,c3,c4.1000次询问每种硬币di个,凑出\(s\le 10^5\)的方案数 完全背包方案数? 询问太多了 看了题解 ...
- iOS学习——布局利器Masonry框架源码深度剖析
iOS开发过程中很大一部分内容就是界面布局和跳转,iOS的布局方式也经历了 显式坐标定位方式 --> autoresizingMask --> iOS 6.0推出的自动布局(Auto La ...
- python爬虫(1)——urllib包
人生苦短,我用python! 一.关于爬虫 鉴于我的windos环境使用命令行感觉非常不便,也懒得折腾虚拟机,于是我选择了一个折中的办法--Cmder.它的下载地址是:cmder.net Cmder是 ...
- 10位时间戳转为C#格式时间
/// <summary> /// 10位时间戳转为C#格式时间 /// </summary> /// <param name=”timeStamp”></p ...
- python脚本0b文件处理
要处理的文件: 此处处理将00的数据干掉. 处理python脚本: dir_fd = open('abc.yuv','rb+') tmp_fd = open('tmp.yuv','wb+') whil ...