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

  • 相关阅读:
    排列数组所有情况
    查到的结果的某个字段在一串字符串之中
    element组件化跳转和路由式跳转
    vue路由and组件操作
    事件 绑定,取消冒泡,拖拽 ,点击,事件委托习题
    窗口属性 和DOM 元素尺寸位置 及习题加强
    DOM树的增删改查 和 Date定时任务
    JS DOM 初做了解,习题笔记
    struts配置及检验
    第一个JSP登录跳转
  • 原文地址:https://www.cnblogs.com/xiaotie/p/1689747.html
Copyright © 2020-2023  润新知