C3032
2025-12-23 7c2a646ce89a06d0bfbb16f993d4ae3734f1de9c
LB_VisionProcesses/Cameras/HRCamera.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1136 @@
using MVSDK_Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace LB_VisionProcesses.Cameras
{
    /// <summary>
    /// åŽç¿2D工业相机实现类
    /// åŸºäºŽMVSDK_Net SDK封装
    /// </summary>
    public class HRCamera : BaseCamera
    {
        #region ç§æœ‰å­—段
        private MyCamera _camera; // åŽç¿ç›¸æœºè®¾å¤‡å¯¹è±¡
        private Thread _grabThread; // å›¾åƒé‡‡é›†çº¿ç¨‹
        private bool _isGrabbing; // é‡‡é›†çŠ¶æ€æ ‡å¿—
        private bool _threadRunning; // çº¿ç¨‹è¿è¡Œæ ‡å¿—
        private bool _handleCreated = false; // å¥æŸ„是否已创建
        private Thread _callbackThread; // å›žè°ƒå¤„理线程
        private List<IMVDefine.IMV_Frame> _frameList; // å›¾åƒç¼“存列表
        private readonly object _frameLock = new object(); // å¸§ç¼“存锁
        // CopyMemory API声明
        [System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
        #endregion
        #region æž„造函数和析构函数
        /// <summary>
        /// æž„造函数
        /// </summary>
        public HRCamera()
        {
            _camera = new MyCamera();
            _frameList = new List<IMVDefine.IMV_Frame>();
            Brand = CameraBrand.HRCamera;
            _isGrabbing = false;
            _threadRunning = false;
        }
        /// <summary>
        /// æžæž„函数
        /// </summary>
        ~HRCamera()
        {
            Dispose(false);
        }
        #endregion
        #region è®¾å¤‡ç®¡ç†æ“ä½œ
        /// <summary>
        /// èŽ·å–ç›¸æœºSN枚举列表
        /// </summary>
        /// <returns>相机SN列表</returns>
        public override List<string> GetListEnum()
        {
            List<string> cameraList = new List<string>();
            try
            {
                // æžšä¸¾æ‰€æœ‰è®¾å¤‡
                IMVDefine.IMV_DeviceList deviceList = new IMVDefine.IMV_DeviceList();
                IMVDefine.IMV_EInterfaceType interfaceType = IMVDefine.IMV_EInterfaceType.interfaceTypeAll;
                int result = MyCamera.IMV_EnumDevices(ref deviceList, (uint)interfaceType);
                if (result == IMVDefine.IMV_OK && deviceList.nDevNum > 0)
                {
                    for (int i = 0; i < deviceList.nDevNum; i++)
                    {
                        IMVDefine.IMV_DeviceInfo deviceInfo = (IMVDefine.IMV_DeviceInfo)
                            Marshal.PtrToStructure(
                                deviceList.pDevInfo + Marshal.SizeOf(typeof(IMVDefine.IMV_DeviceInfo)) * i,
                                typeof(IMVDefine.IMV_DeviceInfo));
                        string cameraInfo = $"{deviceInfo.cameraName}[{deviceInfo.serialNumber}]";
                        cameraList.Add(cameraInfo);
                    }
                }
                else
                {
                    // è®°å½•日志或抛出异常
                    //throw new Exception($"枚举设备失败,错误码:{result}");
                    Debug.WriteLine("枚举设备失败!");
                }
            }
            catch (Exception ex)
            {
                // è®°å½•错误日志
                System.Diagnostics.Debug.WriteLine($"获取相机列表失败:{ex.Message}");
                throw;
            }
            return cameraList;
        }
        /// <summary>
        /// åˆå§‹åŒ–相机设备
        /// </summary>
        /// <param name="SN">相机序列号</param>
        /// <param name="Handle">窗口句柄(可选)</param>
        /// <returns>初始化是否成功</returns>
        public override bool InitDevice(string SN, object Handle = null)
        {
            try
            {
                // ç¡®ä¿å½»åº•关闭和清理
                if (_camera != null)
                {
                    if (_camera.IMV_IsOpen())
                    {
                        _camera.IMV_Close();
                    }
                    if (_handleCreated)
                    {
                        _camera.IMV_DestroyHandle();
                        _handleCreated = false;
                    }
                }
                // æžšä¸¾è®¾å¤‡å¹¶åŒ¹é…SN
                List<string> cameraList = GetListEnum();
                int cameraIndex = -1;
                for (int i = 0; i < cameraList.Count; i++)
                {
                    if (cameraList[i].Contains(SN))
                    {
                        cameraIndex = i;
                        break;
                    }
                }
                if (cameraIndex == -1)
                {
                    throw new Exception($"未找到序列号为 {SN} çš„相机");
                }
                // åˆ›å»ºè®¾å¤‡å¥æŸ„
                int result = _camera.IMV_CreateHandle(IMVDefine.IMV_ECreateHandleMode.modeByIndex, cameraIndex);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"创建设备句柄失败,错误码:{result}");
                }
                _handleCreated = true;
                // æ‰“开设备
                result = _camera.IMV_Open();
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"打开相机失败,错误码:{result}");
                }
                // è®¾ç½®è®¾å¤‡å±žæ€§
                this.SN = SN;
                isGrabbing = false;
                // è®¾ç½®ç¼“存个数为8
                _camera.IMV_SetBufferCount(8);
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"初始化相机失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// å…³é—­ç›¸æœºè®¾å¤‡
        /// </summary>
        /// <returns>关闭是否成功</returns>
        public override bool CloseDevice()
        {
            try
            {
                if (_camera == null)
                    return true;
                // åœæ­¢é‡‡é›†
                if (_camera.IMV_IsGrabbing())
                {
                    StopGrabbing();
                }
                // å…³é—­è®¾å¤‡
                if (_camera.IMV_IsOpen())
                {
                    int result = _camera.IMV_Close();
                    if (result != IMVDefine.IMV_OK)
                    {
                        System.Diagnostics.Debug.WriteLine($"关闭相机失败,错误码:{result}");
                    }
                }
                // é”€æ¯å¥æŸ„
                if (_handleCreated)
                {
                    _camera.IMV_DestroyHandle();
                    _handleCreated = false;
                }
                // é‡Šæ”¾èµ„源
                _isGrabbing = false;
                isGrabbing = false;
                // æ¸…理帧缓存
                lock (_frameLock)
                {
                    foreach (var frame in _frameList)
                    {
                        var tempFrame = frame; // åˆ›å»ºä¸´æ—¶å˜é‡
                        _camera.IMV_ReleaseFrame(ref tempFrame);
                    }
                    _frameList.Clear();
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"关闭相机失败:{ex.Message}");
                return false;
            }
        }
        #endregion
        #region å›¾åƒé‡‡é›†æ“ä½œ
        /// <summary>
        /// å¼€å§‹å›¾åƒé‡‡é›†
        /// </summary>
        /// <returns>采集启动是否成功</returns>
        public override bool StartGrabbing()
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // åœæ­¢çŽ°æœ‰é‡‡é›†
                if (_isGrabbing)
                {
                    StopGrabbing();
                }
                // å¯åЍ采集
                int result = _camera.IMV_StartGrabbing();
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"启动采集失败,错误码:{result}");
                }
                _isGrabbing = true;
                isGrabbing = true;
                // å¯åŠ¨é‡‡é›†çº¿ç¨‹
                _threadRunning = true;
                _grabThread = new Thread(GrabThreadProc);
                _grabThread.IsBackground = true;
                _grabThread.Start();
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"启动采集失败:{ex.Message}");
                _isGrabbing = false;
                isGrabbing = false;
                return false;
            }
        }
        /// <summary>
        /// åœæ­¢å›¾åƒé‡‡é›†
        /// </summary>
        /// <returns>停止是否成功</returns>
        public override bool StopGrabbing()
        {
            try
            {
                if (_camera == null || !_isGrabbing)
                    return true;
                // åœæ­¢çº¿ç¨‹
                _threadRunning = false;
                if (_grabThread != null && _grabThread.IsAlive)
                {
                    _grabThread.Join(1000);
                    _grabThread = null;
                }
                // åœæ­¢é‡‡é›†
                int result = _camera.IMV_StopGrabbing();
                if (result != IMVDefine.IMV_OK)
                {
                    System.Diagnostics.Debug.WriteLine($"停止采集失败,错误码:{result}");
                }
                _isGrabbing = false;
                isGrabbing = false;
                // æ¸…理缓存
                lock (_frameLock)
                {
                    foreach (var frame in _frameList)
                    {
                        var tempFrame = frame; // åˆ›å»ºä¸´æ—¶å˜é‡
                        _camera.IMV_ReleaseFrame(ref tempFrame);
                    }
                    _frameList.Clear();
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"停止采集失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// æ‰§è¡Œè½¯è§¦å‘
        /// </summary>
        /// <returns>触发是否成功</returns>
        public override bool SoftTrigger()
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                int result = _camera.IMV_ExecuteCommandFeature("TriggerSoftware");
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"软触发失败:{ex.Message}");
                return false;
            }
        }
        #endregion
        #region å‚数设置和获取
        /// <summary>
        /// è®¾ç½®è§¦å‘模式
        /// </summary>
        /// <param name="mode">触发模式</param>
        /// <param name="source">触发源</param>
        /// <returns>设置是否成功</returns>
        public override bool SetTriggerMode(TriggerMode mode, TriggerSource source = TriggerSource.Line0)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // è®¾ç½®è§¦å‘模式
                string triggerMode = mode == TriggerMode.On ? "On" : "Off";
                int result = _camera.IMV_SetEnumFeatureSymbol("TriggerMode", triggerMode);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置触发模式失败,错误码:{result}");
                }
                // è®¾ç½®è§¦å‘源
                if (mode == TriggerMode.On)
                {
                    string triggerSource = GetTriggerSourceString(source);
                    result = _camera.IMV_SetEnumFeatureSymbol("TriggerSource", triggerSource);
                    if (result != IMVDefine.IMV_OK)
                    {
                        throw new Exception($"设置触发源失败,错误码:{result}");
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发模式失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘æ¨¡å¼
        /// </summary>
        /// <param name="mode">触发模式</param>
        /// <param name="source">触发源</param>
        /// <returns>获取是否成功</returns>
        public override bool GetTriggerMode(out TriggerMode mode, out TriggerSource source)
        {
            mode = TriggerMode.Off;
            source = TriggerSource.Software;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // èŽ·å–è§¦å‘æ¨¡å¼
                IMVDefine.IMV_String triggerMode = new IMVDefine.IMV_String();
                int result = _camera.IMV_GetEnumFeatureSymbol("TriggerMode", ref triggerMode);
                if (result == IMVDefine.IMV_OK)
                {
                    mode = triggerMode.str == "On" ? TriggerMode.On : TriggerMode.Off;
                }
                // èŽ·å–è§¦å‘æº
                IMVDefine.IMV_String triggerSource = new IMVDefine.IMV_String();
                result = _camera.IMV_GetEnumFeatureSymbol("TriggerSource", ref triggerSource);
                if (result == IMVDefine.IMV_OK)
                {
                    source = GetTriggerSourceFromString(triggerSource.str);
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发模式失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®æ›å…‰æ—¶é—´
        /// </summary>
        /// <param name="value">曝光时间(微秒)</param>
        /// <returns>设置是否成功</returns>
        public override bool SetExpouseTime(double value)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // éªŒè¯æ›å…‰æ—¶é—´èŒƒå›´
                double minExp = 0, maxExp = 0;
                int result = _camera.IMV_GetDoubleFeatureMin("ExposureTime", ref minExp);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取曝光时间最小值失败,错误码:{result}");
                }
                result = _camera.IMV_GetDoubleFeatureMax("ExposureTime", ref maxExp);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取曝光时间最大值失败,错误码:{result}");
                }
                if (value < minExp || value > maxExp)
                {
                    throw new Exception($"曝光时间超出范围,有效范围:{minExp} - {maxExp}");
                }
                // è®¾ç½®æ›å…‰æ—¶é—´
                result = _camera.IMV_SetDoubleFeatureValue("ExposureTime", value);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置曝光时间失败,错误码:{result}");
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置曝光时间失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–æ›å…‰æ—¶é—´
        /// </summary>
        /// <param name="value">曝光时间</param>
        /// <returns>获取是否成功</returns>
        public override bool GetExpouseTime(out double value)
        {
            value = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                int result = _camera.IMV_GetDoubleFeatureValue("ExposureTime", ref value);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取曝光时间失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®å¢žç›Š
        /// </summary>
        /// <param name="gain">增益值</param>
        /// <returns>设置是否成功</returns>
        public override bool SetGain(double gain)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                string gainFeature = _camera.IMV_FeatureIsValid("Gain") ? "Gain" : "GainRaw";
                // éªŒè¯å¢žç›ŠèŒƒå›´
                double minGain = 0, maxGain = 0;
                int result = _camera.IMV_GetDoubleFeatureMin(gainFeature, ref minGain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取增益最小值失败,错误码:{result}");
                }
                result = _camera.IMV_GetDoubleFeatureMax(gainFeature, ref maxGain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取增益最大值失败,错误码:{result}");
                }
                if (gain < minGain) gain = minGain;
                if (gain > maxGain) gain = maxGain;
                // è®¾ç½®å¢žç›Š
                result = _camera.IMV_SetDoubleFeatureValue(gainFeature, gain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置增益失败,错误码:{result}");
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置增益失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–å¢žç›Šå€¼
        /// </summary>
        /// <param name="gain">增益值</param>
        /// <returns>获取是否成功</returns>
        public override bool GetGain(out double gain)
        {
            gain = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                string gainFeature = _camera.IMV_FeatureIsValid("Gain") ? "Gain" : "GainRaw";
                int result = _camera.IMV_GetDoubleFeatureValue(gainFeature, ref gain);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取增益失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®è§¦å‘极性
        /// </summary>
        /// <param name="polarity">触发极性</param>
        /// <returns>是否成功</returns>
        public override bool SetTriggerPolarity(TriggerPolarity polarity)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                string activation = (polarity == TriggerPolarity.RisingEdge || polarity == TriggerPolarity.HighLevel)
                    ? "RisingEdge" : "FallingEdge";
                int result = _camera.IMV_SetEnumFeatureSymbol("TriggerActivation", activation);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发极性失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘æžæ€§
        /// </summary>
        /// <param name="polarity">触发极性</param>
        /// <returns>是否成功</returns>
        public override bool GetTriggerPolarity(out TriggerPolarity polarity)
        {
            polarity = TriggerPolarity.RisingEdge;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                IMVDefine.IMV_String activation = new IMVDefine.IMV_String();
                int result = _camera.IMV_GetEnumFeatureSymbol("TriggerActivation", ref activation);
                if (result == IMVDefine.IMV_OK)
                {
                    polarity = activation.str == "RisingEdge" ? TriggerPolarity.RisingEdge : TriggerPolarity.FallingEdge;
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发极性失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®è§¦å‘滤波时间 (us)
        /// </summary>
        public override bool SetTriggerFliter(double flitertime)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                // åŽç¿ç›¸æœºé€šå¸¸ä½¿ç”¨ LineDebouncerTime æŽ§åˆ¶æ»¤æ³¢
                if (_camera.IMV_FeatureIsValid("LineDebouncerTime"))
                {
                    int result = _camera.IMV_SetDoubleFeatureValue("LineDebouncerTime", flitertime);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发滤波失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘æ»¤æ³¢æ—¶é—´ (us)
        /// </summary>
        public override bool GetTriggerFliter(out double flitertime)
        {
            flitertime = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("LineDebouncerTime"))
                {
                    int result = _camera.IMV_GetDoubleFeatureValue("LineDebouncerTime", ref flitertime);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发滤波失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®è§¦å‘å»¶æ—¶ (us)
        /// </summary>
        public override bool SetTriggerDelay(double delay)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("TriggerDelay"))
                {
                    int result = _camera.IMV_SetDoubleFeatureValue("TriggerDelay", delay);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发延时失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘å»¶æ—¶ (us)
        /// </summary>
        public override bool GetTriggerDelay(out double delay)
        {
            delay = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("TriggerDelay"))
                {
                    int result = _camera.IMV_GetDoubleFeatureValue("TriggerDelay", ref delay);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发延时失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®ä¿¡å·çº¿æ¨¡å¼
        /// </summary>
        public override bool SetLineMode(IOLines line, LineMode mode)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                // é€‰æ‹©çº¿è·¯
                int result = _camera.IMV_SetEnumFeatureSymbol("LineSelector", line.ToString());
                if (result != IMVDefine.IMV_OK) return false;
                // è®¾ç½®æ¨¡å¼
                string lineMode = mode == LineMode.Input ? "Input" : "Output";
                result = _camera.IMV_SetEnumFeatureSymbol("LineMode", lineMode);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置信号线模式失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®ä¿¡å·çº¿ç”µå¹³çŠ¶æ€
        /// </summary>
        public override bool SetLineStatus(IOLines line, LineStatus linestatus)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                // ä»…对输出线路有效
                int result = _camera.IMV_SetEnumFeatureSymbol("LineSelector", line.ToString());
                if (result != IMVDefine.IMV_OK) return false;
                bool status = linestatus == LineStatus.Hight;
                result = _camera.IMV_SetBoolFeatureValue("UserOutputValue", status);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置信号线状态失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–ä¿¡å·çº¿ç”µå¹³çŠ¶æ€
        /// </summary>
        public override bool GetLineStatus(IOLines line, out LineStatus lineStatus)
        {
            lineStatus = LineStatus.Low;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                int result = _camera.IMV_SetEnumFeatureSymbol("LineSelector", line.ToString());
                if (result != IMVDefine.IMV_OK) return false;
                bool status = false;
                result = _camera.IMV_GetBoolFeatureValue("LineStatus", ref status);
                if (result == IMVDefine.IMV_OK)
                {
                    lineStatus = status ? LineStatus.Hight : LineStatus.Low;
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取信号线状态失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è‡ªåŠ¨ç™½å¹³è¡¡
        /// </summary>
        public override bool AutoBalanceWhite()
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("BalanceWhiteAuto"))
                {
                    int result = _camera.IMV_SetEnumFeatureSymbol("BalanceWhiteAuto", "Once");
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"自动白平衡失败:{ex.Message}");
                return false;
            }
        }
        #endregion
        #region é‡‡é›†å’Œè½¬æ¢è¾…助方法
        /// <summary>
        /// å›¾åƒé‡‡é›†çº¿ç¨‹å¤„理函数
        /// </summary>
        private void GrabThreadProc()
        {
            while (_threadRunning)
            {
                IMVDefine.IMV_Frame frame = new IMVDefine.IMV_Frame();
                try
                {
                    // èŽ·å–å›¾åƒå¸§
                    int result = _camera.IMV_GetFrame(ref frame, 1000);
                    if (result == IMVDefine.IMV_OK)
                    {
                        // å¤„理图像帧
                        ProcessFrame(frame);
                    }
                    else
                    {
                        // å³ä½¿èŽ·å–å¤±è´¥ï¼Œä¹Ÿå°è¯•é‡Šæ”¾å¸§ï¼Œé˜²æ­¢SDK内部缓存泄露
                        // æ³¨æ„ï¼šframe是每次新建的,如果GetFrame没填充,这里释放应该是安全的(视SDK实现而定)
                        var tempFrame = frame;
                        _camera.IMV_ReleaseFrame(ref tempFrame);
                        if ((uint)result != 0x80000001 && result != -119 && result != -102) // è¶…时错误代码
                        {
                            // éžè¶…时错误
                            System.Diagnostics.Debug.WriteLine($"获取图像帧失败,错误码:{result}");
                            Thread.Sleep(10); // å‡ºé”™æ—¶ç¨ä½œç­‰å¾…
                        }
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"采集线程异常:{ex.Message}");
                    Thread.Sleep(10);
                }
                Thread.Sleep(1);
            }
        }
        /// <summary>
        /// å¤„理图像帧
        /// </summary>
        /// <param name="frame">图像帧</param>
        private void ProcessFrame(IMVDefine.IMV_Frame frame)
        {
            try
            {
                // å°†å›¾åƒæ•°æ®è½¬æ¢ä¸ºBitmap
                Bitmap bitmap = ConvertFrameToBitmap(frame);
                if (bitmap != null)
                {
                    // è§¦å‘图像采集事件
                    CameraEventArgs args = new CameraEventArgs(SN, bitmap);
                    ImageGrabbed?.Invoke(this, args);
                    // æ›´æ–°å›žè°ƒå›¾åƒ
                    CallBackImg = bitmap;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"处理图像帧失败:{ex.Message}");
            }
            finally
            {
                // ç¡®ä¿æ— è®ºå¦‚何都释放帧,防止缓存占满
                var tempFrame = frame;
                _camera.IMV_ReleaseFrame(ref tempFrame);
            }
        }
        /// <summary>
        /// å°†å›¾åƒå¸§è½¬æ¢ä¸ºBitmap
        /// </summary>
        /// <param name="frame">图像帧</param>
        /// <returns>Bitmap对象</returns>
        private Bitmap ConvertFrameToBitmap(IMVDefine.IMV_Frame frame)
        {
            try
            {
                Bitmap bitmap = null;
                switch (frame.frameInfo.pixelFormat)
                {
                    case IMVDefine.IMV_EPixelType.gvspPixelMono8:
                        bitmap = CreateMono8Bitmap(frame);
                        break;
                    case IMVDefine.IMV_EPixelType.gvspPixelBGR8:
                        bitmap = CreateBgr8Bitmap(frame);
                        break;
                    default:
                        // å…¶ä»–格式需要转换
                        bitmap = ConvertToBGR8(frame);
                        break;
                }
                return bitmap;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"图像格式转换失败:{ex.Message}");
                return null;
            }
        }
        /// <summary>
        /// åˆ›å»ºMono8格式Bitmap
        /// </summary>
        private Bitmap CreateMono8Bitmap(IMVDefine.IMV_Frame frame)
        {
            Bitmap bitmap = new Bitmap((int)frame.frameInfo.width, (int)frame.frameInfo.height, PixelFormat.Format8bppIndexed);
            // è®¾ç½®ç°åº¦è°ƒè‰²æ¿
            ColorPalette palette = bitmap.Palette;
            for (int i = 0; i < 256; i++)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            bitmap.Palette = palette;
            // å¤åˆ¶å›¾åƒæ•°æ®
            BitmapData bmpData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.WriteOnly,
                bitmap.PixelFormat);
            // ä½¿ç”¨CopyMemory API进行内存复制
            CopyMemory(bmpData.Scan0, frame.pData, (uint)Math.Min(frame.frameInfo.size, (uint)(bmpData.Stride * bitmap.Height)));
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
        /// <summary>
        /// åˆ›å»ºBGR8格式Bitmap
        /// </summary>
        private Bitmap CreateBgr8Bitmap(IMVDefine.IMV_Frame frame)
        {
            Bitmap bitmap = new Bitmap((int)frame.frameInfo.width, (int)frame.frameInfo.height, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.WriteOnly,
                bitmap.PixelFormat);
            // ä½¿ç”¨CopyMemory API进行内存复制
            CopyMemory(bmpData.Scan0, frame.pData, (uint)Math.Min(frame.frameInfo.size, (uint)(bmpData.Stride * bitmap.Height)));
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
        /// <summary>
        /// è½¬æ¢ä¸ºBGR8格式
        /// </summary>
        private Bitmap ConvertToBGR8(IMVDefine.IMV_Frame frame)
        {
            IMVDefine.IMV_PixelConvertParam convertParam = new IMVDefine.IMV_PixelConvertParam
            {
                nWidth = frame.frameInfo.width,
                nHeight = frame.frameInfo.height,
                ePixelFormat = frame.frameInfo.pixelFormat,
                pSrcData = frame.pData,
                nSrcDataLen = frame.frameInfo.size,
                nPaddingX = frame.frameInfo.paddingX,
                nPaddingY = frame.frameInfo.paddingY,
                eBayerDemosaic = IMVDefine.IMV_EBayerDemosaic.demosaicBilinear,
                eDstPixelFormat = IMVDefine.IMV_EPixelType.gvspPixelBGR8,
                nDstBufSize = frame.frameInfo.width * frame.frameInfo.height * 3
            };
            IntPtr dstBuffer = Marshal.AllocHGlobal((int)convertParam.nDstBufSize);
            convertParam.pDstBuf = dstBuffer;
            try
            {
                int result = _camera.IMV_PixelConvert(ref convertParam);
                if (result == IMVDefine.IMV_OK)
                {
                    return CreateBgr8BitmapFromBuffer(dstBuffer, frame.frameInfo.width, frame.frameInfo.height);
                }
                return null;
            }
            finally
            {
                Marshal.FreeHGlobal(dstBuffer);
            }
        }
        /// <summary>
        /// ä»Žç¼“冲区创建BGR8 Bitmap
        /// </summary>
        private Bitmap CreateBgr8BitmapFromBuffer(IntPtr buffer, uint width, uint height)
        {
            Bitmap bitmap = new Bitmap((int)width, (int)height, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.WriteOnly,
                bitmap.PixelFormat);
            // ä½¿ç”¨CopyMemory API进行安全的内存复制
            CopyMemory(bmpData.Scan0, buffer, (uint)(width * height * 3));
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
        /// <summary>
        /// å°†è§¦å‘源枚举转换为字符串
        /// </summary>
        private string GetTriggerSourceString(TriggerSource source)
        {
            return source switch
            {
                TriggerSource.Software => "Software",
                TriggerSource.Line0 => "Line0",
                TriggerSource.Line1 => "Line1",
                TriggerSource.Line2 => "Line2",
                TriggerSource.Line3 => "Line3",
                TriggerSource.Line4 => "Line4",
                TriggerSource.Line5 => "Line5",
                _ => "Software"
            };
        }
        /// <summary>
        /// å°†å­—符串转换为触发源枚举
        /// </summary>
        private TriggerSource GetTriggerSourceFromString(string source)
        {
            return source switch
            {
                "Software" => TriggerSource.Software,
                "Line0" => TriggerSource.Line0,
                "Line1" => TriggerSource.Line1,
                "Line2" => TriggerSource.Line2,
                "Line3" => TriggerSource.Line3,
                "Line4" => TriggerSource.Line4,
                "Line5" => TriggerSource.Line5,
                _ => TriggerSource.Software
            };
        }
        #endregion
        #region IDisposable实现
        private bool _disposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    // é‡Šæ”¾æ‰˜ç®¡èµ„源
                }
                // é‡Šæ”¾éžæ‰˜ç®¡èµ„源
                CloseDevice();
                _disposed = true;
            }
        }
        public override void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}