494 lines
20 KiB
C#
494 lines
20 KiB
C#
using System.Diagnostics;
|
|
using OpenCvSharp;
|
|
using MvCamCtrl.NET;
|
|
using System.Runtime.InteropServices;
|
|
using System.Xml.Linq;
|
|
using DH.Commons.Enums;
|
|
using static MvCamCtrl.NET.MyCamera;
|
|
using DH.Devices.Devices;
|
|
|
|
|
|
|
|
namespace DH.Devices.Camera
|
|
{
|
|
public class HikVisionCamera : CameraBase
|
|
{
|
|
readonly MyCamera cameraObj = new MyCamera();
|
|
MyCamera.MV_CC_DEVICE_INFO stDevInfo = new MyCamera.MV_CC_DEVICE_INFO();
|
|
int nRet = MyCamera.MV_OK;
|
|
MyCamera.cbExceptiondelegate pCallBackFunc;
|
|
public MyCamera.cbOutputExdelegate ImageCallback;
|
|
MyCamera.MV_FRAME_OUT _frame = new MyCamera.MV_FRAME_OUT();
|
|
readonly ManualResetEvent _snapHandle = new ManualResetEvent(false);
|
|
bool _snapFlag = false;
|
|
|
|
public HikVisionCamera()
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
public override bool CameraConnect()
|
|
{
|
|
try
|
|
{
|
|
pCallBackFunc = new MyCamera.cbExceptiondelegate(cbExceptiondelegate);
|
|
|
|
#region 根据IP连接相机
|
|
stDevInfo.nTLayerType = MyCamera.MV_GIGE_DEVICE;
|
|
MyCamera.MV_GIGE_DEVICE_INFO stGigEDev = new MyCamera.MV_GIGE_DEVICE_INFO();
|
|
|
|
|
|
var parts = CameraIP.Split('.');
|
|
int nIp1 = Convert.ToInt32(parts[0]);
|
|
int nIp2 = Convert.ToInt32(parts[1]);
|
|
int nIp3 = Convert.ToInt32(parts[2]);
|
|
int nIp4 = Convert.ToInt32(parts[3]);
|
|
stGigEDev.nCurrentIp = (uint)((nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4);
|
|
|
|
parts = ComputerIP.Split('.');
|
|
nIp1 = Convert.ToInt32(parts[0]);
|
|
nIp2 = Convert.ToInt32(parts[1]);
|
|
nIp3 = Convert.ToInt32(parts[2]);
|
|
nIp4 = Convert.ToInt32(parts[3]);
|
|
stGigEDev.nNetExport = (uint)((nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4);
|
|
|
|
IntPtr stGigeInfoPtr = Marshal.AllocHGlobal(216);
|
|
Marshal.StructureToPtr(stGigEDev, stGigeInfoPtr, false);
|
|
stDevInfo.SpecialInfo.stGigEInfo = new Byte[540];
|
|
Marshal.Copy(stGigeInfoPtr, stDevInfo.SpecialInfo.stGigEInfo, 0, 540);
|
|
//释放内存空间
|
|
Marshal.FreeHGlobal(stGigeInfoPtr);
|
|
#endregion
|
|
// ch:创建设备 | en: Create device
|
|
nRet = cameraObj.MV_CC_CreateDevice_NET(ref stDevInfo);
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Create device failed:{nRet:x8}");
|
|
}
|
|
|
|
// ch:打开设备 | en:Open device
|
|
nRet = cameraObj.MV_CC_OpenDevice_NET();
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Open device failed:{nRet:x8}");
|
|
}
|
|
|
|
|
|
// ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
|
|
if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
|
|
{
|
|
int nPacketSize = cameraObj.MV_CC_GetOptimalPacketSize_NET();
|
|
if (nPacketSize > 0)
|
|
{
|
|
nRet = cameraObj.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
|
|
if (nRet != MyCamera.MV_OK)
|
|
{
|
|
Console.WriteLine("Warning: Set Packet Size failed {0:x8}", nRet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Warning: Get Packet Size failed {0:x8}", nPacketSize);
|
|
}
|
|
}
|
|
|
|
// ch:注册异常回调函数 | en:Register Exception Callback
|
|
nRet = cameraObj.MV_CC_RegisterExceptionCallBack_NET(pCallBackFunc, IntPtr.Zero);
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Register expection callback failed:{nRet}");
|
|
}
|
|
GC.KeepAlive(pCallBackFunc);
|
|
|
|
// ch:设置采集连续模式 | en:Set Continues Aquisition Mode
|
|
cameraObj.MV_CC_SetEnumValue_NET("AcquisitionMode", 2);// ch:工作在连续模式 | en:Acquisition On Continuous Mode
|
|
//if (IIConfig.IsContinueMode)
|
|
//{
|
|
// cameraObj.MV_CC_SetEnumValue_NET("TriggerMode", 0); // ch:连续模式 | en:Continuous
|
|
|
|
// // ch:注册回调函数 | en:Register image callback
|
|
// ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
|
|
// nRet = cameraObj.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Register image callback failed!");
|
|
// }
|
|
//}
|
|
//else
|
|
//{
|
|
// ch:设置触发模式为off || en:set trigger mode as off
|
|
nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerMode", 1);
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception("Set TriggerMode failed!");
|
|
}
|
|
|
|
//if (IIConfig.IsHardwareTrigger)
|
|
//{
|
|
// ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0;
|
|
// 1 - Line1;
|
|
// 2 - Line2;
|
|
// 3 - Line3;
|
|
// 4 - Counter;
|
|
// 7 - Software;
|
|
nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 0);
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception("Set Line0 Trigger failed!");
|
|
}
|
|
|
|
// ch:注册回调函数 | en:Register image callback
|
|
ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
|
|
nRet = cameraObj.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception("Register image callback failed!");
|
|
}
|
|
//}
|
|
//else
|
|
//{
|
|
// nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 7);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Set Software Trigger failed!");
|
|
// }
|
|
//}
|
|
//}
|
|
// ch:开启抓图 || en: start grab image
|
|
nRet = cameraObj.MV_CC_StartGrabbing_NET();
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Start grabbing failed:{nRet:x8}");
|
|
}
|
|
|
|
//if (IConfig.DefaultExposure != 0)
|
|
//{
|
|
// cameraObj.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
|
|
// nRet = cameraObj.MV_CC_SetFloatValue_NET("ExposureTime", IConfig.DefaultExposure);
|
|
// if (nRet != MyCamera.MV_OK)
|
|
// {
|
|
// throw new Exception($"Exposure set failed:{nRet}");
|
|
// }
|
|
//}
|
|
//if (IIConfig.Gain >= 0)
|
|
//{
|
|
// nRet = cameraObj.MV_CC_SetFloatValue_NET("Gain", IIConfig.Gain);
|
|
// if (nRet != MyCamera.MV_OK)
|
|
// {
|
|
// throw new Exception($"Gain set failed:{nRet}");
|
|
// }
|
|
//}
|
|
// 设置 触发延迟
|
|
//if (IIConfig.TriggerDelay > 0)
|
|
//{
|
|
// nRet = cameraObj.MV_CC_SetFloatValue_NET("TriggerDelay", IIConfig.TriggerDelay);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Set TriggerDelay failed!");
|
|
// }
|
|
//}
|
|
//if (IIConfig.LineDebouncerTime > 0)
|
|
//{
|
|
// nRet = cameraObj.MV_CC_SetIntValue_NET("LineDebouncerTime", (uint)IIConfig.LineDebouncerTime);
|
|
// if (nRet != MyCamera.MV_OK)
|
|
// {
|
|
// throw new Exception($"LineDebouncerTime set failed:{nRet}");
|
|
// }
|
|
//}
|
|
//IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
|
|
//IIConfig.PropertyChanged += IIConfig_PropertyChanged;
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private void IIConfig_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
|
{
|
|
//if (e.PropertyName == "IsHardwareTrigger" && !IIConfig.IsContinueMode)
|
|
//{
|
|
// // ch:停止抓图 | en:Stop grab image
|
|
// nRet = cameraObj.MV_CC_StopGrabbing_NET();
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception($"Stop grabbing failed{nRet:x8}");
|
|
// }
|
|
|
|
// if (IIConfig.IsHardwareTrigger)
|
|
// {
|
|
// // ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0;
|
|
// // 1 - Line1;
|
|
// // 2 - Line2;
|
|
// // 3 - Line3;
|
|
// // 4 - Counter;
|
|
// // 7 - Software;
|
|
// nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 0);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Set Line0 Trigger failed!");
|
|
// }
|
|
|
|
// // ch:注册回调函数 | en:Register image callback
|
|
// ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
|
|
// nRet = cameraObj.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Register image callback failed!");
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 7);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Set Software Trigger failed!");
|
|
// }
|
|
// }
|
|
|
|
// // ch:开启抓图 || en: start grab image
|
|
// nRet = cameraObj.MV_CC_StartGrabbing_NET();
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception($"Start grabbing failed:{nRet:x8}");
|
|
// }
|
|
|
|
// if (IConfig.DefaultExposure != 0)
|
|
// {
|
|
// cameraObj.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
|
|
// nRet = cameraObj.MV_CC_SetFloatValue_NET("ExposureTime", IConfig.DefaultExposure);
|
|
// if (nRet != MyCamera.MV_OK)
|
|
// {
|
|
// throw new Exception($"Exposure set failed:{nRet}");
|
|
// }
|
|
// }
|
|
// if (IIConfig.Gain >= 0)
|
|
// {
|
|
// nRet = cameraObj.MV_CC_SetFloatValue_NET("Gain", IIConfig.Gain);
|
|
// if (nRet != MyCamera.MV_OK)
|
|
// {
|
|
// throw new Exception($"Gain set failed:{nRet}");
|
|
// }
|
|
// }
|
|
|
|
// // 设置 触发延迟
|
|
// if (IIConfig.TriggerDelay > 0)
|
|
// {
|
|
// nRet = cameraObj.MV_CC_SetFloatValue_NET("TriggerDelay", IIConfig.TriggerDelay);
|
|
// if (MyCamera.MV_OK != nRet)
|
|
// {
|
|
// throw new Exception("Set TriggerDelay failed!");
|
|
// }
|
|
// }
|
|
// if (IIConfig.LineDebouncerTime > 0)
|
|
// {
|
|
// nRet = cameraObj.MV_CC_SetIntValue_NET("LineDebouncerTime", (uint)IIConfig.LineDebouncerTime);
|
|
// if (nRet != MyCamera.MV_OK)
|
|
// {
|
|
// throw new Exception($"LineDebouncerTime set failed:{nRet}");
|
|
// }
|
|
// }
|
|
//}
|
|
}
|
|
|
|
public override bool CameraDisConnect()
|
|
{
|
|
//IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
|
|
|
|
//base.Stop();
|
|
|
|
// ch:停止抓图 | en:Stop grab image
|
|
|
|
try
|
|
{
|
|
nRet = cameraObj.MV_CC_StopGrabbing_NET();
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Stop grabbing failed{nRet:x8}");
|
|
}
|
|
|
|
// ch:关闭设备 | en:Close device
|
|
nRet = cameraObj.MV_CC_CloseDevice_NET();
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Close device failed{nRet:x8}");
|
|
}
|
|
|
|
// ch:销毁设备 | en:Destroy device
|
|
nRet = cameraObj.MV_CC_DestroyDevice_NET();
|
|
if (MyCamera.MV_OK != nRet)
|
|
{
|
|
throw new Exception($"Destroy device failed:{nRet:x8}");
|
|
}
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
|
|
{
|
|
Mat cvImage = new Mat();
|
|
try
|
|
{
|
|
|
|
Interlocked.Increment(ref SnapshotCount);
|
|
int nWidth = pFrameInfo.nWidth;
|
|
int nHeight = pFrameInfo.nHeight;
|
|
switch (pFrameInfo.enPixelType)
|
|
{
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
|
|
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pData);
|
|
break;
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
|
|
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pData);
|
|
Cv2.CvtColor(cvImage, cvImage, ColorConversionCodes.RGB2BGR);
|
|
break;
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
|
|
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pData);
|
|
break;
|
|
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
|
|
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pData);
|
|
break;
|
|
|
|
default:
|
|
throw new NotSupportedException($"Unsupported pixel type: {pFrameInfo.enPixelType}");
|
|
}
|
|
|
|
OnHImageOutput?.Invoke(DateTime.Now, this, cvImage);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
finally
|
|
{
|
|
cvImage?.Dispose();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public MvGvspPixelType GetMvGvspPixelType(StreamFormat streamFormat)
|
|
{
|
|
switch (streamFormat)
|
|
{
|
|
// 原始数据格式映射
|
|
case StreamFormat.S_RAW8:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono8;
|
|
case StreamFormat.S_RAW10:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono10_Packed;
|
|
case StreamFormat.S_RAW12:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono12_Packed;
|
|
case StreamFormat.S_RAW14:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono14;
|
|
case StreamFormat.S_RAW16:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono16;
|
|
|
|
// RGB/BGR格式映射
|
|
case StreamFormat.S_BGR24:
|
|
return MvGvspPixelType.PixelType_Gvsp_BGR8_Packed;
|
|
case StreamFormat.S_BGR32:
|
|
return MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed;
|
|
case StreamFormat.S_RGB24:
|
|
return MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
|
|
case StreamFormat.S_RGB32:
|
|
return MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed;
|
|
case StreamFormat.S_BGR48:
|
|
return MvGvspPixelType.PixelType_Gvsp_BGR10_Packed;
|
|
case StreamFormat.S_RGB48:
|
|
return MvGvspPixelType.PixelType_Gvsp_RGB16_Packed;
|
|
|
|
// YUV格式映射
|
|
case StreamFormat.S_YCBCR_411:
|
|
return MvGvspPixelType.PixelType_Gvsp_YCBCR411_8_CBYYCRYY;
|
|
case StreamFormat.S_YCBCR_422:
|
|
return MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed;
|
|
case StreamFormat.S_YCBCR_444:
|
|
return MvGvspPixelType.PixelType_Gvsp_YUV444_Packed;
|
|
|
|
// 灰度图像映射
|
|
case StreamFormat.S_MONO8:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono8;
|
|
case StreamFormat.S_MONO10:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono10;
|
|
case StreamFormat.S_MONO12:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono12;
|
|
case StreamFormat.S_MONO14:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono14;
|
|
case StreamFormat.S_MONO16:
|
|
return MvGvspPixelType.PixelType_Gvsp_Mono16;
|
|
|
|
// 特殊格式映射
|
|
case StreamFormat.S_B8_G8_R8:
|
|
return MvGvspPixelType.PixelType_Gvsp_RGB8_Planar;
|
|
case StreamFormat.S_B16_G16_R16:
|
|
return MvGvspPixelType.PixelType_Gvsp_RGB16_Planar;
|
|
|
|
default:
|
|
throw new ArgumentException($"Unsupported stream format: {streamFormat}");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// ch:回调函数 | en:Callback function
|
|
private void cbExceptiondelegate(uint nMsgType, IntPtr pUser)
|
|
{
|
|
//if (nMsgType == MyCamera.MV_EXCEPTION_DEV_DISCONNECT)
|
|
//{
|
|
// if (CurrentState != EnumHelper.DeviceState.DSClose)
|
|
// {
|
|
// int reTryTimes = 3;
|
|
// do
|
|
// {
|
|
// try
|
|
// {
|
|
// Task.Delay(1000).Wait();
|
|
// Stop();
|
|
|
|
// Start();
|
|
// reTryTimes = -1;
|
|
// }
|
|
// catch (Exception ex)
|
|
// {
|
|
// reTryTimes--;
|
|
|
|
// if (reTryTimes > 0)
|
|
// {
|
|
// LogAsync(DateTime.Now, LogLevel.Information, $"{this.Name}重新连接异常,{ex.GetExceptionMessage()}");
|
|
// }
|
|
// else
|
|
// {
|
|
// throw ex;
|
|
// }
|
|
// }
|
|
// } while (reTryTimes > 0);
|
|
// }
|
|
//}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|