在循环中创建图像时实时显示图像
Display an image in real time as it is being created in a loop
在我的代码中,输出是一个图像,每个像素都是使用嵌套循环确定的。
1) 如何强制 window 打开并显示在循环中构建的输出图像? (window 当一切都完成时出现。我不想要这个。)
2) 如何在循环进行时逐行(甚至逐像素)显示输出。用户必须具有实时获取输出的意识。
outImage = new Image<Hsv, Byte>(numberOfColumns, numberOfRows);
byte[,,] pixelValue = outImage.Data;
for (int i = 0; i < numberOfRows - 1; i++)
{
for (int j = 0; j < numberOfColumns - 1; j++)
{
//pixelValue[i, j, k] is determined here using some other functions
imageBox1.Image = outImage; //too slow and impossible
}
}
我不是 WinForms 专家,我更喜欢 WPF 类型。但我有一个应用程序 运行 稳定的 30fps,这比人类检测速度更快。我真的不太明白你想在这里做什么。你必须单独 blit 每个像素,但要实时显示? ImageBox 派生自 Windows Forms PictureBox,我认为这行不通。
您可以尝试移动到 WPF,并为 Image 对象的 ImageSource 或 Canvas 对象的背景使用 WriteableBitmap。 WriteableBitmap 将允许您访问每个像素,但刷新率由 WPF 控制,显示器刷新率由交流电流频率控制。
道格
通过将图像放在单独的线程上并使用 GetPixel and SetPixel,您可以实时逐个像素地显示图像。请记住,尽管这些方法很慢,如果您要显示高分辨率图片,则需要一段时间。
您要做的是创建一个带有图片框控件的窗体。接下来,创建一个包含您要显示的图像的 Bitmap 对象。您可以使用这样的行来执行此操作:
Bitmap _bmp = new Bitmap(Image.FromFile(@"C:\MyImage.jpg"));
接下来,在您表单的 shown 事件中,分拆一个新任务来完成这项工作,这样 GUI 就不会锁定:
private void Form1_Shown(object sender, EventArgs e)
{
Task.Factory.StartNew(ShowImage);
}
每次显示表单时,该行都会分出一个新线程。该线程将分叉并调用 ShowImage()
,它应该如下所示:
private void ShowImage()
{
Graphics g = pbImage.CreateGraphics();
for (int x = 0; x < _bmp.Width; x++)
{
for (int y = 0; y < _bmp.Height; y++)
{
Color c = _bmp.GetPixel(x, y);
if (pbImage.InvokeRequired)
{
var x1 = x;
var y1 = y;
pbImage.BeginInvoke((Action) (() =>
{
g.FillRectangle(new SolidBrush(c), x1, y1, 1, 1);
}));
}
else
{
g.FillRectangle(new SolidBrush(c), x, y, 1, 1);
}
System.Threading.Thread.Sleep(1);
}
}
}
如果你想加快一点速度,你可以启动两个或更多任务,每个任务并行工作(例如,一个线程在开头开始,另一个在结尾,另一个可能在中间,等等) ).只要确保您的话题没有 "overlap".
另一种加快速度的方法是使用指针代替 GetPixel()
和 SetPixel()
。不过,您必须将代码标记为 unsafe
。
将你的代码放在后台 Worker => 做工作
将启动一个单独的线程
在我的代码中,输出是一个图像,每个像素都是使用嵌套循环确定的。
1) 如何强制 window 打开并显示在循环中构建的输出图像? (window 当一切都完成时出现。我不想要这个。)
2) 如何在循环进行时逐行(甚至逐像素)显示输出。用户必须具有实时获取输出的意识。
outImage = new Image<Hsv, Byte>(numberOfColumns, numberOfRows);
byte[,,] pixelValue = outImage.Data;
for (int i = 0; i < numberOfRows - 1; i++)
{
for (int j = 0; j < numberOfColumns - 1; j++)
{
//pixelValue[i, j, k] is determined here using some other functions
imageBox1.Image = outImage; //too slow and impossible
}
}
我不是 WinForms 专家,我更喜欢 WPF 类型。但我有一个应用程序 运行 稳定的 30fps,这比人类检测速度更快。我真的不太明白你想在这里做什么。你必须单独 blit 每个像素,但要实时显示? ImageBox 派生自 Windows Forms PictureBox,我认为这行不通。
您可以尝试移动到 WPF,并为 Image 对象的 ImageSource 或 Canvas 对象的背景使用 WriteableBitmap。 WriteableBitmap 将允许您访问每个像素,但刷新率由 WPF 控制,显示器刷新率由交流电流频率控制。
道格
通过将图像放在单独的线程上并使用 GetPixel and SetPixel,您可以实时逐个像素地显示图像。请记住,尽管这些方法很慢,如果您要显示高分辨率图片,则需要一段时间。
您要做的是创建一个带有图片框控件的窗体。接下来,创建一个包含您要显示的图像的 Bitmap 对象。您可以使用这样的行来执行此操作:
Bitmap _bmp = new Bitmap(Image.FromFile(@"C:\MyImage.jpg"));
接下来,在您表单的 shown 事件中,分拆一个新任务来完成这项工作,这样 GUI 就不会锁定:
private void Form1_Shown(object sender, EventArgs e)
{
Task.Factory.StartNew(ShowImage);
}
每次显示表单时,该行都会分出一个新线程。该线程将分叉并调用 ShowImage()
,它应该如下所示:
private void ShowImage()
{
Graphics g = pbImage.CreateGraphics();
for (int x = 0; x < _bmp.Width; x++)
{
for (int y = 0; y < _bmp.Height; y++)
{
Color c = _bmp.GetPixel(x, y);
if (pbImage.InvokeRequired)
{
var x1 = x;
var y1 = y;
pbImage.BeginInvoke((Action) (() =>
{
g.FillRectangle(new SolidBrush(c), x1, y1, 1, 1);
}));
}
else
{
g.FillRectangle(new SolidBrush(c), x, y, 1, 1);
}
System.Threading.Thread.Sleep(1);
}
}
}
如果你想加快一点速度,你可以启动两个或更多任务,每个任务并行工作(例如,一个线程在开头开始,另一个在结尾,另一个可能在中间,等等) ).只要确保您的话题没有 "overlap".
另一种加快速度的方法是使用指针代替 GetPixel()
和 SetPixel()
。不过,您必须将代码标记为 unsafe
。
将你的代码放在后台 Worker => 做工作 将启动一个单独的线程