惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
Know Your Adversary
Know Your Adversary
S
Schneier on Security
K
Kaspersky official blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
Recorded Future
Recorded Future
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
Engineering at Meta
Engineering at Meta
MyScale Blog
MyScale Blog
L
LINUX DO - 热门话题
The Register - Security
The Register - Security
B
Blog
V
Vulnerabilities – Threatpost
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
Latest news
Latest news
Webroot Blog
Webroot Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
L
LINUX DO - 最新话题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
B
Blog RSS Feed
aimingoo的专栏
aimingoo的专栏
The GitHub Blog
The GitHub Blog
D
Docker
G
Google Developers Blog
T
Threatpost
F
Full Disclosure
Attack and Defense Labs
Attack and Defense Labs
L
Lohrmann on Cybersecurity
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
D
DataBreaches.Net
WordPress大学
WordPress大学
F
Fortinet All Blogs
S
Secure Thoughts
Y
Y Combinator Blog
博客园 - Franky
Scott Helme
Scott Helme
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News: Ask HN
Hacker News: Ask HN
酷 壳 – CoolShell
酷 壳 – CoolShell
Cloudbric
Cloudbric
N
News | PayPal Newsroom

博客园 - 夏天/isummer

vcpkg的安装,配置vs2022, 全局使用,清单使用 wsGLCanvas中的OnPaint和OnSize的调用顺序 Visual Studio 2022中配置Eigen.Natvis文件,实现Debug查看:Eigen库查看矩阵与向量的值 “模型法线到视图法线”的变换矩阵(normal matrix)的计算和作用 python 用control库绘制自动控制原理中的根轨迹: C++ 无法从“const char [ ]”转换为“char *” 根据文件内存字节数,返回文件占用内存大小:单位:T,G,M,K,B opengl中的glDrawElements 用法和glDrawArray opengl中的VBO,IBO,VAO,EBO总结: OpenGL着色器Shader小结 VS2022 在编译大型项目出现:c/c++ intellance 操作-优化VS2022,提高Intellance速度 用VS2022创建空桌面程序【Empty】运行wxWidgets应用,报错:MSVCRTD.lib(exe_main.obj) : error LNK2019: 无法解析的外部符号 main VS下使用全局配置的方式使用VCPKG vcpkg 安装过程中install的参数: ApriTags应用 【/MT、/MTd、/MD、/MDd】C++ 出现异常“.... \debug_heap.cpp Line:980 Expression:__acrt_first_block==header"【已解决】 - 夏天/isummer QString的tostdstring问题-提示堆栈内存溢出(2024.12) vsftpd和FileZiler配置:本地登录,支持上传-下载-删除文件和目录-添加文件和目录 PyQt开发-mkvirtualenv虚拟环境 线程池ThreadPool, C++ github 命令git下载失败: Failed to connect to github.com port 443 解决方案,解决CMAKE中下载其他库失败的问题
泛洪算法(Flood fill Algorithm):符号洪水填充算法
夏天/isummer · 2025-07-27 · via 博客园 - 夏天/isummer

泛洪算法(Flood fill Algorithm):符号洪水填充算法

算法别名:

  漫水填充算法、种子填充算法(Seed Fill)

作用:

   用于确定连接到多维数组中给定节点的区域,可以用来标记或者分离图像的一部分,实现如Ps中自动选区功能。

基本思想:

   顾名思义就像洪水漫过一样,把一块连通的区域填满。

  当然水要能漫过需要满足一定的条件,可以理解为满足条件的地方就是低洼的地方,水才能流过去。

  在图像处理中就是给定一个种子点作为起始点,向附近相邻的像素点扩散,把颜色相同或者相近的所有点都找出来,并填充上新的颜色,这些点形成一个连通的区域。

算法参数:

  1. 起始节点(start node)
  2. 目标颜色(target color)
  3. 替换颜色(replacement color)

算法实现:

漫水填充算法实现最常见有四邻域像素填充法,八邻域像素填充法,基于扫描线的填充方法。根据代码实现方式又可以分为递归与非递归。

