漫水填充及Photoshop中魔术棒选择工具的实现
今天写程序中有一个地方用到了漫水填充(FloodFill)。所谓漫水填充,简单来说,如下图中左图,白布上有一块红色的斑点,在这个红色的斑点上点一下,就自动选中了和该点相连的红色的区域,接着将该区域替换成指定的颜色,如下图中右图所示。
GDI中有一个函数 ExtFloodFill ,可以用于漫水填充。函数原型是:
BOOL ExtFloodFill(HDC hdc,int nXStart,int nYStart,COLORREF crColor,UINT fuFillType)
在C#中使用这个函数并不好用,这里有一个例子 http://www.codeproject.com/Feature/WickedCode.aspx?msg=2364985 。照猫画虎的写了一遍,结果返回的结果是false——填充失败。
对win32这些东西看着就烦,也没心思去看到底哪里出错了,干脆自己写一个 FloodFill 算法得了。
算法很简单:
(1)将最初的点作为种子点压入栈中;
(2)弹出一个种子点,把它涂成目标颜色;
(3)对于种子点来说,和它相邻的有4个像素,判断这4个像素中的颜色是否是背景色,如果是,则作为新的种子点入栈;
(4)循环至栈空。
实现起来也很简单,一共只需要22行代码,比用DllImport去调用ExtFloodFill代码量还少:
void FloodFill(ImageRgb24 img, Point location, Rgb24 backColor, Rgb24 fillColor)
{
int width = img.Width;
int height = img.Height;
if (location.X < 0 || location.X >= width || location.Y < 0 || location.Y >= height) return;if (backColor == fillColor) return;
if (img[location.Y, location.X] != backColor) return;Stack<Point> points = new Stack<Point>();
points.Push(location);int ww = width -1;
int hh = height -1;while (points.Count > 0)
{
Point p = points.Pop();
img[p.Y, p.X] = fillColor;
if (p.X > 0 && img[p.Y, p.X - 1] == backColor)
{
img[p.Y, p.X - 1] = fillColor;
points.Push(new Point(p.X - 1, p.Y));
}if (p.X < ww && img[p.Y, p.X + 1] == backColor)
{
img[p.Y, p.X + 1] = fillColor;
points.Push(new Point(p.X + 1, p.Y));
}if (p.Y > 0 && img[p.Y - 1, p.X] == backColor)
{
img[p.Y - 1, p.X] = fillColor;
points.Push(new Point(p.X, p.Y - 1));
}if (p.Y < hh && img[p.Y + 1, p.X] == backColor)
{
img[p.Y + 1, p.X] = fillColor;
points.Push(new Point(p.X, p.Y + 1));
}
}
}
有这个算法为基础,类似photoshop的魔术棒选择工具就很容易实现了。漫水填充(FloodFill)是查找和种子点联通的颜色相同的点,魔术棒选择工具则是查找和种子点联通的颜色相近的点,将和初始种子点颜色相近的点压进栈作为新种子。
在photoshop cs5中新引进了快速选择工具,这个工具看起来很神奇,它背后的算法也研究了有些年了,就是抠图技术,有兴趣的可以去研究,这里有一篇很好的综述文章:《Image and Video Matting: A Survey》。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义