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<string, BaseCamera> dicCameras { get; set; }
|
|
string fullPath = string.Empty;
|
|
public CameraForm()
|
{
|
InitializeComponent();
|
}
|
|
public CameraForm(ConcurrentDictionary<string, BaseCamera> 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<string> lstPaths = (JArray.FromObject(camConfig.Params.Inputs["本地取图路径"]))?.ToObject<List<string>>();
|
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<CameraBrand>();
|
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();
|
}
|
}
|
}
|
|
/// <summary>
|
/// 相机回调运行
|
/// </summary>
|
/// <param name="CCDName"></param>
|
/// <param name="image"></param>
|
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 { }
|
}
|
|
/// <summary>
|
/// 读码回调运行
|
/// </summary>
|
/// <param name="CCDName"></param>
|
/// <param name="image"></param>
|
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<CameraEventArgs> 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<string>().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<string>().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;
|
}
|
}
|
}
|
/// <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();
|
}
|
}
|
|
}
|