using MvCamCtrl.NET; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Drawing.Imaging; using System.Drawing; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Threading; using System.Net; using OpenCvSharp; using System.Reflection.Metadata; //[Device("HikCamera", "海康相机", EnumHelper.DeviceAttributeType.Device)] public class HikCameraDriver { #region CameraBase public bool IfSuccess = false; float _lastExposure = 0; float _lastGain = 0; /// /// 相机拍照计数 /// public volatile int SnapshotCount = 0; public Action OnHImageOutput { get; set; } public void Init() { //_bufferImgSetQueue = new ConcurrentQueue(); //_bufferImgSet = new ImageSet(); //pCallBackFunc = new MyCamera.cbExceptiondelegate(cbExceptiondelegate); #if false #region 根据IP连接相机 stDevInfo.nTLayerType = MyCamera.MV_GIGE_DEVICE; MyCamera.MV_GIGE_DEVICE_INFO stGigEDev = new MyCamera.MV_GIGE_DEVICE_INFO(); //string strCurrentIp = IIConfig.CameraIP;// ch:需要连接的相机ip(根据实际填充) //string strNetExport = IIConfig.ComputerIP; // ch:相机对应的网卡ip(根据实际填充) string strCurrentIp = "192.168.1.21";// ch:需要连接的相机ip(根据实际填充) string strNetExport = "192.168.1.20"; // 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); //释放内存空间 Marshal.FreeHGlobal(stGigeInfoPtr); #endregion #endif } protected void Pause() { } protected void Resume() { } public void Start(string v) { #region 枚举相机后根据IP地址匹配连接相机 //将IP地址转换为字节数组 uint intAddress = 0; if (/*(IIConfig.HikCameraType == EnumHelper.HikCameraType.Gige) &&*/ (!string.IsNullOrWhiteSpace("192.168.1.21"))) { byte[] IPArr = IPAddress.Parse("192.168.1.21").GetAddressBytes(); for (int i = 0; i < IPArr.Length; i++) { intAddress += (uint)(IPArr[i] << (IPArr.Length - 1 - i) * 8); } } MyCamera.MV_CC_DEVICE_INFO_LIST m_pDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST(); int nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_pDeviceList); if (0 != nRet) { throw new Exception($"Enumerate devices fail!"); } else { //LogAsync(DateTime.Now, $"搜索获取{m_pDeviceList.nDeviceNum.ToInt()}台相机在线", ""); } bool isCameraFound = false; for (int i = 0; i < m_pDeviceList.nDeviceNum; i++) { MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO)); IntPtr buffer = IntPtr.Zero; if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE) { buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stGigEInfo, 0); MyCamera.MV_GIGE_DEVICE_INFO stGigEDev = (MyCamera.MV_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO)); if (stGigEDev.nCurrentIp == intAddress) { stDevInfo = device; isCameraFound = true; } } else if (device.nTLayerType == MyCamera.MV_USB_DEVICE) { } //释放内存空间 //Marshal.FreeHGlobal(buffer); if (isCameraFound) break; } if (!isCameraFound) { throw new Exception($"相机未能找到"); } #endregion // 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 (false) { 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 (false) { // 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}"); } else { IfSuccess = true; } } private void IIConfig_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "IsHardwareTrigger" && !false) { // 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 (false) { // 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}"); } } } public void Stop() { // IIConfig.PropertyChanged -= IIConfig_PropertyChanged; // 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; //ImageSet _bufferImgSet = null; ManualResetEvent _bufferHandle = new ManualResetEvent(false); //ConcurrentQueue _bufferImgSetQueue = new ConcurrentQueue(); //volatile ImageSet _bufferImgSet = new ImageSet(); void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser) { try { if (_snapFlag) { _snapFlag = false; _frame = new MyCamera.MV_FRAME_OUT { stFrameInfo = pFrameInfo, pBufAddr = pData }; _snapHandle.Set(); } // } } catch (Exception ex) { //LogAsync(DateTime.Now, LogLevel.Exception, $"{Name}相机取像异常,{ex.GetExceptionMessage()}"); } } private bool IsMonoData(MyCamera.MvGvspPixelType enGvspPixelType) { switch (enGvspPixelType) { case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8: case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10: case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed: case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12: case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed: return true; default: return false; } } public void RefreshImageBufferHandle() { //_bufferImgSet?.Dispose(); //_bufferImgSet = null; _bufferHandle.Reset(); } object _bufferLock = new object(); public void Snapshot(int pageBum, string napshotFileName) { //SnapshotCount = pageBum; //SnapshotFileNames = napshotFileName; Snapshot(); } public void Snapshot() { Stopwatch sw = new Stopwatch(); sw.Start(); MyCamera.MV_FRAME_OUT frameInfo = new MyCamera.MV_FRAME_OUT(); nRet = MyCamera.MV_OK; if (true) { // 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; Mat _mat = new Mat(pFrameInfo.nWidth, pFrameInfo.nHeight, MatType.CV_8UC3, frameInfo.pBufAddr); OnHImageOutput?.Invoke(DateTime.Now, _mat, SnapshotCount); } } } else { throw new Exception($"Grap Image Failed:{nRet:x8}"); } sw.Stop(); //LogAsync(DateTime.Now, LogLevel.Information, $"取像耗时:{sw.ElapsedMilliseconds} ms"); } 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; #endregion }