【IT168 技术】阅读《各种图像处理类库的比较及选择(The Comparison of Image Processing Libraries)》对后面的比较结果感觉怪异。对计算密集型运算,C#和C/C++的性能应该差别不大才是。为了探讨问题,做了以下实验。
本实验比较了五种方式进行图像灰度化计算:
(1)EmguCV实现,见 《各种图像处理类库的比较及选择(The Comparison of Image Processing Libraries)》 文中代码
(2)OpenCV/PInvoke实现,见 《各种图像处理类库的比较及选择(The Comparison of Image Processing Libraries)》 文中代码
(3)BitmapData实现,见 《各种图像处理类库的比较及选择(The Comparison of Image Processing Libraries)》 文中代码
(4)Array实现(ArgbImage8),核心代码如下:
(每一个)ImageChannel8 内含1个Byte数组Data。GrayscaleImage8 继承自 ImageChannel8 。
public class ArgbImage8 : ImageChannelSet8
{
public ImageChannel8 A { get { return this.Channels[0]; } }
public ImageChannel8 R { get { return this.Channels[0]; } }
public ImageChannel8 G { get { return this.Channels[0]; } }
public ImageChannel8 B { get { return this.Channels[0]; } }
public ArgbImage8(int width, int height)
: base(4, width, height)
{
}
public GrayscaleImage8 ToGrayscaleImage()
{
return ToGrayscaleImage(0.299, 0.587, 0.114);
}
public GrayscaleImage8 ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
{
GrayscaleImage8 img = new GrayscaleImage8(this.Width, this.Height);
Byte[] r = R.Data;
Byte[] g = G.Data;
Byte[] b = B.Data;
Byte[] dst = img.Data;
for (int i = 0; i < r.Length; i++)
{
dst[i] = (Byte)(r[i] * rCoeff + g[i] * gCoeff + b[i] * bCoeff);
}
return img;
}
//性能低下,先这样写了
public static ArgbImage8 CreateFromBitmap(Bitmap map)
{
if (map == null) throw new ArgumentNullException("map");
ArgbImage8 img = new ArgbImage8(map.Width, map.Height);
Byte[] a = img.A.Data;
Byte[] r = img.R.Data;
Byte[] g = img.G.Data;
Byte[] b = img.B.Data;
for (int row = 0; row < img.Height; row++)
{
for (int col = 0; col < img.Width; col++)
{
int index = row * img.Width + col;
Color c = map.GetPixel(col, row);
a[index] = c.A;
r[index] = c.R;
r[index] = c.R;
r[index] = c.R;
}
}
return img;
}
}
(5)C# 指针/unsafe 实现(ArgbImage32 ),核心代码如下:
public class UnmanagedMemory<T> : IDisposable
where T : struct
{
public Int32 ByteCount { get; private set; }
public Int32 Length { get; private set; }
public IntPtr Start { get; private set; }
public Int32 SizeOfType { get; private set; }
public UnmanagedMemory(Int32 length)
{
Length = length;
SizeOfType = SizeOfT();
ByteCount = SizeOfType * length;
Start = Marshal.AllocHGlobal(ByteCount);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (false == disposed)
{
disposed = true;
Marshal.FreeHGlobal(Start);
}
}
private bool disposed;
~UnmanagedMemory()
{
Dispose(false);
}
private Int32 SizeOfT()
{
return Marshal.SizeOf(typeof(T));
}
}
public struct Argb32
{
public Byte Alpha;
public Byte Red;
public Byte Green;
public Byte Blue;
}
public class Argb32Image : UnmanagedMemory<Argb32>
{
private unsafe Argb32* m_pointer;
public unsafe Argb32* Pointer { get { return m_pointer; } }
public unsafe Argb32Image(int length)
: base(length)
{
m_pointer = (Argb32*)this.Start;
}
public unsafe Argb32 this[int index]
{
get { return *(m_pointer + index); }
set { *(m_pointer + index) = value; }
}
public Grayscale8Image ToGrayscaleImage()
{
return ToGrayscaleImage(0.299, 0.587, 0.114);
}
public unsafe Grayscale8Image ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
{
Grayscale8Image img = new Grayscale8Image(this.Length);
Argb32* p = Pointer;
Byte* to = img.Pointer;
Argb32* end = p + Length;
while (p != end)
{
*to = (Byte)(p->Red * rCoeff + p->Green * gCoeff + p->Blue * bCoeff);
p++;
to++;
}
return img;
}
public unsafe static Argb32Image CreateFromBitmap(Bitmap map)
{
if (map == null) throw new ArgumentNullException("map");
Argb32Image img = new Argb32Image(map.Width*map.Height);
Argb32* p = img.Pointer;
for (int row = 0; row < map.Height; row++)
{
for (int col = 0; col < map.Width; col++)
{
Color c = map.GetPixel(col, row);
p->Alpha = c.A;
p->Red = c.R;
p->Green = c.G;
p->Blue = c.B;
p++;
}
}
return img;
}
}
{
public ImageChannel8 A { get { return this.Channels[0]; } }
public ImageChannel8 R { get { return this.Channels[0]; } }
public ImageChannel8 G { get { return this.Channels[0]; } }
public ImageChannel8 B { get { return this.Channels[0]; } }
public ArgbImage8(int width, int height)
: base(4, width, height)
{
}
public GrayscaleImage8 ToGrayscaleImage()
{
return ToGrayscaleImage(0.299, 0.587, 0.114);
}
public GrayscaleImage8 ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
{
GrayscaleImage8 img = new GrayscaleImage8(this.Width, this.Height);
Byte[] r = R.Data;
Byte[] g = G.Data;
Byte[] b = B.Data;
Byte[] dst = img.Data;
for (int i = 0; i < r.Length; i++)
{
dst[i] = (Byte)(r[i] * rCoeff + g[i] * gCoeff + b[i] * bCoeff);
}
return img;
}
//性能低下,先这样写了
public static ArgbImage8 CreateFromBitmap(Bitmap map)
{
if (map == null) throw new ArgumentNullException("map");
ArgbImage8 img = new ArgbImage8(map.Width, map.Height);
Byte[] a = img.A.Data;
Byte[] r = img.R.Data;
Byte[] g = img.G.Data;
Byte[] b = img.B.Data;
for (int row = 0; row < img.Height; row++)
{
for (int col = 0; col < img.Width; col++)
{
int index = row * img.Width + col;
Color c = map.GetPixel(col, row);
a[index] = c.A;
r[index] = c.R;
r[index] = c.R;
r[index] = c.R;
}
}
return img;
}
}
(5)C# 指针/unsafe 实现(ArgbImage32 ),核心代码如下:
public class UnmanagedMemory<T> : IDisposable
where T : struct
{
public Int32 ByteCount { get; private set; }
public Int32 Length { get; private set; }
public IntPtr Start { get; private set; }
public Int32 SizeOfType { get; private set; }
public UnmanagedMemory(Int32 length)
{
Length = length;
SizeOfType = SizeOfT();
ByteCount = SizeOfType * length;
Start = Marshal.AllocHGlobal(ByteCount);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (false == disposed)
{
disposed = true;
Marshal.FreeHGlobal(Start);
}
}
private bool disposed;
~UnmanagedMemory()
{
Dispose(false);
}
private Int32 SizeOfT()
{
return Marshal.SizeOf(typeof(T));
}
}
public struct Argb32
{
public Byte Alpha;
public Byte Red;
public Byte Green;
public Byte Blue;
}
public class Argb32Image : UnmanagedMemory<Argb32>
{
private unsafe Argb32* m_pointer;
public unsafe Argb32* Pointer { get { return m_pointer; } }
public unsafe Argb32Image(int length)
: base(length)
{
m_pointer = (Argb32*)this.Start;
}
public unsafe Argb32 this[int index]
{
get { return *(m_pointer + index); }
set { *(m_pointer + index) = value; }
}
public Grayscale8Image ToGrayscaleImage()
{
return ToGrayscaleImage(0.299, 0.587, 0.114);
}
public unsafe Grayscale8Image ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
{
Grayscale8Image img = new Grayscale8Image(this.Length);
Argb32* p = Pointer;
Byte* to = img.Pointer;
Argb32* end = p + Length;
while (p != end)
{
*to = (Byte)(p->Red * rCoeff + p->Green * gCoeff + p->Blue * bCoeff);
p++;
to++;
}
return img;
}
public unsafe static Argb32Image CreateFromBitmap(Bitmap map)
{
if (map == null) throw new ArgumentNullException("map");
Argb32Image img = new Argb32Image(map.Width*map.Height);
Argb32* p = img.Pointer;
for (int row = 0; row < map.Height; row++)
{
for (int col = 0; col < map.Width; col++)
{
Color c = map.GetPixel(col, row);
p->Alpha = c.A;
p->Red = c.R;
p->Green = c.G;
p->Blue = c.B;
p++;
}
}
return img;
}
}