LB_VisionProcesses/Cameras/HRCamera.cs
@@ -1,6 +1,7 @@
using MVSDK_Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
@@ -22,6 +23,7 @@
        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(); // 帧缓存锁
@@ -84,13 +86,14 @@
                                typeof(IMVDefine.IMV_DeviceInfo));
                        
                        string cameraInfo = $"{deviceInfo.cameraName}[{deviceInfo.serialNumber}]";
                        cameraList.Add(cameraInfo);
                        cameraList.Add(cameraInfo);
                    }
                }
                else
                {
                    // 记录日志或抛出异常
                    throw new Exception($"枚举设备失败,错误码:{result}");
                    //throw new Exception($"枚举设备失败,错误码:{result}");
                    Debug.WriteLine("枚举设备失败!");
                }
            }
            catch (Exception ex)
@@ -113,10 +116,19 @@
        {
            try
            {
                // 如果相机已打开,先关闭
                if (_camera != null && _camera.IMV_IsOpen())
                // 确保彻底关闭和清理
                if (_camera != null)
                {
                    CloseDevice();
                    if (_camera.IMV_IsOpen())
                    {
                        _camera.IMV_Close();
                    }
                    if (_handleCreated)
                    {
                        _camera.IMV_DestroyHandle();
                        _handleCreated = false;
                    }
                }
                
                // 枚举设备并匹配SN
@@ -143,6 +155,7 @@
                {
                    throw new Exception($"创建设备句柄失败,错误码:{result}");
                }
                _handleCreated = true;
                
                // 打开设备
                result = _camera.IMV_Open();
@@ -152,7 +165,7 @@
                }
                
                // 设置设备属性
                SN = SN;
                this.SN = SN;
                isGrabbing = false;
                
                // 设置缓存个数为8
@@ -192,6 +205,13 @@
                    {
                        System.Diagnostics.Debug.WriteLine($"关闭相机失败,错误码:{result}");
                    }
                }
                // 销毁句柄
                if (_handleCreated)
                {
                    _camera.IMV_DestroyHandle();
                    _handleCreated = false;
                }
                
                // 释放资源
@@ -519,27 +539,27 @@
                    throw new Exception("相机未打开");
                }
                
                string gainFeature = _camera.IMV_FeatureIsValid("Gain") ? "Gain" : "GainRaw";
                // 验证增益范围
                double minGain = 0, maxGain = 0;
                int result = _camera.IMV_GetDoubleFeatureMin("GainRaw", ref minGain);
                int result = _camera.IMV_GetDoubleFeatureMin(gainFeature, ref minGain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取增益最小值失败,错误码:{result}");
                }
                
                result = _camera.IMV_GetDoubleFeatureMax("GainRaw", ref maxGain);
                result = _camera.IMV_GetDoubleFeatureMax(gainFeature, ref maxGain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取增益最大值失败,错误码:{result}");
                }
                
                if (gain < minGain || gain > maxGain)
                {
                    throw new Exception($"增益值超出范围,有效范围:{minGain} - {maxGain}");
                }
                if (gain < minGain) gain = minGain;
                if (gain > maxGain) gain = maxGain;
                
                // 设置增益
                result = _camera.IMV_SetDoubleFeatureValue("GainRaw", gain);
                result = _camera.IMV_SetDoubleFeatureValue(gainFeature, gain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置增益失败,错误码:{result}");
@@ -570,7 +590,8 @@
                    throw new Exception("相机未打开");
                }
                
                int result = _camera.IMV_GetDoubleFeatureValue("GainRaw", ref gain);
                string gainFeature = _camera.IMV_FeatureIsValid("Gain") ? "Gain" : "GainRaw";
                int result = _camera.IMV_GetDoubleFeatureValue(gainFeature, ref gain);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
