已修改12个文件
已删除1个文件
1654 ■■■■■ 文件已修改
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.cs 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/VisionForm.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/PHM6000/PHM6000Sensor.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PHM6000/PHM6000Profiler.cs 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.Designer.cs 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.cs 291 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/BaseCamera.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/HRCameras/HRCamera.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/ICamera.cs 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/LBCameras/LBCamera.cs 702 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/LBCameras/PHM6000Camera.cs 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.cs
@@ -85,7 +85,9 @@
            else
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0);
            camera.StartGrabbing();
            // æ³¨é‡ŠæŽ‰è‡ªåŠ¨å¯åŠ¨é‡‡é›†é€»è¾‘,防止关闭窗体后相机自动连续采集
            // ç”¨æˆ·éœ€è¦æ‰‹åŠ¨ç‚¹å‡»"启动采集"按钮才会启动相机
            // camera.StartGrabbing();
            Unsubscribe();
        }
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.cs
@@ -1,4 +1,3 @@

using LB_VisionControl;
using LB_VisionProcesses.Cameras;
using OpenCvSharp.Flann;
@@ -177,4 +176,4 @@
            }
        }
    }
}
}
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.cs
@@ -1,5 +1,6 @@
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Cameras.HRCameras;
using LB_VisionProcesses.Cameras.LBCameras;
using RJCP.IO.Ports;
using System;
using System.Collections.Concurrent;
@@ -100,7 +101,7 @@
                    camera = new HRCamera();
                    break;
                case CameraBrand.LBCamera:
                    //camera = new LBCamera();
                    camera = new LBCamera();
                    break;
                default:
                    return;
LB_SmartVision/VisionForm.cs
@@ -16,6 +16,7 @@
using LB_VisionProcesses;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Cameras.HRCameras;
using LB_VisionProcesses.Cameras.LBCameras;
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Communicators.SiemensS7;
using LB_VisionProcesses.Communicators.TCom;
@@ -734,7 +735,7 @@
                        }
                    case CameraBrand.LBCamera:
                        {
                            //camera = new LBCamera();
                            camera = new LBCamera();
                            break;
                        }
                    default:
@@ -744,7 +745,7 @@
                        }
                }
                camera.SN = CameraConnectionString.Key;
                if (!camera.InitDevice(CameraConnectionString.Key, this.Handle))
                if (!camera.InitDevice(CameraConnectionString.Key, IntPtr.Zero))
                {
                    LogInfo($"初始化相机[{CameraConnectionString.Key}]失败", LogInfoType.ERROR);
                    if (camera != null)
LB_SmartVisionCameraDevice/PHM6000/PHM6000Sensor.cs
@@ -1,4 +1,4 @@
using LB_SmartVisionCameraSDK;
using LB_SmartVisionCameraSDK;
using LB_SmartVisionCameraSDK.PHM6000;
using LB_SmartVisionCommon;
using Newtonsoft.Json;
@@ -1227,4 +1227,4 @@
            }
        }
    }
}
}
LB_SmartVisionCameraSDK/PHM6000/PHM6000Profiler.cs
@@ -318,8 +318,8 @@
        /// <param name="szModuleType">模块名, char* szModuleType</param>
        /// <param name="szSerialNumber">序列号, char* szSerialNumber</param>
        /// <returns>获取失败返回-1,否则返回0。</returns>
        [DllImport("PHM6000API", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetCameraInformation")]
        public static extern int GetCameraInformation(IntPtr pHandle, int nIndex, IntPtr szModuleType, IntPtr szSerialNumber);
        //[DllImport("PHM6000API", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetCameraInformation")]
        //public static extern int GetCameraInformation(IntPtr pHandle, int nIndex, IntPtr szModuleType, IntPtr szSerialNumber);
        //PHM6000_API(int) GetCameraInformation(void* pHandle, int nIndex, char* szModuleType, char* szSerialNumber);
        /// <summary>
        /// èŽ·å–ç…§ç›¸æœºä¿¡æ¯
@@ -342,8 +342,8 @@
        /// <param name="szAddress">IP地址字符串, char* szAddress</param>
        /// <param name="nPort">端口号, int* nPort</param>
        /// <returns>获取失败返回-1,否则返回0。</returns>
        [DllImport("PHM6000API", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetCameraAddress")]
        public static extern int GetCameraAddress(IntPtr pHandle, int nIndex, IntPtr szAddress, IntPtr nPort);
        //[DllImport("PHM6000API", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetCameraAddress")]
        //public static extern int GetCameraAddress(IntPtr pHandle, int nIndex, IntPtr szAddress, IntPtr nPort);
        //PHM6000_API(int) GetCameraAddress(void* pHandle, int nIndex, char* szAddress, int* nPort);
        /// <summary>
        /// å¾—到连接的IP
@@ -874,6 +874,35 @@
        /// <param name="KeepImageSize">图像大小是否保持</param>
        [DllImport("PHM6000API", CallingConvention = CallingConvention.StdCall, EntryPoint = "SetTransformParameter")]
        public static extern void SetTransformParameter(IntPtr pHandle, float fAngle, int xOffset, int yOffset, int hMirror, int vMirror, int KeepImageSize = 0);
        #region PointCloud3D Functions
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "AddZAPoints")]
        public static extern int AddZAPoints(IntPtr pInstance, IntPtr points, int nCount, float fStepX, float fStepY, int nDownSample);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "ClearPCLPoints")]
        public static extern int ClearPCLPoints(IntPtr pInstance);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetPointCloudBound")]
        public static extern int GetPointCloudBound(IntPtr pInstance, ref double pMin, ref double pMax);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "RenderPCLWindow")]
        public static extern void RenderPCLWindow(IntPtr pInstance, int nWidth, int nHeight);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "SetLookUpTableRange")]
        public static extern void SetLookUpTableRange(IntPtr pInstance, double fMin, double fMax);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "ShowCubeAxes")]
        public static extern void ShowCubeAxes(IntPtr pInstance, int bInit);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "ShowLookUpTable")]
        public static extern void ShowLookUpTable(IntPtr pInstance, double x, double y, double xWide, double yWide);
        [DllImport("PointCloud3D", CallingConvention = CallingConvention.StdCall, EntryPoint = "UpdatePCLPointColors")]
        public static extern int UpdatePCLPointColors(IntPtr pInstance, string szColoring);
        #endregion
        /// <summary>
        /// å°†ç»“构体指针转换为double(模拟C++的(double)(int64)&操作)
        /// </summary>
LB_VisionProcesses/Cameras/2DCameraForm.Designer.cs
@@ -104,18 +104,20 @@
            // 
            cmbBrand.Dock = DockStyle.Fill;
            cmbBrand.FormattingEnabled = true;
            cmbBrand.Location = new Point(53, 3);
            cmbBrand.Location = new Point(66, 4);
            cmbBrand.Margin = new Padding(4);
            cmbBrand.Name = "cmbBrand";
            cmbBrand.Size = new Size(296, 25);
            cmbBrand.Size = new Size(369, 28);
            cmbBrand.TabIndex = 0;
            // 
            // cmbSN
            // 
            cmbSN.Dock = DockStyle.Fill;
            cmbSN.FormattingEnabled = true;
            cmbSN.Location = new Point(53, 3);
            cmbSN.Location = new Point(66, 4);
            cmbSN.Margin = new Padding(4);
            cmbSN.Name = "cmbSN";
            cmbSN.Size = new Size(296, 25);
            cmbSN.Size = new Size(369, 28);
            cmbSN.TabIndex = 1;
            cmbSN.SelectedIndexChanged += cmbSN_SelectedIndexChanged;
            cmbSN.MouseDown += cmbSN_MouseDown;
@@ -124,9 +126,10 @@
            // 
            label1.AutoSize = true;
            label1.Dock = DockStyle.Fill;
            label1.Location = new Point(3, 0);
            label1.Location = new Point(4, 0);
            label1.Margin = new Padding(4, 0, 4, 0);
            label1.Name = "label1";
            label1.Size = new Size(44, 34);
            label1.Size = new Size(54, 42);
            label1.TabIndex = 2;
            label1.Text = "品牌";
            label1.TextAlign = ContentAlignment.MiddleCenter;
@@ -135,9 +138,10 @@
            // 
            label2.AutoSize = true;
            label2.Dock = DockStyle.Fill;
            label2.Location = new Point(3, 0);
            label2.Location = new Point(4, 0);
            label2.Margin = new Padding(4, 0, 4, 0);
            label2.Name = "label2";
            label2.Size = new Size(44, 34);
            label2.Size = new Size(54, 42);
            label2.TabIndex = 3;
            label2.Text = "SN";
            label2.TextAlign = ContentAlignment.MiddleCenter;
@@ -146,9 +150,10 @@
            // 
            btnStartGrab.Dock = DockStyle.Fill;
            btnStartGrab.ForeColor = SystemColors.ControlText;
            btnStartGrab.Location = new Point(91, 3);
            btnStartGrab.Location = new Point(113, 4);
            btnStartGrab.Margin = new Padding(4);
            btnStartGrab.Name = "btnStartGrab";
            btnStartGrab.Size = new Size(82, 28);
            btnStartGrab.Size = new Size(101, 34);
            btnStartGrab.TabIndex = 5;
            btnStartGrab.Text = "连续采集";
            btnStartGrab.UseVisualStyleBackColor = true;
@@ -158,9 +163,10 @@
            // 
            btnCloseGrab.Dock = DockStyle.Fill;
            btnCloseGrab.ForeColor = SystemColors.Desktop;
            btnCloseGrab.Location = new Point(179, 3);
            btnCloseGrab.Location = new Point(222, 4);
            btnCloseGrab.Margin = new Padding(4);
            btnCloseGrab.Name = "btnCloseGrab";
            btnCloseGrab.Size = new Size(82, 28);
            btnCloseGrab.Size = new Size(101, 34);
            btnCloseGrab.TabIndex = 6;
            btnCloseGrab.Text = "关闭采集";
            btnCloseGrab.UseVisualStyleBackColor = true;
