C3204
2025-12-22 3f517728fd5f55bbd652613d4648cb02587c02d7
添加兴启新增的HR相机类等项目文件。
已修改4个文件
已添加1个文件
1531 ■■■■ 文件已修改
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.Designer.cs 289 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.cs 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/HRCameras/HRCamera.cs 1135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/LB_VisionProcesses.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.cs
@@ -1,4 +1,5 @@
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Cameras.HRCameras;
using RJCP.IO.Ports;
using System;
using System.Collections.Concurrent;
@@ -27,7 +28,7 @@
            // ç¦æ­¢ä¿®æ”¹çª—口大小
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            if (camera == null)
                //camera = new HRCamera();
                camera = new HRCamera();
            uiButtonCreate.Enabled = false;
        }
@@ -96,7 +97,7 @@
            switch (brand)
            {
                case CameraBrand.HRCamera:
                    //camera = new HRCamera();
                    camera = new HRCamera();
                    break;
                case CameraBrand.LBCamera:
                    //camera = new LBCamera();
LB_VisionProcesses/Cameras/2DCameraForm.Designer.cs
@@ -29,15 +29,15 @@
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CameraForm));
            cmbBrand = new ComboBox();
            cmbSN = new ComboBox();
            cmb_Brand = new ComboBox();
            cmb_SN = new ComboBox();
            label1 = new Label();
            label2 = new Label();
            btnStartGrab = new Button();
            btnCloseGrab = new Button();
            btnGrabOnce = new Button();
            btnOpen = new Button();
            btnClose = new Button();
            btn_StartGrab = new Button();
            btn_CloseGrab = new Button();
            btn_GrabOnce = new Button();
            btn_Open = new Button();
            btn_Close = new Button();
            label5 = new Label();
            lblPicCount = new Label();
            txtGain = new TextBox();
@@ -54,9 +54,9 @@
            tableLayoutPanel3 = new TableLayoutPanel();
            tableLayoutPanel4 = new TableLayoutPanel();
            tableLayoutPanel5 = new TableLayoutPanel();
            btnEdit = new Button();
            btn_Edit = new Button();
            tableLayoutPanel6 = new TableLayoutPanel();
            btnSaveImage = new Button();
            btn_SaveImage = new Button();
            tableLayoutPanel7 = new TableLayoutPanel();
            tableLayoutPanel8 = new TableLayoutPanel();
            tableLayoutPanel1 = new TableLayoutPanel();
@@ -70,8 +70,8 @@
            cmbImagesPath = new ComboBox();
            tableLayoutPanel9 = new TableLayoutPanel();
            ckbLocalTest = new CheckBox();
            btnAddImages = new Button();
            btnLocalGrab = new Button();
            btn_AddImages = new Button();
            btn_LocalGrab = new Button();
            tableLayoutPanel10 = new TableLayoutPanel();
            label6 = new Label();
            txtTimeout = new TextBox();
@@ -100,25 +100,25 @@
            panel_2DCameraForm.SuspendLayout();
            SuspendLayout();
            // 
            // cmbBrand
            // cmb_Brand
            // 
            cmbBrand.Dock = DockStyle.Fill;
            cmbBrand.FormattingEnabled = true;
            cmbBrand.Location = new Point(53, 3);
            cmbBrand.Name = "cmbBrand";
            cmbBrand.Size = new Size(297, 25);
            cmbBrand.TabIndex = 0;
            cmb_Brand.Dock = DockStyle.Fill;
            cmb_Brand.FormattingEnabled = true;
            cmb_Brand.Location = new Point(53, 3);
            cmb_Brand.Name = "cmb_Brand";
            cmb_Brand.Size = new Size(297, 25);
            cmb_Brand.TabIndex = 0;
            // 
            // cmbSN
            // cmb_SN
            // 
            cmbSN.Dock = DockStyle.Fill;
            cmbSN.FormattingEnabled = true;
            cmbSN.Location = new Point(53, 3);
            cmbSN.Name = "cmbSN";
            cmbSN.Size = new Size(297, 25);
            cmbSN.TabIndex = 1;
            cmbSN.SelectedIndexChanged += cmbSN_SelectedIndexChanged;
            cmbSN.MouseDown += cmbSN_MouseDown;
            cmb_SN.Dock = DockStyle.Fill;
            cmb_SN.FormattingEnabled = true;
            cmb_SN.Location = new Point(53, 3);
            cmb_SN.Name = "cmb_SN";
            cmb_SN.Size = new Size(297, 25);
            cmb_SN.TabIndex = 1;
            cmb_SN.SelectedIndexChanged += cmbSN_SelectedIndexChanged;
            cmb_SN.MouseDown += cmbSN_MouseDown;
            // 
            // label1
            // 
