using Cognex.VisionPro; using CSScripting; using Microsoft.Win32; using MvCamCtrl.NET; using MvCamCtrl.NET.CameraParams; using NPOI.SS.Formula.Functions; using NPOI.Util; using NPOI.XSSF.Model; using OpenCvSharp.Dnn; using Org.BouncyCastle.Asn1.Tsp; using OxyPlot; using Sdcb.OpenVINO; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Media.Media3D; using TeamAAS_VP; using TeamAAS_VP.Enums; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; namespace TeamAAS_VP.Core.Cameras { public class MvCamera : ICamera, INotifyPropertyChanged { #region 字段 private Thread m_hReceiveThread; // 用于序列化对同一相机实例的操作,防止同一实例被并发操作 private readonly SemaphoreSlim _operationSemaphore = new SemaphoreSlim(1, 1); // 用于保护状态变量(例如 IsGrabbing)的并发访问 private readonly object _stateLock = new object(); #endregion #region 属性 public CameraBrand CameraBrand { get => CameraBrand.HikRobot_MVS; } public string Name { get; private set; } public Guid ID { get; private set; } public int Index { get; set; } public string ManufacturerName { get; private set; } public bool IsFindByIp { get; private set; } public string ModelName { get; private set; } public string SerialNumber { get; private set; } public string CameraIp { get; private set; } public CameraType CameraType { get; private set; } MvCameraAcqTool.MvCameraAcqTool mvCameraAcq; public MyCamera.MV_CC_DEVICE_INFO CameraInfo { get; private set; } public UInt32 ImageWidth { get; private set; } public UInt32 ImageHeight { get; private set; } public MvGvspPixelType PixelType { get; private set; } private bool _IsGrabbing; /// /// 正在采集 /// public bool IsGrabbing { get { return _IsGrabbing; } private set { SetProperty(ref _IsGrabbing, value); } } private ICogImage _Image; public ICogImage Image { get { return _Image; } private set { SetProperty(ref _Image, value); } } public bool IsConnected { get; private set; } private bool IsHaveCamera = false; /// /// 采集用时 /// public TimeSpan TotalTime { get; private set; } /// /// 错误信息 /// public string ErrorMessage { get; private set; } #endregion #region 事件 public event Action ImageCallbackEvent; public event Action CameraConnectChangedEvent; #endregion public MvCamera(Guid id, int index, string name, string serialNumber, string cameraip, bool isFindByIp) { ID = id; Name = serialNumber; Index = index; CameraIp = cameraip; SerialNumber = serialNumber; IsFindByIp = isFindByIp; mvCameraAcq = new MvCameraAcqTool.MvCameraAcqTool(); MyCamera.MV_CC_DEVICE_INFO_LIST stDeviceList = default(MyCamera.MV_CC_DEVICE_INFO_LIST); mvCameraAcq.EnumDeivce(ref stDeviceList); MyCamera.MV_CC_DEVICE_INFO device = default(MyCamera.MV_CC_DEVICE_INFO); for (int i = 0; i < stDeviceList.nDeviceNum; i++) { device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO)); if (device.nTLayerType == CSystem.MV_GIGE_DEVICE) { MV_GIGE_DEVICE_INFO stGigEDeviceInfo = (MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stGigEInfo, typeof(MV_GIGE_DEVICE_INFO)); uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24); uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16); uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8); uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff); string ip = string.Format("{0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4); if (IsFindByIp) { if (CameraIp == ip) { ManufacturerName = stGigEDeviceInfo.chManufacturerName; ModelName = stGigEDeviceInfo.chModelName; SerialNumber = stGigEDeviceInfo.chSerialNumber; CameraType = CameraType.GIGE; CameraInfo = device; IsHaveCamera = true; break; } } else { if (string.Equals(stGigEDeviceInfo.chSerialNumber, serialNumber)) { ManufacturerName = stGigEDeviceInfo.chManufacturerName; ModelName = stGigEDeviceInfo.chModelName; SerialNumber = stGigEDeviceInfo.chSerialNumber; CameraType = CameraType.GIGE; CameraInfo = device; IsHaveCamera = true; break; } } } else if (device.nTLayerType == CSystem.MV_USB_DEVICE) { MV_USB3_DEVICE_INFO usbInfo = (MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stUsb3VInfo, typeof(MV_USB3_DEVICE_INFO)); if (string.Equals(usbInfo.chSerialNumber, serialNumber)) { ManufacturerName = usbInfo.chManufacturerName; ModelName = usbInfo.chModelName; SerialNumber = usbInfo.chSerialNumber; CameraType = CameraType.USB; CameraInfo = device; IsHaveCamera = true; break; } } } IsConnected = false; } #region 方法 /// /// 获取设备 /// /// public static CameraInfo[] GetDevices() { List cameras = new List(); try { if (!CheckSoftwareInstalled().isInstalled) { LogHelper.WriteLogInfo("未安装MVS"); return cameras.ToArray(); } List m_ltDeviceList = new List(); int nRet = CSystem.EnumDevices(CSystem.MV_GIGE_DEVICE | CSystem.MV_USB_DEVICE, ref m_ltDeviceList); if (0 != nRet) { return cameras.ToArray(); } for (int i = 0; i < m_ltDeviceList.Count; i++) { if (m_ltDeviceList[i].nTLayerType == CSystem.MV_GIGE_DEVICE) { CGigECameraInfo gigeInfo = (CGigECameraInfo)m_ltDeviceList[i]; uint nIp1 = ((gigeInfo.nCurrentIp & 0xff000000) >> 24); uint nIp2 = ((gigeInfo.nCurrentIp & 0x00ff0000) >> 16); uint nIp3 = ((gigeInfo.nCurrentIp & 0x0000ff00) >> 8); uint nIp4 = (gigeInfo.nCurrentIp & 0x000000ff); string ip = string.Format("{0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4); cameras.Add(new CameraInfo() { CameraNo = i + 1, CameraName = gigeInfo.UserDefinedName, CameraBrand = CameraBrand.HikRobot_MVS, CameraType = CameraType.GIGE, ManufacturerName = gigeInfo.chManufacturerName, Model = gigeInfo.chModelName, SerialNumber = gigeInfo.chSerialNumber, CameraIp = ip, IsFindByIp = true, }); } else if (m_ltDeviceList[i].nTLayerType == CSystem.MV_USB_DEVICE) { CUSBCameraInfo usbInfo = (CUSBCameraInfo)m_ltDeviceList[i]; cameras.Add(new Models.CameraInfo() { CameraNo = i + 1, CameraName = usbInfo.UserDefinedName, CameraBrand = CameraBrand.HikRobot_MVS, CameraType = CameraType.USB, ManufacturerName = usbInfo.chManufacturerName, Model = usbInfo.chModelName, SerialNumber = usbInfo.chSerialNumber, CameraIp = "", }); } else if (m_ltDeviceList[i].nTLayerType == CSystem.MV_CAMERALINK_DEVICE) { CCamLCameraInfo Info = (CCamLCameraInfo)m_ltDeviceList[i]; cameras.Add(new Models.CameraInfo() { CameraNo = i + 1, CameraName = Info.chModelName, CameraBrand = CameraBrand.HikRobot_MVS, CameraType = CameraType.USB, ManufacturerName = Info.chManufacturerName, Model = Info.chModelName, SerialNumber = Info.chSerialNumber, CameraIp = "", }); } } } catch (Exception ex) { LogHelper.WriteLogError("搜索海康相机列表时出错!", ex); } return cameras.ToArray(); } /// /// 检查相机软件是否安装 /// /// public static (bool isInstalled, string version) CheckSoftwareInstalled() { string softwareName = "MVS"; string softwareVersion = "4.4.0"; string[] registryPaths = new[] { @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" }; foreach (var path in registryPaths) { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path)) { if (key == null) continue; foreach (string subKeyName in key.GetSubKeyNames()) { using (RegistryKey subKey = key.OpenSubKey(subKeyName)) { string displayName = subKey.GetValue("DisplayName")?.ToString(); if (displayName != null && displayName.ToUpper().Trim() == softwareName.ToUpper()) { string version = subKey.GetValue("DisplayVersion")?.ToString(); Version v1 = new Version(version); Version v2 = new Version(softwareVersion); if (v1 >= v2) { return (true, version); } else { return (false, version); } } } } } } return (false, ""); } /// /// 打开相机 /// /// /// public bool OpenDevice() { _operationSemaphore.Wait(); try { if (!IsHaveCamera) { mvCameraAcq = new MvCameraAcqTool.MvCameraAcqTool(); MyCamera.MV_CC_DEVICE_INFO_LIST stDeviceList = default(MyCamera.MV_CC_DEVICE_INFO_LIST); mvCameraAcq.EnumDeivce(ref stDeviceList); MyCamera.MV_CC_DEVICE_INFO device = default(MyCamera.MV_CC_DEVICE_INFO); for (int i = 0; i < stDeviceList.nDeviceNum; i++) { device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO)); if (device.nTLayerType == CSystem.MV_GIGE_DEVICE) { MV_GIGE_DEVICE_INFO stGigEDeviceInfo = (MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stGigEInfo, typeof(MV_GIGE_DEVICE_INFO)); uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24); uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16); uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8); uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff); string ip = string.Format("{0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4); if (IsFindByIp) { if (CameraIp == ip) { ManufacturerName = stGigEDeviceInfo.chManufacturerName; ModelName = stGigEDeviceInfo.chModelName; SerialNumber = stGigEDeviceInfo.chSerialNumber; CameraType = CameraType.GIGE; CameraInfo = device; IsHaveCamera = true; break; } } else { if (string.Equals(stGigEDeviceInfo.chSerialNumber, SerialNumber)) { ManufacturerName = stGigEDeviceInfo.chManufacturerName; ModelName = stGigEDeviceInfo.chModelName; SerialNumber = stGigEDeviceInfo.chSerialNumber; CameraType = CameraType.GIGE; CameraInfo = device; IsHaveCamera = true; break; } } } else if (device.nTLayerType == CSystem.MV_USB_DEVICE) { MV_USB3_DEVICE_INFO usbInfo = (MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stUsb3VInfo, typeof(MV_USB3_DEVICE_INFO)); if (string.Equals(usbInfo.chSerialNumber, SerialNumber)) { ManufacturerName = usbInfo.chManufacturerName; ModelName = usbInfo.chModelName; SerialNumber = usbInfo.chSerialNumber; CameraType = CameraType.USB; CameraInfo = device; IsHaveCamera = true; break; } } } if (!IsHaveCamera) { throw new Exception("没有发现相机"); } } mvCameraAcq.OpenDevice(CameraInfo); mvCameraAcq.AutoExposure = false; mvCameraAcq.TriggerMode = false; if (!IsConnected) { CameraConnectChangedEvent?.Invoke(ID, true); } IsConnected = mvCameraAcq.bIsOpened; return IsConnected; } finally { _operationSemaphore.Release(); } } /// /// 打开相机异步 /// /// public Task OpenDeviceAsync() { return Task.Run(() => { return OpenDevice(); }); } /// /// 关闭相机 /// public void CloseDevice() { // ch:关闭设备 | en:Close Device _operationSemaphore.Wait(); try { mvCameraAcq.CloseDevice(); } finally { _operationSemaphore.Release(); } } /// /// 采集单张图片 /// /// true:采集一张新图像,false:返回最后一张图像 /// public ICogImage Grab(bool lastImageOnly = true) { _operationSemaphore.Wait(); try { Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < 5; i++) { try { if (!mvCameraAcq.bIsOpened) { OpenDevice(); } mvCameraAcq.Run(); if (mvCameraAcq.RunStatus.Result == CogToolResultConstants.Accept) { ErrorMessage = ""; Image = mvCameraAcq.OutputImage; if (!IsConnected) { IsConnected = true; CameraConnectChangedEvent?.Invoke(ID, true); } TotalTime = sw.Elapsed; return Image; } else { ErrorMessage = mvCameraAcq.RunStatus.Message; CloseDevice(); OpenDevice(); } } catch (Exception ex) { CloseDevice(); OpenDevice(); ErrorMessage = ex.Message; } } if (IsConnected) { IsConnected = false; CameraConnectChangedEvent?.Invoke(ID, false); } return null; } finally { _operationSemaphore.Release(); } } /// /// 开始采集图像 /// public void StartGrabbing() { lock (_stateLock) { if (IsGrabbing) return; IsGrabbing = true; } m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true }; m_hReceiveThread.Start(); } /// /// 停止采集图像 /// public void StopGrabbing() { try { lock (_stateLock) { IsGrabbing = false; } Thread.Sleep(1000); if (m_hReceiveThread != null) { m_hReceiveThread.Abort(); m_hReceiveThread = null; } } catch (Exception) { } } /// /// 设置曝光时间 /// /// /// public bool SetExposureTime(float ExposureTime) { _operationSemaphore.Wait(); try { if (!mvCameraAcq.bIsOpened) return false; mvCameraAcq.ExposureTime = (double)ExposureTime; return true; } finally { _operationSemaphore.Release(); } } /// /// 获取曝光时间 /// /// public float GetExposureTime() { _operationSemaphore.Wait(); try { if (!mvCameraAcq.bIsOpened) return 0; return (float)mvCameraAcq.ExposureTime; } finally { _operationSemaphore.Release(); } } /// /// 设置增益 /// /// /// public bool SetGain(float Gain) { _operationSemaphore.Wait(); try { if (!mvCameraAcq.bIsOpened) return false; mvCameraAcq.AnalogGain = (double)Gain; return true; } finally { _operationSemaphore.Release(); } } /// /// 获取增益 /// /// public float GetGain() { _operationSemaphore.Wait(); try { if (!mvCameraAcq.bIsOpened) return 0; return (float)mvCameraAcq.AnalogGain; } finally { _operationSemaphore.Release(); } } private void GetStreamThreadProc() { while (IsGrabbing) { try { Grab(); ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); } catch (Exception) { } Thread.Sleep(10); } IsGrabbing = false; } #endregion #region 属性通知 /// /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; /// /// Checks if a property already matches a desired value. Sets the property and /// notifies listeners only when necessary. /// /// Type of the property. /// Reference to a property with both getter and setter. /// Desired value for the property. /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers that /// support CallerMemberName. /// True if the value was changed, false if the existing value matched the /// desired value. protected virtual bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(storage, value)) return false; storage = value; RaisePropertyChanged(propertyName); return true; } /// /// Checks if a property already matches a desired value. Sets the property and /// notifies listeners only when necessary. /// /// Type of the property. /// Reference to a property with both getter and setter. /// Desired value for the property. /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers that /// support CallerMemberName. /// Action that is called after the property value has been changed. /// True if the value was changed, false if the existing value matched the /// desired value. protected virtual bool SetProperty(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(storage, value)) return false; storage = value; onChanged?.Invoke(); RaisePropertyChanged(propertyName); return true; } /// /// Raises this object's PropertyChanged event. /// /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers /// that support . protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } /// /// Raises this object's PropertyChanged event. /// /// The PropertyChangedEventArgs protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) { PropertyChanged?.Invoke(this, args); } #endregion } }