@@ -170,9 +176,10 @@
            // 
            btnGrabOnce.Dock = DockStyle.Fill;
            btnGrabOnce.ForeColor = SystemColors.ControlText;
            btnGrabOnce.Location = new Point(3, 3);
            btnGrabOnce.Location = new Point(4, 4);
            btnGrabOnce.Margin = new Padding(4);
            btnGrabOnce.Name = "btnGrabOnce";
            btnGrabOnce.Size = new Size(82, 28);
            btnGrabOnce.Size = new Size(101, 34);
            btnGrabOnce.TabIndex = 7;
            btnGrabOnce.Text = "单张采集";
            btnGrabOnce.UseVisualStyleBackColor = true;
@@ -182,9 +189,10 @@
            // 
            btnOpen.Dock = DockStyle.Fill;
            btnOpen.ForeColor = SystemColors.ControlText;
            btnOpen.Location = new Point(3, 3);
            btnOpen.Location = new Point(4, 4);
            btnOpen.Margin = new Padding(4);
            btnOpen.Name = "btnOpen";
            btnOpen.Size = new Size(82, 28);
            btnOpen.Size = new Size(101, 34);
            btnOpen.TabIndex = 8;
            btnOpen.Text = "打开";
            btnOpen.UseVisualStyleBackColor = true;
@@ -194,9 +202,10 @@
            // 
            btnClose.Dock = DockStyle.Fill;
            btnClose.ForeColor = SystemColors.ControlText;
            btnClose.Location = new Point(91, 3);
            btnClose.Location = new Point(113, 4);
            btnClose.Margin = new Padding(4);
            btnClose.Name = "btnClose";
            btnClose.Size = new Size(82, 28);
            btnClose.Size = new Size(101, 34);
            btnClose.TabIndex = 9;
            btnClose.Text = "关闭";
            btnClose.UseVisualStyleBackColor = true;
@@ -206,9 +215,10 @@
            // 
            label5.AutoSize = true;
            label5.Dock = DockStyle.Fill;
            label5.Location = new Point(3, 0);
            label5.Location = new Point(4, 0);
            label5.Margin = new Padding(4, 0, 4, 0);
            label5.Name = "label5";
            label5.Size = new Size(114, 34);
            label5.Size = new Size(142, 42);
            label5.TabIndex = 15;
            label5.Text = "取图数量:";
            label5.TextAlign = ContentAlignment.MiddleCenter;
@@ -217,9 +227,10 @@
            // 
            lblPicCount.AutoSize = true;
            lblPicCount.Dock = DockStyle.Fill;
            lblPicCount.Location = new Point(123, 0);
            lblPicCount.Location = new Point(154, 0);
            lblPicCount.Margin = new Padding(4, 0, 4, 0);
            lblPicCount.Name = "lblPicCount";
            lblPicCount.Size = new Size(226, 34);
            lblPicCount.Size = new Size(281, 42);
            lblPicCount.TabIndex = 16;
            lblPicCount.Text = "0";
            lblPicCount.TextAlign = ContentAlignment.MiddleLeft;
@@ -227,18 +238,20 @@
            // txtGain
            // 
            txtGain.Dock = DockStyle.Fill;
            txtGain.Location = new Point(53, 3);
            txtGain.Location = new Point(66, 4);
            txtGain.Margin = new Padding(4);
            txtGain.Name = "txtGain";
            txtGain.Size = new Size(296, 23);
            txtGain.Size = new Size(369, 27);
            txtGain.TabIndex = 21;
            txtGain.TextChanged += txtGain_TextChanged;
            // 
            // txtExp
            // 
            txtExp.Dock = DockStyle.Fill;
            txtExp.Location = new Point(53, 3);
            txtExp.Location = new Point(66, 4);
            txtExp.Margin = new Padding(4);
            txtExp.Name = "txtExp";
            txtExp.Size = new Size(296, 23);
            txtExp.Size = new Size(369, 27);
            txtExp.TabIndex = 20;
            txtExp.TextChanged += txtExp_TextChanged;
            // 
@@ -246,9 +259,10 @@
            // 
            label4.AutoSize = true;
            label4.Dock = DockStyle.Fill;
            label4.Location = new Point(3, 0);
            label4.Location = new Point(4, 0);
            label4.Margin = new Padding(4, 0, 4, 0);
            label4.Name = "label4";
            label4.Size = new Size(44, 34);
            label4.Size = new Size(54, 42);
            label4.TabIndex = 19;
            label4.Text = "增益";
            label4.TextAlign = ContentAlignment.MiddleCenter;
@@ -257,9 +271,10 @@
            // 
            label3.AutoSize = true;
            label3.Dock = DockStyle.Fill;
            label3.Location = new Point(3, 0);
            label3.Location = new Point(4, 0);
            label3.Margin = new Padding(4, 0, 4, 0);
            label3.Name = "label3";
            label3.Size = new Size(44, 34);
            label3.Size = new Size(54, 42);
            label3.TabIndex = 18;
            label3.Text = "曝光";
            label3.TextAlign = ContentAlignment.MiddleCenter;
@@ -271,8 +286,10 @@
            groupBox1.Dock = DockStyle.Fill;
            groupBox1.ForeColor = SystemColors.Control;
            groupBox1.Location = new Point(0, 0);
            groupBox1.Margin = new Padding(4);
            groupBox1.Name = "groupBox1";
            groupBox1.Size = new Size(487, 591);
            groupBox1.Padding = new Padding(4);
            groupBox1.Size = new Size(610, 739);
            groupBox1.TabIndex = 17;
            groupBox1.TabStop = false;
            groupBox1.Text = "实时采集";
@@ -280,18 +297,20 @@
            // panel_Picture
            // 
            panel_Picture.Dock = DockStyle.Fill;
            panel_Picture.Location = new Point(3, 19);
            panel_Picture.Location = new Point(4, 24);
            panel_Picture.Margin = new Padding(4);
            panel_Picture.Name = "panel_Picture";
            panel_Picture.Size = new Size(481, 569);
            panel_Picture.Size = new Size(602, 711);
            panel_Picture.TabIndex = 0;
            // 
            // radioButtonSoft
            // 
            radioButtonSoft.AutoSize = true;
            radioButtonSoft.Dock = DockStyle.Fill;
            radioButtonSoft.Location = new Point(3, 123);
            radioButtonSoft.Location = new Point(4, 154);
            radioButtonSoft.Margin = new Padding(4);
            radioButtonSoft.Name = "radioButtonSoft";
            radioButtonSoft.Size = new Size(352, 34);
            radioButtonSoft.Size = new Size(439, 42);
            radioButtonSoft.TabIndex = 23;
            radioButtonSoft.TabStop = true;
            radioButtonSoft.Text = "软触发";
@@ -302,9 +321,10 @@
            // 
            radioButtonHard.AutoSize = true;
            radioButtonHard.Dock = DockStyle.Fill;
            radioButtonHard.Location = new Point(3, 203);
            radioButtonHard.Location = new Point(4, 254);
            radioButtonHard.Margin = new Padding(4);
            radioButtonHard.Name = "radioButtonHard";
            radioButtonHard.Size = new Size(352, 34);
            radioButtonHard.Size = new Size(439, 42);
            radioButtonHard.TabIndex = 24;
            radioButtonHard.TabStop = true;
            radioButtonHard.Text = "硬触发";
@@ -313,7 +333,8 @@
            // splitContainer1
            // 
            splitContainer1.Dock = DockStyle.Fill;
            splitContainer1.Location = new Point(5, 5);
            splitContainer1.Location = new Point(6, 6);
            splitContainer1.Margin = new Padding(4);
            splitContainer1.Name = "splitContainer1";
            // 
            // splitContainer1.Panel1
@@ -323,8 +344,9 @@
            // splitContainer1.Panel2
            // 
            splitContainer1.Panel2.Controls.Add(groupBox1);
            splitContainer1.Size = new Size(855, 591);
            splitContainer1.SplitterDistance = 364;
            splitContainer1.Size = new Size(1070, 739);
            splitContainer1.SplitterDistance = 455;
            splitContainer1.SplitterWidth = 5;
            splitContainer1.TabIndex = 19;
            // 
            // groupBox2
@@ -334,9 +356,11 @@
            groupBox2.Dock = DockStyle.Fill;
            groupBox2.ForeColor = SystemColors.Control;
            groupBox2.Location = new Point(0, 0);
            groupBox2.MinimumSize = new Size(261, 61);
            groupBox2.Margin = new Padding(4);
            groupBox2.MinimumSize = new Size(326, 76);
            groupBox2.Name = "groupBox2";
            groupBox2.Size = new Size(364, 591);
            groupBox2.Padding = new Padding(4);
            groupBox2.Size = new Size(455, 739);
            groupBox2.TabIndex = 0;
            groupBox2.TabStop = false;
            groupBox2.Text = "相机参数";
@@ -360,7 +384,8 @@
            tableLayoutPanel2.Controls.Add(tableLayoutPanel9, 0, 10);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel10, 0, 9);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 19);
            tableLayoutPanel2.Location = new Point(4, 24);
            tableLayoutPanel2.Margin = new Padding(4);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 14;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 7.14301062F));
