C3032
3 天以前 ebcc1d53f14112363bbf539bcaf0202aadcdc9d7
LB_VisionProcesses/Cameras/2DCameraForm.cs
@@ -1,5 +1,8 @@
using HalconDotNet;
using LB_SmartVisionCameraDevice.PHM6000;
using LB_VisionControl;
using LB_VisionProcesses.Cameras.HRCameras;
using LB_VisionProcesses.Cameras.LBCameras;
using MVSDK_Net;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
@@ -37,9 +40,9 @@
        {
            InitializeComponent();
            //传入相机句柄后禁用连接/断开按键
            this.btnOpen.Enabled = false;
            this.btnClose.Enabled = false;
            this.cmbBrand.Enabled = false;
            //this.btnOpen.Enabled = false;
            //this.btnClose.Enabled = false;
            //this.cmbBrand.Enabled = false;
            this.panel_Picture.Controls.Clear();
            this.dicCameras = dicCameras;
@@ -75,11 +78,25 @@
        UserPictureBox onlinePictureBox { get; set; }
        private System.Windows.Forms.Timer updateTimer;
        Total total = new Total { iImageCount = 0, iScanCount = 0 };
        Total total = new Total { iImageCount = 0, iScanCount = 0, ImagesPerTyre = 1 };
        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 毫秒
@@ -107,6 +124,12 @@
                cmbSN.Text = SN;
                cmbSN.SelectedIndex = Index;
                // 如果没找到索引(可能是新增的),手动触发一次逻辑以更新UI
                if (Index == -1)
                {
                    cmbSN_SelectedIndexChanged(null, null);
                }
                ckbLocalTest.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否本地取图"].ToString());
                ckbUpParams.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否每次写入参数"].ToString());
                ckbRegrab.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否失败重新取图"].ToString());
@@ -115,6 +138,16 @@
                if (camConfig.OutputImage != null && camConfig.OutputImage is Bitmap bitmap)
                    onlinePictureBox.Image = bitmap;
                lblCapTime.Text = $"{camConfig.RunTime}ms";
            }
        }
        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);
            }
        }
@@ -154,10 +187,10 @@
                switch (brand)
                {
                    case CameraBrand.HRCamera:
                        //camera = new HRCamera();
                        camera = new HRCamera();
                        break;
                    case CameraBrand.LBCamera:
                        //camera = new LBCamera();
                        camera = new LBCamera();
                        break;
                    default:
                        Debug.WriteLine("未知品牌");
@@ -195,14 +228,26 @@
                camera = dicCameras[cmbSN.Text];
            //说明相机已经初始化成功
            if (camera != null && camera.isGrabbing)
            if (camera != null)
            {
                camera.ImageGrabbed -= GetImageBllComplete;
                camera.ImageGrabbed += GetImageBllComplete;
                int Index = cmbBrand.FindString(camera.Brand.ToString());
                if (Index >= 0)
                {
                    cmbBrand.Text = camera.Brand.ToString();
                    cmbBrand.SelectedIndex = Index;
                }
                int Index = cmbBrand.FindString(camera.Brand.ToString()); ;
                cmbBrand.Text = camera.Brand.ToString();
                cmbBrand.SelectedIndex = Index;
                if (camera.isGrabbing)
                {
                    camera.ImageGrabbed -= GetImageBllComplete;
                    camera.ImageGrabbed += GetImageBllComplete;
                    this.btnEdit.Enabled = true;
                }
                // 如果相机存在于字典中,说明是已连接的设备,允许编辑
                else if (dicCameras != null && dicCameras.ContainsKey(camera.SN))
                {
                    this.btnEdit.Enabled = true;
                }
            }
        }
@@ -211,49 +256,123 @@
            // 尝试将输入字符串转换为枚举值
            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 LBCamera();
                        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;
                }
            }
            else
            {
                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);