@@ -142,65 +142,65 @@
            label2.Text = "SN";
            label2.TextAlign = ContentAlignment.MiddleCenter;
            // 
            // btnStartGrab
            // btn_StartGrab
            // 
            btnStartGrab.Dock = DockStyle.Fill;
            btnStartGrab.ForeColor = SystemColors.ControlText;
            btnStartGrab.Location = new Point(91, 3);
            btnStartGrab.Name = "btnStartGrab";
            btnStartGrab.Size = new Size(82, 28);
            btnStartGrab.TabIndex = 5;
            btnStartGrab.Text = "连续采集";
            btnStartGrab.UseVisualStyleBackColor = true;
            btnStartGrab.Click += btnStartGrab_Click;
            btn_StartGrab.Dock = DockStyle.Fill;
            btn_StartGrab.ForeColor = SystemColors.ControlText;
            btn_StartGrab.Location = new Point(91, 3);
            btn_StartGrab.Name = "btn_StartGrab";
            btn_StartGrab.Size = new Size(82, 28);
            btn_StartGrab.TabIndex = 5;
            btn_StartGrab.Text = "连续采集";
            btn_StartGrab.UseVisualStyleBackColor = true;
            btn_StartGrab.Click += btn_StartGrab_Click;
            // 
            // btnCloseGrab
            // btn_CloseGrab
            // 
            btnCloseGrab.Dock = DockStyle.Fill;
            btnCloseGrab.ForeColor = SystemColors.Desktop;
            btnCloseGrab.Location = new Point(179, 3);
            btnCloseGrab.Name = "btnCloseGrab";
            btnCloseGrab.Size = new Size(82, 28);
            btnCloseGrab.TabIndex = 6;
            btnCloseGrab.Text = "关闭采集";
            btnCloseGrab.UseVisualStyleBackColor = true;
            btnCloseGrab.Click += btnCloseGrab_Click;
            btn_CloseGrab.Dock = DockStyle.Fill;
            btn_CloseGrab.ForeColor = SystemColors.Desktop;
            btn_CloseGrab.Location = new Point(179, 3);
            btn_CloseGrab.Name = "btn_CloseGrab";
            btn_CloseGrab.Size = new Size(82, 28);
            btn_CloseGrab.TabIndex = 6;
            btn_CloseGrab.Text = "关闭采集";
            btn_CloseGrab.UseVisualStyleBackColor = true;
            btn_CloseGrab.Click += btn_CloseGrab_Click;
            // 
            // btnGrabOnce
            // btn_GrabOnce
            // 
            btnGrabOnce.Dock = DockStyle.Fill;
            btnGrabOnce.ForeColor = SystemColors.ControlText;
            btnGrabOnce.Location = new Point(3, 3);
            btnGrabOnce.Name = "btnGrabOnce";
            btnGrabOnce.Size = new Size(82, 28);
            btnGrabOnce.TabIndex = 7;
            btnGrabOnce.Text = "单张采集";
            btnGrabOnce.UseVisualStyleBackColor = true;
            btnGrabOnce.Click += btnGrabOnce_Click;
            btn_GrabOnce.Dock = DockStyle.Fill;
            btn_GrabOnce.ForeColor = SystemColors.ControlText;
            btn_GrabOnce.Location = new Point(3, 3);
            btn_GrabOnce.Name = "btn_GrabOnce";
            btn_GrabOnce.Size = new Size(82, 28);
            btn_GrabOnce.TabIndex = 7;
            btn_GrabOnce.Text = "单张采集";
            btn_GrabOnce.UseVisualStyleBackColor = true;
            btn_GrabOnce.Click += btn_GrabOnce_Click;
            // 
            // btnOpen
            // btn_Open
            // 
            btnOpen.Dock = DockStyle.Fill;
            btnOpen.ForeColor = SystemColors.ControlText;
            btnOpen.Location = new Point(3, 3);
            btnOpen.Name = "btnOpen";
            btnOpen.Size = new Size(82, 28);
            btnOpen.TabIndex = 8;
            btnOpen.Text = "打开";
            btnOpen.UseVisualStyleBackColor = true;
            btnOpen.Click += btnOpen_Click;
            btn_Open.Dock = DockStyle.Fill;
            btn_Open.ForeColor = SystemColors.ControlText;
            btn_Open.Location = new Point(3, 3);
            btn_Open.Name = "btn_Open";
            btn_Open.Size = new Size(82, 28);
            btn_Open.TabIndex = 8;
            btn_Open.Text = "打开";
            btn_Open.UseVisualStyleBackColor = true;
            btn_Open.Click += btn_Open_Click;
            // 
            // btnClose
            // btn_Close
            // 
            btnClose.Dock = DockStyle.Fill;
            btnClose.ForeColor = SystemColors.ControlText;
            btnClose.Location = new Point(91, 3);
            btnClose.Name = "btnClose";
            btnClose.Size = new Size(82, 28);
            btnClose.TabIndex = 9;
            btnClose.Text = "关闭";
            btnClose.UseVisualStyleBackColor = true;
            btnClose.Click += btnClose_Click;
            btn_Close.Dock = DockStyle.Fill;
            btn_Close.ForeColor = SystemColors.ControlText;
            btn_Close.Location = new Point(91, 3);
            btn_Close.Name = "btn_Close";
            btn_Close.Size = new Size(82, 28);
            btn_Close.TabIndex = 9;
            btn_Close.Text = "关闭";
            btn_Close.UseVisualStyleBackColor = true;
            btn_Close.Click += btn_Close_Click;
            // 
            // label5
            // 
@@ -231,7 +231,7 @@
            txtGain.Name = "txtGain";
            txtGain.Size = new Size(297, 23);
            txtGain.TabIndex = 21;
            txtGain.TextChanged += txtGain_TextChanged;
            txtGain.TextChanged += txt_Gain_TextChanged;
            // 
            // txtExp
            // 
@@ -240,7 +240,7 @@
            txtExp.Name = "txtExp";
            txtExp.Size = new Size(297, 23);
            txtExp.TabIndex = 20;
            txtExp.TextChanged += txtExp_TextChanged;
            txtExp.TextChanged += txt_Exp_TextChanged;
            // 
            // label4
            // 
@@ -387,7 +387,7 @@
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Controls.Add(label1, 0, 0);
            tableLayoutPanel3.Controls.Add(cmbBrand, 1, 0);
            tableLayoutPanel3.Controls.Add(cmb_Brand, 1, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(3, 3);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
@@ -402,7 +402,7 @@
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Controls.Add(label2, 0, 0);
            tableLayoutPanel4.Controls.Add(cmbSN, 1, 0);
            tableLayoutPanel4.Controls.Add(cmb_SN, 1, 0);
            tableLayoutPanel4.Dock = DockStyle.Fill;
            tableLayoutPanel4.Location = new Point(3, 43);
            tableLayoutPanel4.Name = "tableLayoutPanel4";
@@ -418,9 +418,9 @@
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            tableLayoutPanel5.Controls.Add(btnOpen, 0, 0);
            tableLayoutPanel5.Controls.Add(btnClose, 1, 0);
            tableLayoutPanel5.Controls.Add(btnEdit, 3, 0);
            tableLayoutPanel5.Controls.Add(btn_Open, 0, 0);
            tableLayoutPanel5.Controls.Add(btn_Close, 1, 0);
            tableLayoutPanel5.Controls.Add(btn_Edit, 3, 0);
            tableLayoutPanel5.Dock = DockStyle.Fill;
            tableLayoutPanel5.Location = new Point(3, 83);
            tableLayoutPanel5.Name = "tableLayoutPanel5";
@@ -429,18 +429,18 @@
            tableLayoutPanel5.Size = new Size(353, 34);
            tableLayoutPanel5.TabIndex = 2;
            // 
            // btnEdit
            // btn_Edit
            // 
            btnEdit.Dock = DockStyle.Fill;
            btnEdit.Enabled = false;
            btnEdit.ForeColor = SystemColors.ControlText;
            btnEdit.Location = new Point(267, 3);
            btnEdit.Name = "btnEdit";
            btnEdit.Size = new Size(83, 28);
            btnEdit.TabIndex = 10;
            btnEdit.Text = "编辑";
            btnEdit.UseVisualStyleBackColor = true;
            btnEdit.Click += btnEdit_Click;
            btn_Edit.Dock = DockStyle.Fill;
            btn_Edit.Enabled = false;
            btn_Edit.ForeColor = SystemColors.ControlText;
            btn_Edit.Location = new Point(267, 3);
            btn_Edit.Name = "btn_Edit";
            btn_Edit.Size = new Size(83, 28);
            btn_Edit.TabIndex = 10;
            btn_Edit.Text = "编辑";
            btn_Edit.UseVisualStyleBackColor = true;
            btn_Edit.Click += btn_Edit_Click;
            // 
            // tableLayoutPanel6
            // 
@@ -449,10 +449,10 @@
            tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25.0006275F));
            tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25.0006237F));
            tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 24.9981289F));
            tableLayoutPanel6.Controls.Add(btnGrabOnce, 0, 0);
            tableLayoutPanel6.Controls.Add(btnStartGrab, 1, 0);
            tableLayoutPanel6.Controls.Add(btnCloseGrab, 2, 0);
            tableLayoutPanel6.Controls.Add(btnSaveImage, 3, 0);
            tableLayoutPanel6.Controls.Add(btn_GrabOnce, 0, 0);
            tableLayoutPanel6.Controls.Add(btn_StartGrab, 1, 0);
            tableLayoutPanel6.Controls.Add(btn_CloseGrab, 2, 0);
            tableLayoutPanel6.Controls.Add(btn_SaveImage, 3, 0);
            tableLayoutPanel6.Dock = DockStyle.Fill;
            tableLayoutPanel6.Location = new Point(3, 163);
            tableLayoutPanel6.Name = "tableLayoutPanel6";
