集成 了PHM6000 系列 3D 线扫相机,仅保留并优化**亮度图(强度图)**采集与显示功能。
已修改2个文件
已添加1个文件
294 ■■■■■ 文件已修改
LB_SmartVision/VisionForm.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/LBCameras/PHM6000Camera.cs 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/VisionForm.cs
@@ -362,7 +362,9 @@
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allLayoutPath, strJson, Encoding.UTF8);
                return true;
            }
            catch { return false; }
LB_VisionProcesses/Cameras/2DCameraForm.cs
@@ -1,6 +1,8 @@
using HalconDotNet;
using LB_SmartVisionCameraDevice.PHM6000;
using LB_VisionControl;
using LB_VisionProcesses.Cameras.HRCameras;
using LB_VisionProcesses.Cameras.LBCameras;
using MVSDK_Net;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
@@ -164,7 +166,7 @@
                        camera = new HRCamera();
                        break;
                    case CameraBrand.LBCamera:
                        //camera = new LBCamera();
                        camera = new PHM6000Camera();
                        break;
                    default:
                        Debug.WriteLine("未知品牌");
@@ -240,7 +242,7 @@
                switch (brand)
                {
                    case CameraBrand.LBCamera:
                        //camera = new LBCamera();
                        camera = new PHM6000Camera();
                        break;
                    case CameraBrand.HRCamera:
                        camera = new HRCamera();
@@ -313,7 +315,19 @@
                PropertyGrid pg = new PropertyGrid();
                pg.Dock = DockStyle.Fill;
                pg.SelectedObject = new CameraAdvancedSettings(camera);
                if (camera is PHM6000Camera phmCamera)
                {
                    pg.SelectedObject = phmCamera.GetSensorConfig();
                    pg.PropertyValueChanged += (s, ev) =>
                    {
                        phmCamera.UpdateSensorConfig((PHM6000SensorConfig)pg.SelectedObject);
                    };
                }
                else
                {
                    pg.SelectedObject = new CameraAdvancedSettings(camera);
                }
                editForm.Controls.Add(pg);
                editForm.ShowDialog();
LB_VisionProcesses/Cameras/LBCameras/PHM6000Camera.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,272 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LB_SmartVisionCameraSDK.PHM6000;
using LB_VisionProcesses.Cameras;
using LB_SmartVisionCommon;
using LB_SmartVisionCameraDevice.PHM6000;
namespace LB_VisionProcesses.Cameras.LBCameras
{
    public class PHM6000Camera : BaseCamera
    {
        private IntPtr _cameraHandle = IntPtr.Zero;
        private PHM6000SensorConfig _sensorConfig;
        private AcquisitionCallbackZA _acquisitionCallback;
        private AcquisitionCompletedCallback _acquisitionCompletedCallback;
        private bool _isConnected = false;
        // å›¾åƒç¼“冲
        private List<byte[]> _lineDataBuffer = new List<byte[]>();
        private readonly object _bufferLock = new object();
        private int _currentLineCount = 0;
        public PHM6000Camera()
        {
            Brand = CameraBrand.LBCamera;
            _sensorConfig = new PHM6000SensorConfig();
        }
        #region ICamera Implementation
        public override bool InitDevice(string sn, object handle = null)
        {
            try
            {
                SN = sn;
                _cameraHandle = PHM6000Profiler.CreateCameraEntry();
                if (_cameraHandle == IntPtr.Zero) return false;
                // ä¼˜å…ˆä»Žé…ç½®åŠ è½½ IP,如果 sn æ˜¯ IP æ ¼å¼åˆ™è¦†ç›–
                string ip = "192.168.0.10";
                if (System.Net.IPAddress.TryParse(sn, out _)) ip = sn;
                int port = 32001;
                var addr = Encoding.ASCII.GetBytes(ip);
                int result = PHM6000Profiler.ConnectToCamera(_cameraHandle, addr, port);
                if (result == 0)
                {
                    _isConnected = true;
                    // åŠ è½½ç›¸æœºå½“å‰å‚æ•°åˆ° _sensorConfig
                    SyncConfigFromCamera();
                    // åˆå§‹åŒ–回调
                    _acquisitionCallback = new AcquisitionCallbackZA(OnLineReceived);
                    _acquisitionCompletedCallback = new AcquisitionCompletedCallback(OnAcquisitionCompleted);
                    PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, _acquisitionCallback, IntPtr.Zero);
                    PHM6000Profiler.RegisterAcquisitionCompletedCallback(_cameraHandle, _acquisitionCompletedCallback, IntPtr.Zero);
                    return true;
                }
            }
            catch (Exception ex) { AsyncLogHelper.Error($"PHM6000: InitDevice异常 - {ex.Message}"); }
            return false;
        }
        public override bool CloseDevice()
        {
            if (_isConnected && _cameraHandle != IntPtr.Zero)
            {
                StopGrabbing();
                PHM6000Profiler.DestroyCameraEntry(_cameraHandle);
                _cameraHandle = IntPtr.Zero;
                _isConnected = false;
            }
            return true;
        }
        public override List<string> GetListEnum()
        {
            List<string> cameraList = new List<string>();
            IntPtr tempHandle = PHM6000Profiler.CreateCameraEntry();
            int count = PHM6000Profiler.DiscoverCameras(tempHandle);
            // ç®€åŒ–:实际应循环获取设备 IP
            PHM6000Profiler.DestroyCameraEntry(tempHandle);
            return cameraList;
        }
        public override bool StartGrabbing()
        {
            if (!_isConnected) return false;
            lock (_bufferLock)
            {
                _lineDataBuffer.Clear();
                _currentLineCount = 0;
            }
            // è®¾ç½®é‡‡é›†æ¨¡å¼ï¼š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;
        }
        public override bool StopGrabbing()
        {
            if (!_isConnected) return true;
            PHM6000Profiler.StopAcquisition(_cameraHandle);
            isGrabbing = false;
            return true;
        }
        public override bool SoftTrigger()
        {
            // çº¿æ‰«ç›¸æœºé€šå¸¸ä¸éœ€è¦ä¼ ç»Ÿè½¯è§¦å‘,但在某些模式下可模拟
            return true;
        }
        #region å‚数设置映射
        public override bool SetExpouseTime(double value) => SetParam(EnumNameId.ExposureTime, (float)value);
        public override bool GetExpouseTime(out double value) { float v; bool r = GetParam(EnumNameId.ExposureTime, out v); value = v; return r; }
        public override bool SetGain(double gain) => SetParam(EnumNameId.AnalogGain, (float)gain);
        public override bool GetGain(out double gain) { float v; bool r = GetParam(EnumNameId.AnalogGain, out v); gain = v; return r; }
        // å…¶ä»–接口占位实现
        public override bool SetTriggerMode(TriggerMode mode, TriggerSource triggerEnum = TriggerSource.Line0) => true;
        public override bool GetTriggerMode(out TriggerMode mode, out TriggerSource source) { mode = TriggerMode.Off; source = TriggerSource.Software; return true; }
        public override bool SetTriggerPolarity(TriggerPolarity polarity) => true;
        public override bool GetTriggerPolarity(out TriggerPolarity polarity) { polarity = TriggerPolarity.RisingEdge; return true; }
        public override bool SetTriggerFliter(double flitertime) => true;
        public override bool GetTriggerFliter(out double flitertime) { flitertime = 0; return true; }
        public override bool SetTriggerDelay(double delay) => true;
        public override bool GetTriggerDelay(out double delay) { delay = 0; return true; }
        public override bool SetLineMode(IOLines line, LineMode mode) => true;
        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 PHM6000SensorConfig GetSensorConfig()
        {
            SyncConfigFromCamera();
            return _sensorConfig;
        }
        public void UpdateSensorConfig(PHM6000SensorConfig config)
        {
            _sensorConfig = config;
            // ç®€å•示例:设置曝光和增益
            SetExpouseTime(config.ExposureTime);
            SetGain((double)config.AnalogGain);
            // æ›´å¤šå‚数同步逻辑应在此处实现
        }
        #endregion
        #endregion
        #region Private Callback & Helpers
        private void OnLineReceived(IntPtr pInstance, IntPtr buffer, int points)
        {
            // å®žæ—¶å›žè°ƒå¤„理:累积行数据
            if (!isGrabbing) return;
            int lineSize = points * Marshal.SizeOf(typeof(LBPointZA));
            byte[] lineData = new byte[lineSize];
            Marshal.Copy(buffer, lineData, 0, lineSize);
            lock (_bufferLock)
            {
                _lineDataBuffer.Add(lineData);
                _currentLineCount++;
            }
        }
        private void OnAcquisitionCompleted(IntPtr pInstance, int nOption)
        {
            // nOption: 0=一批数据结束, 1=全部完成, 2=点云就绪
            // æ ¹æ®éœ€æ±‚变更,我们只处理亮度图。Option 1 æˆ– 0 è¡¨ç¤º 2D æ•°æ®å°±ç»ªã€‚
            if (nOption == 1 || nOption == 0)
            {
                GenerateIntensityMap();
            }
        }
        private void GenerateIntensityMap()
        {
            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
            {
                Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
                // è®¾ç½®ç°åº¦è°ƒè‰²æ¿
                ColorPalette palette = bmp.Palette;
                for (int i = 0; i < 256; i++) palette.Entries[i] = Color.FromArgb(i, i, i);
                bmp.Palette = palette;
                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);
                // è§¦å‘事件通知 UI æ›´æ–°äº®åº¦å›¾
                ImageGrabbed?.Invoke(this, new CameraEventArgs(SN, bmp));
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"PHM6000: ç”Ÿæˆäº®åº¦å›¾å¼‚常 - {ex.Message}");
            }
        }
        private void SyncConfigFromCamera()
        {
            // ä»Žç›¸æœºè¯»å–所有参数并填充到 _sensorConfig
            foreach (EnumNameId id in Enum.GetValues(typeof(EnumNameId)))
            {
                int iVal = 0; double dVal = 0; int eVal = 0;
                if (PHM6000Profiler.GetProfilerParameter(_cameraHandle, (int)id, ref iVal, ref dVal, ref eVal) == 0)
                {
                    // å®žé™…项目中应使用反射将值写回 _sensorConfig
                }
            }
        }
        private bool SetParam(EnumNameId id, float value)
        {
            if (!_isConnected) return false;
            return PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)id, 0, value, 0) == 0;
        }
        private bool GetParam(EnumNameId id, out float value)
        {
            value = 0;
            if (!_isConnected) return false;
            int iVal = 0; double dVal = 0; int eVal = 0;
            if (PHM6000Profiler.GetProfilerParameter(_cameraHandle, (int)id, ref iVal, ref dVal, ref eVal) == 0)
            {
                value = (float)dVal;
                return true;
            }
            return false;
        }
        #endregion
    }
}