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 IImageSet Snapshot(IOperationConfig config) { ImageSet set = new ImageSet(); InitialImageSet(set, (config as CameraOprerationConfigBase).ImageSaveOption); 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) { if (CurrentState != EnumHelper.DeviceState.DSClose) { int reTryTimes = 3; do { Thread.Sleep(1000); Stop(); try { Start(); reTryTimes = -1; } catch (Exception ex) { reTryTimes--; if (reTryTimes > 0) { //OnLog?.Invoke(DateTime.Now, this, "重新连接相机异常\r\n" + ex.GetExceptionMessage()); LogAsync(DateTime.Now, $"{this.Name}重新连接异常", ex.GetExceptionMessage()); } else { throw ex; } } } while (reTryTimes > 0); } } } #endregion } }