0
点赞
收藏
分享

微信扫一扫

发布我的高性能纯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

 

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

 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#写出性能更高的代码?小弟奉上银鳞胸甲一件!

版权所有,欢迎转载

举报

相关推荐

0 条评论