@@ -580,46 +601,301 @@
            }
        }
        
        // 其他参数设置方法类似,这里省略部分实现...
        /// <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 辅助方法
        #region 采集和转换辅助方法
        /// <summary>
        /// 图像采集线程处理函数
        /// </summary>
        private void GrabThreadProc()
        {
            IMVDefine.IMV_Frame frame = new IMVDefine.IMV_Frame();
            while (_threadRunning)
            {
                IMVDefine.IMV_Frame frame = new IMVDefine.IMV_Frame();
                try
                {
                    // 获取图像帧
                    int result = _camera.IMV_GetFrame(ref frame, 100);
                    int result = _camera.IMV_GetFrame(ref frame, 1000);
                    if (result == IMVDefine.IMV_OK)
                    {
                        // 处理图像帧
                        ProcessFrame(frame);
                    }
                    else if (result != 0x80000001) // 超时错误代码(常见值)
                    else
                    {
                        // 非超时错误
                        System.Diagnostics.Debug.WriteLine($"获取图像帧失败,错误码:{result}");
                        // 即使获取失败,也尝试释放帧,防止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>
@@ -630,26 +906,29 @@
            {
                // 将图像数据转换为Bitmap
                Bitmap bitmap = ConvertFrameToBitmap(frame);
                if (bitmap != null)
                {
                    // 触发图像采集事件
                    CameraEventArgs args = new CameraEventArgs(SN, bitmap);
                    ImageGrabbed?.Invoke(this, args);
                    // 更新回调图像
                    CallBackImg = bitmap;
                }
                // 释放帧
                _camera.IMV_ReleaseFrame(ref frame);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"处理图像帧失败:{ex.Message}");
            }
            finally
            {
                // 确保无论如何都释放帧,防止缓存占满
                var tempFrame = frame;
                _camera.IMV_ReleaseFrame(ref tempFrame);
            }
        }
        /// <summary>
        /// 将图像帧转换为Bitmap
        /// </summary>
@@ -660,7 +939,7 @@
            try
            {
                Bitmap bitmap = null;
                switch (frame.frameInfo.pixelFormat)
                {
                    case IMVDefine.IMV_EPixelType.gvspPixelMono8:
@@ -674,7 +953,7 @@
                        bitmap = ConvertToBGR8(frame);
                        break;
                }
                return bitmap;
            }
            catch (Exception ex)
@@ -683,14 +962,14 @@
                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++)
@@ -698,39 +977,39 @@
                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>
@@ -749,10 +1028,10 @@
                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);
@@ -767,26 +1046,26 @@
                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>
@@ -804,7 +1083,7 @@
                _ => "Software"
            };
        }
        /// <summary>
        /// 将字符串转换为触发源枚举
        /// </summary>
@@ -822,72 +1101,9 @@
                _ => TriggerSource.Software
            };
        }
        #endregion
        #region 未实现的抽象方法(简化版实现)
        public override bool SetTriggerPolarity(TriggerPolarity polarity)
        {
            // 华睿相机可能不支持该功能,返回成功
            return true;
        }
        public override bool GetTriggerPolarity(out TriggerPolarity polarity)
        {
            polarity = TriggerPolarity.RisingEdge;
            return true;
        }
        public override bool SetTriggerFliter(double flitertime)
        {
            // 暂不支持
            return true;
        }
        public override bool GetTriggerFliter(out double flitertime)
        {
            flitertime = 0;
            return true;
        }
        public override bool SetTriggerDelay(double delay)
        {
            // 暂不支持
            return true;
        }
        public override bool GetTriggerDelay(out double delay)
        {
            delay = 0;
            return true;
        }
        public override bool SetLineMode(IOLines line, LineMode mode)
        {
            // 暂不支持
            return true;
        }
        public override bool SetLineStatus(IOLines line, LineStatus linestatus)
        {
            // 暂不支持
            return true;
        }
        public override bool GetLineStatus(IOLines line, out LineStatus lineStatus)
        {
            lineStatus = LineStatus.Low;
            return true;
        }
        public override bool AutoBalanceWhite()
        {
            // 暂不支持自动白平衡
            return true;
        }
        #endregion
        #region IDisposable实现