@@ -273,24 +392,103 @@
            if (camera.CloseDevice())
            {
                onlinePictureBox.Visible = true;
                MessageBox.Show(camera.SN + "断开成功");
                this.panel_Picture.Controls.Clear();
                this.panel_Picture.Controls.Add(onlinePictureBox);
            }
        }
        private void btnEdit_Click(object sender, EventArgs e)
        {
            if (camera == null)
            {
                return;
            }
            using (Form editForm = new Form())
            {
                editForm.Text = "高级参数设置 - " + camera.SN;
                editForm.Size = new System.Drawing.Size(400, 500);
                editForm.StartPosition = FormStartPosition.CenterParent;
                editForm.FormBorderStyle = FormBorderStyle.SizableToolWindow;
                PropertyGrid pg = new PropertyGrid();
                pg.Dock = DockStyle.Fill;
                if (camera is LBCamera phmCamera)
                {
                    pg.SelectedObject = phmCamera.GetSensorConfig();
                    pg.PropertyValueChanged += (s, ev) =>
                    {
                        phmCamera.UpdateSensorConfig((PHM6000SensorConfig)pg.SelectedObject);
                    };
                }
                else
                {
                    pg.SelectedObject = new CameraAdvancedSettings(camera);
                }
                editForm.Controls.Add(pg);
                editForm.ShowDialog();
            }
        }
        /// <summary>
        /// 相机高级设置包装类
        /// </summary>
        public class CameraAdvancedSettings
        {
            private BaseCamera _camera;
            public CameraAdvancedSettings(BaseCamera camera)
            {
                _camera = camera;
            }
            [System.ComponentModel.Category("触发设置"), System.ComponentModel.Description("触发源")]
            public TriggerSource TriggerSource
            {
                get { _camera.GetTriggerMode(out _, out TriggerSource s); return s; }
                set { _camera.GetTriggerMode(out TriggerMode m, out _); _camera.SetTriggerMode(m, value); }
            }
            [System.ComponentModel.Category("触发设置"), System.ComponentModel.Description("触发极性")]
            public TriggerPolarity TriggerPolarity
            {
                get { _camera.GetTriggerPolarity(out TriggerPolarity p); return p; }
                set { _camera.SetTriggerPolarity(value); }
            }
            [System.ComponentModel.Category("触发设置"), System.ComponentModel.Description("触发延时(us)")]
            public double TriggerDelay
            {
                get { _camera.GetTriggerDelay(out double d); return d; }
                set { _camera.SetTriggerDelay(value); }
            }
            [System.ComponentModel.Category("触发设置"), System.ComponentModel.Description("触发滤波(us)")]
            public double TriggerFilter
            {
                get { _camera.GetTriggerFliter(out double f); return f; }
                set { _camera.SetTriggerFliter(value); }
            }
            [System.ComponentModel.Category("图像设置"), System.ComponentModel.Description("自动白平衡")]
            public void AutoBalanceWhite()
            {
                _camera.AutoBalanceWhite();
            }
        }
        /// <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;
@@ -308,7 +506,6 @@
                    onlinePictureBox.Image = e.Bitmap;
                }
            }
            total.iImageCount++;
            try
            {
@@ -331,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";
                        }
                    }));
                }
            });
        }
@@ -358,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;
@@ -378,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;
        }
@@ -407,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();
                        }
                    });
                }
@@ -463,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;
@@ -516,9 +770,25 @@
            if (res == DialogResult.Yes)  //保存VPP
            {
                TriggerSource actualSource = TriggerSource.Line0;
                TriggerPolarity polarity = TriggerPolarity.RisingEdge;
                double delay = 0;
                double filter = 0;
                if (camera != null)
                {
                    camera.GetTriggerMode(out _, out actualSource);
                    camera.GetTriggerPolarity(out polarity);
                    camera.GetTriggerDelay(out delay);
                    camera.GetTriggerFliter(out filter);
                }
                camConfig.Params.Inputs.Add("相机SN", cmbSN.Text);
                camConfig.Params.Inputs.Add("触发模式", TriggerMode.On);
                camConfig.Params.Inputs.Add("触发方式", radioButtonSoft.Checked ? TriggerSource.Software : TriggerSource.Line0);
                camConfig.Params.Inputs.Add("触发方式", radioButtonSoft.Checked ? TriggerSource.Software : actualSource);
                camConfig.Params.Inputs.Add("触发极性", polarity);
                camConfig.Params.Inputs.Add("触发延时", delay);
                camConfig.Params.Inputs.Add("触发消抖", filter);
                camConfig.Params.Inputs.Add("是否本地取图", ckbLocalTest.Checked);
                camConfig.Params.Inputs.Add("本地取图路径", cmbImagesPath.Items.Cast<string>().ToList());
                camConfig.Params.Inputs.Add("是否失败重新取图", ckbRegrab.Checked);
@@ -541,18 +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);
                if (radioButtonSoft.Checked)
                    camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
                else
                    camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0);
                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();
                    }
                }
            }
            //路径为空说明为测试模式,需要释放相机
@@ -620,10 +906,21 @@
            if (camera == null)
                return;
            camera.GetTriggerMode(out _, out TriggerSource currentSource);
            if (radioButtonSoft.Checked)
            {
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
            }
            else
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0);
            {
                // 如果当前已经是硬件触发源,则保持;否则默认Line0
                if (currentSource == TriggerSource.Software)
                    camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0);
                else
                    camera.SetTriggerMode(TriggerMode.On, currentSource);
            }
        }
        System.Windows.Forms.ToolTip ToolTip = new System.Windows.Forms.ToolTip();
@@ -649,12 +946,17 @@
        private void controlBox_2DCameraForm_Click(object sender, EventArgs e)
        {
        }
        private void dungeonControlBox_2DCameraForm_Click(object sender, EventArgs e)
        {
           // this.Close();
            // this.Close();
        }
        private void theme_2DCameraForm_Click(object sender, EventArgs e)
        {
        }
    }
}