源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

VB.NET中使用种子填充算法实现给图片着色的例子

  • 时间:2022-05-09 10:32 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:VB.NET中使用种子填充算法实现给图片着色的例子
某人最近在使用C#写一个类似Windows的画图工具,在填色的部分卡住了。劳资要他使用种子填充算法着色(不要调用Windows提供的API,否则还锻炼个毛线),现在我把这个功能实现了,程序的效率很高。现在在这里大概写一下实现方法。 程序是用VB.NET写的,C#写法类似(而且还不需要使用Marshal类访问非托管资源,更加方便)。程序的运行结果如下: [img]http://files.jb51.net/file_images/article/201407/2014716110449852.jpg?201461611513[/img]  种子填充算法说白了就是宽度优先搜索算法(BFS),如果你不知道这是什么东西,那说明你数据结构根本就没有学,请自行补充相应的知识。 [b]  第一步:实现“铅笔”工具[/b] 我们定义如下的全局变量(窗体类的私有成员),作用是啥一看名字就知道:
[url=http://www.bobpowell.net/lockingbits.htm]http://www.bobpowell.net/lockingbits.htm[/url]   其中很重要的一点就是要搞清楚如何计算图片上某一点的内存地址。 [img]http://files.jb51.net/file_images/article/201407/2014716110524000.gif?201461611539[/img] 如这张图所示(图片来自那篇博文),坐标为(X,Y)的点在内存中的地址就是Scan0 + (Y * Stride) + X * k。k与图片中每个点占用的字节有关,我们这里使用的是32位ARPG,每个像素占4个字节,因此k就是4。另外注意Stride并不一定是n*k(n表示每行存n个像素),因为末尾可能有多余的位使数组对齐(与处理机的字长匹配)。无论如何,我们可以通过BitmapData对象的Stride属性得到。   由于一个ARGB值是4个字节,所以我们需要调用Marshal类的ReadInt32和WriteInt32方法对每个像素点的颜色进行读取和写入。我们要操作的是颜色的ARGB值而不是Color对象。   那么把上面的代码稍加改造,就可以写出如下程序:
[u]复制代码[/u] 代码如下:
Private Sub FillRegion(sourcePoint As Point, destinationColor As Color)         Dim new_bitmap As Bitmap = DirectCast(PictureBox1.Image, Bitmap)     Dim source_color_int As Integer = new_bitmap.GetPixel(sourcePoint.X, sourcePoint.Y).ToArgb         Dim bitmap_data As BitmapData = new_bitmap.LockBits(New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height), _                                                         Imaging.ImageLockMode.ReadWrite, new_bitmap.PixelFormat)         Dim stride As Integer = Math.Abs(bitmap_data.Stride)         Dim scan0 As IntPtr = bitmap_data.Scan0         Dim bytes As Integer = stride * new_bitmap.Height         Dim MIN_X As Integer = 1, MIN_Y As Integer = 1     Dim MAX_X As Integer = PictureBox1.Width - 1, MAX_Y As Integer = PictureBox1.Height - 1         Dim fill_queue(MAX_FILL_QUEUE) As Point         Dim fill_direction() As Point = {New Point(-1, 0), New Point(1, 0), New Point(0, -1), New Point(0, 1)}         Dim destination_color_int As Integer = destinationColor.ToArgb         Dim queue_head As Integer = 0     Dim queue_tail As Integer = 1         fill_queue(queue_tail) = sourcePoint         Do While queue_head <> queue_tail         queue_head = (queue_head + 1) Mod MAX_FILL_QUEUE         Dim current_point As Point = fill_queue(queue_head)             For i As Integer = 0 To 3             Dim new_point_x As Integer = current_point.X + fill_direction(i).X             Dim new_point_y As Integer = current_point.Y + fill_direction(i).Y                 If new_point_x < MIN_X OrElse new_point_y < MIN_Y OrElse new_point_x > MAX_X OrElse new_point_y > MAX_Y Then Continue For                 Dim offset As Integer = (new_point_y * stride) + new_point_x * 4                 Dim current_color_int As Integer = System.Runtime.InteropServices.Marshal.ReadInt32(scan0, offset)                 If current_color_int = source_color_int Then                 System.Runtime.InteropServices.Marshal.WriteInt32(scan0, offset, destination_color_int)                     queue_tail = (queue_tail + 1) Mod MAX_FILL_QUEUE                 fill_queue(queue_tail) = New Point(new_point_x, new_point_y)             End If         Next         Loop         new_bitmap.UnlockBits(bitmap_data)         PictureBox1.Image = new_bitmap     End Sub
 当然,如果你还有其他更好的实现方法,还请多多指教。(啊,不要告诉我使用Windows的API。。。)  现在运行一下程序,发现效率急剧上升。我测试了一下,在我的电脑上,填充37万个像素大概只需要50~60毫秒左右,效率还是令人满意的。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部