zoukankan      html  css  js  c++  java
  • 哞哞快的 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

    运行后

  • 相关阅读:
    jQuery瀑布流实例无限滚动加载图片
    【转载】IEnumerable<T>和IQueryable<T>区分
    【转载】C#数组,List,Dictionary的相互转换
    【转载】IQueryable和IEnumerable
    【转载】ABP源码分析一:整体项目结构及目录
    【转载】.NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)
    C# DataTable 转换 Model实体类,DataTable 转换 List 集合
    【转载】N 种仅仅使用 HTML/CSS 实现各类进度条的方式
    【转载】IQueryable 和 IEnumerable 的区别
    【转载】SQL Server Profiler工具
  • 原文地址:https://www.cnblogs.com/cinlap/p/3688204.html
Copyright © 2011-2022 走看看