using Cognex.VisionPro; using LampInspectionMachine.Interfaces; using LampInspectionMachine.Log4xml; using LampInspectionMachine.Model; using Microsoft.Win32; using MvCamCtrl.NET; using MvCameraControl; using SqlSugar.DistributedSystem.Snowflake; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Data.SqlTypes; using System.Diagnostics; using System.Drawing.Imaging; using System.Drawing; 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; namespace LampInspectionMachine.Cameralibs.HKCamera { public class MvCamera : ICamera, INotifyPropertyChanged { #region 字段 private IDevice m_MyCamera = null; private Thread m_hReceiveThread; #endregion #region 属性 public CameraBrand CameraBrand { get => CameraBrand.HikRobot_MVS; } public string Name { get; private set; } public Guid ID { get; private set; } public string ManufacturerName { get; private set; } public string ModelName { get; private set; } public string SerialNumber { get; private set; } public CameraType CameraType { get; private set; } public IDeviceInfo 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 GrabImageCallbackEvent; public event Action CameraConnectChangedEvent; #endregion public MvCamera(Guid _ID, string _Name, string _SerialNumber) { ID = _ID; Name = _Name; SerialNumber = _SerialNumber; // ch: 初始化 SDK | en: Initialize SDK SDKSystem.Initialize(); List devInfoList = new List(); // ch:枚举设备 | en:Enum device int nRet = DeviceEnumerator.EnumDevices(DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvVirGigEDevice | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvUsbDevice | DeviceTLayerType.MvVirUsbDevice, out devInfoList); if (nRet != MvError.MV_OK) { throw new Exception($"Enumerate devices fail: {nRet:x8}"); } foreach (var devInfo in devInfoList) { if (devInfo.TLayerType == DeviceTLayerType.MvGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvVirGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvGenTLGigEDevice) { IGigEDeviceInfo gigeDevInfo = devInfo as IGigEDeviceInfo; uint nIp1 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 24); uint nIp2 = ((gigeDevInfo.CurrentIp & 0x00ff0000) >> 16); uint nIp3 = ((gigeDevInfo.CurrentIp & 0x0000ff00) >> 8); uint nIp4 = (gigeDevInfo.CurrentIp & 0x000000ff); Console.WriteLine("DevIP: {0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4); if (string.Equals(devInfo.SerialNumber, _SerialNumber)) { ManufacturerName = devInfo.ManufacturerName; ModelName = devInfo.ModelName; SerialNumber = devInfo.SerialNumber; CameraType = CameraType.GIGE; CameraInfo = devInfo; IsHaveCamera = true; break; } } else if (devInfo.TLayerType == DeviceTLayerType.MvUsbDevice || devInfo.TLayerType == DeviceTLayerType.MvVirUsbDevice) { if (string.Equals(devInfo.SerialNumber, _SerialNumber)) { ManufacturerName = devInfo.ManufacturerName; ModelName = devInfo.ModelName; SerialNumber = devInfo.SerialNumber; CameraType = CameraType.USB; CameraInfo = devInfo; IsHaveCamera = true; break; } } } IsConnected = false; } #region 方法 /// /// 获取设备 /// /// public static CameraInfo[] GetDevices() { List cameras = new List(); try { if (!CheckSoftwareInstalled().isInstalled) { //LogHelper.WriteLogInfo("未安装MVS"); return cameras.ToArray(); } // ch: 初始化 SDK | en: Initialize SDK SDKSystem.Initialize(); List devInfoList = new List(); // ch:枚举设备 | en:Enum device int nRet = DeviceEnumerator.EnumDevices(DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvVirGigEDevice | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvUsbDevice | DeviceTLayerType.MvVirUsbDevice, out devInfoList); if (nRet != MvError.MV_OK) { throw new Exception($"Enumerate devices fail: {nRet:x8}"); } foreach (var devInfo in devInfoList) { if (devInfo.TLayerType == DeviceTLayerType.MvGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvVirGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvGenTLGigEDevice) { IGigEDeviceInfo gigeDevInfo = devInfo as IGigEDeviceInfo; uint nIp1 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 24); uint nIp2 = ((gigeDevInfo.CurrentIp & 0x00ff0000) >> 16); uint nIp3 = ((gigeDevInfo.CurrentIp & 0x0000ff00) >> 8); uint nIp4 = (gigeDevInfo.CurrentIp & 0x000000ff); Console.WriteLine("DevIP: {0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4); cameras.Add(new CameraInfo() { CameraName = "", CameraBrand = CameraBrand.HikRobot_MVS, CameraType = CameraType.GIGE, Id = Guid.NewGuid(), ManufacturerName = devInfo.ManufacturerName, Model = devInfo.ModelName, SerialNumber = devInfo.SerialNumber, CameraIp = $"{nIp1}.{nIp2}.{nIp3}.{nIp4}", }); } else if (devInfo.TLayerType == DeviceTLayerType.MvUsbDevice || devInfo.TLayerType == DeviceTLayerType.MvVirUsbDevice) { cameras.Add(new CameraInfo() { CameraName = "", CameraBrand = CameraBrand.HikRobot_MVS, CameraType = CameraType.USB, Id = Guid.NewGuid(), ManufacturerName = devInfo.ManufacturerName, Model = devInfo.ModelName, SerialNumber = devInfo.SerialNumber, CameraIp = "", }); } } } catch (Exception ex) { // LogHelper.WriteLogError("搜索海康相机列表时出错!", ex); } return cameras.ToArray(); } /// /// 检查相机软件是否安装 /// /// public static (bool isInstalled, string version) CheckSoftwareInstalled() { string softwareName = "MVS"; string softwareVersion = "4.5.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.Contains(softwareName)) { 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() { if (!IsHaveCamera) { List devInfoList = new List(); // ch:枚举设备 | en:Enum device int nRet = DeviceEnumerator.EnumDevices(DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvVirGigEDevice | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvUsbDevice | DeviceTLayerType.MvVirUsbDevice, out devInfoList); if (nRet != MvError.MV_OK) { throw new Exception($"Enumerate devices fail: {nRet:x8}"); } foreach (var devInfo in devInfoList) { if (devInfo.TLayerType == DeviceTLayerType.MvGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvVirGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvGenTLGigEDevice) { IGigEDeviceInfo gigeDevInfo = devInfo as IGigEDeviceInfo; uint nIp1 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 24); uint nIp2 = ((gigeDevInfo.CurrentIp & 0x00ff0000) >> 16); uint nIp3 = ((gigeDevInfo.CurrentIp & 0x0000ff00) >> 8); uint nIp4 = (gigeDevInfo.CurrentIp & 0x000000ff); Console.WriteLine("DevIP: {0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4); if (string.Equals(devInfo.SerialNumber, SerialNumber)) { ManufacturerName = devInfo.ManufacturerName; ModelName = devInfo.ModelName; SerialNumber = devInfo.SerialNumber; CameraType = CameraType.GIGE; CameraInfo = devInfo; IsHaveCamera = true; break; } } else if (devInfo.TLayerType == DeviceTLayerType.MvUsbDevice || devInfo.TLayerType == DeviceTLayerType.MvVirUsbDevice) { if (string.Equals(devInfo.SerialNumber, SerialNumber)) { ManufacturerName = devInfo.ManufacturerName; ModelName = devInfo.ModelName; SerialNumber = devInfo.SerialNumber; CameraType = CameraType.USB; CameraInfo = devInfo; IsHaveCamera = true; break; } } } if (!IsHaveCamera) { throw new Exception("没有发现相机"); } } if (m_MyCamera == null) { // ch:创建设备 | en:Create device try { m_MyCamera = DeviceFactory.CreateDevice(CameraInfo); } catch (Exception) { return false; } //m_MyCamera.RegisterExceptionCallBack(pCallBackFunc, IntPtr.Zero); } int nRet1 = m_MyCamera.Open(DeviceAccessMode.AccessControl, 0); if (nRet1 != MvError.MV_OK) { m_MyCamera.Dispose(); return false; } CameraConnectChangedEvent?.Invoke(ID, true); // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) if (CameraType == CameraType.GIGE) { int packetSize; int ret = (m_MyCamera as IGigEDevice).GetOptimalPacketSize(out packetSize); if (packetSize > 0) { ret = m_MyCamera.Parameters.SetIntValue("GevSCPSPacketSize", packetSize); if (ret != MvError.MV_OK) { Console.WriteLine("Warning: Set Packet Size failed {0:x8}", ret); } else { Console.WriteLine("Set PacketSize to {0}", packetSize); } } else { Console.WriteLine("Warning: Get Packet Size failed {0:x8}", ret); } } //连续采集 m_MyCamera.Parameters.SetEnumValueByString("TriggerMode", "Off"); // ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0; // 1 - Line1; // 2 - Line2; // 3 - Line3; // 4 - Counter; // 7 - Software; // m_MyCamera.Parameters.SetEnumValueByString("TriggerSource", "Software"); m_MyCamera.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous"); //m_MyCamera.Parameters.SetCommandValue("TriggerSoftware"); // ch:注册回调函数 | en:Register image callback // m_MyCamera.StreamGrabber.FrameGrabedEvent += FrameGrabedEventHandler; IsConnected = m_MyCamera.IsConnected; return IsConnected; } /// /// 关闭相机 /// public void CloseDevice() { m_MyCamera.StreamGrabber.FrameGrabedEvent -= FrameGrabedEventHandler; // ch:关闭设备 | en:Close Device m_MyCamera.Close(); m_MyCamera.Dispose(); m_MyCamera = null; if (IsConnected) { IsConnected = false; CameraConnectChangedEvent?.Invoke(ID, IsConnected); } } /// /// 取图前的必要操作步骤 /// /// private Int32 NecessaryOperBeforeGrab() { // ch:取图像宽 | en:Get Iamge Width IIntValue pcWidth = null; int nRet = m_MyCamera.Parameters.GetIntValue("Width", out pcWidth); if (nRet != MvError.MV_OK) { return nRet; } ImageWidth = (UInt32)pcWidth.CurValue; // ch:取图像高 | en:Get Iamge Height IIntValue pcHeight = null; nRet = m_MyCamera.Parameters.GetIntValue("Height", out pcHeight); if (nRet != MvError.MV_OK) { return nRet; } ImageHeight = (UInt32)pcHeight.CurValue; // ch:取像素格式 | en:Get Pixel Format IEnumValue pcPixelFormat = null; nRet = m_MyCamera.Parameters.GetEnumValue("PixelFormat", out pcPixelFormat); if (nRet != MvError.MV_OK) { return nRet; } PixelType = (MvCameraControl.MvGvspPixelType)pcPixelFormat.CurEnumEntry.Value; return MvError.MV_OK; } /// /// 采集图像 /// /// public ICogImage Grab() { m_MyCamera.StreamGrabber.StartGrabbing(); m_MyCamera.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous"); m_MyCamera.Parameters.SetEnumValueByString("TriggerMode", "Off"); m_MyCamera.Parameters.SetFloatValue("ExposureTime", 5000); // 单位μs m_MyCamera.Parameters.SetIntValue("GevSCPSPacketSize", 8164); m_MyCamera.Parameters.SetIntValue("GevSCPD", 12000); // 缓冲区大小 m_MyCamera.Parameters.SetEnumValueByString("PixelFormat", "RGB8"); IFrameOut frameOut = null; bool Succeed = false; int nRet = -1; Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < 5; i++) { try { if (m_MyCamera == null || !m_MyCamera.IsConnected) { OpenDevice(); } ErrorMessage = ""; // ch:前置配置 | en:pre-operation nRet = NecessaryOperBeforeGrab(); if (nRet != MvError.MV_OK) { CloseDevice(); OpenDevice(); ErrorMessage = $"{nRet: x8}"; continue; } // ch:开始采集 | en:Start Grabbing nRet = m_MyCamera.StreamGrabber.StartGrabbing(); if (nRet != MvError.MV_OK) { CloseDevice(); OpenDevice(); ErrorMessage = $"{nRet: x8}"; continue; } nRet = m_MyCamera.StreamGrabber.GetImageBuffer(20000, out frameOut); m_MyCamera.StreamGrabber.StopGrabbing(); if (nRet != MvError.MV_OK) { CloseDevice(); OpenDevice(); ErrorMessage = $"{nRet: x8}"; continue; } m_MyCamera.StreamGrabber.FreeImageBuffer(frameOut); Succeed = true; break; } catch (Exception ex) { CloseDevice(); OpenDevice(); ErrorMessage = ex.Message; } } if (!Succeed) { ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); return null; } if( frameOut !=null) Image = AnalyticImage(frameOut); TotalTime = sw.Elapsed; ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); return Image; } /// /// 开始采集图像 /// public void StartGrabbing() { if (IsGrabbing) return; IsGrabbing = true; m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true }; m_hReceiveThread.Start(); } /// /// 停止采集图像 /// public void StopGrabbing() { try { if ( IsGrabbing ) { IsGrabbing = false; Thread.Sleep(1000); } if (m_hReceiveThread != null) { m_hReceiveThread.Abort(); m_hReceiveThread = null; } } catch (Exception) { } } private void FrameGrabedEventHandler(object sender, FrameGrabbedEventArgs e) { GrabImageCallbackEvent?.Invoke(AnalyticImage(e.FrameOut)); //Console.WriteLine("Get one frame: Width[{0}] , Height[{1}] , ImageSize[{2}], FrameNum[{3}]", e.FrameOut.Image.Width, e.FrameOut.Image.Height, e.FrameOut.Image.ImageSize, e.FrameOut.FrameNum); } /// /// Converts the image data from the specified object into an /// format. /// /// This method processes both color and monochrome images, converting them to a /// compatible format for further analysis. Unsupported pixel formats are not processed, and the method will /// return in such cases. The caller is responsible for ensuring that the parameter is valid and properly initialized. /// The frame output containing the image data to be analyzed and converted. /// An object representing the converted image. Returns if the /// image format is unsupported or if an error occurs during conversion. private ICogImage AnalyticImage(IFrameOut frameOut) { ICogImage image = null; int nRet = -1; //IntPtr pTemp = IntPtr.Zero; IImage pImage = frameOut.Image; MvCameraControl.MvGvspPixelType pixelType = frameOut.Image.PixelType; if (IsColorPixelFormat(frameOut.Image.PixelType)) // 彩色图像处理 { if (frameOut.Image.PixelType == MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) { //pTemp = frameOut.Image.PixelDataPtr; } else { nRet = m_MyCamera.PixelTypeConverter.ConvertPixelType(frameOut.Image, out pImage, MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed); if (nRet != MvError.MV_OK) { frameOut.Dispose(); return null; } pixelType = MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed; } } else if (IsMonoPixelFormat(frameOut.Image.PixelType)) // Mono图像处理 { if (frameOut.Image.PixelType == MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8) { //pTemp = frameOut.Image.PixelDataPtr; } else { // 其他格式Mono转为Mono8 nRet = m_MyCamera.PixelTypeConverter.ConvertPixelType(frameOut.Image, out pImage, MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8); if (nRet != MvError.MV_OK) { frameOut.Dispose(); return null; } } pixelType = MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8; } else { return null; // 不支持的图像格式 } // 直接转换为CogImage,避免不必要的内存拷贝 image = ConvertToICogImage(pImage.Width, pImage.Height, pImage.PixelDataPtr, pixelType); ////2.申请 byte[] //byte[] m_BufForDriver1 = new byte[pImage.ImageSize]; ////3.海康相机取流 指针转 byte[] //Marshal.Copy(pImage.PixelDataPtr, m_BufForDriver1, 0, ((int)pImage.ImageSize)); ////4.转换成 CogImage //image = ConvertToICogImage(pImage.Width, pImage.Height, pImage.PixelDataPtr, pixelType); pImage.Dispose(); frameOut.Dispose(); return image; } /// /// 设置曝光时间 /// /// /// public bool SetExposureTime(float ExposureTime) { int nRet = m_MyCamera.Parameters.SetFloatValue("ExposureTime", ExposureTime); if (nRet != MvError.MV_OK) { return false; } else { return true; } } /// /// 获取曝光时间 /// /// public float GetExposureTime() { IFloatValue pcFloatValue = null; int nRet = m_MyCamera.Parameters.GetFloatValue("ExposureTime", out pcFloatValue); if (nRet == MvError.MV_OK) { return pcFloatValue.CurValue; } else { return 0; } } /// /// 设置增益 /// /// /// public bool SetGain(float Gain) { int nRet = m_MyCamera.Parameters.SetFloatValue("Gain", Gain); if (nRet != MvError.MV_OK) { return false; } else { return true; } } /// /// 获取增益 /// /// public float GetGain() { IFloatValue pcFloatValue = null; int nRet = m_MyCamera.Parameters.GetFloatValue("Gain", out pcFloatValue); if (nRet == MvError.MV_OK) { return pcFloatValue.CurValue; } else { return 0; } } /// /// ch:获取触发模式 | en:Get Trigger Mode /// /// On/Off public bool GetTriggerMode() { IEnumValue enumValue; int result = m_MyCamera.Parameters.GetEnumValue("TriggerMode", out enumValue); if (result == MvError.MV_OK) { if (enumValue.CurEnumEntry.Symbolic == "On") { return true; } return false; } return false; } /// /// 设置触发模式 /// /// 触发模式 /// 触发源0 - Line0;1 - Line1;2 - Line2;3 - Line3;4 - Counter;7 - Software; /// public bool SetTriggerMode(bool mode, int triggerSource) { string strmode = mode ? "On" : "Off"; int nRet = m_MyCamera.Parameters.SetEnumValueByString("TriggerMode", strmode); if (nRet != MvError.MV_OK) { return false; } if (mode) { return SetTriggerSource(triggerSource); } else { nRet = m_MyCamera.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous"); if (nRet != MvError.MV_OK) { return false; } } return true; } /// /// Sets the trigger source for the camera. /// /// 0 - Line0;1 - Line1;2 - Line2;3 - Line3;4 - Counter;7 - Software; /// /// public bool SetTriggerSource(int source) { // ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0; // 1 - Line1; // 2 - Line2; // 3 - Line3; // 4 - Counter; // 7 - Software; string sourceStr; switch (source) { case 0: sourceStr = "Line0"; break; case 1: sourceStr = "Line1"; break; case 2: sourceStr = "Line2"; break; case 3: sourceStr = "Line3"; break; case 4: sourceStr = "Counter"; break; case 7: sourceStr = "Software"; break; default: throw new ArgumentOutOfRangeException(nameof(source), "Invalid trigger source value"); } int nRet = m_MyCamera.Parameters.SetEnumValueByString("TriggerSource", sourceStr); if (nRet != MvError.MV_OK) { return false; } return true; } /// /// Retrieves the current trigger source setting of the camera. /// /// This method queries the camera's parameters to determine the current trigger source. /// If the retrieval is unsuccessful or the trigger source is not recognized, the method returns -1. /// An integer representing the trigger source: 0 for /// "Line0". 1 for "Line1". 2 /// for "Line2". 3 for "Line3". /// 4 for "Counter". 7 for /// "Software". -1 if the trigger source is unknown or if the retrieval /// fails. public int GetTriggerSource() { IEnumValue enumValue; int result = m_MyCamera.Parameters.GetEnumValue("TriggerSource", out enumValue); if (result == MvError.MV_OK) { switch (enumValue.CurEnumEntry.Symbolic) { case "Line0": return 0; case "Line1": return 1; case "Line2": return 2; case "Line3": return 3; case "Counter": return 4; case "Software": return 7; default: return -1; // 未知触发源 } } return -1; // 获取失败 } /// /// Sends a software trigger command to the camera. /// /// This method triggers the camera to capture an image or perform an action based on /// its current configuration. Ensure the camera is properly initialized and configured to respond to software /// triggers before calling this method. public void TriggerSoftware() { // ch:触发软件 | en:Trigger Software m_MyCamera.Parameters.SetCommandValue("TriggerSoftware"); } private void GetStreamThreadProc() { m_MyCamera.StreamGrabber.StartGrabbing(); m_MyCamera.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous"); m_MyCamera.Parameters.SetEnumValueByString("TriggerMode", "Off"); m_MyCamera.Parameters.SetFloatValue("ExposureTime", 5000); // 单位μs m_MyCamera.Parameters.SetIntValue("GevSCPSPacketSize", 8164); m_MyCamera.Parameters.SetIntValue("GevSCPD", 12000); // 缓冲区大小 m_MyCamera.Parameters.SetEnumValueByString("PixelFormat", "RGB8"); while (IsGrabbing) { Stopwatch sw = Stopwatch.StartNew(); try { IFrameOut frameOut = null; int nRet = m_MyCamera.StreamGrabber.GetImageBuffer(5000, out frameOut); double time1 = sw.Elapsed.TotalMilliseconds; Console.WriteLine($"获取图像:{time1}ms"); if ( nRet == MvError.MV_OK ) { Image = AnalyticImage(frameOut); TotalTime = sw.Elapsed; ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); m_MyCamera.StreamGrabber.FreeImageBuffer(frameOut); } else { TotalTime = sw.Elapsed; Thread.Sleep(5); } } catch (Exception ex) { TotalTime = sw.Elapsed; ErrorMessage = ex.Message; ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); continue; } } IsGrabbing = false; } /// /// Converts raw image data into an object, supporting both monochrome and color pixel /// formats. /// /// This method supports both monochrome (PixelType_Gvsp_Mono8) and color pixel formats. /// For color images, the method processes the image data as a planar color format. /// The height of the image in pixels. /// The width of the image in pixels. /// A pointer to the buffer containing the raw image data. /// The pixel format of the image, specified as a value. /// An object representing the converted image. Returns if the /// conversion fails. private ICogImage ConvertToICogImage(UInt32 nHeight, UInt32 nWidth, IntPtr pImageBuf, MvCameraControl.MvGvspPixelType enPixelType) { ICogImage cogImage = null; // ch:获取步长 || en: Get nRowStep uint m_nRowStep = nWidth * nHeight; // ch: 显示 || display try { if (enPixelType == MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8) { CogImage8Root cogImage8Root = new CogImage8Root(); cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null); CogImage8Grey cogImage8Grey = new CogImage8Grey(); cogImage8Grey.SetRoot(cogImage8Root); cogImage = cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight); System.GC.Collect(); } else { CogImage8Root image0 = new CogImage8Root(); IntPtr ptr0 = new IntPtr(pImageBuf.ToInt64()); image0.Initialize((int)nWidth, (int)nHeight, ptr0, (int)nWidth, null); CogImage8Root image1 = new CogImage8Root(); IntPtr ptr1 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep); image1.Initialize((int)nWidth, (int)nHeight, ptr1, (int)nWidth, null); CogImage8Root image2 = new CogImage8Root(); IntPtr ptr2 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep * 2); image2.Initialize((int)nWidth, (int)nHeight, ptr2, (int)nWidth, null); CogImage24PlanarColor colorImage = new CogImage24PlanarColor(); colorImage.SetRoots(image0, image1, image2); cogImage = colorImage.ScaleImage((int)nWidth, (int)nHeight); System.GC.Collect(); } } catch (System.Exception ex) { ErrorMessage = $"转换ICogImage出错: {ex.Message}"; return null; } return cogImage; } /// /// 图像是否为Mono格式 /// /// /// private bool IsMonoPixelFormat(MvCameraControl.MvGvspPixelType enType) { switch (enType) { case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono10: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono12: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono16: return true; default: return false; } } /// /// 图像是否为彩色 /// /// /// private bool IsColorPixelFormat(MvCameraControl.MvGvspPixelType enType) { switch (enType) { case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR8: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG8: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB8: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG8: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRBGG8: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB10: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG10: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG10: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR10: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB12: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG12: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG12: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR12: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR16: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG16: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB16: case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG16: return true; default: return 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 } }