zoukankan      html  css  js  c++  java
  • 编写高效的C#图像处理程序——我的实验(续)

    本文是《编写高效的C#图像处理程序——我的实验》的后续实验。

    昨天,在wuya的提醒下,仔细检查了下测试代码。发现存在2个问题:

    (1)实验对EmguCV和OpenCV不公平,因为,其它测试都是进行处理图像这一个过程,而EmguCV和OpenCV在处理图像之间,需要将Bitmap转换为其内部图像格式IplImage这一过程。因此,今天的测试将这个转换过程提前,不计入执行时间。

    (2)翻看OpenCV的实现代码,发现,它执行的是以下算法:

    代码
     1 static CvStatus CV_STDCALL
     2 icvBGRx2Gray_8u_CnC1R( const uchar* src, int srcstep,
     3                        uchar* dst, int dststep, CvSize size,
     4                        int src_cn, int blue_idx )
     5 {
     6     int i;
     7     srcstep -= size.width*src_cn; 
     8 
     9     if( size.width*size.height >= 1024 )
    10     {
    11         int* tab = (int*)cvStackAlloc( 256*3*sizeof(tab[0]) );
    12         int r = 0, g = 0, b = (1 << (csc_shift-1));
    13         for( i = 0; i < 256; i++ )
    14         {
    15             tab[i] = b;
    16             tab[i+256= g;
    17             tab[i+512= r;
    18             g += cscGg;
    19             if!blue_idx )
    20                 b += cscGb, r += cscGr;
    21             else
    22                 b += cscGr, r += cscGb;
    23         } 
    24 
    25         for( ; size.height--; src += srcstep, dst += dststep )
    26         {
    27             for( i = 0; i < size.width; i++, src += src_cn )
    28             {
    29                 int t0 = tab[src[0]] + tab[src[1+ 256+ tab[src[2+ 512];
    30                 dst[i] = (uchar)(t0 >> csc_shift);
    31             }
    32         }
    33     }
    34     else
    35     {
    36         for( ; size.height--; src += srcstep, dst += dststep )
    37         {
    38             for( i = 0; i < size.width; i++, src += src_cn )
    39             {
    40                 int t0 = src[blue_idx]*cscGb + src[1]*cscGg + src[blue_idx^2]*cscGr;
    41                 dst[i] = (uchar)CV_DESCALE(t0, csc_shift);
    42             }
    43         }
    44     }
    45     return CV_OK;
    46 }

    这一算法有什么特点呢?

    第一,它不进行浮点计算。它首先将浮点数乘于一个Scale(2的N次幂),转换为整数,计算后再经过 >> 计算,消去这个Scale

    第二,对于大图像,它使用的是查表方式而不是乘法方式来计算灰度的。

    鉴于此,我改进了C#的实现代码,对小图像,依然采用浮点计算:

    *to = (Byte)(p->Red * rCoeff + p->Green * gCoeff + p->Blue * bCoeff);

    对大图像,则使用查表计算:

    代码
                    int* rCache = stackalloc int[256];
                    
    int* gCache = stackalloc int[256];
                    
    int* bCache = stackalloc int[256];

                    
    const int shift = 1<<10;
                    
    int rShift = (int)(rCoeff * shift);
                    
    int gShift = (int)(gCoeff * shift);
                    
    int bShift = shift - rShift - gShift;

                    
    int r = 0, g = 0, b = 0;
                    
    for (int i = 0; i < 256; i++)
                    {
                        rCache[i] 
    = r;
                        gCache[i] 
    = g;
                        bCache[i] 
    = b;
                        r 
    += rShift;
                        g 
    += gShift;
                        b 
    += bShift;
                    }

                    
    while (p != end)
                    {
                        
    *to = (Byte)((rCache[p->Red] + gCache[p->Green] + bCache[p->Red]) >> 10);
                        p
    ++;
                        to
    ++;
                    }

    这样,保证对比的是同一算法。今天的实验,主要比较下面五种图像灰度化方法:

    (1)EmguCV实现:

    代码
    1         /// <summary>
    2         /// 使用EmguCv处理图像
    3         /// </summary>
    4         private static void ProcessImageWithEmgucv(Image<Bgr, Byte> imageSource)
    5         {
    6             //灰度
    7             Image<Gray, Byte> imageGrayscale = imageSource.Convert<Gray, Byte>();
    8         }

    (2)OpenCV/PInvoke实现:

    代码
    1         /// <summary>
    2         /// 使用Open Cv P/Invoke处理图像
    3         /// </summary>
    4         unsafe private static void ProcessImageWithOpencv(IntPtr ptrSource, Size size)
    5         {
    6             IntPtr ptrGrayscale = CvInvoke.cvCreateImage(size, IPL_DEPTH.IPL_DEPTH_8U, 1);
    7             CvInvoke.cvCvtColor(ptrSource, ptrGrayscale, COLOR_CONVERSION.CV_BGR2GRAY);
    8         }
    9 

    (3)BitmapData实现:

    代码
     1         /// <summary>
     2         /// 将指定图像转换成灰度图
     3         /// </summary>
     4         /// <param name="bitmapSource">源图像支持3通道或者4通道图像,支持Format24bppRgb、Format32bppRgb和Format32bppArgb这3种像素格式</param>
     5         /// <returns>返回灰度图,如果转化失败,返回null。</returns>
     6         private static Bitmap Grayscale(Bitmap bitmapSource)
     7         {
     8             Bitmap bitmapGrayscale = null;
     9             if (bitmapSource != null && (bitmapSource.PixelFormat == PixelFormat.Format24bppRgb || bitmapSource.PixelFormat == PixelFormat.Format32bppArgb || bitmapSource.PixelFormat == PixelFormat.Format32bppRgb))
    10             {
    11                 int width = bitmapSource.Width;
    12                 int height = bitmapSource.Height;
    13                 Rectangle rect = new Rectangle(00, width, height);
    14                 bitmapGrayscale = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
    15                 //设置调色板
    16                 ColorPalette palette = bitmapGrayscale.Palette;
    17                 for (int i = 0; i < palette.Entries.Length; i++)
    18                     palette.Entries[i] = Color.FromArgb(255, i, i, i);
    19                 bitmapGrayscale.Palette = palette;
    20                 BitmapData dataSource = bitmapSource.LockBits(rect, ImageLockMode.ReadOnly, bitmapSource.PixelFormat);
    21                 BitmapData dataGrayscale = bitmapGrayscale.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
    22                 byte b, g, r;
    23                 int strideSource = dataSource.Stride;
    24                 int strideGrayscale = dataGrayscale.Stride;
    25                 unsafe
    26                 {
    27                     byte* ptrSource = (byte*)dataSource.Scan0.ToPointer();
    28                     byte* ptr1;
    29                     byte* ptrGrayscale = (byte*)dataGrayscale.Scan0.ToPointer();
    30                     byte* ptr2;
    31                     if (bitmapSource.PixelFormat == PixelFormat.Format24bppRgb)
    32                     {
    33                         for (int row = 0; row < height; row++)
    34                         {
    35                             ptr1 = ptrSource + strideSource * row;
    36                             ptr2 = ptrGrayscale + strideGrayscale * row;
    37                             for (int col = 0; col < width; col++)
    38                             {
    39                                 b = *ptr1;
    40                                 ptr1++;
    41                                 g = *ptr1;
    42                                 ptr1++;
    43                                 r = *ptr1;
    44                                 ptr1++;
    45                                 *ptr2 = (byte)(0.114 * b + 0.587 * g + 0.299 * r);
    46                                 ptr2++;
    47                             }
    48                         }
    49                     }
    50                     else    //bitmapSource.PixelFormat == PixelFormat.Format32bppArgb || bitmapSource.PixelFormat == PixelFormat.Format32bppRgb
    51                     {
    52                         for (int row = 0; row < height; row++)
    53                         {
    54                             ptr1 = ptrSource + strideGrayscale * row;
    55                             ptr2 = ptrGrayscale + strideGrayscale * row;
    56                             for (int col = 0; col < width; col++)
    57                             {
    58                                 b = *ptr1;
    59                                 ptr1++;
    60                                 g = *ptr1;
    61                                 ptr1++;
    62                                 r = *ptr1;
    63                                 ptr1 += 2;
    64                                 *ptr2 = (byte)(0.114 * b + 0.587 * g + 0.299 * r);
    65                                 ptr2++;
    66                             }
    67                         }
    68                     }
    69                 }
    70                 bitmapGrayscale.UnlockBits(dataGrayscale);
    71                 bitmapSource.UnlockBits(dataSource);
    72             }
    73             return bitmapGrayscale;
    74         }

    (4)我自己的实现,Argb32Image,采用浮点计算:

    代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Runtime.InteropServices;
      4 using System.Text;
      5 
      6 namespace Orc.SmartImage
      7 {
      8     public class UnmanagedMemory<T> : IDisposable
      9         where T : struct
     10     {
     11         public Int32 ByteCount { getprivate set; }
     12         public Int32 Length { getprivate set; }
     13         public IntPtr Start { getprivate set; }
     14         public Int32 SizeOfType { getprivate set; }
     15 
     16         public UnmanagedMemory(Int32 length)
     17         {
     18             Length = length;
     19             SizeOfType = SizeOfT();
     20             ByteCount = SizeOfType * length;
     21             Start = Marshal.AllocHGlobal(ByteCount);
     22         }
     23 
     24         public void Dispose()
     25         {
     26             Dispose(true);
     27             GC.SuppressFinalize(this);
     28         }
     29 
     30         protected virtual void Dispose(bool disposing)
     31         {
     32             if (false == disposed)
     33             {
     34                  disposed = true;
     35                  Marshal.FreeHGlobal(Start);
     36             }
     37         }
     38 
     39         private bool disposed;
     40 
     41         ~UnmanagedMemory()
     42         {
     43             Dispose(false);
     44         }
     45 
     46         private Int32 SizeOfT()
     47         {
     48             return Marshal.SizeOf(typeof(T));
     49         }
     50     }
     51 }
     52 
     53 
     54 using System;
     55 using System.Collections.Generic;
     56 using System.Drawing;
     57 using System.Text;
     58 
     59 namespace Orc.SmartImage.UnmanagedObjects
     60 {
     61     public struct Argb32
     62     {
     63         public Byte Alpha;
     64         public Byte Red;
     65         public Byte Green;
     66         public Byte Blue;
     67     }
     68 
     69     public class Argb32Image : UnmanagedMemory<Argb32>
     70     {
     71         private unsafe Argb32* m_pointer;
     72 
     73         public unsafe Argb32* Pointer { get { return m_pointer; } }
     74 
     75         public unsafe Argb32Image(int length)
     76             : base(length)
     77         {
     78             m_pointer = (Argb32*)this.Start;
     79         }
     80 
     81         public unsafe Argb32 this[int index]
     82         {
     83             get { return *(m_pointer + index); }
     84             set { *(m_pointer + index) = value; }
     85         }
     86 
     87         public Grayscale8Image ToGrayscaleImage()
     88         {
     89             return ToGrayscaleImage(0.2990.5870.114);
     90         }
     91 
     92         public unsafe Grayscale8Image ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
     93         {
     94             Grayscale8Image img = new Grayscale8Image(this.Length);
     95             Argb32* p = Pointer;
     96             Byte* to = img.Pointer;
     97             Argb32* end = p + Length;
     98 
     99             while (p != end)
    100             {
    101                 *to = (Byte)(p->Red * rCoeff + p->Green * gCoeff + p->Blue * bCoeff);
    102                 p++;
    103                 to++;
    104             }
    105             return img;
    106         }
    107 
    108         public unsafe static Argb32Image CreateFromBitmap(Bitmap map)
    109         {
    110             if (map == nullthrow new ArgumentNullException("map");
    111 
    112             Argb32Image img = new Argb32Image(map.Width*map.Height);
    113 
    114             Argb32* p = img.Pointer;
    115 
    116             for (int row = 0; row < map.Height; row++)
    117             {
    118                 for (int col = 0; col < map.Width; col++)
    119                 {
    120                     Color c = map.GetPixel(col, row);
    121                     p->Alpha = c.A;
    122                     p->Red = c.R;
    123                     p->Green = c.G;
    124                     p->Blue = c.B;
    125                     p++;
    126                 }
    127             }
    128 
    129             return img;
    130         }
    131     }
    132 }
    133 

    (5)我自己的实现,Rgb24Image,对小图像采用浮点计算,对大图像采用查表计算:

    代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Drawing;
      4 using System.Text;
      5 
      6 namespace Orc.SmartImage.UnmanagedObjects
      7 {
      8     public struct Rgb24
      9     {
     10         public Byte Red;
     11         public Byte Green;
     12         public Byte Blue;
     13     }
     14 
     15     public class Rgb24Image : UnmanagedMemory<Rgb24>
     16     {
     17         private unsafe Rgb24* m_pointer;
     18 
     19         public unsafe Rgb24* Pointer { get { return m_pointer; } }
     20 
     21         public unsafe Rgb24Image(int length)
     22             : base(length)
     23         {
     24             m_pointer = (Rgb24*)this.Start;
     25         }
     26 
     27         public unsafe Rgb24 this[int index]
     28         {
     29             get { return *(m_pointer + index); }
     30             set { *(m_pointer + index) = value; }
     31         }
     32 
     33         public Grayscale8Image ToGrayscaleImage()
     34         {
     35             return ToGrayscaleImage(0.2990.5870.114);
     36         }
     37 
     38         public unsafe Grayscale8Image ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
     39         {
     40             Grayscale8Image img = new Grayscale8Image(this.Length);
     41             Rgb24* p = Pointer;
     42             Byte* to = img.Pointer;
     43             Rgb24* end = p + Length;
     44 
     45             if (Length < 1024)
     46             {
     47                 while (p != end)
     48                 {
     49                     *to = (Byte)(p->Red * rCoeff + p->Green * gCoeff + p->Blue * bCoeff);
     50                     p++;
     51                     to++;
     52                 }
     53             }
     54             else
     55             {
     56                 int* rCache = stackalloc int[256];
     57                 int* gCache = stackalloc int[256];
     58                 int* bCache = stackalloc int[256];
     59 
     60                 const int shift = 1<<10;
     61                 int rShift = (int)(rCoeff * shift);
     62                 int gShift = (int)(gCoeff * shift);
     63                 int bShift = shift - rShift - gShift;
     64 
     65                 int r = 0, g = 0, b = 0;
     66                 for (int i = 0; i < 256; i++)
     67                 {
     68                     rCache[i] = r;
     69                     gCache[i] = g;
     70                     bCache[i] = b;
     71                     r += rShift;
     72                     g += gShift;
     73                     b += bShift;
     74                 }
     75 
     76                 while (p != end)
     77                 {
     78                     *to = (Byte)((rCache[p->Red] + gCache[p->Green] + bCache[p->Red]) >> 10);
     79                     p++;
     80                     to++;
     81                 }
     82             }
     83             return img;
     84         }
     85 
     86         public unsafe static Rgb24Image CreateFromBitmap(Bitmap map)
     87         {
     88             if (map == nullthrow new ArgumentNullException("map");
     89 
     90             Rgb24Image img = new Rgb24Image(map.Width * map.Height);
     91 
     92             Rgb24* p = img.Pointer;
     93 
     94             for (int row = 0; row < map.Height; row++)
     95             {
     96                 for (int col = 0; col < map.Width; col++)
     97                 {
     98                     Color c = map.GetPixel(col, row);
     99                     p->Red = c.R;
    100                     p->Green = c.G;
    101                     p->Blue = c.B;
    102                     p++;
    103                 }
    104             }
    105 
    106             return img;
    107         }
    108     }
    109 }
    110 

    测试代码如下:

    代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Runtime.InteropServices;
      4 using System.Diagnostics;
      5 using System.Linq;
      6 using System.Text;
      7 using System.Drawing;
      8 using System.Drawing.Imaging;
      9 using Orc.SmartImage;
     10 using Emgu.CV;
     11 using Emgu.CV.Structure;
     12 using Emgu.CV.CvEnum;
     13 using Orc.SmartImage.Gpu;
     14 using Orc.SmartImage.UnmanagedObjects;
     15 
     16 namespace Orc.SmartImage.PerformanceTest
     17 {
     18     public class PerformanceTestCase0
     19     {
     20         public static String Test(Bitmap src, int count)
     21         {
     22             Argb32Image img32 = Argb32Image.CreateFromBitmap(src);
     23             Rgb24Image img24 = Rgb24Image.CreateFromBitmap(src);
     24             Image<Bgr, Byte> imageSource = new Image<Bgr, byte>(src);
     25             IntPtr ptrSource = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MIplImage)));
     26             Marshal.StructureToPtr(imageSource.MIplImage, ptrSource, true);
     27             Size size = imageSource.Size;
     28             StringBuilder sb = new StringBuilder();
     29             Stopwatch sw = new Stopwatch();
     30 
     31             DoSomething();
     32 
     33             sw.Reset();
     34             sw.Start();
     35             for (int i = 0; i < count; i++)
     36                 ProcessImageWithEmgucv(imageSource);
     37             sw.Stop();
     38             sb.AppendLine("EmguCV:" + sw.ElapsedMilliseconds.ToString());
     39 
     40             DoSomething();
     41             sw.Reset();
     42             sw.Start();
     43             for (int i = 0; i < count; i++)
     44                 ProcessImageWithOpencv(ptrSource, imageSource.Size);
     45             sw.Stop();
     46             sb.AppendLine("OpenCV P/Invoke:" + sw.ElapsedMilliseconds.ToString());
     47 
     48             DoSomething();
     49             sw.Reset();
     50             sw.Start();
     51             for (int i = 0; i < count; i++)
     52                 Grayscale(src);
     53             sw.Stop();
     54             sb.AppendLine("BitmapData:" + sw.ElapsedMilliseconds.ToString());
     55 
     56             DoSomething();
     57             sw.Reset();
     58             sw.Start();
     59             for (int i = 0; i < count; i++)
     60                 img24.ToGrayscaleImage();
     61             sw.Stop();
     62             sb.AppendLine("RgbImage24[use table]:" + sw.ElapsedMilliseconds.ToString());
     63 
     64             DoSomething();
     65             sw.Reset();
     66             sw.Start();
     67             for (int i = 0; i < count; i++)
     68                 img32.ToGrayscaleImage();
     69             sw.Stop();
     70             sb.AppendLine("ArgbImage32:" + sw.ElapsedMilliseconds.ToString());
     71 
     72             return sb.ToString();
     73         }
     74 
     75         private static int[] DoSomething()
     76         {
     77             int[] data = new Int32[20000000];
     78             for (int i = 0; i < data.Length; i++)
     79             {
     80                 data[i] = i;
     81             }
     82             return data;
     83         }
     84 
     85         /// <summary>
     86         /// 使用EmguCv处理图像
     87         /// </summary>
     88         private static void ProcessImageWithEmgucv(Image<Bgr, Byte> imageSource)
     89         {
     90             //灰度
     91             Image<Gray, Byte> imageGrayscale = imageSource.Convert<Gray, Byte>();
     92         }
     93 
     94         /// <summary>
     95         /// 使用Open Cv P/Invoke处理图像
     96         /// </summary>
     97         unsafe private static void ProcessImageWithOpencv(IntPtr ptrSource, Size size)
     98         {
     99             IntPtr ptrGrayscale = CvInvoke.cvCreateImage(size, IPL_DEPTH.IPL_DEPTH_8U, 1);
    100             CvInvoke.cvCvtColor(ptrSource, ptrGrayscale, COLOR_CONVERSION.CV_BGR2GRAY);
    101         }
    102 
    103 
    104 
    105         /// <summary>
    106         /// 将指定图像转换成灰度图
    107         /// </summary>
    108         /// <param name="bitmapSource">源图像支持3通道或者4通道图像,支持Format24bppRgb、Format32bppRgb和Format32bppArgb这3种像素格式</param>
    109         /// <returns>返回灰度图,如果转化失败,返回null。</returns>
    110         private static Bitmap Grayscale(Bitmap bitmapSource)
    111         {
    112             Bitmap bitmapGrayscale = null;
    113             if (bitmapSource != null && (bitmapSource.PixelFormat == PixelFormat.Format24bppRgb || bitmapSource.PixelFormat == PixelFormat.Format32bppArgb || bitmapSource.PixelFormat == PixelFormat.Format32bppRgb))
    114             {
    115                 int width = bitmapSource.Width;
    116                 int height = bitmapSource.Height;
    117                 Rectangle rect = new Rectangle(00, width, height);
    118                 bitmapGrayscale = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
    119                 //设置调色板
    120                 ColorPalette palette = bitmapGrayscale.Palette;
    121                 for (int i = 0; i < palette.Entries.Length; i++)
    122                     palette.Entries[i] = Color.FromArgb(255, i, i, i);
    123                 bitmapGrayscale.Palette = palette;
    124                 BitmapData dataSource = bitmapSource.LockBits(rect, ImageLockMode.ReadOnly, bitmapSource.PixelFormat);
    125                 BitmapData dataGrayscale = bitmapGrayscale.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
    126                 byte b, g, r;
    127                 int strideSource = dataSource.Stride;
    128                 int strideGrayscale = dataGrayscale.Stride;
    129                 unsafe
    130                 {
    131                     byte* ptrSource = (byte*)dataSource.Scan0.ToPointer();
    132                     byte* ptr1;
    133                     byte* ptrGrayscale = (byte*)dataGrayscale.Scan0.ToPointer();
    134                     byte* ptr2;
    135                     if (bitmapSource.PixelFormat == PixelFormat.Format24bppRgb)
    136                     {
    137                         for (int row = 0; row < height; row++)
    138                         {
    139                             ptr1 = ptrSource + strideSource * row;
    140                             ptr2 = ptrGrayscale + strideGrayscale * row;
    141                             for (int col = 0; col < width; col++)
    142                             {
    143                                 b = *ptr1;
    144                                 ptr1++;
    145                                 g = *ptr1;
    146                                 ptr1++;
    147                                 r = *ptr1;
    148                                 ptr1++;
    149                                 *ptr2 = (byte)(0.114 * b + 0.587 * g + 0.299 * r);
    150                                 ptr2++;
    151                             }
    152                         }
    153                     }
    154                     else    //bitmapSource.PixelFormat == PixelFormat.Format32bppArgb || bitmapSource.PixelFormat == PixelFormat.Format32bppRgb
    155                     {
    156                         for (int row = 0; row < height; row++)
    157                         {
    158                             ptr1 = ptrSource + strideGrayscale * row;
    159                             ptr2 = ptrGrayscale + strideGrayscale * row;
    160                             for (int col = 0; col < width; col++)
    161                             {
    162                                 b = *ptr1;
    163                                 ptr1++;
    164                                 g = *ptr1;
    165                                 ptr1++;
    166                                 r = *ptr1;
    167                                 ptr1 += 2;
    168                                 *ptr2 = (byte)(0.114 * b + 0.587 * g + 0.299 * r);
    169                                 ptr2++;
    170                             }
    171                         }
    172                     }
    173                 }
    174                 bitmapGrayscale.UnlockBits(dataGrayscale);
    175                 bitmapSource.UnlockBits(dataSource);
    176             }
    177             return bitmapGrayscale;
    178         }
    179 
    180     }
    181 }
    182 
    版权所有,欢迎转载
  • 相关阅读:
    四则运算2
    进度条博客
    随机生成30道100以内的四则运算题
    构建之法阅读笔记01
    自我介绍
    c# dataGridView cell添加下拉框
    Winform Combobox.Items tooltip
    中医和红外(北京第一个工作)
    pdf修复
    c# 导出数据到excel
  • 原文地址:https://www.cnblogs.com/xiaotie/p/1681476.html
Copyright © 2011-2022 走看看