哞哞快的 C# 高斯模糊实现(续)
昨天刚写了《哞哞快的 C# 高斯模糊实现》,里边提到了用原作者的方法实现对图像快速的高斯模糊处理,说实话,我没看懂,主要是没看懂原理,怎么就“把图片给处理了”,大概是调用了 GDIPlus.dll 里边的函数,所以我看不到算法和细节,但这正是我要的——专业的人才做专业的事儿,我不懂图像处理,我只想有个 void 帮我随时把某个图像处理掉,最好还是免费、开源、快速的 ^^
昨天写完这个之后,继续去研究方法里作者提到的一个函数“int GdipBitmapCreateApplyEffect()”,据说可以不修改原图,将处理后的效果写进另一个图像中,自己照猫画虎的写了写,不出意外的,不成功。程序也不报错,调试了一下,发现函数的处理结果是“OK”,那就是我自己写的有问题。冷静想想……找找资料
谷歌出一篇,在 CodePlex 上有一个对图像处理的项目,里边使用到了 GDIPlus.dll,下载下来步步跟踪,发现了自己的问题:函数的参数传递的是 IntPtr,就是句柄,也可以理解为“指针”,经过函数处理之后,即便成功了,也需要额外的工作,就是把处理后的图像“写回”到某个 Bitmap 对象中去。我之前没成功就是因为函数执行完了,以为定义的新的 Bitmap 对象就被自动修改了,实际上没有。
想到了自己的问题,就看人家怎么处理的,结果,又是两个俺不懂的函数,不过不影响理解原理。拷贝到方法内,运行,成功!Project 下载
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
下面是函数运行完,负责将处理后的数据“赋值”到新的图像的两个俺不懂的方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
三个函数配合后,就会得到一个新的经过高斯模糊的图像,看 MSDN 介绍,有个很重要的四儿:经过“GdiBitmapCreateApplyEffect()”会返回一个指向新图像的指针对象,在资源不用时需要手动进行释放,我的方法里还没有添加完善的释放资源的逻辑,回头还需要研究研究。原文地址是:http://msdn.microsoft.com/en-us/library/windows/desktop/ms536320(v=vs.85).aspx
运行后