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