using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.Communications; using MvCameraControl; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Threading; using VM.PlatformSDKCS; using CameraDevice = MvCameraControl.IDevice; namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MachineVision.HikVision { public class HikGigeCamera : BaseDevice, IConnection, Aitex.Core.RT.Device.IDevice { IDeviceInfo deviceInfo = null; private CameraDevice device; // ch:枚举的相机类型 | en:TLayerType for enumerate devices readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice; private List deviceInfoList = new List(); private string _grabName; private bool _isSaveLocal = false; Thread receiveThread = null; // ch:接收图像线程 | en: Receive image thread public HikGigeCamera(string module, string scRoot, string name) : base(module, name, name, name) { IsConnected = false; receiveThread = new Thread(ReceiveThreadProcess); } public string Address { get; private set; } public string ImageFilePath { get; private set; } public bool IsConnected { get; private set; } = false; public bool IsGrabbing { get; private set; } = false; public string Message { get; private set; } public ImageBaseData ImageData { get; private set; } public byte[] CamBitmap { get; private set; } public bool Connect() { return true; } public bool Disconnect() { return true; } public void CamInitialize() { if (IsConnected) { return; } // ch: 初始化 SDK | en: Initialize SDK SDKSystem.Initialize(); // ch: 枚举设备 | en: Enum Device List RefreshDeviceList(); if (deviceInfoList.Count == 0) { Message = "No Camera be found"; return; } string sAddress = SC.GetStringValue($"{Name}.Address"); Address = sAddress; var dinfo = deviceInfoList.Find(i=>i.SerialNumber == Address); if (dinfo == null) { Message = $"Can no find Camera{Address}"; return; } // 打开摄像头(设备索引 0) try { // ch:打开设备 | en:Open device device = DeviceFactory.CreateDevice(dinfo); } catch (Exception ex) { Message = $"Create {Address} failed"; return; } int result = device.Open(); if (result != MvError.MV_OK) { ShowErrorMsg("Open Device fail!", result); return; } //ch: 判断是否为gige设备 | en: Determine whether it is a GigE device if (device is IGigEDevice) { //ch: 转换为gigE设备 | en: Convert to Gige device IGigEDevice gigEDevice = device as IGigEDevice; // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) int optionPacketSize; result = gigEDevice.GetOptimalPacketSize(out optionPacketSize); if (result != MvError.MV_OK) { ShowErrorMsg("Warning: Get Packet Size failed!", result); } else { result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize); if (result != MvError.MV_OK) { ShowErrorMsg("Warning: Set Packet Size failed!", result); } } } ImageFilePath = SC.SafeGetStringValue($"{Name}.ImageFilePath", "D:\\VMImage"); IsConnected = true; } public bool Initialize() { DATA.Subscribe($"{Module}.{Name}.IsConnected", () => this.IsConnected); DATA.Subscribe($"{Module}.{Name}.Address", () => this.Address); DATA.Subscribe($"{Module}.{Name}.Message", () => this.Message); DATA.Subscribe($"{Module}.{Name}.CamBitmap", () => this.CamBitmap); //转至运行模式 OP.Subscribe($"{Module}.{Name}.Grab", (cmd, param) => { Grab((string)param[0]); return true; }); OP.Subscribe($"{Module}.{Name}.Grabbing", (cmd, param) => { Grabbing(); return true; }); OP.Subscribe($"{Module}.{Name}.Stop", (cmd, param) => { Stop(); return true; }); //CamInitialize(); return true; } public void Reset() { ; } public void Terminate() { Stop(); SDKSystem.Finalize(); } private void RefreshDeviceList() { // ch:创建设备列表 | en:Create Device List int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out deviceInfoList); if (nRet != MvError.MV_OK) { ShowErrorMsg("Enumerate devices fail!", nRet); return; } } /// /// ch:显示错误信息 | en:Show error message /// private void ShowErrorMsg(string message, int errorCode) { string errorMsg; if (errorCode == 0) { errorMsg = message; } else { errorMsg = message + ": Error =" + String.Format("{0:X}", errorCode); } switch (errorCode) { case MvError.MV_E_HANDLE: errorMsg += " Error or invalid handle "; break; case MvError.MV_E_SUPPORT: errorMsg += " Not supported function "; break; case MvError.MV_E_BUFOVER: errorMsg += " Cache is full "; break; case MvError.MV_E_CALLORDER: errorMsg += " Function calling order error "; break; case MvError.MV_E_PARAMETER: errorMsg += " Incorrect parameter "; break; case MvError.MV_E_RESOURCE: errorMsg += " Applying resource failed "; break; case MvError.MV_E_NODATA: errorMsg += " No data "; break; case MvError.MV_E_PRECONDITION: errorMsg += " Precondition error, or running environment changed "; break; case MvError.MV_E_VERSION: errorMsg += " Version mismatches "; break; case MvError.MV_E_NOENOUGH_BUF: errorMsg += " Insufficient memory "; break; case MvError.MV_E_UNKNOW: errorMsg += " Unknown error "; break; case MvError.MV_E_GC_GENERIC: errorMsg += " General error "; break; case MvError.MV_E_GC_ACCESS: errorMsg += " Node accessing condition error "; break; case MvError.MV_E_ACCESS_DENIED: errorMsg += " No permission "; break; case MvError.MV_E_BUSY: errorMsg += " Device is busy, or network disconnected "; break; case MvError.MV_E_NETER: errorMsg += " Network error "; break; } EV.PostWarningLog(Module,errorMsg); } public void Grab(string name) { CamInitialize(); if (IsConnected) { _grabName = name; if (IsGrabbing) { _isSaveLocal = true; return; } device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous"); device.Parameters.SetEnumValueByString("TriggerMode", "On"); device.Parameters.SetEnumValueByString("TriggerSource", "Software"); var result = device.StreamGrabber.StartGrabbing(); if (MvError.MV_OK != result) { ShowErrorMsg("Start grabbing Fail!", result); return; } // ch:触发命令 | en:Trigger command var result2 = device.Parameters.SetCommandValue("TriggerSoftware"); if (result2 != MvError.MV_OK) { ShowErrorMsg("Trigger Software Fail!", result2); return; } GetImage(device,true); Message = "Shot one picture"; Stop(); } } public void Grabbing() { CamInitialize(); if (IsConnected) { if (!IsGrabbing) { // ch:设置采集连续模式 | en:Set Continues Aquisition Mode device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous"); device.Parameters.SetEnumValueByString("TriggerMode", "Off"); try { // ch:标志位置位true | en:Set position bit true IsGrabbing = true; receiveThread = new Thread(ReceiveThreadProcess); receiveThread.Start(); } catch (Exception ex) { ShowErrorMsg("Start grabbing thread Fail!", 0); return; } // ch:开始采集 | en:Start Grabbing var result = device.StreamGrabber.StartGrabbing(); if (result != MvError.MV_OK) { IsGrabbing = false; receiveThread.Join(); ShowErrorMsg("Start Grabbing Fail!", result); return; } Message = "Grabbing pictures"; } else { Stop(); } } } public void ReceiveThreadProcess() { while (IsGrabbing) { GetImage(device,_isSaveLocal); } } /// /// 抓取图像;单次抓取时需要存图 /// /// /// private void GetImage(CameraDevice cam,bool isSaveLocal) { IFrameOut frameOut = null; int result = MvError.MV_OK; result = device.StreamGrabber.GetImageBuffer(1000, out frameOut); if (result == MvError.MV_OK) { if(isSaveLocal) //截图模式,原始图片进行保存 { var folderPath = ImageFilePath + DateTime.Now.ToString("yyyy-MM-dd"); if (!Directory.Exists(folderPath)) { // 创建文件夹 Directory.CreateDirectory(folderPath); Console.WriteLine($"Folder '{folderPath}' created successfully."); } var info = new ImageFormatInfo() { FormatType = ImageFormatType.Jpeg, JpegQuality = 80 }; var f = folderPath + $"\\{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-FFF")}_{_grabName}.{info.FormatType}"; device.ImageSaver.SaveImageToFile(f, frameOut.Image, info, CFAMethod.Equilibrated); EV.PostInfoLog(Module, $"Hik CCD check,Save image in {f}"); ImageData = ConvertImage(frameOut.Image); //注意克隆 _isSaveLocal = false; } CamBitmap = BitmapToBytes(frameOut.Image.ToBitmap()); device.StreamGrabber.FreeImageBuffer(frameOut); } } public byte[] BitmapToBytes(Bitmap bitmap) { using (MemoryStream ms = new MemoryStream()) { bitmap.Save(ms, ImageFormat.Bmp); // 推荐Bmp格式保证数据完整性:ml-citation{ref="1,5" data="citationList"} return ms.ToArray(); // 比GetBuffer()更精确获取有效数据:ml-citation{ref="12" data="citationList"} } } public void Stop() { IsGrabbing = false; if (receiveThread.IsAlive) { receiveThread.Join(); } Message = "Standby"; if (device ==null) { return; } int result = device.StreamGrabber.StopGrabbing(); if (result != MvError.MV_OK) { ShowErrorMsg("Stop Grabbing Fail!", result); } result = device.Close(); if (MvError.MV_OK != result) { ShowErrorMsg("Close device failed", result); } // ch:销毁设备 | en:Destroy device device.Dispose(); device = null; IsConnected = false; } private ImageBaseData ConvertImage(IImage img) { return new ImageBaseData((byte[])img.PixelData.Clone(), (uint)img.ImageSize, (int)img.Width, (int)img.Height, 17301505); } } }