From c4a8ca8cb2f17a48e1c055c5905a2e6c97c5b9fb Mon Sep 17 00:00:00 2001 From: lhiven Date: Sat, 7 Dec 2024 11:07:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=A7=E6=81=92=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E7=9A=84=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Rs.Cameras/BaseCamera.cs | 271 +++++++++++++++++++++++ Rs.Cameras/DaHengCameras.cs | 411 +++++++++++++++++++++++++++++++++++ Rs.Cameras/HikCamera.cs | 21 +- Rs.Cameras/Rs.Cameras.csproj | 5 + 4 files changed, 688 insertions(+), 20 deletions(-) create mode 100644 Rs.Cameras/BaseCamera.cs create mode 100644 Rs.Cameras/DaHengCameras.cs diff --git a/Rs.Cameras/BaseCamera.cs b/Rs.Cameras/BaseCamera.cs new file mode 100644 index 0000000..aaba166 --- /dev/null +++ b/Rs.Cameras/BaseCamera.cs @@ -0,0 +1,271 @@ +using HalconDotNet; +using MvCamCtrl.NET; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Rs.Cameras +{ + /// + /// 方向 + /// + public enum EDir + { + X, + Y + } + + public enum ETriggerSource + { + /// + /// 硬触发 + /// + Line0, + /// + /// 软触发 + /// + Software + } + + public abstract class BaseCameraInfo + { + public MyCamera Camera { get; set; } + public string CameraName { get; set; } + + public int Index { get; set; } + + private List Images; + + int apiResult = -1; + + public BaseCameraInfo() + { + Images = new List(); + } + + public void Deinit() + { + if (Camera != null) + { + Camera.MV_CC_CloseDevice_NET(); + Camera.MV_CC_DestroyDevice_NET(); + } + } + /// + /// 清除内存中的图片 + /// + public void ClearImage() + { + lock (this) + { + if (Images != null) + { + Images.Clear(); + } + } + + } + + /// + /// 取图 + /// + /// + public int Grab() + { + if (Camera != null) + return Camera.MV_CC_SetCommandValue_NET("TriggerSoftware"); + return -1; + } + + public int StartGrabbing() + { + if (Camera != null) + return Camera.MV_CC_StartGrabbing_NET(); + return -1; + } + + public void AddImage(HObject image) + { + lock (this) + { + Images.Add(image); + } + + } + + /// + /// 设置曝光时间 + /// + /// + /// + public int SetExposure(float timer) + { + if (Camera != null) + { + apiResult = Camera.MV_CC_SetEnumValue_NET("ExposureAuto", 0); + if (apiResult != 0) + { + + return apiResult; + } + apiResult = Camera.MV_CC_SetFloatValue_NET("ExposureTime", timer); + if (apiResult != 0) + { + return apiResult; + } + } + else + { + return -1; + } + return 0; + } + + /// + /// 设置相机增益 + /// + /// + /// + /// + public int SetGain(float gain) + { + if (Camera != null) + { + apiResult = Camera.MV_CC_SetEnumValue_NET("GainAuto", 0); + if (apiResult != 0) + { + return apiResult; + } + apiResult = Camera.MV_CC_SetFloatValue_NET("Gain", gain); + if (apiResult != 0) + { + return apiResult; + } + } + else + { + return -1; + } + return 0; + } + + /// + /// 设置相机的触发模式 + /// + /// + /// + /// + public int SetTrigger(ETriggerSource triggerSource = ETriggerSource.Line0) + { + if (Camera != null) + { + if (triggerSource == ETriggerSource.Line0) + { + apiResult = Camera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0); + if (apiResult != 0) + { + apiResult = Camera.MV_CC_SetEnumValue_NET("TriggerActivation", 0);//设置上升沿触发 + if (apiResult != 0) + { + return apiResult; + } + } + else + { + return apiResult; + } + } + else + { + apiResult = Camera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE); + if (apiResult != 0) + { + return apiResult; + } + } + } + else + { + return -1; + } + return 0; + } + + /// + /// 设置相机XY方向是否反转 + /// + /// + /// + /// + /// + public int SetReverse(EDir dir = EDir.X, bool reverse = false) + { + if (Camera != null) + { + if (dir == EDir.X) + { + apiResult = Camera.MV_CC_SetBoolValue_NET("ReverseX", reverse); + if (apiResult != 0) + return apiResult; + } + else + { + apiResult = Camera.MV_CC_SetBoolValue_NET("ReverseY", reverse); + if (apiResult != 0) + return apiResult; + } + } + else + { + return -1; + } + return 0; + } + + /// + /// 获取最后一张图片 + /// + /// + public HObject GetLastImage() + { + lock (this) + { + if (Images != null && Images.Count > 0) + { + return Images[Images.Count - 1]; + } + return null; + } + } + + /// + /// 获取所有的图片 + /// + /// + public List GetAllImages() + { + lock (this) + { + return Images; + } + } + + /// + /// 获取图片数量 + /// + /// + public int GetImageCount() + { + lock (this) + { + if (Images != null && Images.Count > 0) + { + return Images.Count; + } + return 0; + } + } + } +} diff --git a/Rs.Cameras/DaHengCameras.cs b/Rs.Cameras/DaHengCameras.cs new file mode 100644 index 0000000..bde357f --- /dev/null +++ b/Rs.Cameras/DaHengCameras.cs @@ -0,0 +1,411 @@ +using GxIAPINET; +using HalconDotNet; +using Rs.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Rs.Cameras +{ + + public class DaHengCameras + { + private static DaHengCameras instance; + public static DaHengCameras Instance + { + get + { + if (instance == null) + instance = new DaHengCameras(); + return instance; + } + } + + + private DaHengCameras() + { + } + + List cameraInfos = new List(); + + public List Init() + { + IGXFactory.GetInstance().Init(); + List infos = new List(); + IGXFactory.GetInstance().UpdateAllDeviceList(1000, infos); + if(infos!=null && infos.Count>0) + { + foreach (IGXDeviceInfo devInfo in infos) + { + try + { + string userID = string.Empty; + userID = devInfo.GetUserID(); + if(!string.IsNullOrEmpty(userID)) + { + IGXDevice dev = IGXFactory.GetInstance().OpenDeviceByUserID(userID, GX_ACCESS_MODE.GX_ACCESS_EXCLUSIVE); + IGXFeatureControl featureControl = dev.GetRemoteFeatureControl(); + IGXStream stream = dev.OpenStream(0); + IGXFeatureControl streamFeatureControl = stream.GetFeatureControl(); + + GX_DEVICE_CLASS_LIST objDeviceClass = dev.GetDeviceInfo().GetDeviceClass(); + if (GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_GEV == objDeviceClass) + { + // 判断设备是否支持流通道数据包功能 + if (true == featureControl.IsImplemented("GevSCPSPacketSize")) + { + // 获取当前网络环境的最优包长值 + uint nPacketSize = stream.GetOptimalPacketSize(); + // 将最优包长值设置为当前设备的流通道包长值 + featureControl.GetIntFeature("GevSCPSPacketSize").SetValue(nPacketSize); + } + } + featureControl.GetEnumFeature("AcquisitionMode").SetValue("Continuous"); + //m_objIGXStreamFeatureControl = stream.GetFeatureControl(); + DaHengCameraInfo camInfo = new DaHengCameraInfo(userID, dev, featureControl, stream, streamFeatureControl); + cameraInfos.Add(camInfo); + camInfo.SetTrigger(ETriggerSource.Line0); + camInfo.SetExposure(50); + camInfo.SetGain(10); + camInfo.StartGrabbing(); + MessageQueue.Instance.Insert($"Camera {userID} opened success"); + } + } + catch (Exception ex) + { + MessageQueue.Instance.Warn(ex.Message); + } + } + } + else + { + LogHelper.Debug($"cann't find camera"); + } + return cameraInfos; + } + + /// + /// 根据相机名称获取相机 + /// + /// + /// + public DaHengCameraInfo GetCameraInfo(string cameraName) + { + return cameraInfos.Where(c => c.CameraName == cameraName).FirstOrDefault(); + } + + + /// + /// 获取所有的相机 + /// + /// + public List GetAllCameras() + { + return cameraInfos; + } + + public void Deinit() + { + foreach (DaHengCameraInfo ci in cameraInfos) + { + ci.Deinit(); + } + } + } + + /// + /// 相机信息 + /// + public class DaHengCameraInfo + { + public IGXDevice Camera { get; set; } + /// + /// 属性控制 + /// + IGXFeatureControl featureControl; + IGXStream stream; + IGXFeatureControl streamFeatureControl; + public string CameraName { get; set; } + + public int Index { get; set; } + + private List Images; + + public event Action OnImageLoaded; + + + + public DaHengCameraInfo(string userID,IGXDevice _dev, IGXFeatureControl _featureControl, IGXStream _stream, IGXFeatureControl _streamFeatureControl) + { + CameraName = userID; + this.Camera = _dev; + this.featureControl = _featureControl; + this.stream = _stream; + streamFeatureControl = _streamFeatureControl; + Images = new List(); + } + + public void Deinit() + { + if (Camera != null) + { + featureControl.GetCommandFeature("AcquisitionStop").Execute(); + stream.StopGrab(); + //注销采集回调函数 + // m_objIGXStream.UnregisterCaptureCallback(); + stream.Close(); + stream = null; + featureControl = null; + Camera.Close(); + } + } + /// + /// 清除内存中的图片 + /// + public void ClearImage() + { + lock (this) + { + if (Images != null) + { + Images.Clear(); + } + } + + } + + /// + /// 取图 + /// + /// + public void Grab() + { + if (Camera != null) + { + featureControl.GetCommandFeature("TriggerSoftware").Execute(); + } + } + + public void StartGrabbing() + { + if (Camera != null && streamFeatureControl!=null && stream!=null) + { + streamFeatureControl.GetEnumFeature("StreamBufferHandlingMode").SetValue("OldestFirst"); + stream.RegisterCaptureCallback(this, CaptureCallbackPro); + stream.StartGrab(); + featureControl.GetCommandFeature("AcquisitionStart").Execute(); + } + } + + /// + /// 回调函数,用于获取图像信息和显示图像 + /// + /// 用户自定义传入参数 + /// 图像信息对象 + private void CaptureCallbackPro(object objUserParam, IFrameData objIFrameData) + { + try + { + TakePicResult result = new TakePicResult(); + LogHelper.Debug($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}-> 收到相机数据"); + result.TakeTime = DateTime.Now; + //string msg = $"{trayNum},{rowNum},{slotNum},{dt.ToString("yyyy-MM-dd HH:mm:ss fff")},{GetTimeStamp(dt,true)}\r\n"; + //File.AppendAllText("d://temp/test.csv", msg); + HObject image; + HOperatorSet.GenEmptyObj(out image); + image.Dispose(); + HOperatorSet.GenImage1(out image, "byte", objIFrameData.GetWidth(), objIFrameData.GetHeight(), objIFrameData.GetBuffer()); + result.SourceImage = image; + //HOperatorSet.WriteImage(image, "bmp", 0, $"d://temp//{trayNum}_{rowNum}_{slotNum}"); + //HOperatorSet.WriteImage(image, "tiff",0, "d://d"); + AddImage(result); + //GxSingleCam objGxSingleCam = objUserParam as GxSingleCam; + //objGxSingleCam.ImageShowAndSave(objIFrameData); + } + catch (Exception) + { + } + } + + public void AddImage(TakePicResult result) + { + lock (this) + { + Images.Add(result); + OnImageLoaded?.Invoke(result); + } + + } + + /// + /// 设置曝光时间 + /// + /// + /// + public void SetExposure(double timer) + { + if (Camera != null && featureControl != null) + { + featureControl.GetFloatFeature("ExposureTime").SetValue(timer); + } + } + + /// + /// 设置相机增益 + /// + /// + /// + /// + public void SetGain(double gain) + { + if (Camera != null && featureControl != null) + { + featureControl.GetFloatFeature("Gain").SetValue(gain); + } + } + + /// + /// 设置相机的触发模式 + /// + /// + /// + /// + public void SetTrigger(ETriggerSource triggerSource = ETriggerSource.Line0) + { + if (Camera != null) + { + if (triggerSource == ETriggerSource.Line0) + { + featureControl.GetEnumFeature("TriggerMode").SetValue("On"); + featureControl.GetEnumFeature("TriggerSource").SetValue(ETriggerSource.Line0.ToString()); + featureControl.GetEnumFeature("TriggerActivation").SetValue("RisingEdge"); + } + else + { + featureControl.GetEnumFeature("TriggerMode").SetValue("On"); + featureControl.GetEnumFeature("TriggerSource").SetValue(ETriggerSource.Software.ToString()); + } + } + } + + /// + /// 设置相机XY方向是否反转 + /// + /// + /// + /// + /// + public int SetReverse(EDir dir = EDir.X, bool reverse = false) + { + if (Camera != null) + { + if (dir == EDir.X) + { + featureControl.GetBoolFeature("ReverseX").SetValue(reverse); + } + else + { + featureControl.GetBoolFeature("ReverseY").SetValue(reverse); + } + } + else + { + return -1; + } + return 0; + } + + /// + /// 获取最后一张图片 + /// + /// + public TakePicResult GetLastImage() + { + lock (this) + { + if (Images != null && Images.Count > 0) + { + return Images[Images.Count - 1]; + } + return null; + } + } + + /// + /// 获取所有的图片 + /// + /// + public List GetAllImages() + { + lock (this) + { + return Images; + } + } + + /// + /// 获取图片数量 + /// + /// + public int GetImageCount() + { + lock (this) + { + if (Images != null && Images.Count > 0) + { + return Images.Count; + } + return 0; + } + } + + public static long GetTimeStamp(DateTime dt,bool ismilliseconds = false) + { + //时间戳 毫秒值 + //var time = new DateTimeOffset(DateTime.UtcNow); + var time = new DateTimeOffset(dt); + var timestamp = 0L; + if (ismilliseconds) + { + timestamp = time.ToUnixTimeMilliseconds(); + } + else + timestamp = time.ToUnixTimeSeconds(); + + return timestamp; + } + } + + /// + /// 取图结果类 + /// + public class TakePicResult + { + /// + /// 原图 + /// + public HObject SourceImage { get; set; } + /// + /// 相机返回图片时间 + /// + public DateTime TakeTime { get; set; } + /// + /// 二维码 + /// + public string SN { get; set; } + public TakePicResult() + { + + } + + public TakePicResult(HObject sourceImage, DateTime takeTime) + { + SourceImage = sourceImage; + TakeTime = takeTime; + } + } +} diff --git a/Rs.Cameras/HikCamera.cs b/Rs.Cameras/HikCamera.cs index ed3cc93..47c3587 100644 --- a/Rs.Cameras/HikCamera.cs +++ b/Rs.Cameras/HikCamera.cs @@ -11,26 +11,7 @@ using System.Threading.Tasks; namespace Rs.Cameras { - /// - /// 方向 - /// - public enum EDir - { - X, - Y - } - - public enum ETriggerSource - { - /// - /// 硬触发 - /// - Line0, - /// - /// 软触发 - /// - Software - } + public class HikCameras { private static HikCameras instance; diff --git a/Rs.Cameras/Rs.Cameras.csproj b/Rs.Cameras/Rs.Cameras.csproj index d302df5..ba0b5db 100644 --- a/Rs.Cameras/Rs.Cameras.csproj +++ b/Rs.Cameras/Rs.Cameras.csproj @@ -31,6 +31,9 @@ 4 + + bin\Debug\GxIAPINET.dll + ..\Rs.MotionPlat\bin\Debug\halcondotnet.dll @@ -47,6 +50,8 @@ + +