发布我的高性能纯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 {  get private   set ; } 
         
public  Int32 Length {  get private   set ; } 
         
public  Int32 SizeOfType {  get private   set ; } 
         
public  Int32 Width {  get private   set ; } 
         
public  Int32 Height {  get private   set ; } 
         
public  IntPtr StartIntPtr {  get private   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  ==   null throw   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( 0 0 , width, height), PixelFormat.Format32bppArgb); 
                     
break
             } 
             Byte
*  t  =  (Byte * )StartIntPtr; 
             BitmapData data 
=  newMap.LockBits( new  Rectangle( 0 0 , 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  ==   null throw   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( 0 0 , 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 > ( this this .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#写出性能更高的代码?小弟奉上银鳞胸甲一件!

你可能感兴趣的:(图像处理)