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.Commons.Base; 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); // } //} } } }