using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using TeamAAS_VP.Enums; using TeamAAS_VP.Interfaces; using Cognex.VisionPro; using Basler.Pylon; using System.IO; using System.Drawing.Imaging; using System.Drawing; using System.Diagnostics; using ControlzEx.Standard; using System.Windows.Media.Media3D; using MvCamCtrl.NET; using TeamAAS_VP.Models; using Microsoft.Win32; //using System.Drawing; //using System.Drawing.Imaging; namespace TeamAAS_VP.Core.Cameras { public class BaslerCamera : CameraBase, Interfaces.ICamera, INotifyPropertyChanged { #region 字段 private Basler.Pylon.Camera m_MyCamera; private Thread m_hReceiveThread; UInt32 m_nRowStep = 0; // The pixel data converter is used for converting grabbed images to a pixel format that can be displayed. private PixelDataConverter converter = new PixelDataConverter(); #endregion #region 属性 public CameraBrand CameraBrand { get => CameraBrand.Basler_Pylon; } 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; } public UInt32 ImageWidth { get; private set; } public UInt32 ImageHeight { 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; } public ICameraInfo CameraInfo { get; private set; } /// /// 采集用时 /// public TimeSpan TotalTime { get; private set; } /// /// 错误信息 /// public string ErrorMessage { get; private set; } #endregion #region 事件 public event Action ImageCallbackEvent; public event Action CameraConnectChangedEvent; #endregion public BaslerCamera(Guid id, int index, string name, string serialNumber, string cameraip, bool isFindByIp) { ID = id; Name = serialNumber; Index = index; CameraIp = cameraip; SerialNumber = serialNumber; IsFindByIp = isFindByIp; List allCameraInfos = Basler.Pylon.CameraFinder.Enumerate(); foreach (ICameraInfo cameraInfo in allCameraInfos) { if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("gige")) { if (IsFindByIp) { if (cameraInfo[CameraInfoKey.DeviceIpAddress] == CameraIp) { CameraInfo = cameraInfo; m_MyCamera = new Basler.Pylon.Camera(cameraInfo); ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo]; ModelName = cameraInfo[CameraInfoKey.ModelName]; SerialNumber = cameraInfo[CameraInfoKey.SerialNumber]; CameraType = CameraType.GIGE; m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件 m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; break; } } else { if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber) { CameraInfo = cameraInfo; m_MyCamera = new Basler.Pylon.Camera(cameraInfo); ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo]; ModelName = cameraInfo[CameraInfoKey.ModelName]; SerialNumber = cameraInfo[CameraInfoKey.SerialNumber]; CameraType = CameraType.GIGE; CameraIp= cameraInfo[CameraInfoKey.DeviceIpAddress]; m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件 m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; break; } } } else { if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber) { CameraInfo = cameraInfo; m_MyCamera = new Basler.Pylon.Camera(cameraInfo); ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo]; ModelName = cameraInfo[CameraInfoKey.ModelName]; SerialNumber = cameraInfo[CameraInfoKey.SerialNumber]; CameraType = CameraType.USB; m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件 m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; break; } } } IsConnected = false; } #region 方法 /// /// 获取设备 /// /// public static CameraInfo[] GetDevices() { List cameras = new List(); try { if (!CheckSoftwareInstalled().isInstalled) { LogHelper.WriteLogInfo("未安装pylon 7"); return cameras.ToArray(); } List allCameraInfos = Basler.Pylon.CameraFinder.Enumerate(); int i = 0; foreach (ICameraInfo cameraInfo in allCameraInfos) { if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("gige")) { cameras.Add(new Models.CameraInfo() { CameraNo = i + 1, CameraName = cameraInfo[CameraInfoKey.FullName], CameraBrand = CameraBrand.Basler_Pylon, CameraType = CameraType.GIGE, ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo], Model = cameraInfo[CameraInfoKey.ModelName], SerialNumber = cameraInfo[CameraInfoKey.SerialNumber], CameraIp = cameraInfo[CameraInfoKey.DeviceIpAddress], IsFindByIp = true, }); } else if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("usb")) { cameras.Add(new Models.CameraInfo() { CameraNo = i + 1, CameraName = cameraInfo[CameraInfoKey.FullName], CameraBrand = CameraBrand.Basler_Pylon, CameraType = CameraType.USB, ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo], Model = cameraInfo[CameraInfoKey.ModelName], SerialNumber = cameraInfo[CameraInfoKey.SerialNumber], CameraIp = "", }); } else if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("link")) { cameras.Add(new Models.CameraInfo() { CameraNo = i + 1, CameraName = cameraInfo[CameraInfoKey.FullName], CameraBrand = CameraBrand.Basler_Pylon, CameraType = CameraType.Link, ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo], Model = cameraInfo[CameraInfoKey.ModelName], SerialNumber = cameraInfo[CameraInfoKey.SerialNumber], CameraIp = "", }); } else { cameras.Add(new Models.CameraInfo() { CameraNo = i + 1, CameraName = cameraInfo[CameraInfoKey.FullName], CameraBrand = CameraBrand.Basler_Pylon, CameraType = CameraType.Unknown, ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo], Model = cameraInfo[CameraInfoKey.ModelName], SerialNumber = cameraInfo[CameraInfoKey.SerialNumber], CameraIp = "", }); } i++; } } catch (Exception ex) { LogHelper.WriteLogError("搜索巴斯勒相机列表时出错!", ex); } return cameras.ToArray(); } /// /// 检查相机软件是否安装 /// /// public static (bool isInstalled, string version) CheckSoftwareInstalled() { string softwareName = "pylon 7 Camera Software"; string softwareVersion = "7.5.0.15658"; 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() { EnterOperation(); try { if (m_MyCamera == null) { List allCameraInfos = Basler.Pylon.CameraFinder.Enumerate(); foreach (ICameraInfo cameraInfo in allCameraInfos) { if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("gige")) { if (IsFindByIp) { if (cameraInfo[CameraInfoKey.DeviceIpAddress] == CameraIp) { CameraInfo = cameraInfo; m_MyCamera = new Basler.Pylon.Camera(cameraInfo); ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo]; ModelName = cameraInfo[CameraInfoKey.ModelName]; SerialNumber = cameraInfo[CameraInfoKey.SerialNumber]; CameraType = CameraType.GIGE; m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件 m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; break; } } else { if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber) { CameraInfo = cameraInfo; m_MyCamera = new Basler.Pylon.Camera(cameraInfo); ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo]; ModelName = cameraInfo[CameraInfoKey.ModelName]; SerialNumber = cameraInfo[CameraInfoKey.SerialNumber]; CameraType = CameraType.GIGE; CameraIp = cameraInfo[CameraInfoKey.DeviceIpAddress]; m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件 m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; break; } } } else { if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber) { CameraInfo = cameraInfo; m_MyCamera = new Basler.Pylon.Camera(cameraInfo); ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo]; ModelName = cameraInfo[CameraInfoKey.ModelName]; SerialNumber = cameraInfo[CameraInfoKey.SerialNumber]; CameraType = CameraType.USB; m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件 m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed; break; } } } if (m_MyCamera == null) { throw new Exception("没有识别到相机"); } } if (!m_MyCamera.IsOpen) { m_MyCamera.Open(); m_MyCamera.Parameters[PLCamera.TriggerSource].SetValue(PLCamera.TriggerSource.Software); m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous); m_MyCamera.Parameters[PLCamera.TriggerMode].SetValue(PLCamera.TriggerMode.On); } IsConnected = m_MyCamera.IsConnected; return IsConnected; } finally { ExitOperation(); } } /// /// 打开相机异步 /// /// public Task OpenDeviceAsync() { return Task.Run(() => { return OpenDevice(); }); } private void M_MyCamera_CameraClosed(object sender, EventArgs e) { CameraConnectChangedEvent?.Invoke(ID, false); } private void M_MyCamera_CameraOpened(object sender, EventArgs e) { CameraConnectChangedEvent?.Invoke(ID, true); } /// /// 关闭相机 /// public void CloseDevice() { EnterOperation(); try { if (m_MyCamera != null) { if (m_MyCamera.IsOpen) { m_MyCamera.Close(); m_MyCamera.CameraOpened -= Configuration.AcquireContinuous; // 软触发打开 m_MyCamera.CameraOpened -= M_MyCamera_CameraOpened; m_MyCamera.CameraClosed -= M_MyCamera_CameraClosed; IsConnected = m_MyCamera.IsConnected; m_MyCamera.Dispose(); } } } finally { ExitOperation(); } } /// /// 采集单张图片 /// /// true:采集一张新图像,false:返回最后一张图像 /// public ICogImage Grab(bool lastImageOnly = true) { EnterOperation(); try { Stopwatch sw = Stopwatch.StartNew(); if (m_MyCamera == null) { throw new Exception("相机未连接"); } if (!m_MyCamera.IsOpen) { m_MyCamera.Open(); m_MyCamera.Parameters[PLCamera.TriggerSource].SetValue(PLCamera.TriggerSource.Software); m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous); m_MyCamera.Parameters[PLCamera.TriggerMode].SetValue(PLCamera.TriggerMode.On); } if (!m_MyCamera.StreamGrabber.IsGrabbing) { // Start grabbing. m_MyCamera.StreamGrabber.Start(); } bool Succeed = false; IGrabResult grabResult = null; for (int i = 0; i < 5; i++) { try { m_MyCamera.ExecuteSoftwareTrigger(); // Wait for an image and then retrieve it. A timeout of 5000 ms is used. grabResult = m_MyCamera.StreamGrabber.RetrieveResult(1000, TimeoutHandling.ThrowException); if (grabResult != null && grabResult.GrabSucceeded) { ErrorMessage = ""; Succeed = true; break; } else { ErrorMessage = grabResult.ErrorDescription; } } catch (Exception ex) { ErrorMessage = ex.Message; m_MyCamera.Close(); m_MyCamera.CameraOpened -= M_MyCamera_CameraOpened; m_MyCamera.CameraClosed -= M_MyCamera_CameraClosed; m_MyCamera.Open(); m_MyCamera.Parameters[PLCamera.TriggerSource].SetValue(PLCamera.TriggerSource.Software); m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous); m_MyCamera.Parameters[PLCamera.TriggerMode].SetValue(PLCamera.TriggerMode.On); IsConnected = m_MyCamera.IsConnected; } finally { //m_MyCamera.StreamGrabber.Stop(); } } if (!Succeed) { if (IsConnected) { IsConnected = false; CameraConnectChangedEvent?.Invoke(ID, false); } return null; } //m_MyCamera.StreamGrabber.Stop(); Image = GrabResult2CogImage(grabResult); GC.Collect(); grabResult.Dispose(); TotalTime = sw.Elapsed; return Image; } finally { ExitOperation(); } } private void InvertColors(IGrabResult result) { byte pixelSize = 255; byte[] data = (byte[])result.PixelData; for (long i = 0; i < data.Length; i++) { data[i] = (byte)((int)pixelSize - (int)data[i]); } } /// /// 转换成ICogImage图像 /// /// /// /// /// /// public ICogImage ConvertToICogImage(UInt32 nHeight, UInt32 nWidth, IntPtr pImageBuf, Basler.Pylon.PixelType enPixelType) { // ch: 显示 || display try { if (enPixelType == Basler.Pylon.PixelType.Mono8) { CogImage8Root cogImage8Root = new CogImage8Root(); cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null); CogImage8Grey cogImage8Grey = new CogImage8Grey(); cogImage8Grey.SetRoot(cogImage8Root); return cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight); } 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); return colorImage.ScaleImage((int)nWidth, (int)nHeight); } } catch (System.Exception) { return null; } } /// /// 开始采集图像 /// public void StartGrabbing() { EnterOperation(); try { if (m_MyCamera == null) { throw new Exception("相机未连接"); } if (!m_MyCamera.IsOpen) { throw new Exception("相机未打开"); } m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous); //m_MyCamera.StreamGrabber.Start(GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber); if (IsGrabbing) return; if (!m_MyCamera.StreamGrabber.IsGrabbing) { // Start grabbing. m_MyCamera.StreamGrabber.Start(); } lock (_stateLock) { IsGrabbing = true; } m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true }; m_hReceiveThread.Start(); } finally { ExitOperation(); } } /// /// 停止采集图像 /// public void StopGrabbing() { try { lock (_stateLock) { IsGrabbing = false; } Thread.Sleep(1000); if (m_hReceiveThread != null) { m_hReceiveThread.Abort(); m_hReceiveThread = null; } if (m_MyCamera != null && m_MyCamera.StreamGrabber.IsGrabbing) { m_MyCamera.StreamGrabber.Stop(); } } catch (Exception) { } } /// /// 设置曝光时间 /// /// /// public bool SetExposureTime(float ExposureTime) { EnterOperation(); try { if (m_MyCamera == null) { return false; } if (m_MyCamera.Parameters.Contains(PLCamera.ExposureTimeAbs)) { m_MyCamera.Parameters[PLCamera.ExposureTimeAbs].SetValue(ExposureTime); } else m_MyCamera.Parameters[PLCamera.ExposureTime].SetValue(ExposureTime); return true; } finally { ExitOperation(); } } /// /// 获取曝光时间 /// /// public float GetExposureTime() { EnterOperation(); try { if (m_MyCamera == null) { return 0; } if (m_MyCamera.Parameters.Contains(PLCamera.ExposureTimeAbs)) { return (float)m_MyCamera.Parameters[PLCamera.ExposureTimeAbs].GetValue(); } else return (float)m_MyCamera.Parameters[PLCamera.ExposureTime].GetValue(); } finally { ExitOperation(); } } /// /// 设置增益 /// /// /// public bool SetGain(float Gain) { EnterOperation(); try { if (m_MyCamera == null) { return false; } if (m_MyCamera.Parameters.Contains(PLCamera.Gain)) { m_MyCamera.Parameters[PLCamera.Gain].SetValue(Gain); } else if (m_MyCamera.Parameters.Contains(PLCamera.GainRaw)) { m_MyCamera.Parameters[PLCamera.GainRaw].SetValue((int)Gain); } else if (m_MyCamera.Parameters.Contains(PLCamera.GainAbs)) { m_MyCamera.Parameters[PLCamera.GainAbs].SetValue(Gain); } return true; } finally { ExitOperation(); } } /// /// 获取增益 /// /// public float GetGain() { EnterOperation(); try { if (m_MyCamera.Parameters.Contains(PLCamera.Gain)) { return (float)m_MyCamera.Parameters[PLCamera.Gain].GetValue(); } else return (float)m_MyCamera.Parameters[PLCamera.GainAbs].GetValue(); } finally { ExitOperation(); } } private void GetStreamThreadProc() { while (IsGrabbing) { Stopwatch sw = Stopwatch.StartNew(); try { if (!m_MyCamera.IsConnected) { m_MyCamera.Close(); m_MyCamera.CameraOpened -= M_MyCamera_CameraOpened; m_MyCamera.CameraClosed -= M_MyCamera_CameraClosed; m_MyCamera = new Basler.Pylon.Camera(CameraInfo); m_MyCamera.CameraOpened += M_MyCamera_CameraOpened; m_MyCamera.CameraClosed += M_MyCamera_CameraClosed; } if (!m_MyCamera.IsOpen) { m_MyCamera.Open(); IsConnected = m_MyCamera.IsConnected; } m_MyCamera.ExecuteSoftwareTrigger(); // Wait for an image and then retrieve it. A timeout of 5000 ms is used. IGrabResult grabResult = m_MyCamera.StreamGrabber.RetrieveResult(1000, TimeoutHandling.ThrowException); using (grabResult) { // Image grabbed successfully? if (grabResult != null && grabResult.GrabSucceeded) { ErrorMessage = ""; Image = GrabResult2CogImage(grabResult); TotalTime = sw.Elapsed; ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); } else { TotalTime = sw.Elapsed; ErrorMessage = grabResult.ErrorDescription; ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage); } } } catch (Exception ex) { TotalTime = sw.Elapsed; ImageCallbackEvent?.Invoke(Image, TotalTime, ex.Message); } Thread.Sleep(10); GC.Collect(); } IsGrabbing = false; } /// /// 图像是否为彩色 /// /// /// private bool IsColorPixelFormat(Basler.Pylon.PixelType enType) { switch (enType) { case Basler.Pylon.PixelType.RGB8packed: case Basler.Pylon.PixelType.BGR8packed: case Basler.Pylon.PixelType.RGBA8packed: case Basler.Pylon.PixelType.BGRA8packed: case Basler.Pylon.PixelType.YUV422packed: case Basler.Pylon.PixelType.YUV422_YUYV_Packed: case Basler.Pylon.PixelType.BayerGR8: case Basler.Pylon.PixelType.BayerRG8: case Basler.Pylon.PixelType.BayerGB8: case Basler.Pylon.PixelType.BayerBG8: case Basler.Pylon.PixelType.BayerGB10: case Basler.Pylon.PixelType.BayerGB10pp: case Basler.Pylon.PixelType.BayerBG10: case Basler.Pylon.PixelType.BayerBG10pp: case Basler.Pylon.PixelType.BayerRG10: case Basler.Pylon.PixelType.BayerRG10pp: case Basler.Pylon.PixelType.BayerGR10: case Basler.Pylon.PixelType.BayerGR10pp: case Basler.Pylon.PixelType.BayerGB12: case Basler.Pylon.PixelType.BayerGB12p: case Basler.Pylon.PixelType.BayerBG12: case Basler.Pylon.PixelType.BayerBG12Packed: case Basler.Pylon.PixelType.BayerRG12: case Basler.Pylon.PixelType.BayerRG12Packed: case Basler.Pylon.PixelType.BayerGR12: case Basler.Pylon.PixelType.BayerGR12Packed: return true; default: return false; } } /// /// 图像是否为Mono格式 /// /// /// private bool IsMonoPixelFormat(Basler.Pylon.PixelType enType) { switch (enType) { case Basler.Pylon.PixelType.Mono8: case Basler.Pylon.PixelType.Mono10: case Basler.Pylon.PixelType.Mono10packed: case Basler.Pylon.PixelType.Mono12: case Basler.Pylon.PixelType.Mono12packed: return true; default: return false; } } /// /// 将从相机获取的图像IGrabResult转换为CogImage图像 /// 从相机获取的图像 IGrabResult /// private ICogImage GrabResult2CogImage(IGrabResult grabResult) { if (grabResult == null) return null; byte[] pixelData = grabResult.PixelData as byte[]; GCHandle pixelHandle = default; bool pixelPinned = false; GCHandle dstHandle = default; bool dstPinned = false; ICogImage result = null; try { // 尽量 pin 原始像素数据(如果存在) if (pixelData != null && pixelData.Length > 0) { pixelHandle = GCHandle.Alloc(pixelData, GCHandleType.Pinned); pixelPinned = true; } IntPtr pixelPointer = pixelPinned ? pixelHandle.AddrOfPinnedObject() : IntPtr.Zero; // 彩色图像处理 if (IsColorPixelFormat(grabResult.PixelTypeValue)) { // 使用 using 确保 Bitmap 及时释放 using (Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb)) { BitmapData bmpData = null; try { bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); // 使用成员 converter 将 grabResult 转换到 bitmap 的缓冲区 converter.OutputPixelFormat = PixelType.BGRA8packed; IntPtr ptrBmp = bmpData.Scan0; converter.Convert(ptrBmp, Math.Abs(bmpData.Stride) * bitmap.Height, grabResult); } finally { if (bmpData != null) { try { bitmap.UnlockBits(bmpData); } catch { } } } // 构造 Cognex 图像并返回副本(ScaleImage 通常返回独立图像) CogImage24PlanarColor colorImage = null; try { colorImage = new CogImage24PlanarColor(bitmap); result = colorImage.ScaleImage(bitmap.Width, bitmap.Height); } finally { // colorImage 若实现了 IDisposable 则释放(安全检查) (colorImage as IDisposable)?.Dispose(); } } return result; } // 单通道(Mono)图像处理 else if (IsMonoPixelFormat(grabResult.PixelTypeValue)) { Basler.Pylon.PixelType enDstPixelType = Basler.Pylon.PixelType.Mono8; uint nSaveImageNeedSize = (uint)grabResult.Width * (uint)grabResult.Height; IntPtr pTemp = IntPtr.Zero; if (grabResult.PixelTypeValue == Basler.Pylon.PixelType.Mono8) { // 直接使用已 pin 的原始数据指针 if (!pixelPinned) { // 如果原始不是 byte[],尝试从 grabResult 获取 PixelData(若支持) byte[] alt = grabResult.PixelData as byte[]; if (alt != null) { pixelHandle = GCHandle.Alloc(alt, GCHandleType.Pinned); pixelPinned = true; pixelPointer = pixelHandle.AddrOfPinnedObject(); } } pTemp = pixelPointer; } else { // 为转换后的 Mono8 数据分配临时缓冲并 pin byte[] dstBuffer = new byte[nSaveImageNeedSize]; dstHandle = GCHandle.Alloc(dstBuffer, GCHandleType.Pinned); dstPinned = true; pTemp = dstHandle.AddrOfPinnedObject(); // 使用局部的 PixelDataConverter 转换为 Mono8 var pixelConverter = new Basler.Pylon.PixelDataConverter(); pixelConverter.OutputPixelFormat = Basler.Pylon.PixelType.Mono8; pixelConverter.Convert(pTemp, nSaveImageNeedSize, grabResult); } if (pTemp == IntPtr.Zero) { return null; } // ConvertToICogImage 内部会做 ScaleImage,通常会产生独立拷贝 result = ConvertToICogImage((uint)grabResult.Height, (uint)grabResult.Width, pTemp, enDstPixelType); return result; } return null; } finally { // 释放所有固定句柄,确保及时释放 pin 状态 try { if (dstPinned) { dstHandle.Free(); dstPinned = false; } } catch { } try { if (pixelPinned) { pixelHandle.Free(); pixelPinned = false; } } catch { } } } #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 } }