我创建了一个简单的程序,它将Listbox1中所选项目的图像显示到pictureBox1。它工作正常,但显示下一张图像大约需要200毫秒。我的电脑使用的是英特尔i7处理器和Windows 7 64位。请告知我如何加快这个过程。以下是我的代码。谢谢!
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
folderBrowserDlg.SelectedPath = folderpath;
this.folderBrowserDlg.ShowNewFolderButton = false; //Disable New Folder button
DialogResult result = this.folderBrowserDlg.ShowDialog();
if (result == DialogResult.OK)
{
folderpath = this.folderBrowserDlg.SelectedPath;
string ImagePath = folderpath.Substring(0, folderpath.LastIndexOf(("\\")));
folderName = folderpath.Substring(folderpath.LastIndexOf(("\\")) + 1);
PathLength = ImagePath.Length; //Use for Substring later
txtBrowse.Text = folderpath; //Get folder path and display to textbox
var filearray = Directory.EnumerateFiles(folderpath, "*.*", SearchOption.AllDirectories).Where(a => a.EndsWith(".tif") || a.EndsWith(".tiff"));
array = filearray.ToArray();
var filenames = Directory.EnumerateFiles(folderpath, "*.*", SearchOption.AllDirectories).Where(a => a.EndsWith(".tif") || a.EndsWith(".tiff")).Select(Path.GetFileName); // Get all image file names
foreach (string fn in filenames)
{
listBox1.Items.Add(fn); // Add all image file names to listbox
}
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) //Go to next image after press Enter key
{
if (listBox1.SelectedIndex != listBox1.Items.Count - 1)
{
listBox1.SelectedIndex = listBox1.SelectedIndex + 1;
}
e.SuppressKeyPress = true;
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Index = listBox1.SelectedIndex; //Get selected item from listbox
pictureBox1.Image = Image.FromFile(array[Index].ToString()); // display image to picturebox
}
答案 0 :(得分:0)
您正在使用Image.FromFile
,它会从磁盘加载图像。像这样的IO操作通常会很慢,因为它们依赖于磁盘速度来完成。
我建议在将文件夹添加到列表框时,通过另一个线程从文件夹加载所有.tif
个图像。
这将有一些初始加载时间来加载所有图像,但之后你可以点击任何列表项,它们将立即出现。
示例:将图像名称添加到列表框后,将此代码作为新线程运行:(确保您有一个包含所有已加载图像的全局变量List<Bitmap> Images
)
Images = new List<Bitmap>(); //Or use an array, your choice.
foreach (string file in filearray)
{
Images.Add(Image.FromFile(file));
}
然后,当您从列表框中选择一个项目时,请设置图像:
pictureBox1.Image = Images.ElementAt[Index];
请注意,如果图像非常大,这可能无效,因为一次加载所有图像可能会导致内存不足错误。
如果是这种情况,您需要在点击它们时加载它们,然后加载加载时间。因为你有一个i7,许多最终用户的计算机速度可能会慢一些。这就是为什么我建议使用线程操作在后台加载它们,并提供加载栏或动画,因为加载大型tiff文件不会是即时的。
我不会在这篇文章中讨论有关线程的信息,因为答案是this S.O.问题显示了在后台处理操作的好方法,同时向用户报告进度(例如:加载栏)。
简而言之:要么一次加载它们,如果足够小,或者需要时加载它们会更好。没有办法绕过加载时间,所以你需要忍受一个小的等待,或者(推荐),在新线程中运行加载并在图像正在为用户提供加载图像加载。
答案 1 :(得分:0)
Image Loader测试结果: ImageFromFileFast()比 ImageFromFileSlow() 快800%(请记住 ImageFromFileFast()是不安全的代码)
Image Loaded time using the ImageFromFileSlow() is 4351.1889 milliseconds
Image Loaded time using the ImageFromFileFast() is 541.965 milliseconds
ImageFromFileFast() is 802.85% faster than ImageFromFileSlow()
Image Loader Test:
string BigImage19MBpath = @"H:\Earth's_Location_in_the_Universe_(JPEG).jpg";
Stopwatch sw = new Stopwatch();
sw.Start();
Bitmap LoadedImage = (Bitmap)ImageFromFileSlow(BigImage19MBpath);
double TotalMillisecondsSlow = sw.Elapsed.TotalMilliseconds;
Debug.WriteLine(string.Format("Image Loaded time using the ImageFromFileSlow() is {0} milliseconds", TotalMillisecondsSlow.ToString()));
sw.Restart();
Bitmap LoadedImage1 = (Bitmap)ImageFromFileFast(BigImage19MBpath);
double TotalMillisecondsFast = sw.Elapsed.TotalMilliseconds;
Debug.WriteLine(string.Format("Image Loaded time using the ImageFromFileFast() is {0} milliseconds", TotalMillisecondsFast.ToString()));
Debug.WriteLine(string.Format("ImageFromFileFast() is {0}% faster then ImageFromFileSlow()", (100*TotalMillisecondsSlow/TotalMillisecondsFast).ToString("0.00")));
图像加载器功能:
[DllImport("Kernel32.dll", EntryPoint = "CopyMemory")]
private static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
/// <summary>
/// loads image fast but UNSAFE
/// </summary>
/// <param name="iPath"></param>
/// <returns></returns>
public static Image ImageFromFileFast(string iPath)
{
using (Bitmap sourceImage = (Bitmap)Image.FromFile(iPath))
{
Bitmap targetImage = new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
BitmapData sourceBitmapData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
BitmapData targetBitmapData = targetImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.WriteOnly, targetImage.PixelFormat);
CopyMemory(targetBitmapData.Scan0, sourceBitmapData.Scan0, Convert.ToUInt32(sourceBitmapData.Stride) * Convert.ToUInt32(sourceBitmapData.Height));
sourceImage.UnlockBits(sourceBitmapData);
targetImage.UnlockBits(targetBitmapData);
return targetImage;
}
}
public static Image ImageFromFileSlow(string iPath)
{
using (Bitmap sourceImage = (Bitmap)Image.FromFile(iPath))
{
Bitmap targetImage = new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
using (Graphics g = Graphics.FromImage(targetImage))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.DrawImage(sourceImage, 0, 0, sourceImage.Width, sourceImage.Height);
}
return targetImage;
}
}
答案 2 :(得分:0)
3184x4208的图像(来自您的评论)需要大约40 Mb的内存
如果用户快速浏览/打开这些图像,让我们说每秒1次,应用程序将在一分钟内声明2.4千兆字节(通过打开/浏览60张图像)。
如果您没有释放声明的内存,这将导致应用程序内存不足并显着减慢速度。 阅读此问题并回答有关清理的问题:.NET Memory issues loading ~40 images, memory not reclaimed, potentially due to LOH fragmentation
根据程序的实际功能,您可能需要创建缩略图并加载这些缩略图。这将占用更少的内存(你仍然需要释放它)并且将加载更快。请参阅此问题,并提供有关如何创建缩略图的多项建议:Generating image thumbnails in ASP.NET?(问题与Web应用程序有关,但仍在讨论同一问题)