@@ -461,18 +461,18 @@
            tableLayoutPanel6.Size = new Size(353, 34);
            tableLayoutPanel6.TabIndex = 24;
            // 
            // btnSaveImage
            // btn_SaveImage
            // 
            btnSaveImage.Dock = DockStyle.Fill;
            btnSaveImage.ForeColor = SystemColors.Desktop;
            btnSaveImage.Location = new Point(266, 2);
            btnSaveImage.Margin = new Padding(2);
            btnSaveImage.Name = "btnSaveImage";
            btnSaveImage.Size = new Size(85, 30);
            btnSaveImage.TabIndex = 8;
            btnSaveImage.Text = "保存图片";
            btnSaveImage.UseVisualStyleBackColor = true;
            btnSaveImage.Click += btnSaveImage_Click;
            btn_SaveImage.Dock = DockStyle.Fill;
            btn_SaveImage.ForeColor = SystemColors.Desktop;
            btn_SaveImage.Location = new Point(266, 2);
            btn_SaveImage.Margin = new Padding(2);
            btn_SaveImage.Name = "btn_SaveImage";
            btn_SaveImage.Size = new Size(85, 30);
            btn_SaveImage.TabIndex = 8;
            btn_SaveImage.Text = "保存图片";
            btn_SaveImage.UseVisualStyleBackColor = true;
            btn_SaveImage.Click += btn_SaveImage_Click;
            // 
            // tableLayoutPanel7
            // 
@@ -524,13 +524,14 @@
            // btnStartHard
            // 
            btnStartHard.Dock = DockStyle.Fill;
            btnStartHard.ForeColor = SystemColors.InfoText;
            btnStartHard.Location = new Point(3, 3);
            btnStartHard.Name = "btnStartHard";
            btnStartHard.Size = new Size(64, 28);
            btnStartHard.TabIndex = 22;
            btnStartHard.Text = "等待触发";
            btnStartHard.UseVisualStyleBackColor = true;
            btnStartHard.Click += btnStartHard_Click;
            btnStartHard.Click += btn_StartHard_Click;
            // 
            // ckbUpParams
            // 
@@ -626,8 +627,8 @@
            tableLayoutPanel9.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel9.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel9.Controls.Add(ckbLocalTest, 0, 0);
            tableLayoutPanel9.Controls.Add(btnAddImages, 1, 0);
            tableLayoutPanel9.Controls.Add(btnLocalGrab, 2, 0);
            tableLayoutPanel9.Controls.Add(btn_AddImages, 1, 0);
            tableLayoutPanel9.Controls.Add(btn_LocalGrab, 2, 0);
            tableLayoutPanel9.Dock = DockStyle.Fill;
            tableLayoutPanel9.Location = new Point(3, 403);
            tableLayoutPanel9.Name = "tableLayoutPanel9";
@@ -647,29 +648,29 @@
            ckbLocalTest.Text = "本地取图";
            ckbLocalTest.UseVisualStyleBackColor = true;
            // 
            // btnAddImages
            // btn_AddImages
            // 
            btnAddImages.Dock = DockStyle.Fill;
            btnAddImages.ForeColor = SystemColors.Desktop;
            btnAddImages.Location = new Point(120, 3);
            btnAddImages.Name = "btnAddImages";
            btnAddImages.Size = new Size(111, 28);
            btnAddImages.TabIndex = 1;
            btnAddImages.Text = "添加图片";
            btnAddImages.UseVisualStyleBackColor = true;
            btnAddImages.Click += btnAddImages_Click;
            btn_AddImages.Dock = DockStyle.Fill;
            btn_AddImages.ForeColor = SystemColors.Desktop;
            btn_AddImages.Location = new Point(120, 3);
            btn_AddImages.Name = "btn_AddImages";
            btn_AddImages.Size = new Size(111, 28);
            btn_AddImages.TabIndex = 1;
            btn_AddImages.Text = "添加图片";
            btn_AddImages.UseVisualStyleBackColor = true;
            btn_AddImages.Click += btn_AddImages_Click;
            // 
            // btnLocalGrab
            // btn_LocalGrab
            // 
            btnLocalGrab.Dock = DockStyle.Fill;
            btnLocalGrab.ForeColor = SystemColors.Desktop;
            btnLocalGrab.Location = new Point(237, 3);
            btnLocalGrab.Name = "btnLocalGrab";
            btnLocalGrab.Size = new Size(113, 28);
            btnLocalGrab.TabIndex = 2;
            btnLocalGrab.Text = "本地取图";
            btnLocalGrab.UseVisualStyleBackColor = true;
            btnLocalGrab.Click += btnLocalGrab_Click;
            btn_LocalGrab.Dock = DockStyle.Fill;
            btn_LocalGrab.ForeColor = SystemColors.Desktop;
            btn_LocalGrab.Location = new Point(237, 3);
            btn_LocalGrab.Name = "btn_LocalGrab";
            btn_LocalGrab.Size = new Size(113, 28);
            btn_LocalGrab.TabIndex = 2;
            btn_LocalGrab.Text = "本地取图";
            btn_LocalGrab.UseVisualStyleBackColor = true;
            btn_LocalGrab.Click += btn_LocalGrab_Click;
            // 
            // tableLayoutPanel10
            // 
@@ -806,15 +807,15 @@
        #endregion
        private ComboBox cmbBrand;
        private ComboBox cmbSN;
        private ComboBox cmb_Brand;
        private ComboBox cmb_SN;
        private Label label1;
        private Label label2;
        private Button btnStartGrab;
        private Button btnCloseGrab;
        private Button btnGrabOnce;
        private Button btnOpen;
        private Button btnClose;
        private Button btn_StartGrab;
        private Button btn_CloseGrab;
        private Button btn_GrabOnce;
        private Button btn_Open;
        private Button btn_Close;
        private TextBox txtGain;
        private TextBox txtExp;
        private Label label4;
@@ -843,11 +844,11 @@
        private TableLayoutPanel tableLayoutPanel12;
        private ComboBox cmbImagesPath;
        private CheckBox ckbLocalTest;
        private Button btnAddImages;
        private Button btnLocalGrab;
        private Button btnEdit;
        private Button btn_AddImages;
        private Button btn_LocalGrab;
        private Button btn_Edit;
        private CheckBox ckbUpParams;
        private Button btnSaveImage;
        private Button btn_SaveImage;
        private TableLayoutPanel tableLayoutPanel10;
        private Label label6;
        private TextBox txtTimeout;
