C3032
2026-01-08 116ed6b584bbdb40c5b65e7cb57e039b6ae57800
LB_VisionProcesses/Cameras/LBCameras/LBCamera.cs
@@ -30,6 +30,12 @@
        private readonly object _bufferLock = new object();
        private int _currentLineCount = 0;
        // 显示句柄和函数(与LLSystem示例保持一致)
        private IntPtr _lightPic = IntPtr.Zero;
        private IntPtr _deepPic = IntPtr.Zero;
        private IntPtr _pointPic = IntPtr.Zero;
        private IntPtr _outlinePic = IntPtr.Zero;
        public LBCamera()
        {
            Brand = CameraBrand.LBCamera;
@@ -93,7 +99,7 @@
                if (!found)
                {
                    // 如果没找到但 sn 本身看起来像 IP,尝试直接连接(兼容旧逻辑)
                    // 如果没找到但 sn 本身看起来像 IP,尝试直接连接
                    if (System.Net.IPAddress.TryParse(sn, out _))
                    {
                        targetIp = sn;
@@ -123,7 +129,7 @@
                    _acquisitionCallback = new AcquisitionCallbackZA(OnLineReceived);
                    _acquisitionCompletedCallback = new AcquisitionCompletedCallback(OnAcquisitionCompleted);
                    
                    PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, _acquisitionCallback, IntPtr.Zero);
                    //PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, _acquisitionCallback, IntPtr.Zero);
                    PHM6000Profiler.RegisterAcquisitionCompletedCallback(_cameraHandle, _acquisitionCompletedCallback, IntPtr.Zero);
                    
                    return true;
@@ -197,6 +203,63 @@
                _currentLineCount = 0;
            }
            // 禁用行回调
            PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, IntPtr.Zero, IntPtr.Zero);
            // 设置采集模式:1=扫描模式,1=连续模式
            PHM6000Profiler.SetAcquisitionMode(_cameraHandle, 1, 1);
            int result = PHM6000Profiler.StartAcquisition(_cameraHandle, 0, 0, 0.0);
            if (result == 0)
            {
                isGrabbing = true;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 单次采集模式(适用于线扫相机)
        /// 设置采集模式为扫描模式,单次触发
        /// </summary>
        public bool StartSingleGrab()
        {
            if (!_isConnected) return false;
            lock (_bufferLock)
            {
                _lineDataBuffer.Clear();
                _currentLineCount = 0;
            }
            // 禁用行回调(与示例一致)
            PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, IntPtr.Zero, IntPtr.Zero);
            // 设置采集模式:1=扫描模式,0=单次模式
            PHM6000Profiler.SetAcquisitionMode(_cameraHandle, 1, 0);
            int result = PHM6000Profiler.StartAcquisition(_cameraHandle, 0, 0, 0.0);
            if (result == 0)
            {
                isGrabbing = true;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 连续采集模式(适用于线扫相机)
        /// 设置采集模式为扫描模式,连续触发
        /// </summary>
        public bool StartContinuousGrab()
        {
            if (!_isConnected) return false;
            lock (_bufferLock)
            {
                _lineDataBuffer.Clear();
                _currentLineCount = 0;
            }
            // 禁用行回调(与示例一致)
            PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, IntPtr.Zero, IntPtr.Zero);
            // 设置采集模式:1=扫描模式,1=连续模式
            PHM6000Profiler.SetAcquisitionMode(_cameraHandle, 1, 1);
            int result = PHM6000Profiler.StartAcquisition(_cameraHandle, 0, 0, 0.0);
@@ -214,6 +277,19 @@
            PHM6000Profiler.StopAcquisition(_cameraHandle);
            isGrabbing = false;
            return true;
        }
        public override bool StartWith_SoftTriggerModel()
        {
            // 对于LBCamera(线扫相机),软件触发连续采集使用连续采集模式
            return StartContinuousGrab();
        }
        public override bool StartWith_HardTriggerModel(TriggerSource hardtriggeritem = TriggerSource.Line0)
        {
            // 对于LBCamera(线扫相机),硬件触发也使用连续采集模式
            // 外部硬件信号会触发相机开始采集
            return StartContinuousGrab();
        }
        public override bool SoftTrigger()
@@ -242,6 +318,56 @@
        public override bool SetLineStatus(IOLines line, LineStatus linestatus) => true;
        public override bool GetLineStatus(IOLines line, out LineStatus lineStatus) { lineStatus = LineStatus.Low; return true; }
        public override bool AutoBalanceWhite() => true;
        // 不实现的方法
        public override void SetCamConfig(CameraConfig config) { }
        public override void GetCamConfig(out CameraConfig config) { config = new CameraConfig(null); }
        public override bool GetImage(out Bitmap bitmap, int outtime = 3000) { bitmap = null; return false; }
        public override bool GetImageWithSoftTrigger(out Bitmap bitmap, int outtime = 3000)
        {
            bitmap = null;
            if (!_isConnected) return false;
            using (AutoResetEvent waitHandle = new AutoResetEvent(false))
            {
                Bitmap captured = null;
                EventHandler<CameraEventArgs> handler = (s, e) =>
                {
                    try
                    {
                        if (e.Bitmap != null)
                        {
                            captured = e.Bitmap.Clone() as Bitmap;
                        }
                    }
                    catch (Exception ex)
                    {
                        AsyncLogHelper.Error($"LBCamera: GetImageWithSoftTrigger clone error - {ex.Message}");
                    }
                    waitHandle.Set();
                };
                this.ImageGrabbed += handler;
                try
                {
                    if (StartSingleGrab())
                    {
                        if (waitHandle.WaitOne(outtime))
                        {
                            bitmap = captured;
                            return bitmap != null;
                        }
                    }
                }
                finally
                {
                    this.ImageGrabbed -= handler;
                    StopGrabbing();
                }
            }
            return false;
        }
        public PHM6000SensorConfig GetSensorConfig()
        {
@@ -266,43 +392,74 @@
        private void OnLineReceived(IntPtr pInstance, IntPtr buffer, int points)
        {
            // 实时回调处理:累积行数据
            if (!isGrabbing) return;
                // 实时回调处理:累积行数据
                if (!isGrabbing) return;
            int lineSize = points * Marshal.SizeOf(typeof(LBPointZA));
            byte[] lineData = new byte[lineSize];
            Marshal.Copy(buffer, lineData, 0, lineSize);
                int lineSize = points * Marshal.SizeOf(typeof(LBPointZA));
                byte[] lineData = new byte[lineSize];
                Marshal.Copy(buffer, lineData, 0, lineSize);
            lock (_bufferLock)
            {
                _lineDataBuffer.Add(lineData);
                _currentLineCount++;
            }
                lock (_bufferLock)
                {
                    _lineDataBuffer.Add(lineData);
                    _currentLineCount++;
                }
        }
        private void OnAcquisitionCompleted(IntPtr pInstance, int nOption)
        {
            // nOption: 0=一批数据结束, 1=全部完成, 2=点云就绪
            if (nOption == 1 || nOption == 0)
            {
                GenerateIntensityMap();
            }
                // 根据SDK文档:nOption为0时表示一批数据结束,为1时表示全部采集完成
                // 为了兼容性,也处理nOption == 2(点云就绪)
                // 此时使用主动获取方式替代可能会导致crash的GenerateIntensityMap
                if (nOption == 0 || nOption == 1 || nOption == 2)
                {
                    RetrieveDataAndGenerateImage();
                }
        }
        private void GenerateIntensityMap()
        private void RetrieveDataAndGenerateImage()
        {
            if (_cameraHandle == IntPtr.Zero) return;
            int width = 0;
            int height = 0;
            // 直接从 SDK 获取合并后的强度数据指针 (unsigned char*)
            IntPtr pIntensity = PHM6000Profiler.GetIntensityData(_cameraHandle, ref width, ref height);
            if (pIntensity == IntPtr.Zero || width <= 0 || height <= 0) return;
            try
            {
                List<byte[]> lineBuffers = new List<byte[]>();
                ulong index = 0;
                IntPtr ptr = IntPtr.Zero;
                // 像示例一样通过索引获取行数据
                while ((ptr = PHM6000Profiler.GetLineDataByIndex(_cameraHandle, index)) != IntPtr.Zero)
                {
                    try
                    {
                        LBLineDataZA lineData = PHM6000Profiler.ConvertToLBLineDataZA(ptr);
                        // 提取强度数据 (Alpha通道)
                        if (lineData.data != null && lineData.data.Length > 0)
                        {
                            int lineWidth = lineData.data.Length;
                            byte[] intensityLine = new byte[lineWidth];
                            for (int i = 0; i < lineWidth; i++)
                            {
                                intensityLine[i] = lineData.data[i].alpha;
                            }
                            lineBuffers.Add(intensityLine);
                        }
                    }
                    catch (Exception ex)
                    {
                        // 忽略单行转换错误
                    }
                    index++;
                }
                if (lineBuffers.Count == 0) return;
                int height = lineBuffers.Count;
                int width = lineBuffers[0].Length;
                if (width <= 0 || height <= 0) return;
                Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
                
                // 设置灰度调色板
@@ -312,20 +469,30 @@
                BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
                
                // 高性能内存拷贝
                int size = width * height;
                byte[] managedData = new byte[size];
                Marshal.Copy(pIntensity, managedData, 0, size);
                Marshal.Copy(managedData, 0, bmpData.Scan0, size);
                bmp.UnlockBits(bmpData);
                try
                {
                    int stride = bmpData.Stride;
                    IntPtr scan0 = bmpData.Scan0;
                    for (int y = 0; y < height; y++)
                    {
                        if (lineBuffers[y].Length == width) // 确保宽度一致
                        {
                            Marshal.Copy(lineBuffers[y], 0, scan0 + y * stride, width);
                        }
                    }
                }
                finally
                {
                    bmp.UnlockBits(bmpData);
                }
                // 触发事件通知 UI 更新亮度图
                ImageGrabbed?.Invoke(this, new CameraEventArgs(SN, bmp));
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"LBCamera: 生成亮度图异常 - {ex.Message}");
                AsyncLogHelper.Error($"LBCamera: 生成图像异常 - {ex.Message}");
            }
        }