使用WPF和MVVM我尝试将相机图像显示为Image
。
每个帧摄像机都有一个回调叫做:
视图模型
public void OnNewFrame(object sender, EventArgs e)
{
Camera camera = sender as MyCamera;
camera.ToBitmap(out _bmpImage);
RaisePropertyChanged("BMPImage");
}
每一帧,我更新变量_bmpImage:
视图模型
private Bitmap _bmpImage;
public Bitmap BMPImage
{
get
{ return _bmpImage; }
private set
{ _bmpImage = value; RaisePropertyChanged("BMPImage"); }
}
为了将Bitmap
转换为BitmapImage
我使用转换器:
转换器
public class ImageToSource : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Image image = value as Image;
if (image != null)
{
MemoryStream ms = new MemoryStream();
image.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
return bi;
}
return null;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Finnaly绑定到我的观点:
<Image Source="{Binding Main.BMPImage, Converter={StaticResource ImageToSource}}"></Image>
在第一秒的第15秒,它的工作很好,但是在这个延迟之后:我的Image
变成了白色。在转换器中,image
永远不会null
,因此相机效果很好。问题是组件Image
停止重新绘制
当Image
为白色时,我可以调整窗口大小或移动窗口,因为Image
正在重新绘制,图像会变好。
我做错了什么?
有一种方法可以强制Image
重画吗?
为什么Image
停止重新粉饰?
由于
EDIT1:
经过一些验证后,当图像变白时,所有ui都会冻结(所以我的按钮不可点击,直到我调整大小或移动窗口)
EDIT2
由于丹尼斯在评论中提示我,我试图在我的ViewModel中进行转换:
为此,我添加了一个表示转换后图像的属性:
private BitmapImage _testImage;
public BitmapImage TestImage
{
get
{ return _testImage; }
private set
{ _testImage = value; RaisePropertyChanged("TestImage"); }
}
我将_bmpImage
直接转换为OnNewFrame
:
public void OnNewFrame(object sender, EventArgs e)
{
Camera camera = sender as MyCamera;
camera.ToBitmap(out _bmpImage);
//RaisePropertyChanged("BMPImage");
if (_bmpImage != null)
{
// Convertion
MemoryStream ms = new MemoryStream();
_bmpImage.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
_testImage = new BitmapImage();
_testImage.BeginInit();
_testImage.StreamSource = ms;
_testImage.EndInit();
RaisePropertyChanged("TestImage");
}
}
并直接绑定TestImage
上的Image
查看
<Image Source="{Binding Main.TestImage}" />
使用此代码,我有例外:
Must create DependencySource on same Thread as the DependencyObject
编辑3
我考虑过你的评论,这是我的新代码:
if (_bmpImage != null)
{
// Convertion
Console.WriteLine("ok");
MemoryStream ms = new MemoryStream();
_bmpImage.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
_testImage = new BitmapImage();
_testImage.BeginInit();
_testImage.StreamSource = ms;
_testImage.EndInit();
ms.Dispose();
System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)(() =>
{
RaisePropertyChanged("TestImage");
}));
}
我在RaisePropertyChanged("TestImage");
Juste注意到Edit2和Edit3是一个测试,并没有回答我原来的问题
对不起,很长的帖子
答案 0 :(得分:2)
我敢打赌你的OnNewFrame方法不会在UI线程上运行。
在你的代码中,更改此行,使其在UI线程上运行,在窗口/控件的Dispatcher属性上调用Invoke或BeginInvoke:
windowOrControlDispatcher.BeginInvoke((Action) (() =>
{
RaisePropertyChanged("TestImage");
}));
答案 1 :(得分:0)
检查应用程序的内存消耗。
如果位图占用大量内存且应用程序没有处理图像和缓冲区
camera.ToBitmap(out _bmpImage);
// does this clean up the old _bmpImage?
MemoryStream ms = new MemoryStream();
// no dispose!
应用程序可能会花时间收集垃圾而不是更新UI。
答案 2 :(得分:0)
我终于找到了解决方案。我使用另一种方法来转换我的Bitmap(可能更快)
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Bitmap bmp = value as Bitmap;
if (bmp != null)
{
IntPtr hBitmap = bmp.GetHbitmap();
var drawable = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
bmp.Dispose();
return drawable;
}
return null;
}