哞哞快的 C# 高斯模糊实现(续)

  昨天刚写了《哞哞快的 C# 高斯模糊实现》,里边提到了用原作者的方法实现对图像快速的高斯模糊处理,说实话,我没看懂,主要是没看懂原理,怎么就“把图片给处理了”,大概是调用了 GDIPlus.dll 里边的函数,所以我看不到算法和细节,但这正是我要的——专业的人才做专业的事儿,我不懂图像处理,我只想有个 void 帮我随时把某个图像处理掉,最好还是免费、开源、快速的 ^^

  昨天写完这个之后,继续去研究方法里作者提到的一个函数“int GdipBitmapCreateApplyEffect()”,据说可以不修改原图,将处理后的效果写进另一个图像中,自己照猫画虎的写了写,不出意外的,不成功。程序也不报错,调试了一下,发现函数的处理结果是“OK”,那就是我自己写的有问题。冷静想想……找找资料

   谷歌出一篇,在 CodePlex 上有一个对图像处理的项目,里边使用到了 GDIPlus.dll,下载下来步步跟踪,发现了自己的问题:函数的参数传递的是 IntPtr,就是句柄,也可以理解为“指针”,经过函数处理之后,即便成功了,也需要额外的工作,就是把处理后的图像“写回”到某个 Bitmap 对象中去。我之前没成功就是因为函数执行完了,以为定义的新的 Bitmap 对象就被自动修改了,实际上没有。

   想到了自己的问题,就看人家怎么处理的,结果,又是两个俺不懂的函数,不过不影响理解原理。拷贝到方法内,运行,成功!Project 下载

 1         /// <summary>
 2         /// 使用高斯模糊效果创建一个新的图像
 3         /// </summary>
 4         /// <returns></returns>
 5         public static Bitmap CreateNewWithEffect(this Bitmap image, ref Rectangle Rect, float Radius = 10, bool ExpandEdge = false)
 6         {
 7             // 新图像
 8             Bitmap newImage = new Bitmap(image);
 9             
10             int Result;
11             IntPtr BlurEffect;
12             BlurParameters BlurPara;
13             if ((Radius < 0) || (Radius > 255))
14             {
15                 throw new ArgumentOutOfRangeException("Radius 参数错误,半径必须在 [0,255] 范围内");
16             }
17             BlurPara.Radius = Radius;
18             BlurPara.ExpandEdges = ExpandEdge;
19             Result = GdipCreateEffect(BlurEffectGuid, out BlurEffect);
20 
21             if (Result == 0)
22             {
23                 IntPtr Handle = Marshal.AllocHGlobal(Marshal.SizeOf(BlurPara));
24                 Marshal.StructureToPtr(BlurPara, Handle, true);
25                 GdipSetEffectParameters(BlurEffect, Handle, (uint)Marshal.SizeOf(BlurPara));
26                 // 准备参数
27                 IntPtr scrImagePointer = image.NativeHandle();  // 原图像的句柄
28                 Rectangle newImageRect = new Rectangle(Rect.Location, Rect.Size); // 创建一个和要处理的范围同样尺寸的 Rectangle
29                 IntPtr newImagePointer = IntPtr.Zero;
30 
31                 //GdipBitmapApplyEffect(image.NativeHandle(), BlurEffect, ref Rect, false, IntPtr.Zero, 0);
32                 // 使用GdipBitmapCreateApplyEffect函数可以不改变原始的图像,而把模糊的结果写入到一个新的图像中
33                 int ok = GdipBitmapCreateApplyEffect(ref scrImagePointer, 1, BlurEffect, ref Rect,ref newImageRect,out newImagePointer, false, IntPtr.Zero, 0);
34 
35                 if (ok == 0) // 成功
36                 {
37                     // 执行后,newImagePointer 应不为 IntPtr.Zero
38                     if (newImagePointer != IntPtr.Zero)
39                     {
40                         newImage = newImagePointer.NativeBitmapPtrToBitmap();
41                     }
42                 }
43 
44                 GdipDeleteEffect(BlurEffect);
45                 Marshal.FreeHGlobal(Handle);
46             }
47             else
48             {
49                 throw new ExternalException("不支持的GDI+版本,必须为GDI+1.1及以上版本,且操作系统要求为Win Vista及之后版本.");
50             }
51             return newImage;
52         }
View Code

下面是函数运行完,负责将处理后的数据“赋值”到新的图像的两个俺不懂的方法

 1         /// <summary>
 2         /// Gets a Bitmap object for a native GDI+ bitmap handle.
 3         /// </summary>
 4         /// <param name="nativeBitmap">The native handle to get the bitmap for.</param>
 5         /// <returns>A Bitmap.</returns>
 6         public static Bitmap NativeBitmapPtrToBitmap(this IntPtr nativeBitmap)
 7         {
 8             return typeof(Bitmap).InvokeStaticPrivateMethod<Bitmap>("FromGDIplus", nativeBitmap);
 9         }
10 
11         /// <summary>
12         /// Invokes a non-public static method for a Type.
13         /// </summary>
14         /// <typeparam name="TResult">The return type of the static method.</typeparam>
15         /// <param name="type">The Type to invoke the static method for.</param>
16         /// <param name="methodName">The name of the static method.</param>
17         /// <param name="args">The arguments for the static method.</param>
18         /// <returns>The return value of the static method.</returns>
19         /// <exception cref="System.InvalidOperationException">Static method could not be located.</exception>
20         public static TResult InvokeStaticPrivateMethod<TResult>(this Type type, string methodName, params object[] args)
21         {
22             MethodInfo lmiInfo = type.GetMethod(methodName,
23                 BindingFlags.Static | BindingFlags.NonPublic);
24 
25             if (lmiInfo != null)
26                 return (TResult)(lmiInfo.Invoke(null, args));
27             else
28                 throw new InvalidOperationException(
29                     string.Format(
30                         "Static method '{0}' could not be located in object type '{1}'.",
31                         methodName, type.FullName));
32         }
View Code

三个函数配合后,就会得到一个新的经过高斯模糊的图像,看 MSDN 介绍,有个很重要的四儿:经过“GdiBitmapCreateApplyEffect()”会返回一个指向新图像的指针对象,在资源不用时需要手动进行释放,我的方法里还没有添加完善的释放资源的逻辑,回头还需要研究研究。原文地址是:http://msdn.microsoft.com/en-us/library/windows/desktop/ms536320(v=vs.85).aspx

运行后

posted @ 2014-04-25 10:45  试试手气  阅读(3270)  评论(1编辑  收藏  举报