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
}
}