LB_VisionProcesses/Cameras/2DCameraForm.cs
@@ -1,5 +1,6 @@
using HalconDotNet;
using LB_VisionControl;
using LB_VisionProcesses.Cameras.HRCameras;
using MVSDK_Net;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
@@ -37,9 +38,9 @@
        {
            InitializeComponent();
            //传入相机句柄后禁用连接/断开按键
            this.btnOpen.Enabled = false;
            this.btnClose.Enabled = false;
            this.cmbBrand.Enabled = false;
            this.btn_Open.Enabled = false;
            this.btn_Close.Enabled = false;
            this.cmb_Brand.Enabled = false;
            this.panel_Picture.Controls.Clear();
            this.dicCameras = dicCameras;
@@ -47,7 +48,7 @@
            this.camConfig = camConfig;
            foreach (var CamSN in dicCameras.Keys)
                cmbSN.Items.Add(CamSN);
                cmb_SN.Items.Add(CamSN);
            Enum.TryParse(camConfig.Params.Inputs["触发方式"].ToString(), out TriggerSource TriggerSource);
@@ -95,17 +96,17 @@
            var brands = Enum.GetValues(typeof(CameraBrand)).Cast<CameraBrand>();
            foreach (var brand in brands)
            {
                cmbBrand.Items.Add(brand.ToString());
                cmb_Brand.Items.Add(brand.ToString());
            }
            //选择Cam会触发ValueChanged事件,没有输入相机的情况下选择到-1
            if (camConfig != null)
            {
                string SN = camConfig.Params.Inputs["相机SN"].ToString();
                int Index = cmbSN.FindString(SN);
                int Index = cmb_SN.FindString(SN);
                cmbSN.Text = SN;
                cmbSN.SelectedIndex = Index;
                cmb_SN.Text = SN;
                cmb_SN.SelectedIndex = Index;
                ckbLocalTest.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否本地取图"].ToString());
                ckbUpParams.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否每次写入参数"].ToString());
@@ -146,15 +147,15 @@
            if (dicCameras != null && dicCameras.Count > 0)
                return;
            cmbSN.Items.Clear();
            cmb_SN.Items.Clear();
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            if (Enum.TryParse(cmb_Brand.Text, true, out CameraBrand brand))
            {
                // ä½¿ç”¨ switch è¯­å¥æ¥åˆ¤æ–­æžšä¸¾å€¼
                switch (brand)
                {
                    case CameraBrand.HRCamera:
                        //camera = new HRCamera();
                        camera = new HRCamera();
                        break;
                    case CameraBrand.LBCamera:
                        //camera = new LBCamera();
@@ -166,8 +167,8 @@
                foreach (var item in camera.GetListEnum())
                {
                    if (!cmbSN.Items.Contains(item))
                        cmbSN.Items.Add(item);
                    if (!cmb_SN.Items.Contains(item))
                        cmb_SN.Items.Add(item);
                }
            }
            else
@@ -178,7 +179,7 @@
        private void cmbSN_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnEdit.Enabled = false;
            btn_Edit.Enabled = false;
            //camConfig不为空(输入有相机),更改相机选择需要重新加载刷图事件
            if (camConfig != null && camera != null)
            {
@@ -191,8 +192,8 @@
                camera.Dispose();
            }
            if (dicCameras != null && dicCameras.Count > 0 && dicCameras.ContainsKey(cmbSN.Text))
                camera = dicCameras[cmbSN.Text];
            if (dicCameras != null && dicCameras.Count > 0 && dicCameras.ContainsKey(cmb_SN.Text))
                camera = dicCameras[cmb_SN.Text];
            //说明相机已经初始化成功
            if (camera != null && camera.isGrabbing)
@@ -200,16 +201,16 @@
                camera.ImageGrabbed -= GetImageBllComplete;
                camera.ImageGrabbed += GetImageBllComplete;
                int Index = cmbBrand.FindString(camera.Brand.ToString()); ;
                cmbBrand.Text = camera.Brand.ToString();
                cmbBrand.SelectedIndex = Index;
                int Index = cmb_Brand.FindString(camera.Brand.ToString()); ;
                cmb_Brand.Text = camera.Brand.ToString();
                cmb_Brand.SelectedIndex = Index;
            }
        }
        private void btnOpen_Click(object sender, EventArgs e)
        private void btn_Open_Click(object sender, EventArgs e)
        {
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            if (Enum.TryParse(cmb_Brand.Text, true, out CameraBrand brand))
            {
                if (camera != null)
                {
@@ -224,14 +225,14 @@
                        //camera = new LBCamera();
                        break;
                    case CameraBrand.HRCamera:
                        //camera = new 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))
                if (cmb_SN.Items.Count > 0 && camera.InitDevice(cmb_SN.Text.ToString(), this.Handle))
                {
                    camera.ImageGrabbed -= GetImageBllComplete;
                    camera.ImageGrabbed += GetImageBllComplete;
@@ -265,11 +266,11 @@
            }
        }
        private void btnClose_Click(object sender, EventArgs e)
        private void btn_Close_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            this.btnEdit.Enabled = false;
            this.btn_Edit.Enabled = false;
            if (camera.CloseDevice())
            {
@@ -278,7 +279,7 @@
            }
        }
        private void btnEdit_Click(object sender, EventArgs e)
        private void btn_Edit_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
@@ -323,7 +324,7 @@
        private Pen pen = new Pen(Color.Blue, 3f);
        private System.Drawing.Point[] stPointList = new System.Drawing.Point[4];
        private void btnGrabOnce_Click(object sender, EventArgs e)
        private void btn_GrabOnce_Click(object sender, EventArgs e)
        {
            DateTime StartTime = DateTime.Now;
            if (camera == null)
@@ -331,7 +332,7 @@
            Task.Factory.StartNew(() =>
            {
                //camera.GetCamConfig(out CameraConfig OriCamConfig);
                camera.GetCamConfig(out CameraConfig OriCamConfig);
                camera.SetExpouseTime(Convert.ToDouble(txtExp.Text));
                camera.SetGain(Convert.ToDouble(txtGain.Text));
@@ -347,11 +348,11 @@
                }));
                //复原原通讯口设置
                //camera.SetCamConfig(OriCamConfig);
                camera.SetCamConfig(OriCamConfig);
            });
        }
        private void btnStartHard_Click(object sender, EventArgs e)
        private void btn_StartHard_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
@@ -359,7 +360,7 @@
            total.Clear();
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            if (Enum.TryParse(cmb_Brand.Text, true, out CameraBrand brand))
            {
                camera.StopGrabbing();
                camera.StartWith_HardTriggerModel();
@@ -367,11 +368,11 @@
            startGrabtime = DateTime.Now;
            cmbSN.Enabled = false;
            cmbBrand.Enabled = false;
            cmb_SN.Enabled = false;
            cmb_Brand.Enabled = false;
        }
        private void btnStartGrab_Click(object sender, EventArgs e)
        private void btn_StartGrab_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
