图像处理------泛洪填充算法(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到 ...
随机推荐
- vsftp 的安装及配置
安装vsftpd 直接用 yum安装,方便的很 yum -y install vsftpd #进入vsftpd目录cd /etc/vsftpd/ #Create The Virtual Users D ...
- 让浏览器全面兼容WebP图片格式
WebP格式 WebP是Google推出的一种图片格式,它基于VP8编码,可对图像大幅压缩.与JPEG相同,WebP也是一种有损压缩,但在画质相同的情况下,WebP格式比JPEG图像小40%. Wik ...
- Installing VirtualBox
The (VirtualBox) website has a lot of quality documentation including: End-user documentation Techni ...
- snowflake分布式唯一id c#实现
snowflake算法 snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID.其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心, ...
- HTA基础
HTA是HTML应用程序(HTML Application)的缩写,可以使用HTML中的绝大多数标签.脚本等.直接将HTML保存成HTA的格式,就是一个能够独立运行的应用软件. 与普通HTML网页相比 ...
- Go基础之--接口
定义 在Go语言中,一个类只要实现了接口要求的所有函数,我们就说这个类实现了该接口 interface类型可以定义一组方法,用来表示一个对象的行为特征,interface不能包含任何变量,接口是引用类 ...
- 2018/2/13 ElasticSearch学习笔记三 自动映射以及创建自动映射模版,ElasticSearch聚合查询
终于把这些命令全敲了一遍,话说ELK技术栈L和K我今天花了一下午全部搞定,学完后还都是花式玩那种...E却学了四天(当然主要是因为之前上班一直没时间学,还有安装服务时出现的各种error真是让我扎心了 ...
- 织梦调用seotitle
如果有seotitle则调用seotitle,没有则调用title {dede:field.array runphp='yes'} if(@me['seotitle']=='') {@me=@me[' ...
- ng-csv 异步数据下载
相信很多码友遇到一个很坑的问题吧,就是使用ng-csv 的时候 lazy-load="true" 设置为true 还是 会下载0行数据 var getArray= functio ...
- linux 下安装php curl扩展
方法一 安装cURL wget https://curl.haxx.se/download/curl-7.53.1.tar.gz tar -zxf curl-7.17.1.tar.gz ./confi ...