@@ -377,38 +402,40 @@
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 7.14301062F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 7.143011F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 7.14086771F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
            tableLayoutPanel2.Size = new Size(358, 569);
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 25F));
            tableLayoutPanel2.Size = new Size(447, 711);
            tableLayoutPanel2.TabIndex = 25;
            // 
            // tableLayoutPanel3
            // 
            tableLayoutPanel3.ColumnCount = 2;
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 62F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Controls.Add(label1, 0, 0);
            tableLayoutPanel3.Controls.Add(cmbBrand, 1, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(3, 3);
            tableLayoutPanel3.Location = new Point(4, 4);
            tableLayoutPanel3.Margin = new Padding(4);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
            tableLayoutPanel3.RowCount = 1;
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Size = new Size(352, 34);
            tableLayoutPanel3.Size = new Size(439, 42);
            tableLayoutPanel3.TabIndex = 0;
            // 
            // tableLayoutPanel4
            // 
            tableLayoutPanel4.ColumnCount = 2;
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 62F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Controls.Add(label2, 0, 0);
            tableLayoutPanel4.Controls.Add(cmbSN, 1, 0);
            tableLayoutPanel4.Dock = DockStyle.Fill;
            tableLayoutPanel4.Location = new Point(3, 43);
            tableLayoutPanel4.Location = new Point(4, 54);
            tableLayoutPanel4.Margin = new Padding(4);
            tableLayoutPanel4.Name = "tableLayoutPanel4";
            tableLayoutPanel4.RowCount = 1;
            tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Size = new Size(352, 34);
            tableLayoutPanel4.Size = new Size(439, 42);
            tableLayoutPanel4.TabIndex = 1;
            // 
            // tableLayoutPanel5
@@ -422,11 +449,12 @@
            tableLayoutPanel5.Controls.Add(btnClose, 1, 0);
            tableLayoutPanel5.Controls.Add(btnEdit, 3, 0);
            tableLayoutPanel5.Dock = DockStyle.Fill;
            tableLayoutPanel5.Location = new Point(3, 83);
            tableLayoutPanel5.Location = new Point(4, 104);
            tableLayoutPanel5.Margin = new Padding(4);
            tableLayoutPanel5.Name = "tableLayoutPanel5";
            tableLayoutPanel5.RowCount = 1;
            tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel5.Size = new Size(352, 34);
            tableLayoutPanel5.Size = new Size(439, 42);
            tableLayoutPanel5.TabIndex = 2;
            // 
            // btnEdit
@@ -434,9 +462,10 @@
            btnEdit.Dock = DockStyle.Fill;
            btnEdit.Enabled = false;
            btnEdit.ForeColor = SystemColors.ControlText;
            btnEdit.Location = new Point(267, 3);
            btnEdit.Location = new Point(331, 4);
            btnEdit.Margin = new Padding(4);
            btnEdit.Name = "btnEdit";
            btnEdit.Size = new Size(82, 28);
            btnEdit.Size = new Size(104, 34);
            btnEdit.TabIndex = 10;
            btnEdit.Text = "编辑";
            btnEdit.UseVisualStyleBackColor = true;
@@ -454,21 +483,22 @@
            tableLayoutPanel6.Controls.Add(btnCloseGrab, 2, 0);
            tableLayoutPanel6.Controls.Add(btnSaveImage, 3, 0);
            tableLayoutPanel6.Dock = DockStyle.Fill;
            tableLayoutPanel6.Location = new Point(3, 163);
            tableLayoutPanel6.Location = new Point(4, 204);
            tableLayoutPanel6.Margin = new Padding(4);
            tableLayoutPanel6.Name = "tableLayoutPanel6";
            tableLayoutPanel6.RowCount = 1;
            tableLayoutPanel6.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel6.Size = new Size(352, 34);
            tableLayoutPanel6.Size = new Size(439, 42);
            tableLayoutPanel6.TabIndex = 24;
            // 
            // btnSaveImage
            // 
            btnSaveImage.Dock = DockStyle.Fill;
            btnSaveImage.ForeColor = SystemColors.Desktop;
            btnSaveImage.Location = new Point(266, 2);
            btnSaveImage.Location = new Point(329, 2);
            btnSaveImage.Margin = new Padding(2);
            btnSaveImage.Name = "btnSaveImage";
            btnSaveImage.Size = new Size(84, 30);
            btnSaveImage.Size = new Size(108, 38);
            btnSaveImage.TabIndex = 8;
            btnSaveImage.Text = "保存图片";
            btnSaveImage.UseVisualStyleBackColor = true;
@@ -477,31 +507,33 @@
            // tableLayoutPanel7
            // 
            tableLayoutPanel7.ColumnCount = 2;
            tableLayoutPanel7.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel7.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 62F));
            tableLayoutPanel7.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel7.Controls.Add(label3, 0, 0);
            tableLayoutPanel7.Controls.Add(txtExp, 1, 0);
            tableLayoutPanel7.Dock = DockStyle.Fill;
            tableLayoutPanel7.Location = new Point(3, 283);
            tableLayoutPanel7.Location = new Point(4, 354);
            tableLayoutPanel7.Margin = new Padding(4);
            tableLayoutPanel7.Name = "tableLayoutPanel7";
            tableLayoutPanel7.RowCount = 1;
            tableLayoutPanel7.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
            tableLayoutPanel7.Size = new Size(352, 34);
            tableLayoutPanel7.Size = new Size(439, 42);
            tableLayoutPanel7.TabIndex = 25;
            // 
            // tableLayoutPanel8
            // 
            tableLayoutPanel8.ColumnCount = 2;
            tableLayoutPanel8.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel8.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 62F));
            tableLayoutPanel8.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel8.Controls.Add(label4, 0, 0);
            tableLayoutPanel8.Controls.Add(txtGain, 1, 0);
            tableLayoutPanel8.Dock = DockStyle.Fill;
            tableLayoutPanel8.Location = new Point(3, 323);
            tableLayoutPanel8.Location = new Point(4, 404);
            tableLayoutPanel8.Margin = new Padding(4);
            tableLayoutPanel8.Name = "tableLayoutPanel8";
            tableLayoutPanel8.RowCount = 1;
            tableLayoutPanel8.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel8.Size = new Size(352, 34);
            tableLayoutPanel8.Size = new Size(439, 42);
            tableLayoutPanel8.TabIndex = 26;
            // 
            // tableLayoutPanel1
@@ -514,19 +546,21 @@
            tableLayoutPanel1.Controls.Add(ckbUpParams, 1, 0);
            tableLayoutPanel1.Controls.Add(ckbRegrab, 2, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(3, 243);
            tableLayoutPanel1.Location = new Point(4, 304);
            tableLayoutPanel1.Margin = new Padding(4);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 1;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Size = new Size(352, 34);
            tableLayoutPanel1.Size = new Size(439, 42);
            tableLayoutPanel1.TabIndex = 29;
            // 
            // btnStartHard
            // 
            btnStartHard.Dock = DockStyle.Fill;
            btnStartHard.Location = new Point(3, 3);
            btnStartHard.Location = new Point(4, 4);
            btnStartHard.Margin = new Padding(4);
            btnStartHard.Name = "btnStartHard";
            btnStartHard.Size = new Size(64, 28);
            btnStartHard.Size = new Size(79, 34);
            btnStartHard.TabIndex = 22;
            btnStartHard.Text = "等待触发";
            btnStartHard.UseVisualStyleBackColor = true;
@@ -536,9 +570,10 @@
            // 
            ckbUpParams.AutoSize = true;
            ckbUpParams.Dock = DockStyle.Fill;
            ckbUpParams.Location = new Point(73, 3);
            ckbUpParams.Location = new Point(91, 4);
            ckbUpParams.Margin = new Padding(4);
            ckbUpParams.Name = "ckbUpParams";
            ckbUpParams.Size = new Size(134, 28);
            ckbUpParams.Size = new Size(167, 34);
            ckbUpParams.TabIndex = 23;
            ckbUpParams.Text = "是否每次写入参数";
            ckbUpParams.UseVisualStyleBackColor = true;
@@ -547,9 +582,10 @@
            // 
            ckbRegrab.AutoSize = true;
            ckbRegrab.Dock = DockStyle.Fill;
            ckbRegrab.Location = new Point(213, 3);
            ckbRegrab.Location = new Point(266, 4);
            ckbRegrab.Margin = new Padding(4);
            ckbRegrab.Name = "ckbRegrab";
            ckbRegrab.Size = new Size(136, 28);
            ckbRegrab.Size = new Size(169, 34);
            ckbRegrab.TabIndex = 24;
            ckbRegrab.Text = "是否失败重新取图";
            ckbRegrab.UseVisualStyleBackColor = true;
@@ -557,25 +593,27 @@
            // tableLayoutPanel12
            // 
            tableLayoutPanel12.ColumnCount = 2;
            tableLayoutPanel12.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120F));
            tableLayoutPanel12.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150F));
            tableLayoutPanel12.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel12.Controls.Add(lblCapTime, 1, 0);
            tableLayoutPanel12.Controls.Add(label7, 0, 0);
            tableLayoutPanel12.Dock = DockStyle.Fill;
            tableLayoutPanel12.Location = new Point(3, 523);
            tableLayoutPanel12.Location = new Point(4, 654);
            tableLayoutPanel12.Margin = new Padding(4);
            tableLayoutPanel12.Name = "tableLayoutPanel12";
            tableLayoutPanel12.RowCount = 1;
            tableLayoutPanel12.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel12.Size = new Size(352, 43);
            tableLayoutPanel12.Size = new Size(439, 53);
            tableLayoutPanel12.TabIndex = 31;
            // 
            // lblCapTime
            // 
            lblCapTime.AutoSize = true;
            lblCapTime.Dock = DockStyle.Fill;
            lblCapTime.Location = new Point(123, 0);
            lblCapTime.Location = new Point(154, 0);
            lblCapTime.Margin = new Padding(4, 0, 4, 0);
            lblCapTime.Name = "lblCapTime";
            lblCapTime.Size = new Size(226, 43);
            lblCapTime.Size = new Size(281, 53);
            lblCapTime.TabIndex = 16;
            lblCapTime.Text = "0ms";
            lblCapTime.TextAlign = ContentAlignment.MiddleLeft;
@@ -584,9 +622,10 @@
            // 
            label7.AutoSize = true;
            label7.Dock = DockStyle.Fill;
            label7.Location = new Point(3, 0);
            label7.Location = new Point(4, 0);
            label7.Margin = new Padding(4, 0, 4, 0);
            label7.Name = "label7";
            label7.Size = new Size(114, 43);
            label7.Size = new Size(142, 53);
            label7.TabIndex = 15;
            label7.Text = "取图时间:";
            label7.TextAlign = ContentAlignment.MiddleCenter;
