using HalconDotNet; using LB_SmartVisionCameraDevice.PHM6000; using LB_VisionControls; using LB_VisionProcesses; using LB_VisionProcesses.Cameras; using LB_VisionProcesses.Cameras.HikCameras; using LB_VisionProcesses.Cameras.HRCameras; using LB_VisionProcesses.Cameras.LBCameras; using LB_VisionProcesses.Cameras.LocalCameras; using LB_VisionProcesses.Cameras.MicroCameras; using LB_VisionProcesses.Cameras.MindCameras; using MvCamCtrl.NET; using MVSDK; using Newtonsoft.Json.Linq; using OpenCvSharp; using System; using System.Collections.Concurrent; using System.Data; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Text; using System.Windows.Forms; using System.Xml.Linq; namespace LB_VisionProcesses.Cameras { public partial class CameraForm : Form { Bitmap Bitmap = null; BaseCamera camera { get; set; } CameraConfig camConfig { get; set; } ConcurrentDictionary dicCameras { get; set; } string fullPath = string.Empty; public CameraForm() { InitializeComponent(); } public CameraForm(ConcurrentDictionary dicCameras, CameraConfig camConfig, string fullPath) { InitializeComponent(); //传入相机句柄后禁用连接/断开按键 //this.btnOpen.Enabled = false; //this.btnClose.Enabled = false; //this.cmbBrand.Enabled = false; this.panel1.Controls.Clear(); this.dicCameras = dicCameras; this.fullPath = fullPath; this.camConfig = camConfig; foreach (var CamSN in dicCameras.Keys) { cmbSN.Items.Add(CamSN); } Enum.TryParse(camConfig.Params.Inputs["触发方式"].ToString(), out TriggerSource TriggerSource); if (TriggerSource == TriggerSource.Software) { radioButtonSoft.Checked = true; } else { radioButtonHard.Checked = true; } this.Text = camConfig.strProcessName; txtExp.Text = camConfig.Params.Inputs["曝光时间"]?.ToString(); txtGain.Text = camConfig.Params.Inputs["增益"]?.ToString(); txtTimeout.Text = camConfig.Params.Inputs["超时时间"]?.ToString(); ckbLocalTest.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否本地取图"].ToString()); string strPath = camConfig.Params.Inputs["本地取图路径"]?.ToString(); if (!string.IsNullOrEmpty(strPath)) { List lstPaths = (JArray.FromObject(camConfig.Params.Inputs["本地取图路径"]))?.ToObject>(); if (lstPaths != null && lstPaths.Count > 0) { foreach (var path in lstPaths) { cmbImagesPath.Items.Add(path); } cmbImagesPath.Text = lstPaths[0]; } } } UserPictureBox onlinePictureBox { get; set; } private System.Windows.Forms.Timer updateTimer; Total total = new Total { iImageCount = 0, iScanCount = 0 }; DateTime startGrabtime = DateTime.Now; // 动态添加的增益下拉框 private ComboBox cmbGain; private void CameraForm_Load(object sender, EventArgs e) { // 初始化增益下拉框 cmbGain = new ComboBox(); cmbGain.Visible = false; // 默认隐藏 cmbGain.DropDownStyle = ComboBoxStyle.DropDownList; cmbGain.Size = txtGain.Size; cmbGain.Location = txtGain.Location; cmbGain.Font = txtGain.Font; cmbGain.SelectedIndexChanged += CmbGain_SelectedIndexChanged; this.txtGain.Parent.Controls.Add(cmbGain); cmbGain.BringToFront(); // 设置一个定时器,每 100 毫秒触发一次 updateTimer = new System.Windows.Forms.Timer(); updateTimer.Interval = 1000; // 设置定时器间隔为 1000 毫秒 updateTimer.Tick += (sender, e) => UpdateUI(); updateTimer.Start(); onlinePictureBox = new UserPictureBox(panel1); this.panel1.Controls.Clear(); this.panel1.Controls.Add(onlinePictureBox); onlinePictureBox.Dock = DockStyle.Fill; // 使用 LINQ 获取所有枚举值并打印 var brands = Enum.GetValues(typeof(CameraBrand)).Cast(); foreach (var brand in brands) { cmbBrand.Items.Add(brand.ToString()); } //选择Cam会触发ValueChanged事件,没有输入相机的情况下选择到-1 if (camConfig != null) { string SN = camConfig.Params.Inputs["相机SN"].ToString(); int Index = cmbSN.FindString(SN); if (dicCameras.ContainsKey(SN)) { cmbBrand.Text = dicCameras[SN].Brand.ToString(); } cmbSN.Text = SN; cmbSN.SelectedIndex = Index; ckbLocalTest.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否本地取图"].ToString()); ckbUpParams.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否每次写入参数"].ToString()); ckbRegrab.Checked = Convert.ToBoolean(camConfig.Params.Inputs["是否失败重新取图"].ToString()); txtTimeout.Text = camConfig.Params.Inputs["超时时间"].ToString(); 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); } } private void UpdateUI() { try { // 如果当前不是 UI 线程,则通过 Invoke 将操作调度到 UI 线程 if (this.InvokeRequired) { this.Invoke(new Action(() => { double fps = total.iImageCount / (DateTime.Now - startGrabtime).TotalSeconds; this.lblPicCount.Text = total.iImageCount.ToString(); })); } else { // 如果已经在 UI 线程上,直接更新 double fps = total.iImageCount / (DateTime.Now - startGrabtime).TotalSeconds; this.lblPicCount.Text = total.iImageCount.ToString(); } } catch { } } private void cmbSN_MouseDown(object sender, MouseEventArgs e) { if (dicCameras != null && dicCameras.Count > 0) { return; } cmbSN.Items.Clear(); // 尝试将输入字符串转换为枚举值 if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand)) { // 使用 switch 语句来判断枚举值 switch (brand) { case CameraBrand.HRCamera: { camera = new HRCamera(); break; } case CameraBrand.LBCamera: { camera = new LBCamera(); break; } case CameraBrand.LocalCamera: { camera = new LocalCamera(); break; } case CameraBrand.HikCamera: { camera = new HikCamera(); break; } case CameraBrand.HikCodeReader: { camera = new HikCodeReader(); break; } case CameraBrand.MindCamera: { camera = new MindCamera(); break; } case CameraBrand.MicroCamera: { camera = new MicroCamera(); break; } default: { Debug.WriteLine("未知品牌"); break; } } foreach (var item in camera.GetListEnum()) { if (!cmbSN.Items.Contains(item)) { cmbSN.Items.Add(item); } } } else { Debug.WriteLine("无效的枚举值!"); } } private void cmbSN_SelectedIndexChanged(object sender, EventArgs e) { btnEdit.Enabled = false; //camConfig不为空(输入有相机),更改相机选择需要重新加载刷图事件 if (camConfig != null && camera != null) { camera.ImageGrabbed -= GetImageBllComplete; } //输入无camConfig,但是该相机已经打开过了需要释放原相机 else if (camera != null) { camera.ImageGrabbed -= GetImageBllComplete; camera.Dispose(); } if (dicCameras != null && dicCameras.Count > 0 && dicCameras.ContainsKey(cmbSN.Text)) { camera = dicCameras[cmbSN.Text]; } //说明相机已经初始化成功 if (camera != null && camera.isGrabbing) { if (camera is MindCamera || camera is LocalCamera || camera is LBCamera || camera is HRCamera) { btnEdit.Enabled = true; } camera.ImageGrabbed -= GetImageBllComplete; camera.ImageGrabbed += GetImageBllComplete; int Index = cmbBrand.FindString(camera.Brand.ToString()); ; cmbBrand.Text = camera.Brand.ToString(); cmbBrand.SelectedIndex = Index; } else if (dicCameras != null && dicCameras.ContainsKey(camera.SN)) { this.btnEdit.Enabled = true; } } private void btnOpen_Click(object sender, EventArgs e) { // 尝试将输入字符串转换为枚举值 if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand)) { 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) { case CameraBrand.LBCamera: { camera = new LBCamera(); break; } case CameraBrand.HRCamera: { camera = new HRCamera(); break; } case CameraBrand.LocalCamera: { camera = new LocalCamera(); break; } case CameraBrand.HikCamera: { camera = new HikCamera(); break; } case CameraBrand.HikCodeReader: { camera = new HikCodeReader(); break; } case CameraBrand.MindCamera: { camera = new MindCamera(); break; } case CameraBrand.MicroCamera: { camera = new MicroCamera(); break; } default: { Debug.WriteLine($"【{DateTime.Now:HH:mm:ss.fff}】未知品牌"); return; } } 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(cmbSN.Text.ToString(), this.Handle)) //{ // camera.ImageGrabbed -= GetImageBllComplete; // camera.ImageGrabbed += GetImageBllComplete; // if (camera is MindCamera || camera is LBCamera || camera is HRCamera) // { // this.btnEdit.Enabled = true; // } // MessageBox.Show(camera.SN + "打开成功"); //} 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; this.btnEdit.Enabled = true; } } else { Debug.WriteLine($"【{DateTime.Now:HH:mm:ss.fff}】无效的枚举值!"); } if (camera != null) { this.BeginInvoke(new Action(() => { 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" }); 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); if (source != TriggerSource.Software) { radioButtonHard.Checked = true; } else { radioButtonSoft.Checked = true; } })); } } private void btnClose_Click(object sender, EventArgs e) { if (camera == null) { return; } this.btnEdit.Enabled = false; if (camera.CloseDevice()) { MessageBox.Show(camera.SN + "断开成功"); this.panel1.Controls.Clear(); } } private void btnEdit_Click(object sender, EventArgs e) { if (camera == null) { return; } if (camera is MindCamera) { ((MindCamera)camera).SetSetting(); } else if (camera is LocalCamera) { ((LocalCamera)camera).SetSetting(); } else { 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(); } } } /// /// 相机回调运行 /// /// /// private void GetImageBllComplete(object sender, CameraEventArgs e) { if (e.Bitmap == null) { return; } lock (e.Bitmap) { if (this.InvokeRequired) // 检查是否需要在UI线程上调用 { this.Invoke(new Action(() => { onlinePictureBox.Image = e.Bitmap; })); // 递归调用自身,但这次在UI线程上 } else { onlinePictureBox.Image = e.Bitmap; } } total.iImageCount++; try { Bitmap = e.Bitmap.Clone() as Bitmap; } catch { } } /// /// 读码回调运行 /// /// /// private void GetCodeImageBllComplete(object sender, HikCodeReaderEventArgs e) { if (e.Bitmap == null && e.Image == null) { return; } total.iImageCount++; DateTime now = DateTime.Now; if (e.pixelType == HikCodeReaderEventArgs.PixelType.Mono8 && e.Bitmap != null) { lock (e.Bitmap) { onlinePictureBox.Image = e.Bitmap; } } else if (e.pixelType == HikCodeReaderEventArgs.PixelType.Jpeg && e.Image != null) { lock (e.Image) { ImageWidth = (ulong)e.Image.Width; ImageHeight = (ulong)e.Image.Height; onlinePictureBox.Image = new Bitmap(e.Image); if (((HikCodeReader)camera).resultEx.nCodeNum > 0) { onlinePictureBox.Image = new Bitmap(e.Image); total.iScanCount++; } } } DateTime end = DateTime.Now; string spanTime = (end - now).TotalMilliseconds.ToString(); } private ulong ImageWidth; private ulong ImageHeight; 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) { DateTime StartTime = DateTime.Now; if (camera == null) { return; } 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); //this.BeginInvoke(new Action(() => //{ // if (bitmap != null) // { // this.lblCapTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms"; // } // else // { // this.lblCapTime.Text = "-1ms"; // } //})); //复原原通讯口设置 //camera.SetCamConfig(OriCamConfig); bool success = false; Bitmap bitmap = null; // 调用基类接口的单次采集方法 // LBCamera重写了StartSingleGrab方法,其他相机调用返回false success = camera.StartSingleGrab(); if (success) { // 等待图像数据 using (AutoResetEvent waitHandle = new AutoResetEvent(false)) { Bitmap captured = null; EventHandler handler = (s, evt) => { if (evt.Bitmap != null) { captured = evt.Bitmap.Clone() as Bitmap; waitHandle.Set(); } }; 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"; } })); } }); } private void btnStartHard_Click(object sender, EventArgs e) { if (camera == null) { return; } total.Clear(); // 尝试将输入字符串转换为枚举值 if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand)) { camera.StopGrabbing(); // 调用基类接口的连续采集方法 // LBCamera会调用StartContinuousGrab方法,其他相机使用原有的StartWith_HardTriggerModel camera.StartContinuousGrab(); } startGrabtime = DateTime.Now; cmbSN.Enabled = false; cmbBrand.Enabled = false; } private void btnStartGrab_Click(object sender, EventArgs e) { if (camera == null) { return; } total.Clear(); // 尝试将输入字符串转换为枚举值 if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand)) { Task.Factory.StartNew(() => { camera.StopGrabbing(); // 调用基类接口的连续采集方法 // LBCamera会调用StartContinuousGrab方法,其他相机使用原有的StartWith_SoftTriggerModel camera.StartContinuousGrab(); }); } startGrabtime = DateTime.Now; cmbSN.Enabled = false; cmbBrand.Enabled = false; } private void btnCloseGrab_Click(object sender, EventArgs e) { try { if (camera == null) { return; } // 尝试将输入字符串转换为枚举值 if (Enum.TryParse(cmbBrand.Text, true, out CameraBrand brand)) { Task.Factory.StartNew(() => { camera.StopGrabbing(); if (brand != CameraBrand.LBCamera) { camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software); camera.StartGrabbing(); } }); } cmbSN.Enabled = true; cmbBrand.Enabled = true; } catch { } } private void btnLocalGrab_Click(object sender, EventArgs e) { try { if (cmbImagesPath.Items.Count <= 0) { return; } DateTime StartTime = DateTime.Now; int index = cmbImagesPath.SelectedIndex; if (cmbImagesPath.Items.Count > index + 1) { cmbImagesPath.Text = cmbImagesPath.Items[index + 1].ToString(); } else { cmbImagesPath.Text = cmbImagesPath.Items[0].ToString(); } //Mat src = Cv2.ImRead(cmbImagesPath.Text); //if (src != null && !src.Empty()) //{ // Bitmap bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src); // this.BeginInvoke(new Action(() => // { // this.lblCapTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms"; // })); // onlinePictureBox.Image = bitmap; //} using (Mat src = Cv2.ImRead(cmbImagesPath.Text)) { if (src != null && !src.Empty()) { using (Bitmap bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src)) { this.Invoke(new Action(() => { this.lblCapTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms"; })); onlinePictureBox.Image = bitmap; } } } } catch { } } private void txtExp_TextChanged(object sender, EventArgs e) { if (camera == null) { return; } double exp = 1000; if (double.TryParse(txtExp.Text.ToString(), out exp)) { camera.SetExpouseTime(exp); } } private void txtGain_TextChanged(object sender, EventArgs e) { if (camera == null) { return; } double gain = 10; if (double.TryParse(txtGain.Text.ToString(), out gain)) { camera.SetGain(gain); } } private void btnAddImages_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); // 设置文件对话框的属性 openFileDialog.Multiselect = true; // 不允许多选 // 设置文件过滤器,支持多种文件类型 openFileDialog.Filter = "Image Files (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp|All Files (*.*)|*.*"; // 显示文件对话框 DialogResult result = openFileDialog.ShowDialog(); // 处理对话框返回结果 if (result == DialogResult.OK) { cmbImagesPath.Items.Clear(); // 获取用户选择的文件名 string[] selectedFiles = openFileDialog.FileNames; // 将文件路径添加到队列中 foreach (string file in selectedFiles) { cmbImagesPath.Items.Add(file); } if (selectedFiles.Length > 0) { cmbImagesPath.Text = selectedFiles[0]; } } } private void CameraForm_FormClosing(object sender, FormClosingEventArgs e) { //路径为空说明无需保存 if (string.IsNullOrEmpty(fullPath)) { e.Cancel = false; //确认关闭窗体 return; } DialogResult res = MessageBox.Show("是否保存?", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); //保存结果信息 /// 参数1:显示文本,参数2:标题,参数3:按键类型,参数4:显示图标 if (res == DialogResult.Cancel) //取消 { e.Cancel = true; //取消关闭窗体 return; } if (res == DialogResult.Yes) //保存VPP { 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("是否本地取图", ckbLocalTest.Checked); camConfig.Params.Inputs.Add("本地取图路径", cmbImagesPath.Items.Cast().ToList()); camConfig.Params.Inputs.Add("是否失败重新取图", ckbRegrab.Checked); if (int.TryParse(txtTimeout.Text, out int timeout)) { camConfig.Params.Inputs.Add("超时时间", timeout); } if (float.TryParse(txtExp.Text, out float exp)) { camConfig.Params.Inputs.Add("曝光时间", exp); } if (float.TryParse(txtGain.Text, out float gain)) { camConfig.Params.Inputs.Add("增益", gain); } string filePath = Path.GetDirectoryName(fullPath); camConfig.Save(filePath); e.Cancel = false; //确认关闭窗体 return; //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 : 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().ToList()); //camConfig.Params.Inputs.Add("是否失败重新取图", ckbRegrab.Checked); //if (int.TryParse(txtTimeout.Text, out int timeout)) //{ // camConfig.Params.Inputs.Add("超时时间", timeout); //} //if (float.TryParse(txtExp.Text, out float exp)) //{ // camConfig.Params.Inputs.Add("曝光时间", exp); //} //if (float.TryParse(txtGain.Text, out float gain)) //{ // camConfig.Params.Inputs.Add("增益", gain); //} //string filePath = Path.GetDirectoryName(fullPath); //camConfig.Save(filePath); //e.Cancel = false; //确认关闭窗体 //return; } } private void CameraForm_FormClosed(object sender, FormClosedEventArgs e) { try { this.onlinePictureBox.Image = null; if (camera != null) { camera.ImageGrabbed -= GetImageBllComplete; //camera.StopGrabbing(); //if (radioButtonSoft.Checked) //{ // camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software); //} //else //{ // camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0); //} //camera.StartGrabbing(); // 检查该相机是否由主系统管理 bool isManagedBySystem = dicCameras != null && dicCameras.ContainsKey(camera.SN); if (!isManagedBySystem) { // 只有非托管的(临时打开的)相机才停止采集和释放 camera.StopGrabbing(); 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(); } } } //路径为空说明为测试模式,需要释放相机 if (string.IsNullOrEmpty(fullPath) && camera != null) { camera.Dispose(); } } catch { } } private ImageFormat GetImageFormat(string extension) { return extension.ToLower() switch { ".jpg" or ".jpeg" => ImageFormat.Jpeg, ".png" => ImageFormat.Png, ".bmp" => ImageFormat.Bmp, ".gif" => ImageFormat.Gif, ".tiff" => ImageFormat.Tiff, _ => ImageFormat.Png // 默认格式 }; } private void btnSaveImage_Click(object sender, EventArgs e) { if (Bitmap == null) { MessageBox.Show("没有图像可保存!", "异常"); return; } // 创建 SaveFileDialog 实例 using (SaveFileDialog saveFileDialog = new SaveFileDialog()) { // 设置对话框标题 saveFileDialog.Title = "保存文件"; // 设置默认路径 saveFileDialog.InitialDirectory = Application.StartupPath; // 设置文件过滤器,支持多种文件类型 saveFileDialog.Filter = "Image Files (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp|All Files (*.*)|*.*"; // 设置默认文件名 saveFileDialog.FileName = "output.jpg"; // 显示对话框并检查用户是否点击了保存按钮 if (saveFileDialog.ShowDialog() == DialogResult.OK) { // 获取用户选择的文件路径 string fullPath = saveFileDialog.FileName; Debug.WriteLine("选择的文件路径是: " + fullPath); if (!string.IsNullOrEmpty(fullPath)) { Bitmap.Save(fullPath, GetImageFormat(Path.GetExtension(fullPath))); } } } } private void radioButtonSoft_CheckedChanged(object sender, EventArgs e) { btnGrabOnce.Enabled = radioButtonSoft.Checked; btnStartGrab.Enabled = radioButtonSoft.Checked; btnCloseGrab.Enabled = radioButtonSoft.Checked; btnStartHard.Enabled = !radioButtonSoft.Checked; if (camera == null) { return; } //if (radioButtonSoft.Checked) //{ // camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software); //} //else //{ // camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0); //} camera.GetTriggerMode(out _, out TriggerSource currentSource); if (radioButtonSoft.Checked) { camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software); } else { // 如果当前已经是硬件触发源,则保持;否则默认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(); private void cmbImagesPath_MouseHover(object sender, EventArgs e) { if (cmbImagesPath.SelectedIndex != -1 && camConfig != null && int.TryParse(camConfig.Params.Inputs["本地取图序号"]?.ToString(), out int indexPath)) { // 显示ToolTip(相对于控件的位置) ToolTip.Show($"当前索引序号:{indexPath}", (Control)sender, ((Control)sender).Width / 2, // x偏移 -20, // y偏移(负值表示上方) 2000); // 显示时间(ms) } } private void cmbImagesPath_SelectedIndexChanged(object sender, EventArgs e) { if (camConfig != null) { camConfig.Params.Inputs["本地取图序号"] = cmbImagesPath.SelectedIndex; } } } /// /// 相机高级设置包装类 /// 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(); } } }