MoS2/App/SicUI/Controls/CameraControl.xaml.cs

161 lines
5.3 KiB
C#
Raw Normal View History

2026-08-13 22:07:07 +08:00
using Aitex.Core.RT.Log;
using CommandLine;
using MECF.Framework.Common.DataCenter;
using SicUI.Controls.M2C4Parts;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using VM.PlatformSDKCS;
namespace SicUI.Controls
{
/// <summary>
/// CameraControl.xaml 的交互逻辑
/// </summary>
public partial class CameraControl : UserControl
{
private WriteableBitmap _bitmap;
private Int32Rect _rect;
private CancellationTokenSource _cts;
public CameraControl()
{
InitializeComponent();
// 获取摄像头分辨率
var width = (int)QueryDataClient.Instance.Service.GetConfig("HikGigeCamera.Width");
var height = (int)QueryDataClient.Instance.Service.GetConfig("HikGigeCamera.Height");
// 创建 WriteableBitmap注意像素格式需要与摄像头输出匹配例如 Bgr24
_bitmap = new WriteableBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null);
_rect = new Int32Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight);
// 只需设置一次 Source不必每帧重新赋值
imageControl.Source = _bitmap;
}
private async Task CaptureLoop(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
try
{
var obj = QueryDataClient.Instance.Service.GetData($"LoadLock.HikGigeCamera.CamBitmap");
if (obj != null)
{
Bitmap b = BytesToBitmap((byte[])obj);
// 在 UI 线程更新图像数据
#pragma warning disable CS4014
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => UpdateBitmap(b)));
#pragma warning restore CS4014
}
}
catch (Exception ex)
{
LOG.Warning($"Camera Capture failed{ex}");
}
// 根据需要调整延时,防止 CPU 占用过高
// 异步延时,释放后台线程资源,并响应取消请求
try
{
await Task.Delay(20, token);
}
catch (OperationCanceledException)
{
break;
}
}
}
public Bitmap BytesToBitmap(byte[] bytes)
{
using (MemoryStream ms = new MemoryStream(bytes))
{
return new Bitmap(ms); // 或使用Image.FromStream:ml-citation{ref="1,18" data="citationList"}
}
}
/// <summary>
/// 更新预先创建的 WriteableBitmap 的像素数据
/// </summary>
private void UpdateBitmap(Bitmap frame)
{
if (frame == null || _bitmap == null) return;
_bitmap.Lock();
try
{
// 3. 移除类级别的 _bitmapData改为局部变量
var rect = new System.Drawing.Rectangle(0, 0, frame.Width, frame.Height);
var bitmapData = frame.LockBits(rect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
try
{
int size = bitmapData.Height * bitmapData.Stride;
_bitmap.WritePixels(_rect, bitmapData.Scan0, size, bitmapData.Stride, 0, 0);
}
finally
{
// 4. 无论如何必须解锁 GDI 数据
frame.UnlockBits(bitmapData);
}
}
finally
{
// 5. 无论如何必须释放 Bitmap 和解锁 WriteableBitmap
frame.Dispose();
_bitmap.Unlock();
}
}
private void ButtonGrab_Click(object sender, RoutedEventArgs e)
{
InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Grab","UIGrab");
}
private void ButtonGrabbing_Click(object sender, RoutedEventArgs e)
{
InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Grabbing");
}
private void CameraControl_Unloaded(object sender, RoutedEventArgs e)
{
_cts?.Cancel();
InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Stop");
}
private void CameraControl_loaded(object sender, RoutedEventArgs e)
{
_cts = new CancellationTokenSource();
_ = CaptureLoop(_cts.Token);
}
private void ButtonStop_Click(object sender, RoutedEventArgs e)
{
InvokeClient.Instance.Service.DoOperation($"LoadLock.HikGigeCamera.Stop");
}
}
}