404 lines
14 KiB
C#
404 lines
14 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|