@@ -594,16 +633,17 @@
            // tableLayoutPanel11
            // 
            tableLayoutPanel11.ColumnCount = 2;
            tableLayoutPanel11.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120F));
            tableLayoutPanel11.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150F));
            tableLayoutPanel11.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel11.Controls.Add(label5, 0, 0);
            tableLayoutPanel11.Controls.Add(lblPicCount, 1, 0);
            tableLayoutPanel11.Dock = DockStyle.Fill;
            tableLayoutPanel11.Location = new Point(3, 483);
            tableLayoutPanel11.Location = new Point(4, 604);
            tableLayoutPanel11.Margin = new Padding(4);
            tableLayoutPanel11.Name = "tableLayoutPanel11";
            tableLayoutPanel11.RowCount = 1;
            tableLayoutPanel11.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel11.Size = new Size(352, 34);
            tableLayoutPanel11.Size = new Size(439, 42);
            tableLayoutPanel11.TabIndex = 30;
            // 
            // cmbImagesPath
@@ -612,9 +652,10 @@
            cmbImagesPath.Dock = DockStyle.Fill;
            cmbImagesPath.ForeColor = SystemColors.ControlText;
            cmbImagesPath.FormattingEnabled = true;
            cmbImagesPath.Location = new Point(3, 443);
            cmbImagesPath.Location = new Point(4, 554);
            cmbImagesPath.Margin = new Padding(4);
            cmbImagesPath.Name = "cmbImagesPath";
            cmbImagesPath.Size = new Size(352, 25);
            cmbImagesPath.Size = new Size(439, 28);
            cmbImagesPath.TabIndex = 0;
            cmbImagesPath.SelectedIndexChanged += cmbImagesPath_SelectedIndexChanged;
            cmbImagesPath.MouseHover += cmbImagesPath_MouseHover;
@@ -629,20 +670,22 @@
            tableLayoutPanel9.Controls.Add(btnAddImages, 1, 0);
            tableLayoutPanel9.Controls.Add(btnLocalGrab, 2, 0);
            tableLayoutPanel9.Dock = DockStyle.Fill;
            tableLayoutPanel9.Location = new Point(3, 403);
            tableLayoutPanel9.Location = new Point(4, 504);
            tableLayoutPanel9.Margin = new Padding(4);
            tableLayoutPanel9.Name = "tableLayoutPanel9";
            tableLayoutPanel9.RowCount = 1;
            tableLayoutPanel9.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel9.Size = new Size(352, 34);
            tableLayoutPanel9.Size = new Size(439, 42);
            tableLayoutPanel9.TabIndex = 27;
            // 
            // ckbLocalTest
            // 
            ckbLocalTest.AutoSize = true;
            ckbLocalTest.Dock = DockStyle.Fill;
            ckbLocalTest.Location = new Point(3, 3);
            ckbLocalTest.Location = new Point(4, 4);
            ckbLocalTest.Margin = new Padding(4);
            ckbLocalTest.Name = "ckbLocalTest";
            ckbLocalTest.Size = new Size(111, 28);
            ckbLocalTest.Size = new Size(138, 34);
            ckbLocalTest.TabIndex = 0;
            ckbLocalTest.Text = "本地取图";
            ckbLocalTest.UseVisualStyleBackColor = true;
@@ -651,9 +694,10 @@
            // 
            btnAddImages.Dock = DockStyle.Fill;
            btnAddImages.ForeColor = SystemColors.Desktop;
            btnAddImages.Location = new Point(120, 3);
            btnAddImages.Location = new Point(150, 4);
            btnAddImages.Margin = new Padding(4);
            btnAddImages.Name = "btnAddImages";
            btnAddImages.Size = new Size(111, 28);
            btnAddImages.Size = new Size(138, 34);
            btnAddImages.TabIndex = 1;
            btnAddImages.Text = "添加图片";
            btnAddImages.UseVisualStyleBackColor = true;
@@ -663,9 +707,10 @@
            // 
            btnLocalGrab.Dock = DockStyle.Fill;
            btnLocalGrab.ForeColor = SystemColors.Desktop;
            btnLocalGrab.Location = new Point(237, 3);
            btnLocalGrab.Location = new Point(296, 4);
            btnLocalGrab.Margin = new Padding(4);
            btnLocalGrab.Name = "btnLocalGrab";
            btnLocalGrab.Size = new Size(112, 28);
            btnLocalGrab.Size = new Size(139, 34);
            btnLocalGrab.TabIndex = 2;
            btnLocalGrab.Text = "本地取图";
            btnLocalGrab.UseVisualStyleBackColor = true;
@@ -674,25 +719,27 @@
            // tableLayoutPanel10
            // 
            tableLayoutPanel10.ColumnCount = 2;
            tableLayoutPanel10.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel10.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 62F));
            tableLayoutPanel10.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel10.Controls.Add(label6, 0, 0);
            tableLayoutPanel10.Controls.Add(txtTimeout, 1, 0);
            tableLayoutPanel10.Dock = DockStyle.Fill;
            tableLayoutPanel10.Location = new Point(3, 363);
            tableLayoutPanel10.Location = new Point(4, 454);
            tableLayoutPanel10.Margin = new Padding(4);
            tableLayoutPanel10.Name = "tableLayoutPanel10";
            tableLayoutPanel10.RowCount = 1;
            tableLayoutPanel10.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel10.Size = new Size(352, 34);
            tableLayoutPanel10.Size = new Size(439, 42);
            tableLayoutPanel10.TabIndex = 32;
            // 
            // label6
            // 
            label6.AutoSize = true;
            label6.Dock = DockStyle.Fill;
            label6.Location = new Point(3, 0);
            label6.Location = new Point(4, 0);
            label6.Margin = new Padding(4, 0, 4, 0);
            label6.Name = "label6";
            label6.Size = new Size(44, 34);
            label6.Size = new Size(54, 42);
            label6.TabIndex = 0;
            label6.Text = "超时";
            label6.TextAlign = ContentAlignment.MiddleCenter;
@@ -700,9 +747,10 @@
            // txtTimeout
            // 
            txtTimeout.Dock = DockStyle.Fill;
            txtTimeout.Location = new Point(53, 3);
            txtTimeout.Location = new Point(66, 4);
            txtTimeout.Margin = new Padding(4);
            txtTimeout.Name = "txtTimeout";
            txtTimeout.Size = new Size(296, 23);
            txtTimeout.Size = new Size(369, 27);
            txtTimeout.TabIndex = 1;
            // 
            // theme_2DCameraForm
@@ -715,11 +763,12 @@
            theme_2DCameraForm.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
            theme_2DCameraForm.Image = (Image)resources.GetObject("theme_2DCameraForm.Image");
            theme_2DCameraForm.Location = new Point(0, 0);
            theme_2DCameraForm.Margin = new Padding(4);
            theme_2DCameraForm.Name = "theme_2DCameraForm";
            theme_2DCameraForm.Padding = new Padding(10, 70, 10, 9);
            theme_2DCameraForm.Padding = new Padding(12, 88, 12, 11);
            theme_2DCameraForm.RoundCorners = true;
            theme_2DCameraForm.Sizable = true;
            theme_2DCameraForm.Size = new Size(885, 680);
            theme_2DCameraForm.Size = new Size(1106, 850);
            theme_2DCameraForm.SmartBounds = true;
            theme_2DCameraForm.StartPosition = FormStartPosition.WindowsDefaultLocation;
            theme_2DCameraForm.TabIndex = 20;
@@ -736,7 +785,8 @@
            controlBox1.EnableMaximizeButton = false;
            controlBox1.EnableMinimizeButton = false;
            controlBox1.ForeColor = Color.FromArgb(155, 155, 155);
            controlBox1.Location = new Point(785, 18);
            controlBox1.Location = new Point(981, 18);
            controlBox1.Margin = new Padding(4);
            controlBox1.MaximizeHoverColor = Color.FromArgb(74, 74, 74);
            controlBox1.MinimizeHoverColor = Color.FromArgb(63, 63, 65);
            controlBox1.Name = "controlBox1";
@@ -750,22 +800,24 @@
            panel_2DCameraForm.Controls.Add(splitContainer1);
            panel_2DCameraForm.Dock = DockStyle.Fill;
            panel_2DCameraForm.EdgeColor = Color.FromArgb(32, 41, 50);
            panel_2DCameraForm.Location = new Point(10, 70);
            panel_2DCameraForm.Location = new Point(12, 88);
            panel_2DCameraForm.Margin = new Padding(4);
            panel_2DCameraForm.Name = "panel_2DCameraForm";
            panel_2DCameraForm.Padding = new Padding(5);
            panel_2DCameraForm.Size = new Size(865, 601);
            panel_2DCameraForm.Padding = new Padding(6);
            panel_2DCameraForm.Size = new Size(1082, 751);
            panel_2DCameraForm.SmoothingType = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            panel_2DCameraForm.TabIndex = 20;
            panel_2DCameraForm.Text = "panel2";
            // 
            // CameraForm
            // 
            AutoScaleDimensions = new SizeF(96F, 96F);
            AutoScaleDimensions = new SizeF(120F, 120F);
            AutoScaleMode = AutoScaleMode.Dpi;
            ClientSize = new Size(885, 680);
            ClientSize = new Size(1106, 850);
            Controls.Add(theme_2DCameraForm);
            FormBorderStyle = FormBorderStyle.None;
            MinimumSize = new Size(261, 61);
            Margin = new Padding(4);
            MinimumSize = new Size(326, 76);
            Name = "CameraForm";
            Text = "2D相机设置界面";
            TransparencyKey = Color.Fuchsia;
