using Bro.Common.Base;
|
using Bro.Common.Helper;
|
using Bro.Common.Interface;
|
using HalconDotNet;
|
using MvCamCtrl.NET;
|
using System;
|
using System.Drawing;
|
using System.Drawing.Imaging;
|
using System.Runtime.InteropServices;
|
using System.Threading;
|
using System.Threading.Tasks;
|
|
namespace Bro.Device.HikCamera
|
{
|
[Device("HikCamera", "海康相机", EnumHelper.DeviceAttributeType.Device)]
|
public class HikCameraDriver : CameraBase
|
{
|
#region CameraBase
|
public override IOperationConfig GetOperationConfigFromDevice()
|
{
|
HikCameraOperationConfig opConfig = new HikCameraOperationConfig();
|
|
MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
|
int nRet = device.MV_CC_GetFloatValue_NET("ExposureTime", ref stParam);
|
if (MyCamera.MV_OK == nRet)
|
{
|
opConfig.Exposure = stParam.fCurValue;
|
}
|
|
nRet = device.MV_CC_GetFloatValue_NET("Gain", ref stParam);
|
if (MyCamera.MV_OK == nRet)
|
{
|
opConfig.Gain = stParam.fCurValue;
|
}
|
|
return opConfig;
|
}
|
|
float _lastExposure = 0;
|
float _lastGain = 0;
|
|
public override void UploadOperationConfig(IOperationConfig config)
|
{
|
if (CurrentState != EnumHelper.DeviceState.DSOpen)
|
return;
|
|
CameraOprerationConfigBase opConfig = config as CameraOprerationConfigBase;
|
|
int nRet;
|
|
if (opConfig.Exposure != 0 && opConfig.Exposure != _lastExposure)
|
{
|
device.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
|
nRet = device.MV_CC_SetFloatValue_NET("ExposureTime", opConfig.Exposure);
|
if (nRet != MyCamera.MV_OK)
|
{
|
throw new Exception($"Exposure set failed:{nRet}");
|
}
|
|
_lastExposure = opConfig.Exposure;
|
}
|
|
if (opConfig.Gain != 0 && opConfig.Gain != _lastGain)
|
{
|
device.MV_CC_SetEnumValue_NET("GainAuto", 0);
|
nRet = device.MV_CC_SetFloatValue_NET("Gain", opConfig.Gain);
|
if (nRet != MyCamera.MV_OK)
|
{
|
throw new Exception($"Gain set failed:{nRet}");
|
}
|
|
_lastGain = opConfig.Gain;
|
}
|
}
|
|
protected override void Init()
|
{
|
stDevInfo.nTLayerType = MyCamera.MV_GIGE_DEVICE;
|
MyCamera.MV_GIGE_DEVICE_INFO stGigEDev = new MyCamera.MV_GIGE_DEVICE_INFO();
|
pCallBackFunc = new MyCamera.cbExceptiondelegate(cbExceptiondelegate);
|
|
string strCurrentIp = IConfig.CameraIP;// ch:需要连接的相机ip(根据实际填充)
|
|
string strNetExport = IConfig.ComputerIP; // ch:相机对应的网卡ip(根据实际填充)
|
|
var parts = strCurrentIp.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 = strNetExport.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);
|
}
|
|
protected override void Pause()
|
{
|
}
|
|
protected override void Resume()
|
{
|
}
|
|
protected override void Start()
|
{
|
base.Start();
|
|
// ch:创建设备 | en: Create device
|
nRet = device.MV_CC_CreateDevice_NET(ref stDevInfo);
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"Create device failed:{nRet:x8}");
|
}
|
|
// ch:打开设备 | en:Open device
|
nRet = device.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 = device.MV_CC_GetOptimalPacketSize_NET();
|
if (nPacketSize > 0)
|
{
|
nRet = device.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 = device.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
|
device.MV_CC_SetEnumValue_NET("AcquisitionMode", 2);// ch:工作在连续模式 | en:Acquisition On Continuous Mode
|
if (IIConfig.IsContinueMode)
|
{
|
device.MV_CC_SetEnumValue_NET("TriggerMode", 0); // ch:连续模式 | en:Continuous
|
|
// ch:注册回调函数 | en:Register image callback
|
ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
|
nRet = device.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 = device.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 = device.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 = device.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception("Register image callback failed!");
|
}
|
}
|
else
|
{
|
nRet = device.MV_CC_SetEnumValue_NET("TriggerSource", 7);
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception("Set Software Trigger failed!");
|
}
|
}
|
}
|
// ch:开启抓图 || en: start grab image
|
nRet = device.MV_CC_StartGrabbing_NET();
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"Start grabbing failed:{nRet:x8}");
|
}
|
|
IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
|
IIConfig.PropertyChanged += IIConfig_PropertyChanged;
|
}
|
|
private void IIConfig_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
{
|
if (e.PropertyName == "IsHardwareTrigger" && !IIConfig.IsContinueMode)
|
{
|
// ch:停止抓图 | en:Stop grab image
|
nRet = device.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 = device.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 = device.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception("Register image callback failed!");
|
}
|
}
|
else
|
{
|
nRet = device.MV_CC_SetEnumValue_NET("TriggerSource", 7);
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception("Set Software Trigger failed!");
|
}
|
}
|
|
// ch:开启抓图 || en: start grab image
|
nRet = device.MV_CC_StartGrabbing_NET();
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"Start grabbing failed:{nRet:x8}");
|
}
|
}
|
}
|
|
protected override void Stop()
|
{
|
IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
|
|
base.Stop();
|
|
// ch:停止抓图 | en:Stop grab image
|
nRet = device.MV_CC_StopGrabbing_NET();
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"Stop grabbing failed{nRet:x8}");
|
}
|
|
// ch:关闭设备 | en:Close device
|
nRet = device.MV_CC_CloseDevice_NET();
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"Close device failed{nRet:x8}");
|
}
|
|
// ch:销毁设备 | en:Destroy device
|
nRet = device.MV_CC_DestroyDevice_NET();
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"Destroy device failed:{nRet:x8}");
|
}
|
}
|
#endregion
|
|
#region HikCamera
|
public MyCamera.cbOutputExdelegate ImageCallback;
|
MyCamera.MV_FRAME_OUT _frame = new MyCamera.MV_FRAME_OUT();
|
readonly ManualResetEvent _snapHandle = new ManualResetEvent(false);
|
bool _snapFlag = false;
|
void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
|
{
|
if ((IIConfig.IsHardwareTrigger))
|
{
|
int nWidth = pFrameInfo.nWidth;
|
int nHeight = pFrameInfo.nHeight;
|
|
HImage hImage = new HImage();
|
hImage.GenImage1((HTuple)"byte", nWidth, nHeight, pData);
|
|
ImageSet set = new ImageSet
|
{
|
HImage = hImage
|
};
|
set.ImageSaveOption.DataFrom(IConfig.ImageSaveOption);
|
NewImageSet(set);
|
OnHImageOutput?.BeginInvoke(this, hImage, set.Id, null, null);
|
|
Generate8GrayImageByPointer(nWidth, nHeight, pData, set.Id);
|
}
|
else
|
{
|
if (_snapFlag)
|
{
|
_snapFlag = false;
|
_frame = new MyCamera.MV_FRAME_OUT
|
{
|
stFrameInfo = pFrameInfo,
|
pBufAddr = pData
|
};
|
_snapHandle.Set();
|
}
|
}
|
}
|
|
public override void Snapshot()
|
{
|
MyCamera.MV_FRAME_OUT frameInfo = new MyCamera.MV_FRAME_OUT();
|
nRet = MyCamera.MV_OK;
|
|
if (!IIConfig.IsContinueMode)
|
{
|
// ch: 触发命令 || en: Trigger command
|
nRet = device.MV_CC_SetCommandValue_NET("TriggerSoftware");
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"相机拍照触发失败:{nRet}");
|
}
|
|
nRet = device.MV_CC_GetImageBuffer_NET(ref frameInfo, 1000);
|
nRet = device.MV_CC_FreeImageBuffer_NET(ref frameInfo);
|
}
|
else
|
{
|
_snapHandle.Reset();
|
_snapFlag = true;
|
_snapHandle.WaitOne();
|
//lock (_imgCallBackLock)
|
{
|
frameInfo.stFrameInfo = _frame.stFrameInfo;
|
frameInfo.pBufAddr = _frame.pBufAddr;
|
}
|
}
|
|
// ch:获取一帧图像 | en:Get one image
|
if (MyCamera.MV_OK == nRet)
|
{
|
if (frameInfo.pBufAddr != IntPtr.Zero)
|
{
|
if (nRet == MyCamera.MV_OK)
|
{
|
var pFrameInfo = frameInfo.stFrameInfo;
|
uint nWidth = pFrameInfo.nWidth;
|
uint nHeight = pFrameInfo.nHeight;
|
|
//HikToBitmap(pFrameInfo, frameInfo.pBufAddr);
|
Generate8GrayImageByPointer((int)nWidth, (int)nHeight, frameInfo.pBufAddr, "");
|
}
|
}
|
}
|
else
|
{
|
throw new Exception($"Grap Image Failed:{nRet:x8}");
|
}
|
}
|
|
public override ImageSet Snapshot(IOperationConfig config)
|
{
|
ImageSet set = base.Snapshot(config);
|
MyCamera.MV_FRAME_OUT frameInfo = new MyCamera.MV_FRAME_OUT();
|
nRet = MyCamera.MV_OK;
|
|
if (!IIConfig.IsContinueMode)
|
{
|
// ch: 触发命令 || en: Trigger command
|
nRet = device.MV_CC_SetCommandValue_NET("TriggerSoftware");
|
if (MyCamera.MV_OK != nRet)
|
{
|
throw new Exception($"相机拍照触发失败:{nRet}");
|
}
|
|
nRet = device.MV_CC_GetImageBuffer_NET(ref frameInfo, 500);
|
nRet = device.MV_CC_FreeImageBuffer_NET(ref frameInfo);
|
}
|
else
|
{
|
_snapHandle.Reset();
|
_snapFlag = true;
|
_snapHandle.WaitOne();
|
{
|
frameInfo.stFrameInfo = _frame.stFrameInfo;
|
frameInfo.pBufAddr = _frame.pBufAddr;
|
}
|
}
|
|
// ch:获取一帧图像 | en:Get one image
|
if (MyCamera.MV_OK == nRet)
|
{
|
if (frameInfo.pBufAddr != IntPtr.Zero)
|
{
|
if (nRet == MyCamera.MV_OK)
|
{
|
var pFrameInfo = frameInfo.stFrameInfo;
|
uint nWidth = pFrameInfo.nWidth;
|
uint nHeight = pFrameInfo.nHeight;
|
|
HImage hImage = new HImage();
|
hImage.GenImage1("byte", pFrameInfo.nWidth, pFrameInfo.nHeight, frameInfo.pBufAddr);
|
|
set.HImage = hImage;
|
|
Generate8GrayImageByPointer((int)nWidth, (int)nHeight, frameInfo.pBufAddr, set.Id);
|
return set;
|
}
|
}
|
}
|
|
throw new Exception($"Grap Image Failed:{nRet:x8}");
|
}
|
|
readonly MyCamera device = new MyCamera();
|
MyCamera.MV_CC_DEVICE_INFO stDevInfo = new MyCamera.MV_CC_DEVICE_INFO();
|
int nRet = MyCamera.MV_OK;
|
MyCamera.cbExceptiondelegate pCallBackFunc;
|
|
public HikCameraInitialConfig IIConfig
|
{
|
get => InitialConfig as HikCameraInitialConfig;
|
}
|
|
// ch:回调函数 | en:Callback function
|
private void cbExceptiondelegate(uint nMsgType, IntPtr pUser)
|
{
|
if (nMsgType == MyCamera.MV_EXCEPTION_DEV_DISCONNECT)
|
{
|
Thread.Sleep(1000);
|
|
Stop();
|
|
if (CurrentState != EnumHelper.DeviceState.DSClose)
|
{
|
int reTryTimes = 3;
|
do
|
{
|
try
|
{
|
Start();
|
reTryTimes = -1;
|
}
|
catch (Exception ex)
|
{
|
reTryTimes--;
|
|
if (reTryTimes > 0)
|
{
|
//OnLog?.Invoke(DateTime.Now, this, "重新连接相机异常\r\n" + ex.GetExceptionMessage());
|
LogAsync(DateTime.Now, "重新连接异常", ex.GetExceptionMessage());
|
}
|
else
|
{
|
throw ex;
|
}
|
}
|
} while (reTryTimes > 0);
|
}
|
}
|
}
|
#endregion
|
}
|
}
|