我最近开始研究图像处理的主题。我认为我应该做的第一件事就是学习图像是如何工作的。我最近的项目涉及制作一个图像的新副本。我想尽快完成它,所以我试着想出尽可能多的方法。我为每种方法编写了一个方法,然后计算调用该方法100次所需的时间。这些是我的结果:
Marshal: 0.45584
Instance: 1.69299
Clone: 0.30687
GetSet: 341.74056
Pointer: 2.54130
Graphics: 1.07960
每个方法传递一个源图像和目标图像。最终目标是将第一张图像中的所有像素复制到第二张图像中。
private void MarshalCopyMethod(Bitmap sourceImage, Bitmap destinationImage)
{
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
BitmapData readData = sourceImage.LockBits(rect, ImageLockMode.ReadOnly, sourceImage.PixelFormat);
BitmapData writeData = destinationImage.LockBits(rect, ImageLockMode.WriteOnly, sourceImage.PixelFormat);
// Get the address of the first line.
IntPtr sourcePtr = readData.Scan0;
IntPtr destinationPtr = writeData.Scan0;
byte[] rgbValues = new byte[readData.Stride * readData.Height];
Marshal.Copy(sourcePtr, rgbValues, 0, rgbValues.Length);
Marshal.Copy(rgbValues, 0, destinationPtr, rgbValues.Length);
sourceImage.UnlockBits(readData);
destinationImage.UnlockBits(writeData);
}
private void PointerCopyMethod(Bitmap sourceImage, Bitmap destinationImage)
{
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
BitmapData readData = sourceImage.LockBits(rect, ImageLockMode.ReadOnly, sourceImage.PixelFormat);
BitmapData writeData = destinationImage.LockBits(rect, ImageLockMode.WriteOnly, sourceImage.PixelFormat);
unsafe
{
// Get the address of the first line.
byte* readPointer = (byte*)readData.Scan0.ToPointer();
byte* writePointer = (byte*)writeData.Scan0.ToPointer();
int lengthOfData = readData.Stride * readData.Height;
for (int i = 0; i < lengthOfData; i++)
{
*writePointer++ = *readPointer++;
}
}
sourceImage.UnlockBits(readData);
destinationImage.UnlockBits(writeData);
}
private void InstanceCopyMethod(Bitmap sourceImage, Bitmap destinationImage)
{
destinationImage = new Bitmap(sourceImage);
}
private void CloneRegionMethod(Bitmap sourceImage, Bitmap destinationImage)
{
destinationImage = sourceImage.Clone(new Rectangle(860, 440, 200, 200), sourceImage.PixelFormat);
}
private void CloneCopyMethod(Bitmap sourceImage, Bitmap destinationImage)
{
destinationImage = (Bitmap)sourceImage.Clone();
}
private void GetSetPixelCopyMethod(Bitmap sourceImage, Bitmap destinationImage)
{
for (int y = 0; y < sourceImage.Height; y++)
{
for (int x = 0; x < sourceImage.Width; x++)
{
destinationImage.SetPixel(x, y, destinationImage.GetPixel(x, y));
}
}
}
private void GraphicsCopyMethod(Bitmap sourceImage, Bitmap destinationImage)
{
using(Graphics g = Graphics.FromImage(destinationImage))
{
g.DrawImage(sourceImage, new Point(0, 0));
}
}
以下两行也被添加到每个方法的末尾:
destinationImage.SetPixel(955, 535, Color.Red);
destinationImage.SetPixel(965, 545, Color.Green);
我这样做是因为我读到一些关于Image.Clone()的东西。它的效果是,直到你修改了克隆的一部分,副本才真正被创建。如果不设置这些像素,Clone()方法的完成速度似乎要快1000倍。我不太清楚那里到底发生了什么。
结果似乎和我在网上读到的一样。然而,指针方法是我在Get/Set Pixel方法之外实现的最慢的方法。从我个人的研究来看,我希望指针是最快的,如果不是最快的。
我有几个与我的项目有关的问题。对于这种情况,我是否使用了最佳的指针?为什么更改克隆图像中的一个像素会影响克隆方法?有没有其他方法可以在更短的时间内复制图像?还有其他建议吗?谢谢。数字看起来很合理。摘要:
-
GetPixel
/SetPixel
慢 - 特别编写的代码更快
- 编写快速版本的
memcpy
是非常困难的,在任何语言的一般情况下,击败库版本几乎是不可能的(可以期望在特定大小/目标CPU等特殊情况下获得更好的性能)。
如果你想玩更多的指针-尝试测量:-在常规c#中尝试相同的代码(索引)-尝试切换到int
进行复制-注意每一行都是DWORD对齐的-不需要为tail设置特殊情况。-从封送示例中重新实现块复制