@@ -379,7 +380,7 @@
            total.Clear();
            // å°è¯•将输入字符串转换为枚举值
            if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
            if (Enum.TryParse(cmb_Brand.Text, true, out CameraBrand brand))
            {
                Task.Factory.StartNew(() =>
                {
@@ -390,11 +391,11 @@
            }
            startGrabtime = DateTime.Now;
            cmbSN.Enabled = false;
            cmbBrand.Enabled = false;
            cmb_SN.Enabled = false;
            cmb_Brand.Enabled = false;
        }
        private void btnCloseGrab_Click(object sender, EventArgs e)
        private void btn_CloseGrab_Click(object sender, EventArgs e)
        {
            try
            {
@@ -402,7 +403,7 @@
                    return;
                // å°è¯•将输入字符串转换为枚举值
                if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand))
                if (Enum.TryParse(cmb_Brand.Text, true, out CameraBrand brand))
                {
                    Task.Factory.StartNew(() =>
                    {
@@ -412,13 +413,13 @@
                    });
                }
                cmbSN.Enabled = true;
                cmbBrand.Enabled = true;
                cmb_SN.Enabled = true;
                cmb_Brand.Enabled = true;
            }
            catch { }
        }
        private void btnLocalGrab_Click(object sender, EventArgs e)
        private void btn_LocalGrab_Click(object sender, EventArgs e)
        {
            try
            {
@@ -451,7 +452,7 @@
            catch { }
        }
        private void txtExp_TextChanged(object sender, EventArgs e)
        private void txt_Exp_TextChanged(object sender, EventArgs e)
        {
            if (camera == null)
                return;
@@ -461,7 +462,7 @@
                camera.SetExpouseTime(exp);
        }
        private void txtGain_TextChanged(object sender, EventArgs e)
        private void txt_Gain_TextChanged(object sender, EventArgs e)
        {
            if (camera == null)
                return;
@@ -471,7 +472,7 @@
                camera.SetGain(gain);
        }
        private void btnAddImages_Click(object sender, EventArgs e)
        private void btn_AddImages_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
@@ -516,7 +517,7 @@
            if (res == DialogResult.Yes)  //保存VPP
            {
                camConfig.Params.Inputs.Add("相机SN", cmbSN.Text);
                camConfig.Params.Inputs.Add("相机SN", cmb_SN.Text);
                camConfig.Params.Inputs.Add("触发模式", TriggerMode.On);
                camConfig.Params.Inputs.Add("触发方式", radioButtonSoft.Checked ? TriggerSource.Software : TriggerSource.Line0);
                camConfig.Params.Inputs.Add("是否本地取图", ckbLocalTest.Checked);
@@ -573,7 +574,7 @@
            };
        }
        private void btnSaveImage_Click(object sender, EventArgs e)
        private void btn_SaveImage_Click(object sender, EventArgs e)
        {
            if (Bitmap == null)
            {
@@ -613,9 +614,9 @@
        private void radioButtonSoft_CheckedChanged(object sender, EventArgs e)
        {
            btnGrabOnce.Enabled = radioButtonSoft.Checked;
            btnStartGrab.Enabled = radioButtonSoft.Checked;
            btnCloseGrab.Enabled = radioButtonSoft.Checked;
            btn_GrabOnce.Enabled = radioButtonSoft.Checked;
            btn_StartGrab.Enabled = radioButtonSoft.Checked;
            btn_CloseGrab.Enabled = radioButtonSoft.Checked;
            btnStartHard.Enabled = !radioButtonSoft.Checked;
            if (camera == null)
LB_VisionProcesses/Cameras/HRCameras/HRCamera.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1135 @@
using MVSDK_Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace LB_VisionProcesses.Cameras.HRCameras
{
    /// <summary>
    /// åŽç¿2D工业相机实现类
    /// åŸºäºŽMVSDK_Net SDK封装
    /// </summary>
    public class HRCamera : BaseCamera
    {
        #region ç§æœ‰å­—段
        private MyCamera _camera; // åŽç¿ç›¸æœºè®¾å¤‡å¯¹è±¡
        private Thread _grabThread; // å›¾åƒé‡‡é›†çº¿ç¨‹
        private bool _isGrabbing; // é‡‡é›†çŠ¶æ€æ ‡å¿—
        private bool _threadRunning; // çº¿ç¨‹è¿è¡Œæ ‡å¿—
        private bool _handleCreated = false; // å¥æŸ„是否已创建
        private Thread _callbackThread; // å›žè°ƒå¤„理线程
        private List<IMVDefine.IMV_Frame> _frameList; // å›¾åƒç¼“存列表
        private readonly object _frameLock = new object(); // å¸§ç¼“存锁
        // CopyMemory API声明
        [System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
        #endregion
        #region æž„造函数和析构函数
        /// <summary>
        /// æž„造函数
        /// </summary>
        public HRCamera()
        {
            _camera = new MyCamera();
            _frameList = new List<IMVDefine.IMV_Frame>();
            Brand = CameraBrand.HRCamera;
            _isGrabbing = false;
            _threadRunning = false;
        }
        /// <summary>
        /// æžæž„函数
        /// </summary>
        ~HRCamera()
        {
            Dispose(false);
        }
        #endregion
        #region è®¾å¤‡ç®¡ç†æ“ä½œ
        /// <summary>
        /// èŽ·å–ç›¸æœºSN枚举列表
        /// </summary>
        /// <returns>相机SN列表</returns>
        public override List<string> GetListEnum()
        {
            List<string> cameraList = new List<string>();
            try
            {
                // æžšä¸¾æ‰€æœ‰è®¾å¤‡
                IMVDefine.IMV_DeviceList deviceList = new IMVDefine.IMV_DeviceList();
                IMVDefine.IMV_EInterfaceType interfaceType = IMVDefine.IMV_EInterfaceType.interfaceTypeAll;
                int result = MyCamera.IMV_EnumDevices(ref deviceList, (uint)interfaceType);
                if (result == IMVDefine.IMV_OK && deviceList.nDevNum > 0)
                {
                    for (int i = 0; i < deviceList.nDevNum; i++)
                    {
                        IMVDefine.IMV_DeviceInfo deviceInfo = (IMVDefine.IMV_DeviceInfo)
                            Marshal.PtrToStructure(
                                deviceList.pDevInfo + Marshal.SizeOf(typeof(IMVDefine.IMV_DeviceInfo)) * i,
                                typeof(IMVDefine.IMV_DeviceInfo));
                        string cameraInfo = $"{deviceInfo.cameraName}[{deviceInfo.serialNumber}]";
                        cameraList.Add(cameraInfo);
                    }
                }
                else
                {
                    // è®°å½•日志或抛出异常
                    //throw new Exception($"枚举设备失败,错误码:{result}");
                    Debug.WriteLine("枚举设备失败!");
                }
            }
            catch (Exception ex)
            {
                // è®°å½•错误日志
                System.Diagnostics.Debug.WriteLine($"获取相机列表失败:{ex.Message}");
                throw;
            }
            return cameraList;
        }
        /// <summary>
        /// åˆå§‹åŒ–相机设备
        /// </summary>
        /// <param name="SN">相机序列号</param>
        /// <param name="Handle">窗口句柄(可选)</param>
        /// <returns>初始化是否成功</returns>
        public override bool InitDevice(string SN, object Handle = null)
        {
            try
            {
                // ç¡®ä¿å½»åº•关闭和清理
                if (_camera != null)
                {
                    if (_camera.IMV_IsOpen())
                    {
                        _camera.IMV_Close();
                    }
                    if (_handleCreated)
                    {
                        _camera.IMV_DestroyHandle();
                        _handleCreated = false;
                    }
                }
                // æžšä¸¾è®¾å¤‡å¹¶åŒ¹é…SN
                List<string> cameraList = GetListEnum();
                int cameraIndex = -1;
                for (int i = 0; i < cameraList.Count; i++)
                {
                    if (cameraList[i].Contains(SN))
                    {
                        cameraIndex = i;
                        break;
                    }
                }
                if (cameraIndex == -1)
                {
                    throw new Exception($"未找到序列号为 {SN} çš„相机");
                }
                // åˆ›å»ºè®¾å¤‡å¥æŸ„
                int result = _camera.IMV_CreateHandle(IMVDefine.IMV_ECreateHandleMode.modeByIndex, cameraIndex);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"创建设备句柄失败,错误码:{result}");
                }
                _handleCreated = true;
                // æ‰“开设备
                result = _camera.IMV_Open();
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"打开相机失败,错误码:{result}");
                }
                // è®¾ç½®è®¾å¤‡å±žæ€§
                this.SN = SN;
                isGrabbing = false;
                // è®¾ç½®ç¼“存个数为8
                _camera.IMV_SetBufferCount(8);
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"初始化相机失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// å…³é—­ç›¸æœºè®¾å¤‡
        /// </summary>
        /// <returns>关闭是否成功</returns>
        public override bool CloseDevice()
        {
            try
            {
                if (_camera == null)
                    return true;
                // åœæ­¢é‡‡é›†
                if (_camera.IMV_IsGrabbing())
                {
                    StopGrabbing();
                }
                // å…³é—­è®¾å¤‡
                if (_camera.IMV_IsOpen())
                {
                    int result = _camera.IMV_Close();
                    if (result != IMVDefine.IMV_OK)
                    {
                        System.Diagnostics.Debug.WriteLine($"关闭相机失败,错误码:{result}");
                    }
                }
                // é”€æ¯å¥æŸ„
                if (_handleCreated)
                {
                    _camera.IMV_DestroyHandle();
                    _handleCreated = false;
                }
                // é‡Šæ”¾èµ„源
                _isGrabbing = false;
                isGrabbing = false;
                // æ¸…理帧缓存
                lock (_frameLock)
                {
                    foreach (var frame in _frameList)
                    {
                        var tempFrame = frame; // åˆ›å»ºä¸´æ—¶å˜é‡
                        _camera.IMV_ReleaseFrame(ref tempFrame);
                    }
                    _frameList.Clear();
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"关闭相机失败:{ex.Message}");
                return false;
            }
        }
        #endregion
        #region å›¾åƒé‡‡é›†æ“ä½œ
        /// <summary>
        /// å¼€å§‹å›¾åƒé‡‡é›†
        /// </summary>
        /// <returns>采集启动是否成功</returns>
        public override bool StartGrabbing()
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // åœæ­¢çŽ°æœ‰é‡‡é›†
                if (_isGrabbing)
                {
                    StopGrabbing();
                }
                // å¯åЍ采集
                int result = _camera.IMV_StartGrabbing();
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"启动采集失败,错误码:{result}");
                }
                _isGrabbing = true;
                isGrabbing = true;
                // å¯åŠ¨é‡‡é›†çº¿ç¨‹
                _threadRunning = true;
                _grabThread = new Thread(GrabThreadProc);
                _grabThread.IsBackground = true;
                _grabThread.Start();
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"启动采集失败:{ex.Message}");
                _isGrabbing = false;
                isGrabbing = false;
                return false;
            }
        }
        /// <summary>
        /// åœæ­¢å›¾åƒé‡‡é›†
        /// </summary>
        /// <returns>停止是否成功</returns>
        public override bool StopGrabbing()
        {
            try
            {
                if (_camera == null || !_isGrabbing)
                    return true;
                // åœæ­¢çº¿ç¨‹
                _threadRunning = false;
                if (_grabThread != null && _grabThread.IsAlive)
                {
                    _grabThread.Join(1000);
                    _grabThread = null;
                }
                // åœæ­¢é‡‡é›†
                int result = _camera.IMV_StopGrabbing();
                if (result != IMVDefine.IMV_OK)
                {
                    System.Diagnostics.Debug.WriteLine($"停止采集失败,错误码:{result}");
                }
                _isGrabbing = false;
                isGrabbing = false;
                // æ¸…理缓存
                lock (_frameLock)
                {
                    foreach (var frame in _frameList)
                    {
                        var tempFrame = frame; // åˆ›å»ºä¸´æ—¶å˜é‡
                        _camera.IMV_ReleaseFrame(ref tempFrame);
                    }
                    _frameList.Clear();
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"停止采集失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// æ‰§è¡Œè½¯è§¦å‘
        /// </summary>
        /// <returns>触发是否成功</returns>
        public override bool SoftTrigger()
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                int result = _camera.IMV_ExecuteCommandFeature("TriggerSoftware");
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"软触发失败:{ex.Message}");
                return false;
            }
        }
        #endregion
        #region å‚数设置和获取
        /// <summary>
        /// è®¾ç½®è§¦å‘模式
        /// </summary>
        /// <param name="mode">触发模式</param>
        /// <param name="source">触发源</param>
        /// <returns>设置是否成功</returns>
        public override bool SetTriggerMode(TriggerMode mode, TriggerSource source = TriggerSource.Line0)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // è®¾ç½®è§¦å‘模式
                string triggerMode = mode == TriggerMode.On ? "On" : "Off";
                int result = _camera.IMV_SetEnumFeatureSymbol("TriggerMode", triggerMode);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置触发模式失败,错误码:{result}");
                }
                // è®¾ç½®è§¦å‘源
                if (mode == TriggerMode.On)
                {
                    string triggerSource = GetTriggerSourceString(source);
                    result = _camera.IMV_SetEnumFeatureSymbol("TriggerSource", triggerSource);
                    if (result != IMVDefine.IMV_OK)
                    {
                        throw new Exception($"设置触发源失败,错误码:{result}");
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发模式失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘æ¨¡å¼
        /// </summary>
        /// <param name="mode">触发模式</param>
        /// <param name="source">触发源</param>
        /// <returns>获取是否成功</returns>
        public override bool GetTriggerMode(out TriggerMode mode, out TriggerSource source)
        {
            mode = TriggerMode.Off;
            source = TriggerSource.Software;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // èŽ·å–è§¦å‘æ¨¡å¼
                IMVDefine.IMV_String triggerMode = new IMVDefine.IMV_String();
                int result = _camera.IMV_GetEnumFeatureSymbol("TriggerMode", ref triggerMode);
                if (result == IMVDefine.IMV_OK)
                {
                    mode = triggerMode.str == "On" ? TriggerMode.On : TriggerMode.Off;
                }
                // èŽ·å–è§¦å‘æº
                IMVDefine.IMV_String triggerSource = new IMVDefine.IMV_String();
                result = _camera.IMV_GetEnumFeatureSymbol("TriggerSource", ref triggerSource);
                if (result == IMVDefine.IMV_OK)
                {
                    source = GetTriggerSourceFromString(triggerSource.str);
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发模式失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®æ›å…‰æ—¶é—´
        /// </summary>
        /// <param name="value">曝光时间(微秒)</param>
        /// <returns>设置是否成功</returns>
        public override bool SetExpouseTime(double value)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                // éªŒè¯æ›å…‰æ—¶é—´èŒƒå›´
                double minExp = 0, maxExp = 0;
                int result = _camera.IMV_GetDoubleFeatureMin("ExposureTime", ref minExp);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取曝光时间最小值失败,错误码:{result}");
                }
                result = _camera.IMV_GetDoubleFeatureMax("ExposureTime", ref maxExp);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取曝光时间最大值失败,错误码:{result}");
                }
                if (value < minExp || value > maxExp)
                {
                    throw new Exception($"曝光时间超出范围,有效范围:{minExp} - {maxExp}");
                }
                // è®¾ç½®æ›å…‰æ—¶é—´
                result = _camera.IMV_SetDoubleFeatureValue("ExposureTime", value);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置曝光时间失败,错误码:{result}");
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置曝光时间失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–æ›å…‰æ—¶é—´
        /// </summary>
        /// <param name="value">曝光时间</param>
        /// <returns>获取是否成功</returns>
        public override bool GetExpouseTime(out double value)
        {
            value = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                int result = _camera.IMV_GetDoubleFeatureValue("ExposureTime", ref value);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取曝光时间失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®å¢žç›Š
        /// </summary>
        /// <param name="gain">增益值</param>
        /// <returns>设置是否成功</returns>
        public override bool SetGain(double gain)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                string gainFeature = _camera.IMV_FeatureIsValid("Gain") ? "Gain" : "GainRaw";
                // éªŒè¯å¢žç›ŠèŒƒå›´
                double minGain = 0, maxGain = 0;
                int result = _camera.IMV_GetDoubleFeatureMin(gainFeature, ref minGain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取增益最小值失败,错误码:{result}");
                }
                result = _camera.IMV_GetDoubleFeatureMax(gainFeature, ref maxGain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"获取增益最大值失败,错误码:{result}");
                }
                if (gain < minGain) gain = minGain;
                if (gain > maxGain) gain = maxGain;
                // è®¾ç½®å¢žç›Š
                result = _camera.IMV_SetDoubleFeatureValue(gainFeature, gain);
                if (result != IMVDefine.IMV_OK)
                {
                    throw new Exception($"设置增益失败,错误码:{result}");
                }
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置增益失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–å¢žç›Šå€¼
        /// </summary>
        /// <param name="gain">增益值</param>
        /// <returns>获取是否成功</returns>
        public override bool GetGain(out double gain)
        {
            gain = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen())
                {
                    throw new Exception("相机未打开");
                }
                string gainFeature = _camera.IMV_FeatureIsValid("Gain") ? "Gain" : "GainRaw";
                int result = _camera.IMV_GetDoubleFeatureValue(gainFeature, ref gain);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取增益失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®è§¦å‘极性
        /// </summary>
        /// <param name="polarity">触发极性</param>
        /// <returns>是否成功</returns>
        public override bool SetTriggerPolarity(TriggerPolarity polarity)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                string activation = (polarity == TriggerPolarity.RisingEdge || polarity == TriggerPolarity.HighLevel)
                    ? "RisingEdge" : "FallingEdge";
                int result = _camera.IMV_SetEnumFeatureSymbol("TriggerActivation", activation);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发极性失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘æžæ€§
        /// </summary>
        /// <param name="polarity">触发极性</param>
        /// <returns>是否成功</returns>
        public override bool GetTriggerPolarity(out TriggerPolarity polarity)
        {
            polarity = TriggerPolarity.RisingEdge;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                IMVDefine.IMV_String activation = new IMVDefine.IMV_String();
                int result = _camera.IMV_GetEnumFeatureSymbol("TriggerActivation", ref activation);
                if (result == IMVDefine.IMV_OK)
                {
                    polarity = activation.str == "RisingEdge" ? TriggerPolarity.RisingEdge : TriggerPolarity.FallingEdge;
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发极性失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®è§¦å‘滤波时间 (us)
        /// </summary>
        public override bool SetTriggerFliter(double flitertime)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                // åŽç¿ç›¸æœºé€šå¸¸ä½¿ç”¨ LineDebouncerTime æŽ§åˆ¶æ»¤æ³¢
                if (_camera.IMV_FeatureIsValid("LineDebouncerTime"))
                {
                    int result = _camera.IMV_SetDoubleFeatureValue("LineDebouncerTime", flitertime);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发滤波失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘æ»¤æ³¢æ—¶é—´ (us)
        /// </summary>
        public override bool GetTriggerFliter(out double flitertime)
        {
            flitertime = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("LineDebouncerTime"))
                {
                    int result = _camera.IMV_GetDoubleFeatureValue("LineDebouncerTime", ref flitertime);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发滤波失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®è§¦å‘å»¶æ—¶ (us)
        /// </summary>
        public override bool SetTriggerDelay(double delay)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("TriggerDelay"))
                {
                    int result = _camera.IMV_SetDoubleFeatureValue("TriggerDelay", delay);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置触发延时失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–è§¦å‘å»¶æ—¶ (us)
        /// </summary>
        public override bool GetTriggerDelay(out double delay)
        {
            delay = 0;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("TriggerDelay"))
                {
                    int result = _camera.IMV_GetDoubleFeatureValue("TriggerDelay", ref delay);
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取触发延时失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®ä¿¡å·çº¿æ¨¡å¼
        /// </summary>
        public override bool SetLineMode(IOLines line, LineMode mode)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                // é€‰æ‹©çº¿è·¯
                int result = _camera.IMV_SetEnumFeatureSymbol("LineSelector", line.ToString());
                if (result != IMVDefine.IMV_OK) return false;
                // è®¾ç½®æ¨¡å¼
                string lineMode = mode == LineMode.Input ? "Input" : "Output";
                result = _camera.IMV_SetEnumFeatureSymbol("LineMode", lineMode);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置信号线模式失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è®¾ç½®ä¿¡å·çº¿ç”µå¹³çŠ¶æ€
        /// </summary>
        public override bool SetLineStatus(IOLines line, LineStatus linestatus)
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                // ä»…对输出线路有效
                int result = _camera.IMV_SetEnumFeatureSymbol("LineSelector", line.ToString());
                if (result != IMVDefine.IMV_OK) return false;
                bool status = linestatus == LineStatus.Hight;
                result = _camera.IMV_SetBoolFeatureValue("UserOutputValue", status);
                return result == IMVDefine.IMV_OK;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"设置信号线状态失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// èŽ·å–ä¿¡å·çº¿ç”µå¹³çŠ¶æ€
        /// </summary>
        public override bool GetLineStatus(IOLines line, out LineStatus lineStatus)
        {
            lineStatus = LineStatus.Low;
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                int result = _camera.IMV_SetEnumFeatureSymbol("LineSelector", line.ToString());
                if (result != IMVDefine.IMV_OK) return false;
                bool status = false;
                result = _camera.IMV_GetBoolFeatureValue("LineStatus", ref status);
                if (result == IMVDefine.IMV_OK)
                {
                    lineStatus = status ? LineStatus.Hight : LineStatus.Low;
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"获取信号线状态失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// è‡ªåŠ¨ç™½å¹³è¡¡
        /// </summary>
        public override bool AutoBalanceWhite()
        {
            try
            {
                if (_camera == null || !_camera.IMV_IsOpen()) return false;
                if (_camera.IMV_FeatureIsValid("BalanceWhiteAuto"))
                {
                    int result = _camera.IMV_SetEnumFeatureSymbol("BalanceWhiteAuto", "Once");
                    return result == IMVDefine.IMV_OK;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"自动白平衡失败:{ex.Message}");
                return false;
            }
        }
        #endregion
        #region é‡‡é›†å’Œè½¬æ¢è¾…助方法
        /// <summary>
        /// å›¾åƒé‡‡é›†çº¿ç¨‹å¤„理函数
        /// </summary>
        private void GrabThreadProc()
        {
            while (_threadRunning)
            {
                IMVDefine.IMV_Frame frame = new IMVDefine.IMV_Frame();
                try
                {
                    // èŽ·å–å›¾åƒå¸§
                    int result = _camera.IMV_GetFrame(ref frame, 1000);
                    if (result == IMVDefine.IMV_OK)
                    {
                        // å¤„理图像帧
                        ProcessFrame(frame);
                    }
                    else
                    {
                        // å³ä½¿èŽ·å–å¤±è´¥ï¼Œä¹Ÿå°è¯•é‡Šæ”¾å¸§ï¼Œé˜²æ­¢SDK内部缓存泄露
                        // æ³¨æ„ï¼šframe是每次新建的,如果GetFrame没填充,这里释放应该是安全的(视SDK实现而定)
                        var tempFrame = frame;
                        _camera.IMV_ReleaseFrame(ref tempFrame);
                        if ((uint)result != 0x80000001 && result != -119 && result != -102) // è¶…时错误代码
                        {
                            // éžè¶…时错误
                            System.Diagnostics.Debug.WriteLine($"获取图像帧失败,错误码:{result}");
                            Thread.Sleep(10); // å‡ºé”™æ—¶ç¨ä½œç­‰å¾…
                        }
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"采集线程异常:{ex.Message}");
                    Thread.Sleep(10);
                }
                Thread.Sleep(1);
            }
        }
        /// <summary>
        /// å¤„理图像帧
        /// </summary>
        /// <param name="frame">图像帧</param>
        private void ProcessFrame(IMVDefine.IMV_Frame frame)
        {
            try
            {
                // å°†å›¾åƒæ•°æ®è½¬æ¢ä¸ºBitmap
                Bitmap bitmap = ConvertFrameToBitmap(frame);
                if (bitmap != null)
                {
                    // è§¦å‘图像采集事件
                    CameraEventArgs args = new CameraEventArgs(SN, bitmap);
                    ImageGrabbed?.Invoke(this, args);
                    // æ›´æ–°å›žè°ƒå›¾åƒ
                    CallBackImg = bitmap;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"处理图像帧失败:{ex.Message}");
            }
            finally
            {
                // ç¡®ä¿æ— è®ºå¦‚何都释放帧,防止缓存占满
                var tempFrame = frame;
                _camera.IMV_ReleaseFrame(ref tempFrame);
            }
        }
        /// <summary>
        /// å°†å›¾åƒå¸§è½¬æ¢ä¸ºBitmap
        /// </summary>
        /// <param name="frame">图像帧</param>
        /// <returns>Bitmap对象</returns>
        private Bitmap ConvertFrameToBitmap(IMVDefine.IMV_Frame frame)
        {
            try
            {
                Bitmap bitmap = null;
                switch (frame.frameInfo.pixelFormat)
                {
                    case IMVDefine.IMV_EPixelType.gvspPixelMono8:
                        bitmap = CreateMono8Bitmap(frame);
                        break;
                    case IMVDefine.IMV_EPixelType.gvspPixelBGR8:
                        bitmap = CreateBgr8Bitmap(frame);
                        break;
                    default:
                        // å…¶ä»–格式需要转换
                        bitmap = ConvertToBGR8(frame);
                        break;
                }
                return bitmap;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"图像格式转换失败:{ex.Message}");
                return null;
            }
        }
        /// <summary>
        /// åˆ›å»ºMono8格式Bitmap
        /// </summary>
        private Bitmap CreateMono8Bitmap(IMVDefine.IMV_Frame frame)
        {
            Bitmap bitmap = new Bitmap((int)frame.frameInfo.width, (int)frame.frameInfo.height, PixelFormat.Format8bppIndexed);
            // è®¾ç½®ç°åº¦è°ƒè‰²æ¿
            ColorPalette palette = bitmap.Palette;
            for (int i = 0; i < 256; i++)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            bitmap.Palette = palette;
            // å¤åˆ¶å›¾åƒæ•°æ®
            BitmapData bmpData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.WriteOnly,
                bitmap.PixelFormat);
            // ä½¿ç”¨CopyMemory API进行内存复制
            CopyMemory(bmpData.Scan0, frame.pData, (uint)Math.Min(frame.frameInfo.size, (uint)(bmpData.Stride * bitmap.Height)));
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
        /// <summary>
        /// åˆ›å»ºBGR8格式Bitmap
        /// </summary>
        private Bitmap CreateBgr8Bitmap(IMVDefine.IMV_Frame frame)
        {
            Bitmap bitmap = new Bitmap((int)frame.frameInfo.width, (int)frame.frameInfo.height, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.WriteOnly,
                bitmap.PixelFormat);
            // ä½¿ç”¨CopyMemory API进行内存复制
            CopyMemory(bmpData.Scan0, frame.pData, (uint)Math.Min(frame.frameInfo.size, (uint)(bmpData.Stride * bitmap.Height)));
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
        /// <summary>
        /// è½¬æ¢ä¸ºBGR8格式
        /// </summary>
        private Bitmap ConvertToBGR8(IMVDefine.IMV_Frame frame)
        {
            IMVDefine.IMV_PixelConvertParam convertParam = new IMVDefine.IMV_PixelConvertParam
            {
                nWidth = frame.frameInfo.width,
                nHeight = frame.frameInfo.height,
                ePixelFormat = frame.frameInfo.pixelFormat,
                pSrcData = frame.pData,
                nSrcDataLen = frame.frameInfo.size,
                nPaddingX = frame.frameInfo.paddingX,
                nPaddingY = frame.frameInfo.paddingY,
                eBayerDemosaic = IMVDefine.IMV_EBayerDemosaic.demosaicBilinear,
                eDstPixelFormat = IMVDefine.IMV_EPixelType.gvspPixelBGR8,
                nDstBufSize = frame.frameInfo.width * frame.frameInfo.height * 3
            };
            IntPtr dstBuffer = Marshal.AllocHGlobal((int)convertParam.nDstBufSize);
            convertParam.pDstBuf = dstBuffer;
            try
            {
                int result = _camera.IMV_PixelConvert(ref convertParam);
                if (result == IMVDefine.IMV_OK)
                {
                    return CreateBgr8BitmapFromBuffer(dstBuffer, frame.frameInfo.width, frame.frameInfo.height);
                }
                return null;
            }
            finally
            {
                Marshal.FreeHGlobal(dstBuffer);
            }
        }
        /// <summary>
        /// ä»Žç¼“冲区创建BGR8 Bitmap
        /// </summary>
        private Bitmap CreateBgr8BitmapFromBuffer(IntPtr buffer, uint width, uint height)
        {
            Bitmap bitmap = new Bitmap((int)width, (int)height, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.WriteOnly,
                bitmap.PixelFormat);
            // ä½¿ç”¨CopyMemory API进行安全的内存复制
            CopyMemory(bmpData.Scan0, buffer, (uint)(width * height * 3));
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
        /// <summary>
        /// å°†è§¦å‘源枚举转换为字符串
        /// </summary>
        private string GetTriggerSourceString(TriggerSource source)
        {
            return source switch
            {
                TriggerSource.Software => "Software",
                TriggerSource.Line0 => "Line0",
                TriggerSource.Line1 => "Line1",
                TriggerSource.Line2 => "Line2",
                TriggerSource.Line3 => "Line3",
                TriggerSource.Line4 => "Line4",
                TriggerSource.Line5 => "Line5",
                _ => "Software"
            };
        }
        /// <summary>
        /// å°†å­—符串转换为触发源枚举
        /// </summary>
        private TriggerSource GetTriggerSourceFromString(string source)
        {
            return source switch
            {
                "Software" => TriggerSource.Software,
                "Line0" => TriggerSource.Line0,
                "Line1" => TriggerSource.Line1,
                "Line2" => TriggerSource.Line2,
                "Line3" => TriggerSource.Line3,
                "Line4" => TriggerSource.Line4,
                "Line5" => TriggerSource.Line5,
                _ => TriggerSource.Software
            };
        }
        #endregion
        #region IDisposable实现
        private bool _disposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    // é‡Šæ”¾æ‰˜ç®¡èµ„源
                }
                // é‡Šæ”¾éžæ‰˜ç®¡èµ„源
                CloseDevice();
                _disposed = true;
            }
        }
        public override void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
LB_VisionProcesses/LB_VisionProcesses.csproj
@@ -37,7 +37,6 @@
  <ItemGroup>
    <Folder Include="Alogrithms\VisualLargeModel\" />
    <Folder Include="Cameras\HRCameras\" />
    <Folder Include="Cameras\LBCameras\" />
    <Folder Include="Communicators\SiemensS7\" />
    <Folder Include="Communicators\MES\" />