C# 魔棒工具-漫水填充算法优化

2023-11-11 18:11

本文主要是介绍C# 魔棒工具-漫水填充算法优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前在魔棒工具的文章里写过一个漫水填充算法,实际使用效果并不好。这是因为算法将图片转为灰度再去与种子点的灰度比较。可以想象,这种做法是不合理的(虽然通常都是这么做)。比如两个视觉上相差很明显的颜色,其灰度值很有可能一样或者相差不大(无论你怎么修改RGB三者权重,终归会遇到这种情况)。所以最好是对颜色的ARGB四个分值分开进行比较,如果速度允许,可以计算方差;如果希望速度快一点,就直接计算差值。

1.按灰度检测

        /// <summary>///  漫水填充 FloodFill()按灰度检测,FloodFill_argb()按四通道分量检测/// </summary>/// <param name="src">原图</param>/// <param name="location">检测点</param>/// <param name="fillColor">填充颜色</param>/// <param name="threshould">阈值</param>/// <returns>填充图,非填充部分为默认值</returns>unsafe public Bitmap FloodFill(Bitmap src, Point location, Color fillColor, int threshould){try{Bitmap srcbmp = src;Color backColor = srcbmp.GetPixel(location.X, location.Y);Bitmap dstbmp = new Bitmap(src.Width, src.Height);int w = srcbmp.Width;int h = srcbmp.Height;Stack<Point> fillPoints = new Stack<Point>(w * h);System.Drawing.Imaging.BitmapData srcbmpData = srcbmp.LockBits(new Rectangle(0, 0, srcbmp.Width, srcbmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);System.Drawing.Imaging.BitmapData dstbmpData = dstbmp.LockBits(new Rectangle(0, 0, dstbmp.Width, dstbmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);int stride = srcbmpData.Stride;byte* srcbuf = (byte*)srcbmpData.Scan0.ToPointer();byte* dstbuf = (byte*)dstbmpData.Scan0.ToPointer();int  cr = backColor.R,  cg = backColor.G, cb = backColor.B, ca = backColor.A;byte fcr = fillColor.R, fcg = fillColor.G, fcb = fillColor.B;if (location.X < 0 || location.X >= w || location.Y < 0 || location.Y >= h) return null;fillPoints.Push(new Point(location.X, location.Y));int[,] mask = new int[w, h];while (fillPoints.Count > 0){Point p = fillPoints.Pop();mask[p.X, p.Y] = 1;dstbuf[3 * p.X + p.Y * stride] = fcb;dstbuf[3 * p.X + 1 + p.Y * stride] =  fcg;dstbuf[3 * p.X + 2 + p.Y * stride] =  fcr;if (p.X > 0 && (mask[p.X - 1, p.Y] != 1)&& Math.Abs(cb - srcbuf[3 * (p.X - 1) + p.Y * stride]) + Math.Abs(cg - srcbuf[3 * (p.X - 1) + 1 + p.Y * stride]) + Math.Abs(cr - srcbuf[3 * (p.X - 1) + 2 + p.Y * stride]) < threshould){dstbuf[3 * (p.X - 1) + p.Y * stride] = fcb;dstbuf[3 * (p.X - 1) + 1 + p.Y * stride] = fcg;dstbuf[3 * (p.X - 1) + 2 + p.Y * stride] = fcr;fillPoints.Push(new Point(p.X - 1, p.Y));mask[p.X - 1, p.Y] = 1;}if (p.X < w - 1 && (mask[p.X + 1, p.Y] != 1)&& Math.Abs(cb - srcbuf[3 * (p.X + 1) + p.Y * stride]) + Math.Abs(cg - srcbuf[3 * (p.X + 1) + 1 + p.Y * stride]) + Math.Abs(cr - srcbuf[3 * (p.X + 1) + 2+p.Y * stride]) < threshould ){dstbuf[3 * (p.X + 1) + p.Y * stride] = fcb;dstbuf[3 * (p.X + 1) + 1 + p.Y * stride] = fcg;dstbuf[3 * (p.X + 1) + 2 + p.Y * stride] = fcr;fillPoints.Push(new Point(p.X + 1, p.Y));mask[p.X + 1, p.Y] = 1;}if (p.Y > 0 && (mask[p.X, p.Y - 1] != 1)&& Math.Abs(cb - srcbuf[3 * p.X + (p.Y - 1) * stride]) + Math.Abs(cg - srcbuf[3 * p.X + 1 + (p.Y - 1) * stride]) + Math.Abs(cr - srcbuf[3 * p.X +2+ (p.Y - 1) * stride]) < threshould){dstbuf[3 * p.X + (p.Y - 1) * stride] = fcb;dstbuf[3 * p.X + 1 + (p.Y - 1) * stride] = fcg;dstbuf[3 * p.X + 2 + (p.Y - 1) * stride] = fcr;fillPoints.Push(new Point(p.X, p.Y - 1));mask[p.X, p.Y - 1] = 1;}if (p.Y < h - 1 && (mask[p.X, p.Y + 1] != 1)&& Math.Abs(cb - srcbuf[3 * p.X + (p.Y + 1) * stride]) + Math.Abs(cg - srcbuf[3 * p.X +1+ (p.Y + 1) * stride]) + Math.Abs(cr - srcbuf[3 * p.X +2+ (p.Y + 1) * stride]) < threshould){dstbuf[3 * p.X + (p.Y + 1) * stride] = fcb;dstbuf[3 * p.X + 1 + (p.Y + 1) * stride] = fcg;dstbuf[3 * p.X + 2 + (p.Y + 1) * stride] = fcr;fillPoints.Push(new Point(p.X, p.Y + 1));mask[p.X, p.Y + 1] = 1;}}fillPoints.Clear();srcbmp.UnlockBits(srcbmpData);dstbmp.UnlockBits(dstbmpData);return dstbmp;}catch (Exception exp){System.Windows.MessageBox.Show(exp.Message);return null;}}
        public int GetGray(byte r, byte g, byte b){return (int)(r * 77 + g * 151 + b * 28) >> 8;//按权重计算灰度值}


2.按颜色ARGB四分量检测

这里直接计算差值儿没有计算方差,其实效果已经足够。

        unsafe public Bitmap FloodFill_argb(Bitmap src, Point location, Color fillColor, int threshould){try{Bitmap srcbmp = src;Color backColor = srcbmp.GetPixel(location.X, location.Y);Bitmap dstbmp = new Bitmap(src.Width, src.Height);int w = srcbmp.Width;int h = srcbmp.Height;Stack<Point> fillPoints = new Stack<Point>(w * h);System.Drawing.Imaging.BitmapData bmpData = srcbmp.LockBits(new Rectangle(0, 0, srcbmp.Width, srcbmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);System.Drawing.Imaging.BitmapData dstbmpData = dstbmp.LockBits(new Rectangle(0, 0, dstbmp.Width, dstbmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);int stride = bmpData.Stride;int stridedst = dstbmpData.Stride;byte* srcbuf = (byte*)bmpData.Scan0.ToPointer();int* dstbuf = (int*)dstbmpData.Scan0.ToPointer();int cr = backColor.R, cg = backColor.G, cb = backColor.B, ca = backColor.A;byte fcr = fillColor.R, fcg = fillColor.G, fcb = fillColor.B;int fc = fillColor.ToArgb();if (location.X < 0 || location.X >= w || location.Y < 0 || location.Y >= h) return null;fillPoints.Push(new Point(location.X, location.Y));int[,] mask = new int[w, h];while (fillPoints.Count > 0){Point p = fillPoints.Pop();mask[p.X, p.Y] = 1;dstbuf[  p.X + p.Y * w] = fc;if (p.X > 0 && (mask[p.X - 1, p.Y] != 1)&& Math.Abs(cb - srcbuf[4 * (p.X - 1) + p.Y * stride]) + Math.Abs(cg - srcbuf[4 * (p.X - 1) + 1 + p.Y * stride]) + Math.Abs(cr - srcbuf[4 * (p.X - 1) + 2 + p.Y * stride]) < threshould&& Math.Abs(ca - srcbuf[4 * (p.X - 1) +3+ p.Y * stride]) < threshould/2){dstbuf[  (p.X - 1) + p.Y * w] = fc;fillPoints.Push(new Point(p.X - 1, p.Y));mask[p.X - 1, p.Y] = 1;}if (p.X < w - 1 && (mask[p.X + 1, p.Y] != 1)&& Math.Abs(cb - srcbuf[4 * (p.X + 1) + p.Y * stride]) + Math.Abs(cg - srcbuf[4 * (p.X + 1) + 1 + p.Y * stride]) + Math.Abs(cr - srcbuf[4 * (p.X + 1) + 2 + p.Y * stride]) < threshould&& Math.Abs(ca - srcbuf[4 * (p.X + 1) + 3 + p.Y * stride]) < threshould / 2){dstbuf[  (p.X + 1) + p.Y * w] = fc;fillPoints.Push(new Point(p.X + 1, p.Y));mask[p.X + 1, p.Y] = 1;}if (p.Y > 0 && (mask[p.X, p.Y - 1] != 1)&& Math.Abs(cb - srcbuf[4 * p.X + (p.Y - 1) * stride]) + Math.Abs(cg - srcbuf[4 * p.X + 1 + (p.Y - 1) * stride]) + Math.Abs(cr - srcbuf[4 * p.X + 2 + (p.Y - 1) * stride]) < threshould&& Math.Abs(ca - srcbuf[4 * p.X +3+ (p.Y - 1) * stride]) < threshould / 2){dstbuf[  p.X + (p.Y - 1) * w] = fc ;fillPoints.Push(new Point(p.X, p.Y - 1));mask[p.X, p.Y - 1] = 1;}if (p.Y < h - 1 && (mask[p.X, p.Y + 1] != 1)&& Math.Abs(cb - srcbuf[4 * p.X + (p.Y + 1) * stride]) + Math.Abs(cg - srcbuf[4 * p.X + 1 + (p.Y + 1) * stride]) + Math.Abs(cr - srcbuf[4 * p.X + 2 + (p.Y + 1) * stride]) < threshould&& Math.Abs(ca - srcbuf[4 * p.X +3+ (p.Y + 1) * stride]) < threshould /2){dstbuf[  p.X + (p.Y + 1) *w] = fc;fillPoints.Push(new Point(p.X, p.Y + 1));mask[p.X, p.Y + 1] = 1;}}fillPoints.Clear();srcbmp.UnlockBits(bmpData);dstbmp.UnlockBits(dstbmpData);return dstbmp;}catch (Exception exp){System.Windows.MessageBox.Show(exp.Message);return null;}}

3.测试

是驴是马,拉出来遛一遛
下图中要处理的图片,向日葵的花心与花瓣,分别为橙色与黄色,灰度值相差很小,右上角有个透明区域,里面有个黑色方框。
使用


调整阈值,为了观察,把透明度也调整一下,点选花瓣


试一下透明区域


结果不错。



这篇关于C# 魔棒工具-漫水填充算法优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/391938

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只