发布我的高性能纯C#图像处理基本类,顺便也挑战一下极限。:)

前些天写了《编写高效的C#图像处理程序——我的实验》《编写高效的C#图像处理程序——我的实验(续)》,后来,在这两篇文章的基础上,整理了代码,发布在 http://code.google.com/p/smartimage/ ;可以使用SVN通过下面地址:http://smartimage.googlecode.com/svn/trunk/ smartimage-read-only 下载源代码。

其中:Orc.SmartImage.Common 项目是C#图像处理的基础类。Orc.SmartImage.CommonTest 是单元测试(需nunit),Orc.SmartImageLab.PerformanceTest是性能测试。关于这些基础类和EmguCV和OpenCV(P/Invoke)的性能比较见我的博客:《编写高效的C#图像处理程序——我的实验(续)》,项目核心是泛型类 UnmanagedImage.cs

代码
 using System; 
 
using System.Collections.Generic; 
 
using System.Runtime.InteropServices; 
 
using System.Text; 
 
using System.Drawing; 
 
using System.Drawing.Imaging; 
 
namespace Orc.SmartImage 
 { 
     
public abstract class UnmanagedImage<T> : IDisposable, IEnumerable<T> 
         
where T : struct 
     { 
         
public Int32 ByteCount { getprivate set; } 
         
public Int32 Length { getprivate set; } 
         
public Int32 SizeOfType { getprivate set; } 
         
public Int32 Width { getprivate set; } 
         
public Int32 Height { getprivate set; } 
         
public IntPtr StartIntPtr { getprivate set; } 
         
private IByteConverter<T> m_converter; 
         
private unsafe Byte* m_start; 
         
public unsafe UnmanagedImage(Int32 width, Int32 height) 
         { 
             Width 
= width; 
             Height 
= height; 
             Length 
= Width * Height; 
             SizeOfType 
= SizeOfT(); 
             ByteCount 
= SizeOfType * Length; 
             m_converter 
= this.CreateByteConverter(); 
             StartIntPtr 
= Marshal.AllocHGlobal(ByteCount); 
             m_start 
= (Byte*)StartIntPtr; 
         } 
         
public UnmanagedImage(Bitmap map):this(map.Width, map.Height) 
         { 
             
if (map == nullthrow new ArgumentNullException("map"); 
             
this.CreateFromBitmap(map); 
         } 
         
/// <summary> 
         
/// 性能约是指针操作的1/4。不适用于性能要求高的地方。 
         
/// </summary> 
         
/// <param name="index"></param> 
         
/// <returns></returns> 
         public unsafe T this[int index] 
         { 
             
get 
             { 
                 T t 
= new T(); 
                 m_converter.Copy(m_start 
+ index * SizeOfType, ref t); 
                 
return t; 
             } 
             
set  
             { 
                 Byte
* to = m_start + index * SizeOfType; 
                 m_converter.Copy(
ref value, to); 
             } 
         } 
         
/// <summary> 
         
/// 性能约是指针操作的1/4。不适用于性能要求高的地方。 
         
/// </summary> 
         
/// <param name="row"></param> 
         
/// <param name="col"></param> 
         
/// <returns></returns> 
         public unsafe T this[int row, int col] 
         { 
              
get 
             { 
                 T t 
= new T(); 
                 m_converter.Copy(m_start 
+ (row * Width + col) * SizeOfType, ref t); 
                 
return t; 
             } 
             
set  
             { 
                 Byte
* to = m_start + (row * Width + col) * SizeOfType; 
                 m_converter.Copy(
ref value, to); 
             } 
         } 
         
public void Dispose() 
         { 
             Dispose(
true); 
             GC.SuppressFinalize(
this); 
         } 
         
protected virtual void Dispose(bool disposing) 
         { 
             
if (false == disposed) 
             { 
                  disposed 
= true
                  Marshal.FreeHGlobal(StartIntPtr); 
             } 
         } 
         
private bool disposed; 
         
~UnmanagedImage() 
         { 
             Dispose(
false); 
         } 
         
private static Int32 SizeOfT() 
         { 
             
return Marshal.SizeOf(typeof(T)); 
         } 
         
private unsafe void CreateFromBitmap(Bitmap map) 
         { 
             
int height = map.Height; 
             
int width = map.Width; 
             PixelFormat format 
= map.PixelFormat; 
             
if (this.Width != width || this.Height != height) 
             { 
                 
return
             } 
             Bitmap newMap 
= map; 
             Int32 step 
= SizeOfT(); 
             
switch (format) 
             { 
                 
case PixelFormat.Format24bppRgb: 
                     
break
                 
case PixelFormat.Format32bppArgb: 
                     
break
                 
default
                     format 
= PixelFormat.Format32bppArgb; 
                     newMap 
= map.Clone(new Rectangle(00, width, height), PixelFormat.Format32bppArgb); 
                     
break
             } 
             Byte
* t = (Byte*)StartIntPtr; 
             BitmapData data 
= newMap.LockBits(new Rectangle(00, width, height), ImageLockMode.ReadOnly, format); 
             
try 
             { 
                 
if (format == PixelFormat.Format24bppRgb) 
                 { 
                     Byte
* line = (Byte*)data.Scan0; 
                     
for (int h = 0; h < height; h++
                     { 
                         Rgb24
* c = (Rgb24*)line; 
                         
for (int w = 0; w < width; w++
                         { 
                             m_converter.Copy(c, t); 
                             t 
+= step; 
                             c
++
                         } 
                         line 
+= data.Stride; 
                     } 
                 } 
                 
else 
                 { 
                     Byte
* line = (Byte*)data.Scan0; 
                     
for (int h = 0; h < height; h++
                     { 
                         Argb32
* c = (Argb32*)line; 
                         
for (int w = 0; w < width; w++
                         { 
                             m_converter.Copy(c, t); 
                             t 
+= step; 
                             c
++
                         } 
                         line 
+= data.Stride; 
                     } 
                 } 
             } 
             
catch (Exception) 
             { 
                 
throw
             } 
             
finally 
             { 
                 newMap.UnlockBits(data); 
             } 
         } 
         
public unsafe Bitmap ToBitmap() 
         { 
             Bitmap map 
= new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb); 
             ToBitmap(map); 
             
return map; 
         } 
         
public unsafe void ToBitmap(Bitmap map) 
         { 
             
if (map == nullthrow new ArgumentNullException("map"); 
             
if (map.Width != this.Width || map.Height != this.Height) 
             { 
                 
throw new ArgumentException("尺寸不匹配."); 
             } 
             
if (map.PixelFormat != PixelFormat.Format32bppArgb) 
             { 
                 
throw new ArgumentException("只支持 Format32bppArgb 格式。 "); 
             } 
             Int32 step 
= SizeOfT(); 
             Byte
* t = (Byte*)StartIntPtr; 
             BitmapData data 
= map.LockBits(new Rectangle(00, map.Width, map.Height), ImageLockMode.ReadWrite, map.PixelFormat); 
             
try 
             { 
                 
int width = map.Width; 
                 
int height = map.Height; 
                 Byte
* line = (Byte*)data.Scan0; 
                 
for (int h = 0; h < height; h++
                 { 
                     Argb32
* c = (Argb32*)line; 
                     
for (int w = 0; w < width; w++
                     { 
                         m_converter.Copy(t, c); 
                         t 
+= step; 
                         c
++
                     } 
                     line 
+= data.Stride; 
                 } 
             } 
             
finally 
             { 
                 map.UnlockBits(data); 
             } 
         } 
         
protected abstract IByteConverter<T> CreateByteConverter(); 
         
#region IEnumerable<T> Members 
         
public IEnumerator<T> GetEnumerator() 
         { 
             
return new ImageEnum<T>(thisthis.m_converter); 
         } 
         
#endregion 
         
#region IEnumerable Members 
         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
         { 
             
return GetEnumerator(); 
         } 
         
#endregion 
     } 
     
internal class ImageEnum<T> : IEnumerator<T> 
         
where T : struct 
     { 
         
private UnmanagedImage<T> m_img; 
         
private unsafe Byte* m_start; 
         
private Int32 m_step; 
         
private unsafe Byte* m_end; 
         
private unsafe Byte* m_current; 
         
private IByteConverter<T> m_converter; 
         
public unsafe ImageEnum(UnmanagedImage<T> img, IByteConverter<T> converter) 
         { 
             m_img 
= img; 
             m_start 
= (Byte*)m_img.StartIntPtr; 
             m_step 
= m_img.SizeOfType; 
             m_end 
= m_start + m_step * m_img.Length; 
             m_current 
= m_start; 
             m_converter 
= converter; 
         } 
         
#region IEnumerator<T> Members 
         
public unsafe T Current 
         { 
             
get  
             {  
                 T t 
= new T(); 
                 m_converter.Copy(m_current, 
ref t);  
                 
return t;  
             } 
         } 
         
#endregion 
         
#region IDisposable Members 
         
public void Dispose() 
         { 
         } 
         
#endregion 
         
#region IEnumerator Members 
         
object System.Collections.IEnumerator.Current 
         { 
             
get { return Current; } 
         } 
         
public unsafe bool MoveNext() 
         { 
             m_current 
+= this.m_step; 
             
return m_current < m_end; 
         } 
         
public unsafe void Reset() 
         { 
             m_current 
= m_start; 
         } 
         
#endregion 
     } 
 } 

Argb32Image,GrayscaleImage, ImageU8, Rgb24Image是UnmanagedImage<T>的四个实现。对于具体的图像类,可以直接使用指针进行操作,也可以通过索引器和迭代器进行操作。直接通过指针操作的性能大概是后者的4倍。通过迭代器进行操作不用考虑指针越界问题。通过指针和索引器进行操作需自行判断指针越界的问题。

这几个基本类和Bitmap之间的转换很简单高效,如:

Rgb24Image rgb24 = new Rgb24Image(map);
Bitmap to = rgb24.ToBitmap();

使用这几个类进行图像处理,性能逼近C/C++代码。且使用的是非托管内存,又实现了Dispose模式,不会发生内存泄漏。想要及时释放内存,Dispose一下即可。

==================================

在此挑战一下,哪位兄弟能用C#写出性能更高的代码?小弟奉上银鳞胸甲一件!

原文地址:https://www.cnblogs.com/xiaotie/p/1689747.html