SIC-12/Framework/MECF.Framework.RT.EquipmentLibrary/HardwareUnits/MachineVision/HikVision/HikGigeCamera.cs

404 lines
14 KiB
C#
Raw Normal View History

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<IDeviceInfo> deviceInfoList = new List<IDeviceInfo>();
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;
}
}
/// <summary>
/// ch:显示错误信息 | en:Show error message
/// </summary>
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);
}
}
/// <summary>
/// 抓取图像;单次抓取时需要存图
/// </summary>
/// <param name="cam"></param>
/// <param name="isSaveLocal"></param>
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);
}
}
}