LB_VisionProcesses/Cameras/2DCameraForm.cs
@@ -80,9 +80,23 @@
        private System.Windows.Forms.Timer updateTimer;
        Total total = new Total { iImageCount = 0, iScanCount = 0 };
        DateTime startGrabtime = DateTime.Now;
        // åŠ¨æ€æ·»åŠ çš„å¢žç›Šä¸‹æ‹‰æ¡†
        private ComboBox cmbGain;
        private void CameraForm_Load(object sender, EventArgs e)
        {
            // åˆå§‹åŒ–增益下拉框
            cmbGain = new ComboBox();
            cmbGain.Visible = false; // é»˜è®¤éšè—
            cmbGain.DropDownStyle = ComboBoxStyle.DropDownList;
            cmbGain.Size = txtGain.Size;
            cmbGain.Location = txtGain.Location;
            cmbGain.Font = txtGain.Font;
            cmbGain.SelectedIndexChanged += CmbGain_SelectedIndexChanged;
            this.txtGain.Parent.Controls.Add(cmbGain);
            cmbGain.BringToFront();
            // è®¾ç½®ä¸€ä¸ªå®šæ—¶å™¨ï¼Œæ¯ 100 æ¯«ç§’触发一次
            updateTimer = new System.Windows.Forms.Timer();
            updateTimer.Interval = 1000;  // è®¾ç½®å®šæ—¶å™¨é—´éš”为 1000 æ¯«ç§’
@@ -127,6 +141,16 @@
            }
        }
        private void CmbGain_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (camera != null && camera is LBCamera && cmbGain.Visible)
            {
                // LBCamera SetGain expects double which is cast to int for enum value
                // ComboBox index corresponds directly to EnumAnalogGain value (0-4)
                camera.SetGain((double)cmbGain.SelectedIndex);
            }
        }
        private void UpdateUI()
        {
            try
@@ -166,7 +190,7 @@
                        camera = new HRCamera();
                        break;
                    case CameraBrand.LBCamera:
                        camera = new PHM6000Camera();
                        camera = new LBCamera();
                        break;
                    default:
                        Debug.WriteLine("未知品牌");
@@ -232,31 +256,71 @@
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            {
                if (camera != null)
                string selectedSN = cmbSN.Text.ToString();
                bool isReusingExisting = false;
                // 1. å°è¯•从现有字典中查找已初始化的相机
                if (dicCameras != null && dicCameras.ContainsKey(selectedSN))
                {
                    var existingCamera = dicCameras[selectedSN];
                    // ç¡®ä¿å“ç‰ŒåŒ¹é…
                    if (existingCamera.Brand == brand)
                    {
                        camera = existingCamera;
                        isReusingExisting = true;
                    }
                }
                // 2. å¦‚果没有复用现有相机,且当前camera对象不是我们要复用的对象,则清理旧对象
                if (!isReusingExisting && camera != null)
                {
                    camera.ImageGrabbed -= GetImageBllComplete;
                    camera.Dispose();
                    camera = null;
                }
                // ä½¿ç”¨ switch è¯­å¥æ¥åˆ¤æ–­æžšä¸¾å€¼
                switch (brand)
                // 3. å¦‚果没有复用,则创建新实例
                if (!isReusingExisting)
                {
                    case CameraBrand.LBCamera:
                        camera = new PHM6000Camera();
                        break;
                    case CameraBrand.HRCamera:
                        camera = new HRCamera();
                        break;
                    default:
                        Debug.WriteLine($"【{DateTime.Now:HH:mm:ss.fff}】未知品牌");
                        return;
                    // ä½¿ç”¨ switch è¯­å¥æ¥åˆ¤æ–­æžšä¸¾å€¼
                    switch (brand)
                    {
                        case CameraBrand.LBCamera:
                            camera = new LBCamera();
                            break;
                        case CameraBrand.HRCamera:
                            camera = new HRCamera();
                            break;
                        default:
                            Debug.WriteLine($"【{DateTime.Now:HH:mm:ss.fff}】未知品牌");
                            return;
                    }
                }
                if (cmbSN.Items.Count > 0 && camera.InitDevice(cmbSN.Text.ToString(), this.Handle))
                IntPtr displayHandle = onlinePictureBox.Handle;
                onlinePictureBox.Visible = true;
                bool initSuccess = false;
                if (isReusingExisting)
                {
                    // å¤ç”¨æ—¶ä¸éœ€è¦å†æ¬¡InitDevice,但可能需要更新显示句柄(视具体SDK实现而定,LBCamera通常不需要)
                    initSuccess = true;
                    MessageBox.Show(camera.SN + "已连接 (复用)");
                }
                else
                {
                    if (cmbSN.Items.Count > 0 && camera.InitDevice(selectedSN, displayHandle))
                    {
                        initSuccess = true;
                        MessageBox.Show(camera.SN + "打开成功");
                    }
                }
                if (initSuccess)
                {
                    // é‡æ–°ç»‘定显示回调
                    camera.ImageGrabbed -= GetImageBllComplete;
                    camera.ImageGrabbed += GetImageBllComplete;
                    MessageBox.Show(camera.SN + "打开成功");
                    this.btnEdit.Enabled = true;
                }
            }
@@ -264,18 +328,51 @@
            {
                Debug.WriteLine($"【{DateTime.Now:HH:mm:ss.fff}】无效的枚举值!");
            }
            // ... (rest of the UI update logic)
            if (camera != null)
            {
                this.BeginInvoke(new Action(() =>
                {
                    double exp = 0;
                    double gain = 0;
                    camera.GetExpouseTime(out exp);
                    txtExp.Text = exp.ToString();
                    if (camera is LBCamera lbCam)
                    {
                        // åˆ‡æ¢åˆ°ä¸‹æ‹‰æ¡†æ˜¾ç¤º
                        txtGain.Visible = false;
                        cmbGain.Visible = true;
                        // å¡«å……选项 (对应 EnumAnalogGain: Gain_1_0, Gain_1_3, Gain_1_9, Gain_2_8, Gain_5_5)
                        cmbGain.Items.Clear();
                        cmbGain.Items.AddRange(new object[] { "1.0x", "1.3x", "1.9x", "2.8x", "5.5x" });
                    camera.GetGain(out gain);
                    txtGain.Text = gain.ToString();
                        var config = lbCam.GetSensorConfig();
                        txtExp.Text = config.ExposureTime.ToString();
                        // è®¾ç½®å½“前选中的增益
                        int gainIndex = (int)config.AnalogGain;
                        if (gainIndex >= 0 && gainIndex < cmbGain.Items.Count)
                        {
                            cmbGain.SelectedIndex = gainIndex;
                        }
                        else
                        {
                            cmbGain.SelectedIndex = 0;
                        }
                    }
                    else
                    {
                        // æ¢å¤æ–‡æœ¬æ¡†æ˜¾ç¤º
                        txtGain.Visible = true;
                        cmbGain.Visible = false;
                        double exp = 0;
                        double gain = 0;
                        camera.GetExpouseTime(out exp);
                        txtExp.Text = exp.ToString();
                        camera.GetGain(out gain);
                        txtGain.Text = gain.ToString();
                    }
                    camera.GetTriggerMode(out TriggerMode mode, out TriggerSource source);
@@ -295,8 +392,10 @@
            if (camera.CloseDevice())
            {
                onlinePictureBox.Visible = true;
                MessageBox.Show(camera.SN + "断开成功");
                this.panel_Picture.Controls.Clear();
                this.panel_Picture.Controls.Add(onlinePictureBox);
            }
        }
@@ -316,7 +415,7 @@
                PropertyGrid pg = new PropertyGrid();
                pg.Dock = DockStyle.Fill;
                if (camera is PHM6000Camera phmCamera)
                if (camera is LBCamera phmCamera)
                {
                    pg.SelectedObject = phmCamera.GetSensorConfig();
                    pg.PropertyValueChanged += (s, ev) =>
@@ -382,11 +481,14 @@
        /// <summary>
        /// ç›¸æœºå›žè°ƒè¿è¡Œ
        /// æ³¨æ„ï¼šå¯¹äºŽLBCamera(3D线扫相机),使用SDK自动显示模式
        /// SDK会自动将图像显示到对应的控件上,此回调只用于统计采集次数
        /// </summary>
        /// <param name="CCDName"></param>
        /// <param name="image"></param>
        private void GetImageBllComplete(object sender, CameraEventArgs e)
        {
            // å¯¹äºŽ2D相机(手动处理模式)和现在的LBCamera(手动处理模式)
            if (e.Bitmap == null)
                return;
@@ -404,7 +506,6 @@
                    onlinePictureBox.Image = e.Bitmap;
                }
            }
            total.iImageCount++;
            try
            {
@@ -427,23 +528,79 @@
            Task.Factory.StartNew(() =>
            {
                //camera.GetCamConfig(out CameraConfig OriCamConfig);
                // è®¾ç½®æ›å…‰å’Œå¢žç›Š
                camera.SetExpouseTime(Convert.ToDouble(txtExp.Text));
                camera.SetGain(Convert.ToDouble(txtGain.Text));
                camera.GetImageWithSoftTrigger(out Bitmap bitmap);
                bool success = false;
                Bitmap bitmap = null;
                this.BeginInvoke(new Action(() =>
                // è°ƒç”¨åŸºç±»æŽ¥å£çš„单次采集方法
                // LBCamera重写了StartSingleGrab方法,其他相机调用返回false
                success = camera.StartSingleGrab();
                if (success)
                {
                    if (bitmap != null)
                        this.lblCapTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms";
                    else
                        this.lblCapTime.Text = "-1ms";
                }));
                    // ç­‰å¾…图像数据
                    using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                    {
                        Bitmap captured = null;
                        EventHandler<CameraEventArgs> handler = (s, evt) =>
                        {
                            if (evt.Bitmap != null)
                            {
                                captured = evt.Bitmap.Clone() as Bitmap;
                                waitHandle.Set();
                            }
                        };
                //复原原通讯口设置
                //camera.SetCamConfig(OriCamConfig);
                        camera.ImageGrabbed += handler;
                        try
                        {
                            // ç­‰å¾…5秒超时
                            if (waitHandle.WaitOne(5000))
                            {
                                bitmap = captured;
                            }
                        }
                        finally
                        {
                            camera.ImageGrabbed -= handler;
                            camera.StopGrabbing();
                        }
                    }
                    this.BeginInvoke(new Action(() =>
                    {
                        if (bitmap != null)
                        {
                            this.lblCapTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms";
                            onlinePictureBox.Image = bitmap;
                        }
                        else
                        {
                            this.lblCapTime.Text = "-1ms";
                        }
                    }));
                }
                else
                {
                    // å¦‚æžœStartSingleGrab失败,回退到传统的GetImageWithSoftTrigger
                    camera.GetImageWithSoftTrigger(out bitmap);
                    this.BeginInvoke(new Action(() =>
                    {
                        if (bitmap != null)
                        {
                            this.lblCapTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms";
                            onlinePictureBox.Image = bitmap;
                        }
                        else
                        {
                            this.lblCapTime.Text = "-1ms";
                        }
                    }));
                }
            });
        }
@@ -454,12 +611,12 @@
            total.Clear();
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            {
                camera.StopGrabbing();
                camera.StartWith_HardTriggerModel();
            }
            // åœæ­¢å½“前采集
            camera.StopGrabbing();
            // è°ƒç”¨åŸºç±»æŽ¥å£çš„连续采集方法
            // LBCamera会调用StartContinuousGrab方法,其他相机使用原有的StartWith_HardTriggerModel
            camera.StartContinuousGrab();
            startGrabtime = DateTime.Now;
@@ -474,18 +631,15 @@
            total.Clear();
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            {
                Task.Factory.StartNew(() =>
                {
                    camera.StopGrabbing();
                    camera.StartWith_SoftTriggerModel();
            // åœæ­¢å½“前采集
            camera.StopGrabbing();
                });
            }
            // è°ƒç”¨åŸºç±»æŽ¥å£çš„连续采集方法
            // LBCamera会调用StartContinuousGrab方法,其他相机使用原有的StartWith_SoftTriggerModel
            camera.StartContinuousGrab();
            startGrabtime = DateTime.Now;
            cmbSN.Enabled = false;
            cmbBrand.Enabled = false;
        }
@@ -503,8 +657,11 @@
                    Task.Factory.StartNew(() =>
                    {
                        camera.StopGrabbing();
                        camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
                        camera.StartGrabbing();
                        if (brand != CameraBrand.LBCamera)
                        {
                            camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
                            camera.StartGrabbing();
                        }
                    });
                }
@@ -559,7 +716,8 @@
        private void txtGain_TextChanged(object sender, EventArgs e)
        {
            if (camera == null)
            // å¦‚果正在使用下拉框模式(LBCamera),忽略文本框的变化
            if (camera == null || (cmbGain != null && cmbGain.Visible))
                return;
            double gain = 10;
@@ -653,19 +811,34 @@
        private void CameraForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            onlinePictureBox.Visible = true;
            this.panel_Picture.Controls.Clear();
            this.panel_Picture.Controls.Add(onlinePictureBox);
            this.onlinePictureBox.Image = null;
            if (camera != null)
            {
                camera.ImageGrabbed -= GetImageBllComplete;
                camera.StopGrabbing();
                // æ£€æŸ¥è¯¥ç›¸æœºæ˜¯å¦ç”±ä¸»ç³»ç»Ÿç®¡ç†
                bool isManagedBySystem = dicCameras != null && dicCameras.ContainsKey(camera.SN);
                camera.GetTriggerMode(out _, out TriggerSource actualSource);
                if (radioButtonSoft.Checked)
                    camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
                else
                    camera.SetTriggerMode(TriggerMode.On, actualSource);
                if (!isManagedBySystem)
                {
                    // åªæœ‰éžæ‰˜ç®¡çš„(临时打开的)相机才停止采集和释放
                    camera.StopGrabbing();
                camera.StartGrabbing();
                    camera.GetTriggerMode(out _, out TriggerSource actualSource);
                    if (radioButtonSoft.Checked)
                        camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
                    else
                        camera.SetTriggerMode(TriggerMode.On, actualSource);
                    if (camera.Brand != CameraBrand.LBCamera)
                    {
                        camera.StartGrabbing();
                    }
                }
            }
            //路径为空说明为测试模式,需要释放相机
LB_VisionProcesses/Cameras/BaseCamera.cs
@@ -191,12 +191,29 @@
        #region  protected abstract
        /// <summary>
        /// å¼€å§‹é‡‡å›¾
        /// å¼€å§‹é‡‡å›¾ï¼ˆé»˜è®¤å•次采集)
        /// </summary>
        /// <returns></returns>
        public abstract bool StartGrabbing();
        /// <summary>
        /// å•次采集模式(适用于线扫相机)
        /// </summary>
        /// <returns></returns>
        public virtual bool StartSingleGrab()
        {
            // é»˜è®¤å®žçŽ°ï¼šæ™®é€šç›¸æœºä¸æ”¯æŒå•æ¬¡é‡‡é›†ï¼Œç›´æŽ¥è¿”å›žfalse
            // çº¿æ‰«ç›¸æœºéœ€è¦é‡å†™æ­¤æ–¹æ³•
            return false;
        }
        /// <summary>
        /// è¿žç»­é‡‡é›†æ¨¡å¼
        /// </summary>
        /// <returns></returns>
        public abstract bool StartContinuousGrab();
        /// <summary>
        /// åœæ­¢é‡‡å›¾
        /// </summary>
        /// <returns></returns>
LB_VisionProcesses/Cameras/HRCameras/HRCamera.cs
@@ -1412,6 +1412,11 @@
            config.Params.Inputs.Add("增益", gain);
        }
        public override bool StartContinuousGrab()
        {
            return true;
        }
        #endregion
    }
}
LB_VisionProcesses/Cameras/ICamera.cs
@@ -79,11 +79,18 @@
        bool GetImageWithSoftTrigger(out Bitmap bitmap, int outtime = 3000);
        /// <summary>
        /// è½¯è§¦å‘
        /// è½¯è§¦å‘单次
        /// </summary>
        /// <returns></returns>
        bool SoftTrigger();
        /// <summary>
        /// è¿žç»­é‡‡é›†æ¨¡å¼
        /// </summary>
        /// <returns></returns>
        bool StartContinuousGrab();
        #endregion
        #region SettingConfig