1、四邻域递归实现

image

 将像素点(x,y)周围的上下左右四个点分别进行着色。

//Recursive 4-way floodfill, crashes if recursion stack is full
public void floodFill4(int x, int y, int newColor, int oldColor)  
{  
    if(x >= 0 && x < width && y >= 0 && y < height   
         && getPixel(x, y) == oldColor && getPixel(x, y) != newColor)   
    {   
        setPixel(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);  
    }     
}

2、八邻域递归实现

image

 将一个像素点的上下左右,左上,左下,右上,右下都进行着色。

public void floodFill8(int x, int y, int newColor, int oldColor)  
{  
    if(x >= 0 && x < width && y >= 0 && y < height &&   
            getPixel(x, y) == oldColor && getPixel(x, y) != newColor)   
    {   
        setPixel(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);  
    }     
} 

3、扫描线算法(Scanline Fill):

  利用填充线来加速算法, 它不是在堆栈上推动每个潜在的未来像素坐标,而是检查相邻线(前一个和下一个)以找到可能在未来通过中填充的相邻段, 线段的坐标(开始或结束)被推到堆栈上。 在大多数情况下,该扫描线算法至少比每像素算法快一个数量级。 

  该算法的过程是:先扫描一行或者一列内的连通像素,然后再上下行或者左右列扫描,可以减少递归栈的深度

image

 递归方式:递归实现算法好理解,但当连通的区域很大时,很可能会导致栈溢出。

void floodFillScanline(int x, int y, int newColor, int oldColor){
    if(newColor==oldColor) return;
    if(screen[x][y]!=oldColor) return;
    int x1=x;
    while(x1<w&&screen[x1][y]==oldColor){
        screen[x1][y]=newColor;
        x1++;
    }
    x1=x-1;
    while(x1>=0&&screen[x1][y]==oldColor){
        screen[x1][y]=newColor;
        x1--;
    }
    x1=x;
    while(x1<w&&screen[x1][y]==newColor){
        if(y<h-1&&screen[x1][y+1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);
        x1++;
    }
    x1=x-1;
    while(x1>0&&screen[x1][y]==newColor){
        if(y>0&&screen[x1][y+1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);
        x1--;
    }
    x1=x;
    while(x1<w&&screen[x1][y]==newColor){
        if(y<h-1&&screen[x1][y-1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);
        x1++;
    }
    x1=x-1;
    while(x1>0&&screen[x1][y]==newColor){
        if(y>0&&screen[x1][y-1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);
        x1--;
    }
}

非递归方式:

void floodFillScanline(int x, int y, int newColor, int oldColor){
    if(newColor==oldColor) return;
    if(screen[x][y]!=oldColor) return;
    emptyStack();
    int x1;
    bool spanAbove, spanBelow;
    if(!push(x,y)) return;
    while(pop(x,y)){
        x1=x;
        while(x1>0&&screen[x1][y]==oldColor) x1--;
        x1++;
        spanAbove = spanBelow = 0;
        while(x1<w&&screen[x1][y]==oldColor){
            screen[x1][y]=newColor;
            if(!spanAbove&&y>0&&screen[x1][y-1]==oldColor){ //这里判断出了上行的元素可以被染色,可能为了修改screen的访存连续性,所以这里没修改。而且你改了上行的值,却没考虑其四周,会有完备性的问题。
                if(!push(x1,y-1)) return;
                spanAbove=1;
            }
            else if(spanAbove&&y>0&&screen[x1][y-1]!=oldColor){
                spanAbove=0; //不压入重复过多的元素
            }
            if(!spanBelow&&y<h-1&&screen[x1][y+1]==oldColor){
                if(!push(x1,y+1)) return;
                spanBelow=1;
            }
            else if(spanBelow&&y<h-1&&screen[x1][y+1]!=oldColor){
                spanBelow=0;
            }
            x1++;
        }
    }
}

参考:https://blog.csdn.net/Eason_Y/article/details/127782837