MoS2/Framework/MECF.Framework.RT.EquipmentLibrary/HardwareUnits/MachineVision/HikVision/HikGigeCamera.cs
2026-06-15 10:56:30 +08:00

404 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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