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

    运行后

  • 相关阅读:
    常用知识点集合
    LeetCode 66 Plus One
    LeetCode 88 Merge Sorted Array
    LeetCode 27 Remove Element
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 448 Find All Numbers Disappeared in an Array
    LeetCode 219 Contains Duplicate II
    LeetCode 118 Pascal's Triangle
    LeetCode 119 Pascal's Triangle II
    LeetCode 1 Two Sum
  • 原文地址:https://www.cnblogs.com/cinlap/p/3688204.html
Copyright © 2011-2022 走看看