在缓冲区中存储图像
Storing images in buffer
我正在编写我的第一个图像编辑程序(c#、winforms),但我对缓冲区和高效存储数据非常不满意。
我有一个包含图片的文件夹,并通过 FolderBrowserDialog
:
将文件加载到 string[]
files = Directory.GetFiles(fbd.SelectedPath);
我总是在图片框中显示其中一张图片。我有各种适用的功能,例如显示图像上的过滤器。我所有的函数都在位图上工作,我所有的函数基本上都是通过调用另一个函数开始的:
Bitmap bmp = GetImage();
和:
Image GetImage()
{
FileStream imageStream = new FileStream(Convert.ToString(files[SelIndex]), FileMode.Open);
Image image = Image.FromStream(imageStream);
imageStream.Close();
return image;
}
每当我调用我的一个函数时(例如因为我想显示不同的图像并查看过滤器如何应用),在显示新图片之前我会遇到痛苦的滞后。就我而言,每次我调用我的一个函数时,它都会深入到图片所在的原始文件夹并从那里获取数据,我相信这就是延迟的原因。
首先:对吗?其次:有什么方法可以避免这种情况? 我可以想象将数据保存在某种缓冲区中吗?
我的 functions/filters 非常基础,我不使用 SetPixel
方法但是:
BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
byte[] bytes = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
//whatever my filter is
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
bmp.UnlockBits(data);
因为速度更快,所以延迟不应该来自于此。
编辑: 另外,我正在处理 .tif 文件,每个大约 12 MB,这绝对是问题的一部分。
你说得对,文件操作很昂贵。它们涉及两个相对较慢的操作:从磁盘读取数据和解压缩数据。
首先,考虑用这个简单的替代方法来替代您编写的所有 FileStream 内容。
Bitmap input = new Bitmap(pathToFile);
此外,您的 GetImage
函数实际上是一个 LoadImageFromDisk
函数。所以首先要做的是确保只执行一次并将输入的 Bitmap 对象保存在内存中并重新使用它。在输入图像上调用 LockBits 时,使用 ReadOnly 访问。
如果您想进行修改(如应用图像滤镜),则将此滤镜操作的结果存储在新的 output 图像中,而不是覆盖原始图像记忆。然后如果你想改变过滤器的细节,你仍然有原来的东西。
Bitmap output = new Bitmap(input.Width, input.Height, PixelFormat.Format32bppRgb);
当您对输出图像进行 LockBit 时,请使用 WriteOnly 访问权限。
此外,考虑使用 不安全的 上下文直接访问数据而不是使用 Marshal.Copy,它会为您节省一个缓冲区副本。
最后,无论您的过滤器是什么,看看您是否可以利用 Parallel.For 一次在其上运行并利用所有处理器。
我正在编写我的第一个图像编辑程序(c#、winforms),但我对缓冲区和高效存储数据非常不满意。
我有一个包含图片的文件夹,并通过 FolderBrowserDialog
:
string[]
files = Directory.GetFiles(fbd.SelectedPath);
我总是在图片框中显示其中一张图片。我有各种适用的功能,例如显示图像上的过滤器。我所有的函数都在位图上工作,我所有的函数基本上都是通过调用另一个函数开始的:
Bitmap bmp = GetImage();
和:
Image GetImage()
{
FileStream imageStream = new FileStream(Convert.ToString(files[SelIndex]), FileMode.Open);
Image image = Image.FromStream(imageStream);
imageStream.Close();
return image;
}
每当我调用我的一个函数时(例如因为我想显示不同的图像并查看过滤器如何应用),在显示新图片之前我会遇到痛苦的滞后。就我而言,每次我调用我的一个函数时,它都会深入到图片所在的原始文件夹并从那里获取数据,我相信这就是延迟的原因。 首先:对吗?其次:有什么方法可以避免这种情况? 我可以想象将数据保存在某种缓冲区中吗?
我的 functions/filters 非常基础,我不使用 SetPixel
方法但是:
BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
byte[] bytes = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
//whatever my filter is
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
bmp.UnlockBits(data);
因为速度更快,所以延迟不应该来自于此。
编辑: 另外,我正在处理 .tif 文件,每个大约 12 MB,这绝对是问题的一部分。
你说得对,文件操作很昂贵。它们涉及两个相对较慢的操作:从磁盘读取数据和解压缩数据。
首先,考虑用这个简单的替代方法来替代您编写的所有 FileStream 内容。
Bitmap input = new Bitmap(pathToFile);
此外,您的 GetImage
函数实际上是一个 LoadImageFromDisk
函数。所以首先要做的是确保只执行一次并将输入的 Bitmap 对象保存在内存中并重新使用它。在输入图像上调用 LockBits 时,使用 ReadOnly 访问。
如果您想进行修改(如应用图像滤镜),则将此滤镜操作的结果存储在新的 output 图像中,而不是覆盖原始图像记忆。然后如果你想改变过滤器的细节,你仍然有原来的东西。
Bitmap output = new Bitmap(input.Width, input.Height, PixelFormat.Format32bppRgb);
当您对输出图像进行 LockBit 时,请使用 WriteOnly 访问权限。
此外,考虑使用 不安全的 上下文直接访问数据而不是使用 Marshal.Copy,它会为您节省一个缓冲区副本。
最后,无论您的过滤器是什么,看看您是否可以利用 Parallel.For 一次在其上运行并利用所有处理器。