本文是《编写高效的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 }
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++;
}
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 /// 使用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
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(0, 0, 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 }
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(0, 0, 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 { get; private set; }
12 public Int32 Length { get; private set; }
13 public IntPtr Start { get; private set; }
14 public Int32 SizeOfType { get; private 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.299, 0.587, 0.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 == null) throw 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
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 { get; private set; }
12 public Int32 Length { get; private set; }
13 public IntPtr Start { get; private set; }
14 public Int32 SizeOfType { get; private 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.299, 0.587, 0.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 == null) throw 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.299, 0.587, 0.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 == null) throw 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
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.299, 0.587, 0.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 == null) throw 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(0, 0, 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 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(0, 0, 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