using MvCamCtrl.NET; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TeamAAS_VP.Core.Cameras; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; namespace TeamAAS_VP.Services { /// /// 提供相机对象的创建、管理、查找和释放功能的服务类。 /// 线程安全:内部使用 进行并发访问同步。 /// 资源管理:实现 ,在释放时会关闭并清理所有已注册相机。 /// public class CameraService : ICameraService, IDisposable { /// /// 保存相机实例的字典,键为相机的唯一标识 。 /// private readonly Dictionary _CameraCollection; /// /// 用于保证对 并发访问的同步对象。 /// private readonly object _sync = new object(); /// /// 初始化一个新的 实例。 /// public CameraService() { _CameraCollection = new Dictionary(); } /// /// 创建并注册一个相机实例。如果同一 已存在,则会先尝试关闭并替换之。 /// /// 要注册的相机唯一标识符。 /// 用于创建相机的配置信息,不能为空。 /// 始终返回 true(当前实现不表示创建失败)。 /// 为 null 时抛出。 public bool CreateCamera(Guid id, CameraInfo cameraInfo) { if (cameraInfo == null) throw new ArgumentNullException(nameof(cameraInfo)); var camera = CreateCameraInstance(id, cameraInfo); lock (_sync) { if (_CameraCollection.ContainsKey(id)) { var currenCamera = _CameraCollection[id]; try { currenCamera.CloseDevice(); } catch { // 忽略关闭异常 } } _CameraCollection[id] = camera; } return true; } /// /// 异步创建并注册一个相机实例(内部使用 Task.Run 包装同步方法)。 /// /// 相机唯一标识符。 /// 相机配置信息。 /// 表示创建结果的任务,结果为布尔值。 public Task CreateCameraAsync(Guid id, CameraInfo cameraInfo) { return Task.Run(() => CreateCamera(id, cameraInfo)); } /// /// 根据 获取已注册的相机实例,如果未找到则返回 null。 /// /// 相机唯一标识符。 /// 找到的 实例或 null。 public ICamera GetCamera(Guid id) { lock (_sync) { if (_CameraCollection.TryGetValue(id, out var cam)) return cam; } return null; } /// /// 异步获取相机实例(包装同步调用)。 /// /// 相机唯一标识符。 /// 表示查找结果的任务,任务结果为 或 null。 public Task GetCameraAsync(Guid id) { return Task.Run(() => { return GetCamera(id); }); } /// /// 取消注册指定 的相机并尝试关闭其设备资源。 /// 如果不存在则无操作。 /// /// 要取消注册的相机标识符。 public void UnRegisterCamera(Guid id) { ICamera camera = null; lock (_sync) { if (_CameraCollection.TryGetValue(id, out camera)) { _CameraCollection.Remove(id); } } if (camera != null) { try { camera.CloseDevice(); } catch { // 忽略关闭异常 } } } /// /// 异步取消注册相机(包装同步调用)。 /// /// 相机唯一标识符。 /// 表示操作完成的任务。 public Task UnRegisterCameraAsync(Guid id) { return Task.Run(() => UnRegisterCamera(id)); } /// /// 获取当前已注册的所有相机的只读集合快照。 /// /// 只读集合,包含当前注册的所有相机实例。 public IReadOnlyCollection GetAllCameras() { lock (_sync) { return _CameraCollection.Values.ToList().AsReadOnly(); } } /// /// 异步获取所有已注册相机(包装同步调用)。 /// /// 表示只读相机集合的任务。 public Task> GetAllCamerasAsync() { return Task.Run(() => { return GetAllCameras(); }); } /// /// 尝试根据 获取相机实例。 /// /// 相机唯一标识符。 /// 若找到则输出相机实例,否则为 null。 /// 找到返回 true,否则返回 false public bool TryGetCamera(Guid id, out ICamera camera) { lock (_sync) { return _CameraCollection.TryGetValue(id, out camera); } } /// /// 异步尝试获取相机实例,返回一个包含是否找到及相机实例的元组。 /// /// 相机唯一标识符。 /// 任务结果为 (found, camera) 元组。 public Task<(bool found, ICamera camera)> TryGetCameraAsync(Guid id) { return Task.Run(() => { ICamera camera; bool found; lock (_sync) { found = _CameraCollection.TryGetValue(id, out camera); } return (found, camera); }); } /// /// 判断是否包含指定 的相机注册项。 /// /// 相机唯一标识符。 /// 存在返回 true,否则返回 false public bool ContainsCamera(Guid id) { lock (_sync) { return _CameraCollection.ContainsKey(id); } } /// /// 异步判断相机是否存在(包装同步调用)。 /// /// 相机唯一标识符。 /// 表示存在性的任务结果(布尔值)。 public Task ContainsCameraAsync(Guid id) { return Task.Run(() => { return ContainsCamera(id); }); } /// /// 移除指定 的相机并关闭其设备资源(如存在)。 /// /// 要移除的相机标识符。 /// 如果存在并已移除返回 true,否则返回 false public bool RemoveCamera(Guid id) { ICamera camera = null; lock (_sync) { if (_CameraCollection.TryGetValue(id, out camera)) { _CameraCollection.Remove(id); } } if (camera != null) { try { camera.CloseDevice(); } catch { // 忽略关闭异常 } return true; } return false; } /// /// 异步移除相机(包装同步调用)。 /// /// 相机唯一标识符。 /// 表示操作是否成功的任务。 public Task RemoveCameraAsync(Guid id) { return Task.Run(() => { return RemoveCamera(id); }); } /// /// 根据相机编号查找相机实例,找不到返回 null。 /// 该方法内部使用反射来兼容不同相机实现中编号属性的命名差异。 /// /// 相机的编号(业务编号、索引等)。 /// 找到的 实例或 null。 public ICamera GetCameraByNumber(int number) { if (TryFindCameraByNumber(number, out _, out var camera)) return camera; return null; } /// /// 异步根据编号获取相机实例(包装同步调用)。 /// /// 相机编号。 /// 表示相机实例的任务,未找到为 null。 public Task GetCameraByNumberAsync(int number) { return Task.Run(() => { return GetCameraByNumber(number); }); } /// /// 异步根据编号取消注册相机(包装同步实现)。 /// /// 相机编号。 /// 表示操作完成的任务。 public Task UnRegisterCameraByNumberAsync(int number) { return Task.Run(() => { UnRegisterCameraByNumber(number); }); } /// /// 根据编号查找并取消注册相机(如果找到则调用 )。 /// /// 相机编号。 public void UnRegisterCameraByNumber(int number) { if (TryFindCameraByNumber(number, out var id, out var camera)) { UnRegisterCamera(id); } } /// /// 移除并关闭所有已注册的相机,逐个移除以确保资源被正确释放。 /// public void RemoveAllCameras() { //依次移除每一个相机,确保资源释放 List cameraIds; lock (_sync) { cameraIds = _CameraCollection.Keys.ToList(); } foreach (var id in cameraIds) { RemoveCamera(id); } } /// /// 使用提供的相机配置信息数组初始化并尝试打开所有相机。 /// 该方法会先清除已有相机,再为每个配置创建实例并尝试打开设备。 /// /// 要初始化的相机信息数组。 /// /// 返回元组,IsSucceed 表示是否所有相机均打开成功;Message 为失败信息或成功消息。 /// public (bool IsSucceed, string Message) InitializeAllCameras(CameraInfo[] cameras) { //清除现有相机 RemoveAllCameras(); foreach (var camInfo in cameras) { var camera = CreateCameraInstance(camInfo.Id, camInfo); lock (_sync) { _CameraCollection[camInfo.Id] = camera; } } bool allConnected = true; StringBuilder errorMessages = new StringBuilder(); //获取所有相机并尝试打开设备 foreach (var camInfo in cameras) { if (TryGetCamera(camInfo.Id, out var camera)) { bool opened = camera.OpenDevice(); if (!opened) { allConnected = false; errorMessages.AppendLine($"相机 {camInfo.CameraName}(编号: {camInfo.CameraNo})打开失败: {camera.ErrorMessage}"); } } else { allConnected = false; errorMessages.AppendLine($"未找到相机 {camInfo.CameraName}(编号: {camInfo.CameraNo})的实例。"); } } if (allConnected) { return (true, "所有相机均已成功初始化并连接。"); } else { return (false, errorMessages.ToString()); } } /// /// 异步初始化所有相机(包装同步实现)。 /// /// 相机信息数组。 /// 返回包含是否成功及消息的任务。 public Task<(bool IsSucceed, string Message)> InitializeAllCamerasAsync(CameraInfo[] cameras) { return Task.Run(() => InitializeAllCameras(cameras)); } /// /// 更新指定相机的业务编号(Index)。若未找到对应相机则无操作。 /// /// 相机唯一标识符。 /// 新的编号值。 public void UpdateCameraNumber(Guid id, int newNumber) { if (TryGetCamera(id, out var camera)) { camera.Index = newNumber; } } /// /// 根据提供的 创建具体相机实现的实例。 /// 支持不同品牌的相机类型分发;默认使用 。 /// /// 相机唯一标识符。 /// 相机配置信息。 /// 创建的 实例(未打开设备)。 private ICamera CreateCameraInstance(Guid id, CameraInfo cameraInfo) { ICamera camera; if (cameraInfo.CameraBrand == Enums.CameraBrand.Basler_Pylon) { camera = new BaslerCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else if (cameraInfo.CameraBrand == Enums.CameraBrand.HikRobot_MVS) { camera = new MvCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else if (cameraInfo.CameraBrand == Enums.CameraBrand.IRayple) { camera = new AHuaCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else if (cameraInfo.CameraBrand == Enums.CameraBrand.Cognex) { camera = new CognexCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else if (cameraInfo.CameraBrand == Enums.CameraBrand.Galaxy) { camera = new GalaxyCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else if (cameraInfo.CameraBrand == Enums.CameraBrand.Opt) { camera = new OptCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else if (cameraInfo.CameraBrand == Enums.CameraBrand.SSZN) { camera = new SSZNCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } else { camera = new MvCamera(id, cameraInfo.CameraNo, cameraInfo.CameraName, cameraInfo.SerialNumber, cameraInfo.CameraIp, cameraInfo.IsFindByIp); } return camera; } /// /// 根据业务编号在已注册相机中查找匹配项。 /// 实现要点: /// - 对每个相机尝试通过常见属性名("CameraNo", "Number", "No")读取编号; /// - 若未直接在相机对象找到编号,则尝试从其可能的 CameraInfo / Info 属性中读取; /// - 使用 Convert.ToInt32 进行通用转换,忽略无法转换或异常的项; /// - 在找到匹配编号时返回 true,并输出相机 id 与实例;否则返回 false。 /// /// 要匹配的编号。 /// 若找到则输出相机的 标识符,未找到为 。 /// 若找到则输出对应的 实例,否则为 null。 /// 找到匹配项返回 true,否则返回 false private bool TryFindCameraByNumber(int number, out Guid id, out ICamera camera) { lock (_sync) { foreach (var kvp in _CameraCollection) { var c = kvp.Value; if (c == null) continue; object rawValue = null; var type = c.GetType(); var prop = type.GetProperty("CameraNo") ?? type.GetProperty("Number") ?? type.GetProperty("No") ; if (prop != null) { try { rawValue = prop.GetValue(c); } catch { rawValue = null; } } if (rawValue == null) { var infoProp = type.GetProperty("CameraInfo") ?? type.GetProperty("Info"); if (infoProp != null) { try { var infoObj = infoProp.GetValue(c); if (infoObj != null) { var infoType = infoObj.GetType(); var numberProp = infoType.GetProperty("CameraNo") ?? infoType.GetProperty("CameraNumber") ?? infoType.GetProperty("Number") ?? infoType.GetProperty("No"); if (numberProp != null) { try { rawValue = numberProp.GetValue(infoObj); } catch { rawValue = null; } } } } catch { rawValue = null; } } } if (rawValue != null) { int parsed; try { if (rawValue is int) parsed = (int)rawValue; else parsed = Convert.ToInt32(rawValue); } catch { continue; } if (parsed == number) { id = kvp.Key; camera = c; return true; } } if(c.Index== number) { id = kvp.Key; camera = c; return true; } } } id = Guid.Empty; camera = null; return false; } /// /// 释放服务占用的资源:关闭所有相机设备并清空内部集合。 /// public void Dispose() { List cameras; lock (_sync) { cameras = _CameraCollection.Values.ToList(); _CameraCollection.Clear(); } foreach (var c in cameras) { try { c.CloseDevice(); } catch { // 忽略单个相机关闭异常 } } GC.SuppressFinalize(this); } } }