使用 WPF、Caliburn 和 C# 从图像转换为图像源
Converting from Image to Imagesource using WPF, Caliburn and C#
我正在尝试在 WPF 中设置网络摄像头流。我有一个项目在工作,其中的一切都是代码隐藏的。但是,我想让它更干净并将其转换为 MVVM。
我的问题是,我无法将流中的图像绑定到视图,并收到以下错误:
Binding path Cameraimage, Taget Image.Source, Target Type ImageSource Without the dot
Cannot convert from type "System.Windows.Controls.Image" to "System.Windows.Media.ImageSource". Consider setting a converter on the binding.
这部分程序主要处理的是View.xamlViewModel.cs和一个实用程序CameraStreaming.cs - (很明显它被称为视图和视图模型以外的东西,但我尽量保持简单)
View.xaml-片段
<Border
x:Name="webcamContainer"
Grid.Column="0"
Grid.Row="3"
BorderBrush="Black"
BorderThickness="1">
<Image Source="{Binding CameraImage}" VerticalAlignment="Top" />
</Border>
ViewModel.cs-片段
private Image _cameraImage;
public Image CameraImage
{
get { return _cameraImage; }
set { _cameraImage = value;
NotifyOfPropertyChange(() => CameraImage);
}
(....)
var selectedCameraDeviceId = SelectedCamera.OpenCvId;
if (_camera == null || _camera.CameraDeviceId != selectedCameraDeviceId)
{
_camera?.Dispose();
_camera = new CameraStreaming(
imageControlForRendering: CameraImage, // See my CameraStreaming utility
cameraDeviceId: SelectedCamera.OpenCvId);
}
try
{
await _camera.StartCamera(true);
// await _ultraSound.Start(false);
}
CameraStreaming.cs-片段
private readonly Image _imageControlForRendering;
public CameraStreaming(Image imageControlForRendering, int cameraDeviceId)
{
_imageControlForRendering = imageControlForRendering;
CameraDeviceId = cameraDeviceId;
}
public async Task StartCamera(bool crop)
{
if (_previewTask != null && !_previewTask.IsCompleted)
return;
var initializationSemaphore = new SemaphoreSlim(0, 1);
_cancellationTokenSource = new CancellationTokenSource();
_previewTask = Task.Run(async () =>
{
try
{
var videoCapture = new VideoCapture();
if (!videoCapture.Open(CameraDeviceId))
{
throw new ApplicationException("Cannot connect to camera");
}
using (var frame = new Mat())
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
videoCapture.Read(frame);
if (!frame.Empty())
{
// Releases the lock on first not empty frame
if (initializationSemaphore != null)
initializationSemaphore.Release();
// _lastFrame = BitmapConverter.ToBitmap(frame);
_lastFrame = BitmapConverter.ToBitmap(frame.Flip(FlipMode.Y));
var lastFrameBitmapImage = _lastFrame.ToBitmapSource();
lastFrameBitmapImage.Freeze();
_imageControlForRendering.Dispatcher.Invoke(
() => _imageControlForRendering.Source = lastFrameBitmapImage);
}
await Task.Delay(10);
}
}
videoCapture?.Dispose();
}
finally
{
if (initializationSemaphore != null)
initializationSemaphore.Release();
}
}, _cancellationTokenSource.Token);
await initializationSemaphore.WaitAsync();
initializationSemaphore.Dispose();
initializationSemaphore = null;
if (_previewTask.IsFaulted)
{
// To let the exceptions exit
await _previewTask;
}
}
所以..我迷路了。目前由于log4j-issue,大部分官方文档都down了,我想我可能看了这么久都瞎了:P
出于两个原因,您不得在视图模型中使用 System.Windows.Controls.Image
作为图像 属性 的类型。
- 它是一个
UIElement
,因此不属于视图模型
- 无法分配给视图中另一个图像元素的
Source
属性
将类型更改为 ImageSource
private ImageSource _cameraImage;
public ImageSource CameraImage
{
get { return _cameraImage; }
set
{
_cameraImage = value;
NotifyOfPropertyChange(() => CameraImage);
}
}
并使用新的相机框架更新视图模型:
var lastFrameBitmapSource = _lastFrame.ToBitmapSource();
lastFrameBitmapSource.Freeze();
viewModel.CameraImage = lastFrameBitmapSource;
如果您不想将视图模型的引用传递给助手 class,您将需要另一种通知机制。
我正在尝试在 WPF 中设置网络摄像头流。我有一个项目在工作,其中的一切都是代码隐藏的。但是,我想让它更干净并将其转换为 MVVM。 我的问题是,我无法将流中的图像绑定到视图,并收到以下错误:
Binding path Cameraimage, Taget Image.Source, Target Type ImageSource Without the dot
Cannot convert from type "System.Windows.Controls.Image" to "System.Windows.Media.ImageSource". Consider setting a converter on the binding.
这部分程序主要处理的是View.xamlViewModel.cs和一个实用程序CameraStreaming.cs - (很明显它被称为视图和视图模型以外的东西,但我尽量保持简单)
View.xaml-片段
<Border
x:Name="webcamContainer"
Grid.Column="0"
Grid.Row="3"
BorderBrush="Black"
BorderThickness="1">
<Image Source="{Binding CameraImage}" VerticalAlignment="Top" />
</Border>
ViewModel.cs-片段
private Image _cameraImage;
public Image CameraImage
{
get { return _cameraImage; }
set { _cameraImage = value;
NotifyOfPropertyChange(() => CameraImage);
}
(....)
var selectedCameraDeviceId = SelectedCamera.OpenCvId;
if (_camera == null || _camera.CameraDeviceId != selectedCameraDeviceId)
{
_camera?.Dispose();
_camera = new CameraStreaming(
imageControlForRendering: CameraImage, // See my CameraStreaming utility
cameraDeviceId: SelectedCamera.OpenCvId);
}
try
{
await _camera.StartCamera(true);
// await _ultraSound.Start(false);
}
CameraStreaming.cs-片段
private readonly Image _imageControlForRendering;
public CameraStreaming(Image imageControlForRendering, int cameraDeviceId)
{
_imageControlForRendering = imageControlForRendering;
CameraDeviceId = cameraDeviceId;
}
public async Task StartCamera(bool crop)
{
if (_previewTask != null && !_previewTask.IsCompleted)
return;
var initializationSemaphore = new SemaphoreSlim(0, 1);
_cancellationTokenSource = new CancellationTokenSource();
_previewTask = Task.Run(async () =>
{
try
{
var videoCapture = new VideoCapture();
if (!videoCapture.Open(CameraDeviceId))
{
throw new ApplicationException("Cannot connect to camera");
}
using (var frame = new Mat())
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
videoCapture.Read(frame);
if (!frame.Empty())
{
// Releases the lock on first not empty frame
if (initializationSemaphore != null)
initializationSemaphore.Release();
// _lastFrame = BitmapConverter.ToBitmap(frame);
_lastFrame = BitmapConverter.ToBitmap(frame.Flip(FlipMode.Y));
var lastFrameBitmapImage = _lastFrame.ToBitmapSource();
lastFrameBitmapImage.Freeze();
_imageControlForRendering.Dispatcher.Invoke(
() => _imageControlForRendering.Source = lastFrameBitmapImage);
}
await Task.Delay(10);
}
}
videoCapture?.Dispose();
}
finally
{
if (initializationSemaphore != null)
initializationSemaphore.Release();
}
}, _cancellationTokenSource.Token);
await initializationSemaphore.WaitAsync();
initializationSemaphore.Dispose();
initializationSemaphore = null;
if (_previewTask.IsFaulted)
{
// To let the exceptions exit
await _previewTask;
}
}
所以..我迷路了。目前由于log4j-issue,大部分官方文档都down了,我想我可能看了这么久都瞎了:P
出于两个原因,您不得在视图模型中使用 System.Windows.Controls.Image
作为图像 属性 的类型。
- 它是一个
UIElement
,因此不属于视图模型 - 无法分配给视图中另一个图像元素的
Source
属性
将类型更改为 ImageSource
private ImageSource _cameraImage;
public ImageSource CameraImage
{
get { return _cameraImage; }
set
{
_cameraImage = value;
NotifyOfPropertyChange(() => CameraImage);
}
}
并使用新的相机框架更新视图模型:
var lastFrameBitmapSource = _lastFrame.ToBitmapSource();
lastFrameBitmapSource.Freeze();
viewModel.CameraImage = lastFrameBitmapSource;
如果您不想将视图模型的引用传递给助手 class,您将需要另一种通知机制。