LB_VisionProcesses/Cameras/LBCameras/LBCamera.cs
@@ -1,164 +1,678 @@
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
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 LBCameraEventArgs : CameraEventArgs
    {
        public bool IsComplete { get; set; }
        public LBCameraEventArgs(string sn, Bitmap bitmap, bool isComplete) : base(sn, bitmap)
        {
            IsComplete = isComplete;
        }
    }
    /// <summary>
    /// LB3D工业相机实现类
    /// åŸºäºŽPHM6000系列封装
    /// </summary>
    internal class LBCamera : BaseCamera
    public class LBCamera : BaseCamera
    {
        public override bool AutoBalanceWhite()
        private IntPtr _cameraHandle = IntPtr.Zero;
        private PHM6000SensorConfig _sensorConfig;
        // é‡‡é›†å›žè°ƒ
        private AcquisitionCallbackZA _acquisitionCallback;
        private AcquisitionCompletedCallback _acquisitionCompletedCallback;
        private bool _isConnected = false;
        private int _frameCount = 0; // é‡‡é›†å¸§è®¡æ•°
        // å›¾åƒç¼“冲
        private byte[] _rawPixelBuffer = null; // ç”¨äºŽå­˜å‚¨æ•´å¼ å›¾çš„像素数据 (8bpp)
        private int _currentBitmapHeight = 0;
        private int _currentBitmapWidth = 0;
        private int _currentLineCount = 0;
        private object _bufferLock = new object();
        private bool _isBufferReady = false;
        // ä¸´æ—¶è¡Œç¼“冲,用于接收回调数据
        private byte[] _tempLineBuffer = null;
        private bool _isContinuous = false;
        public LBCamera()
        {
            return true;
            Brand = CameraBrand.LBCamera;
            _sensorConfig = new PHM6000SensorConfig();
        }
        #region ICamera Implementation
        public override bool InitDevice(string sn, object handle = null)
        {
            // å¦‚果已连接,直接返回true
            if (_isConnected && _cameraHandle != IntPtr.Zero)
            {
                return true;
            }
            IntPtr tempHandle = IntPtr.Zero;
            try
            {
                SN = sn;
                // 1. åˆ›å»ºä¸´æ—¶å¥æŸ„用于发现设备
                tempHandle = PHM6000Profiler.CreateCameraEntry();
                if (tempHandle == IntPtr.Zero) return false;
                // 2. å‘现相机
                int cameraCount = PHM6000Profiler.DiscoverCameras(tempHandle);
                if (cameraCount <= 0)
                {
                    PHM6000Profiler.DestroyCameraEntry(tempHandle);
                    return false;
                }
                string targetIp = string.Empty;
                int targetPort = 0;
                bool found = false;
                // 3. éåŽ†ç›¸æœºå¯»æ‰¾åŒ¹é…çš„SN
                for (int i = 0; i < cameraCount; i++)
                {
                    byte[] moduleTypeBytes = new byte[64];
                    byte[] serialNumberBytes = new byte[64];
                    if (PHM6000Profiler.GetCameraInformation(tempHandle, i, moduleTypeBytes, serialNumberBytes) == 0)
                    {
                        string currentSn = Encoding.UTF8.GetString(serialNumberBytes).TrimEnd('\0');
                        // åŒ¹é…SN或IP
                        if (currentSn == sn || sn.Contains(currentSn))
                        {
                            byte[] addressBytes = new byte[64];
                            int port = 0;
                            if (PHM6000Profiler.GetCameraAddress(tempHandle, i, addressBytes, ref port) == 0)
                            {
                                targetIp = Encoding.UTF8.GetString(addressBytes).TrimEnd('\0');
                                targetPort = port;
                                found = true;
                                break;
                            }
                        }
                    }
                }
                PHM6000Profiler.DestroyCameraEntry(tempHandle);
                tempHandle = IntPtr.Zero;
                if (!found)
                {
                    if (System.Net.IPAddress.TryParse(sn, out _))
                    {
                        targetIp = sn;
                        targetPort = 5577;
                    }
                    else
                    {
                        AsyncLogHelper.Error($"LBCamera: æœªæ‰¾åˆ°SN为 {sn} çš„相机");
                        return false;
                    }
                }
                // 4. åˆ›å»ºæ­£å¼ç›¸æœºå¥æŸ„并连接
                _cameraHandle = PHM6000Profiler.CreateCameraEntry();
                if (_cameraHandle == IntPtr.Zero) return false;
                var addr = Encoding.ASCII.GetBytes(targetIp);
                int result = PHM6000Profiler.ConnectToCamera(_cameraHandle, addr, targetPort);
                if (result == 0)
                {
                    _isConnected = true;
                    // åŠ è½½ç›¸æœºå½“å‰å‚æ•°åˆ° _sensorConfig
                    SyncConfigFromCamera();
                    // åˆå§‹åŒ–并注册采集回调 (获取数据用)
                    _acquisitionCallback = new AcquisitionCallbackZA(OnAcquisitionCallbackZA);
                    PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, _acquisitionCallback, IntPtr.Zero);
                    // åˆå§‹åŒ–并注册采集完成回调 (状态通知用)
                    _acquisitionCompletedCallback = new AcquisitionCompletedCallback(OnAcquisitionCompleted);
                    PHM6000Profiler.RegisterAcquisitionCompletedCallback(_cameraHandle, _acquisitionCompletedCallback, IntPtr.Zero);
                    // å¼ºåˆ¶åº”用当前配置(确保触发模式等参数正确,避免相机处于未知状态)
                    UpdateSensorConfig(_sensorConfig);
                    AsyncLogHelper.Info($"LBCamera[{SN}]: Connected and initialized successfully (Manual Data Mode)");
                    return true;
                }
                else
                {
                    AsyncLogHelper.Error($"LBCamera[{SN}]: ConnectToCamera failed, result={result}");
                }
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"LBCamera: InitDevice异常 - {ex.Message}");
                if (tempHandle != IntPtr.Zero) PHM6000Profiler.DestroyCameraEntry(tempHandle);
            }
            return false;
        }
        public override bool CloseDevice()
        {
            return true;
        }
        public override void GetCamConfig(out CameraConfig config)
        {
            throw new NotImplementedException();
        }
        public override bool GetExpouseTime(out double value)
        {
            value = 0;
            return true;
        }
        public override bool GetGain(out double gain)
        {
            gain = 0;
            return true;
        }
        public override bool GetImage(out Bitmap bitmap, int outtime = 3000)
        {
            throw new NotImplementedException();
        }
        public override bool GetImageWithSoftTrigger(out Bitmap bitmap, int outtime = 3000)
        {
            throw new NotImplementedException();
        }
        public override bool GetLineStatus(IOLines line, out LineStatus lineStatus)
        {
            lineStatus = LineStatus.Hight;
            if (_isConnected && _cameraHandle != IntPtr.Zero)
            {
                StopGrabbing();
                PHM6000Profiler.DestroyCameraEntry(_cameraHandle);
                _cameraHandle = IntPtr.Zero;
                _isConnected = false;
                AsyncLogHelper.Info($"LBCamera[{SN}]: Closed");
            }
            return true;
        }
        public override List<string> GetListEnum()
        {
            return new List<string>();
            List<string> cameraList = new List<string>();
            IntPtr tempHandle = IntPtr.Zero;
            try
            {
                tempHandle = PHM6000Profiler.CreateCameraEntry();
                if (tempHandle != IntPtr.Zero)
                {
                    int count = PHM6000Profiler.DiscoverCameras(tempHandle);
                    for (int i = 0; i < count; i++)
                    {
                        byte[] moduleTypeBytes = new byte[64];
                        byte[] serialNumberBytes = new byte[64];
                        if (PHM6000Profiler.GetCameraInformation(tempHandle, i, moduleTypeBytes, serialNumberBytes) == 0)
                        {
                            string sn = Encoding.UTF8.GetString(serialNumberBytes).TrimEnd('\0');
                            if (!string.IsNullOrEmpty(sn))
                            {
                                cameraList.Add(sn);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"LBCamera: èŽ·å–è®¾å¤‡åˆ—è¡¨å¼‚å¸¸ - {ex.Message}");
            }
            finally
            {
                if (tempHandle != IntPtr.Zero)
                    PHM6000Profiler.DestroyCameraEntry(tempHandle);
            }
            return cameraList;
        }
        public override bool GetTriggerDelay(out double delay)
        private void InitBuffer()
        {
            delay = 0;
            lock (_bufferLock)
            {
                _currentBitmapHeight = _sensorConfig.ScanLineCount > 0 ? _sensorConfig.ScanLineCount : 5000;
                // å®½åº¦åœ¨ç¬¬ä¸€è¡Œæ•°æ®åˆ°è¾¾æ—¶ç¡®å®š
                _currentBitmapWidth = 0;
                _rawPixelBuffer = null;
                _currentLineCount = 0;
                _isBufferReady = false;
            }
        }
        public override bool StartGrabbing()
        {
            // é»˜è®¤è¿žç»­æ¨¡å¼
            return StartSingleGrab();
        }
        public bool StartSingleGrab()
        {
            if (!_isConnected) return false;
            _isContinuous = false;
            InitBuffer();
            AsyncLogHelper.Info($"LBCamera[{SN}]: å¼€å§‹å•次采集");
            // 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;
        }
        public override bool StartContinuousGrab()
        {
            if (!_isConnected) return false;
            _isContinuous = true;
            InitBuffer();
            AsyncLogHelper.Info($"LBCamera[{SN}]:开始连续采集");
            // 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()
        {
            _isContinuous = false;
            if (!_isConnected) return true;
            PHM6000Profiler.StopAcquisition(_cameraHandle);
            // åœæ­¢æ—¶å¦‚果有未显示的缓存数据,将其显示出来(支持显示不完整的帧)
            lock (_bufferLock)
            {
                if (_currentLineCount > 0)
                {
                    AsyncLogHelper.Info($"LBCamera[{SN}]: Flushing partial buffer ({_currentLineCount} lines) on stop");
                    CreateAndFireBitmap();
                    _currentLineCount = 0;
                }
            }
            isGrabbing = false;
            return true;
        }
        public override bool GetTriggerFliter(out double flitertime)
        public override bool StartWith_SoftTriggerModel() => StartContinuousGrab();
        public override bool StartWith_HardTriggerModel(TriggerSource hardtriggeritem = TriggerSource.Line0) => StartSingleGrab();
        public override bool SoftTrigger() => 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, (int)gain);
        public override bool GetGain(out double gain) { int v; bool r = GetParam(EnumNameId.AnalogGain, out v); gain = v; return r; }
        public override bool SetTriggerMode(TriggerMode mode, TriggerSource triggerEnum = TriggerSource.Line0)
        {
            flitertime = 0;
            if (!_isConnected) return false;
            if (triggerEnum == TriggerSource.Software)
            {
                _sensorConfig.LineScanTriggerSource = EnumLineScanTriggerSource.固定频率;
                _sensorConfig.DataAcquisitionTriggerSource = EnumDataAcquisitionTriggerSource.软触发;
            }
            else
            {
                _sensorConfig.LineScanTriggerSource = EnumLineScanTriggerSource.编码器;
                _sensorConfig.DataAcquisitionTriggerSource = EnumDataAcquisitionTriggerSource.外部触发;
            }
            UpdateSensorConfig(_sensorConfig);
            return true;
        }
        public override bool GetTriggerMode(out TriggerMode mode, out TriggerSource source)
        {
            mode = TriggerMode.On;
            source = TriggerSource.Line0;
            source = _sensorConfig.DataAcquisitionTriggerSource == EnumDataAcquisitionTriggerSource.软触发 ? TriggerSource.Software : TriggerSource.Line0;
            return true;
        }
        public override bool GetTriggerPolarity(out TriggerPolarity polarity)
        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 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)
        {
            polarity = TriggerPolarity.RisingEdge;
            return true;
            // ç®€å•实现:软触发等待
            bitmap = null;
            if(!_isConnected) return false;
            // è®¡ç®—理论最小耗时 (仅当使用固定频率触发时)
            int minTime = 0;
            if (_sensorConfig.LineScanTriggerSource == EnumLineScanTriggerSource.固定频率)
            {
                float rate = _sensorConfig.SoftwareTriggerRate > 0 ? _sensorConfig.SoftwareTriggerRate : 1000f;
                int lines = _sensorConfig.ScanLineCount > 0 ? _sensorConfig.ScanLineCount : 5000;
                minTime = (int)((lines / rate) * 1000);
            }
            // å¦‚果传入超时时间不够,自动延长
            int actualTimeout = outtime;
            if (actualTimeout < minTime + 2000)
            {
                actualTimeout = minTime + 3000; // é¢„ç•™3秒余量
                AsyncLogHelper.Warn($"LBCamera: Provided timeout {outtime}ms is too short for {minTime}ms scan. Extended to {actualTimeout}ms.");
            }
            using (AutoResetEvent waitHandle = new AutoResetEvent(false))
            {
                Bitmap res = null;
                EventHandler<CameraEventArgs> handler = (s, e) => {
                    if(e.Bitmap != null) {
                         res = e.Bitmap.Clone() as Bitmap;
                         waitHandle.Set();
                    }
                };
                ImageGrabbed += handler;
                if (StartSingleGrab())
                {
                    if (!waitHandle.WaitOne(actualTimeout))
                    {
                        AsyncLogHelper.Error($"LBCamera: GetImageWithSoftTrigger timeout after {actualTimeout}ms");
                    }
                }
                else
                {
                    AsyncLogHelper.Error("LBCamera: StartSingleGrab failed");
                }
                ImageGrabbed -= handler;
                // ç¡®ä¿åœæ­¢é‡‡é›†
                StopGrabbing();
                bitmap = res;
                return bitmap != null;
            }
        }
        public override bool InitDevice(string SN, object Handle = null)
        public PHM6000SensorConfig GetSensorConfig()
        {
            return true;
            SyncConfigFromCamera();
            return _sensorConfig;
        }
        public override void SetCamConfig(CameraConfig config)
        public void UpdateSensorConfig(PHM6000SensorConfig config)
        {
            throw new NotImplementedException();
            _sensorConfig = config;
            if (!_isConnected) return;
            SetParam(EnumNameId.ExposureTime, (float)config.ExposureTime);
            SetParam(EnumNameId.AnalogGain, (float)config.AnalogGain);
            PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)EnumNameId.ScanLineCount, config.ScanLineCount, 0, 0);
            PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)EnumNameId.LineScanTriggerSource, 0, 0, (int)config.LineScanTriggerSource);
            PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)EnumNameId.DataAcquisitionTriggerSource, 0, 0, (int)config.DataAcquisitionTriggerSource);
            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.固定频率)
            {
                PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)EnumNameId.SoftwareTriggerRate, 0, config.SoftwareTriggerRate, 0);
            }
            PHM6000Profiler.SaveAllParametersToDevice(_cameraHandle);
        }
        public override bool SetExpouseTime(double value)
        #endregion
        #endregion
        #region Callbacks
        private void OnAcquisitionCallbackZA(IntPtr pInstance, IntPtr buffer, int points)
        {
            return true;
            if (buffer == IntPtr.Zero || points <= 0) return;
            lock (_bufferLock)
            {
                // åˆå§‹åŒ–缓冲区
                if (_rawPixelBuffer == null)
                {
                    _currentBitmapWidth = points;
                    if (_currentBitmapHeight <= 0) _currentBitmapHeight = 2000; // é»˜è®¤é˜²å‘†
                    _rawPixelBuffer = new byte[_currentBitmapWidth * _currentBitmapHeight];
                    _currentLineCount = 0;
                }
                if (_currentLineCount >= _currentBitmapHeight) return; // ç¼“冲区满,忽略多余数据
                // å‡†å¤‡ä¸´æ—¶ç¼“冲区接收行数据 (LBPointZA = 8 bytes)
                int lineBytes = points * 8;
                if (_tempLineBuffer == null || _tempLineBuffer.Length != lineBytes)
                {
                    _tempLineBuffer = new byte[lineBytes];
                }
                // æ‹·è´éžæ‰˜ç®¡å†…存到托管数组
                Marshal.Copy(buffer, _tempLineBuffer, 0, lineBytes);
                // æå–灰度(Intensity/Alpha)数据填充到 _rawPixelBuffer
                // LBPointZA结构: float(4) + res(3) + alpha(1). Alpha在偏移7
                int bufferOffset = _currentLineCount * _currentBitmapWidth;
                for (int i = 0; i < points; i++)
                {
                    if (bufferOffset + i < _rawPixelBuffer.Length)
                    {
                        _rawPixelBuffer[bufferOffset + i] = _tempLineBuffer[i * 8 + 7];
                    }
                }
                _currentLineCount++;
                // å¦‚果达到预定高度,生成图像
                if (_currentLineCount >= _currentBitmapHeight)
                {
                    CreateAndFireBitmap();
                    // é‡ç½®ï¼Œå‡†å¤‡ä¸‹ä¸€å¸§ (如果是连续采集)
                    _currentLineCount = 0;
                    // _rawPixelBuffer å¯ä»¥å¤ç”¨ï¼Œä¸éœ€è¦ç½®ç©º
                }
            }
        }
        public override bool SetGain(double gain)
        private void OnAcquisitionCompleted(IntPtr pInstance, int nOption)
        {
            return true;
            // nOption: 0=Batch End, 1=All End(Single), 2=Processing End
            // æ­¤å¤„主要用于日志或状态监控
            // å®žé™…图像生成在 Data Callback ä¸­å®Œæˆ
            if (nOption == 1) // å•次采集结束
            {
                if (_isContinuous && isGrabbing)
                {
                    // å¦‚果在连续模式下收到结束信号,尝试自动重启采集
                    AsyncLogHelper.Info($"LBCamera[{SN}]: Continuous mode frame ended, restarting...");
                    Task.Run(() =>
                    {
                        if (_isContinuous && _isConnected)
                        {
                            PHM6000Profiler.StartAcquisition(_cameraHandle, 0, 0, 0.0);
                        }
                    });
                }
                else
                {
                    isGrabbing = false;
                    AsyncLogHelper.Info($"LBCamera[{SN}]: Single grab completed by SDK");
                    // å•次采集结束时,如果有未显示的缓冲数据,立即生成图像
                    // é˜²æ­¢å› æ•°æ®é‡ä¸è¶³(小于ScanLineCount)导致GetImageWithSoftTrigger一直等待
                    lock (_bufferLock)
                    {
                        if (_currentLineCount > 0)
                        {
                            AsyncLogHelper.Info($"LBCamera[{SN}]: Flushing partial buffer ({_currentLineCount} lines) on completion");
                            CreateAndFireBitmap();
                            _currentLineCount = 0;
                        }
                    }
                }
            }
        }
        public override bool SetLineMode(IOLines line, LineMode mode)
        private void CreateAndFireBitmap()
        {
            return true;
            try
            {
                int width = _currentBitmapWidth;
                int height = _currentLineCount; // ä½¿ç”¨å®žé™…采集到的行数
                if (width <= 0 || height <= 0 || _rawPixelBuffer == null) return;
                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);
                // æ³¨æ„ï¼šBitmap Stride å¯èƒ½ä¸ç­‰äºŽ Width,需要逐行拷贝
                int stride = bmpData.Stride;
                IntPtr ptr = bmpData.Scan0;
                for (int y = 0; y < height; y++)
                {
                    // ç¡®ä¿ä¸è¶Šç•Œ
                    if ((y * width) + width <= _rawPixelBuffer.Length)
                    {
                        Marshal.Copy(_rawPixelBuffer, y * width, ptr + y * stride, width);
                    }
                }
                bmp.UnlockBits(bmpData);
                _frameCount++;
                AsyncLogHelper.Info($"LBCamera[{SN}]: Frame {_frameCount} generated ({width}x{height})");
                // å¼‚步触发事件,避免阻塞SDK回调线程
                Task.Run(() =>
                {
                    try
                    {
                        ImageGrabbed?.Invoke(this, new LBCameraEventArgs(SN, bmp, true));
                    }
                    catch (Exception ex)
                    {
                        AsyncLogHelper.Error($"LBCamera: Event Invoke error - {ex.Message}");
                        bmp.Dispose(); // å¼‚常时释放资源
                    }
                });
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"LBCamera: CreateBitmap error - {ex.Message}");
            }
        }
        public override bool SetLineStatus(IOLines line, LineStatus linestatus)
        private void SyncConfigFromCamera()
        {
            return true;
            try
            {
                if (!_isConnected) return;
                PropertyInfo[] props = _sensorConfig.GetType().GetProperties();
                foreach (PropertyInfo p in props)
                {
                    // è·³è¿‡è‡ªå®šä¹‰å‚æ•°
                    var iscustomAttr = p.GetCustomAttribute<IsCustomAttribute>();
                    if (iscustomAttr != null) continue;
                    if (Enum.TryParse(typeof(EnumNameId), p.Name, out object nameIdObj))
                    {
                        EnumNameId nameId = (EnumNameId)nameIdObj;
                        int intValue = 0;
                        double doubleValue = 0;
                        int enumValue = 0;
                        if (PHM6000Profiler.GetProfilerParameter(_cameraHandle, (int)nameId, ref intValue, ref doubleValue, ref enumValue) == 0)
                        {
                            if (p.PropertyType == typeof(int))
                            {
                                p.SetValue(_sensorConfig, intValue);
                            }
                            else if (p.PropertyType == typeof(float))
                            {
                                p.SetValue(_sensorConfig, (float)doubleValue);
                            }
                            else if (p.PropertyType == typeof(double))
                            {
                                p.SetValue(_sensorConfig, doubleValue);
                            }
                            else // Enum or other types
                            {
                                p.SetValue(_sensorConfig, enumValue);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"LBCamera: SyncConfigFromCamera error - {ex.Message}");
            }
        }
        public override bool SetTriggerDelay(double delay)
        private bool SetParam(EnumNameId id, float value)
        {
            return true;
            if (!_isConnected) return false;
            return PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)id, 0, value, 0) == 0;
        }
        public override bool SetTriggerFliter(double flitertime)
        private bool SetParam(EnumNameId id, int value)
        {
            return true;
            if (!_isConnected) return false;
            // å¯¹äºŽæžšä¸¾ç±»åž‹ï¼Œé€šå¸¸é€šè¿‡ enumValue (最后一个参数) ä¼ é€’
            return PHM6000Profiler.SetProfilerParameter(_cameraHandle, (int)id, 0, 0, value) == 0;
        }
        public override bool SetTriggerMode(TriggerMode mode, TriggerSource triggerEnum = TriggerSource.Line0)
        private bool GetParam(EnumNameId id, out float value)
        {
            return true;
            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;
        }
        public override bool SetTriggerPolarity(TriggerPolarity polarity)
        private bool GetParam(EnumNameId id, out int value)
        {
            return true;
            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 = eVal; // Assuming it returns in enumValue
                return true;
            }
            return false;
        }
        public override bool SoftTrigger()
        {
            return true;
        }
        public override bool StartGrabbing()
        {
            return true;
        }
        public override bool StartWith_HardTriggerModel(TriggerSource hardtriggeritem = TriggerSource.Line0)
        {
            throw new NotImplementedException();
        }
        public override bool StartWith_SoftTriggerModel()
        {
            throw new NotImplementedException();
        }
        public override bool StopGrabbing()
        {
            return true;
        }
        #endregion
    }
}
}
LB_VisionProcesses/Cameras/LBCameras/PHM6000Camera.cs
ÎļþÒÑɾ³ý