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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|