哞哞快的 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

運行后


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM