using HalconDotNet;
|
using LB_SmartVisionCommon;
|
using LB_VisionControls;
|
using Newtonsoft.Json.Linq;
|
using OpenCvSharp;
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Data;
|
using System.Diagnostics;
|
using System.Drawing;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using System.Windows.Forms;
|
|
namespace LB_VisionProcesses.Alogrithms.BigModel.Segment
|
{
|
public partial class SegmentToolEdit : TAlgorithmEdit
|
{
|
public SegmentToolEdit(TAlgorithm subject = null)
|
{
|
if (subject != null && subject is SegmentTool)
|
{
|
Subject = subject;
|
}
|
else
|
{
|
Subject = new SegmentTool();
|
}
|
this.Dock = DockStyle.Fill;
|
InitializeComponent();
|
InitDataGridViewColumns();
|
}
|
|
#region 初始化DataGridView列结构
|
private void InitDataGridViewColumns()
|
{
|
// 清空原有列
|
dataGridView1.Columns.Clear();
|
|
// 1. 类别名称列
|
DataGridViewTextBoxColumn colClassName = new DataGridViewTextBoxColumn
|
{
|
Name = "colClassName",
|
HeaderText = "类别名称",
|
DataPropertyName = "ClassName",
|
Width = 120,
|
ReadOnly = false
|
};
|
dataGridView1.Columns.Add(colClassName);
|
|
// 2. 面积阈值列(整数)
|
DataGridViewTextBoxColumn colAreaThreshold = new DataGridViewTextBoxColumn
|
{
|
Name = "colAreaThreshold",
|
HeaderText = "面积阈值",
|
DataPropertyName = "AreaThreshold",
|
Width = 120,
|
DefaultCellStyle = { Format = "N2" }, // 整数格式
|
ReadOnly = false
|
};
|
dataGridView1.Columns.Add(colAreaThreshold);
|
|
// 3. 长边阈值列(浮点数,保留2位小数)
|
DataGridViewTextBoxColumn colLongSideThreshold = new DataGridViewTextBoxColumn
|
{
|
Name = "colLongSideThreshold",
|
HeaderText = "长边阈值",
|
DataPropertyName = "LongSideThreshold",
|
Width = 120,
|
DefaultCellStyle = { Format = "N2" },
|
ReadOnly = false
|
};
|
dataGridView1.Columns.Add(colLongSideThreshold);
|
|
// 4. 短边阈值列(浮点数,保留2位小数)
|
DataGridViewTextBoxColumn colShortSideThreshold = new DataGridViewTextBoxColumn
|
{
|
Name = "colShortSideThreshold",
|
HeaderText = "短边阈值",
|
DataPropertyName = "ShortSideThreshold",
|
Width = 120,
|
DefaultCellStyle = { Format = "N2" },
|
ReadOnly = false
|
};
|
dataGridView1.Columns.Add(colShortSideThreshold);
|
|
// 5. 类别置信度阈值列(浮点数,0~1,保留4位小数)
|
DataGridViewTextBoxColumn colClassesScoreThreshold = new DataGridViewTextBoxColumn
|
{
|
Name = "colClassesScoreThreshold",
|
HeaderText = "类别置信度阈值",
|
DataPropertyName = "ClassesScoreThreshold",
|
Width = 150,
|
DefaultCellStyle = { Format = "N3" },
|
ReadOnly = false
|
};
|
dataGridView1.Columns.Add(colClassesScoreThreshold);
|
|
// DataGridView基础设置
|
dataGridView1.AllowUserToAddRows = true; // 允许添加行
|
dataGridView1.AllowUserToDeleteRows = true; // 允许删除行
|
dataGridView1.ReadOnly = false;
|
dataGridView1.AutoGenerateColumns = false;
|
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
dataGridView1.CellValidating += DataGridView1_CellValidating; // 单元格验证
|
dataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
|
}
|
|
private void DataGridView1_CellValueChanged(object? sender, DataGridViewCellEventArgs e)
|
{
|
UpdateInputs();
|
}
|
#endregion
|
|
#region 按钮事件绑定
|
//private void BindButtonEvents()
|
//{
|
// // 保存参数按钮
|
// btnSaveParas.Click += (s, e) =>
|
// {
|
// UpdateInputs(); // 更新参数到SegmentTool
|
// lblMsg.Text = "参数保存成功";
|
// lblResult.Text = "True";
|
// lblRunTime.Text = "0ms";
|
// };
|
|
// // 加载参数按钮
|
// btnLoadParas.Click += (s, e) =>
|
// {
|
// LoadParamsToDataGridView(); // 从SegmentTool加载参数到表格
|
// lblMsg.Text = "参数加载成功";
|
// lblResult.Text = "True";
|
// lblRunTime.Text = "0ms";
|
// };
|
|
// // 选择模型按钮
|
// btnChoseModel.Click += (s, e) =>
|
// {
|
// using (OpenFileDialog ofd = new OpenFileDialog())
|
// {
|
// ofd.Filter = "ViMo解决方案文件 (*.vimosln)|*.vimosln|所有文件 (*.*)|*.*";
|
// if (ofd.ShowDialog() == DialogResult.OK)
|
// {
|
// txtModelPath.Text = ofd.FileName;
|
// //if (_segmentTool != null)
|
// //{
|
// // _segmentTool.LoadModel(ofd.FileName); // 加载模型
|
// // LoadParamsToDataGridView(); // 刷新参数表格
|
// //}
|
// }
|
// }
|
// };
|
//}
|
#endregion
|
|
#region 数据验证(防止非法输入)
|
private void DataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
|
{
|
var dgv = sender as DataGridView;
|
if (dgv == null || e.RowIndex < 0 || e.RowIndex == dgv.NewRowIndex) return;
|
|
var column = dgv.Columns[e.ColumnIndex];
|
var cellValue = e.FormattedValue.ToString().Trim();
|
|
// 验证类别名称(非空)
|
if (column.Name == "colClassName")
|
{
|
if (string.IsNullOrWhiteSpace(cellValue))
|
{
|
e.Cancel = true;
|
MessageBox.Show("类别名称不能为空!", "验证错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
}
|
return;
|
}
|
|
// 验证面积阈值(正整数)
|
if (column.Name == "colAreaThreshold")
|
{
|
if (!double.TryParse(cellValue, out double area) || area < 0)
|
{
|
e.Cancel = true;
|
MessageBox.Show("面积阈值必须是≥0的整数!", "验证错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
}
|
return;
|
}
|
|
// 验证长边/短边阈值(非负数)
|
if (column.Name is "colLongSideThreshold" or "colShortSideThreshold")
|
{
|
if (!double.TryParse(cellValue, out double val) || val < 0)
|
{
|
e.Cancel = true;
|
MessageBox.Show($"{column.HeaderText}必须是≥0的数字!", "验证错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
}
|
return;
|
}
|
|
// 验证类别置信度阈值(0~1之间)
|
if (column.Name == "colClassesScoreThreshold")
|
{
|
if (!double.TryParse(cellValue, out double score) || score < 0 || score > 1)
|
{
|
e.Cancel = true;
|
MessageBox.Show("类别置信度阈值必须是0~1之间的数字!", "验证错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
}
|
}
|
}
|
#endregion
|
|
#region 参数加载/更新核心方法
|
|
|
/// <summary>
|
/// 加载参数到DataGridView
|
/// </summary>
|
private void LoadParamsToDataGridView()
|
{
|
if (SegFeatures == null) return;
|
|
|
Dictionary<string, double> areaThresholds = null;
|
Dictionary<string, double> longSideThresholds = null;
|
Dictionary<string, double> shortSideThresholds = null;
|
Dictionary<string, double> classesScoreThresholds = null;
|
|
// 获取SegmentTool中的阈值字典
|
var areaThresholdsObj = ((SegmentTool)Subject).Params.Inputs["AreaThresholds"];
|
|
if (areaThresholdsObj is JObject jObject)
|
{
|
// 最终转换为目标字典类型
|
areaThresholds = jObject.ToObject<Dictionary<string, double>>();
|
|
}
|
else if (areaThresholdsObj is Object)
|
{
|
areaThresholds = areaThresholdsObj as Dictionary<string, double>;
|
}
|
else
|
{
|
//// 处理类型不符的异常情况(可选,增强健壮性)
|
//throw new System.Exception("AreaThresholds的实际类型不是JObject,转换失败");
|
areaThresholds = new Dictionary<string, double>();
|
}
|
|
var longSideThresholdsObj = ((SegmentTool)Subject).Params.Inputs["LongSideThresholds"];
|
|
if (longSideThresholdsObj is JObject jObjectL)
|
{
|
// 最终转换为目标字典类型
|
longSideThresholds = jObjectL.ToObject<Dictionary<string, double>>();
|
|
}
|
else if (longSideThresholdsObj is Object)
|
{
|
longSideThresholds = longSideThresholdsObj as Dictionary<string, double>;
|
}
|
else
|
{
|
//// 处理类型不符的异常情况(可选,增强健壮性)
|
//throw new System.Exception("LongSideThresholds的实际类型不是JObject,转换失败");
|
longSideThresholds = new Dictionary<string, double>();
|
}
|
|
|
var shortSideThresholdsObj = ((SegmentTool)Subject).Params.Inputs["ShortSideThresholds"];
|
|
if (shortSideThresholdsObj is JObject jObjectS)
|
{
|
// 最终转换为目标字典类型
|
shortSideThresholds = jObjectS.ToObject<Dictionary<string, double>>();
|
|
}
|
else if (shortSideThresholdsObj is Object)
|
{
|
shortSideThresholds = shortSideThresholdsObj as Dictionary<string, double>;
|
}
|
else
|
{
|
//// 处理类型不符的异常情况(可选,增强健壮性)
|
//throw new System.Exception("shortSideThresholds的实际类型不是JObject,转换失败");
|
shortSideThresholds = new Dictionary<string, double>();
|
}
|
|
var classesScoreThresholdsObj = ((SegmentTool)Subject).Params.Inputs["ClassesScoreThresholds"];
|
|
if (classesScoreThresholdsObj is JObject jObjectC)
|
{
|
// 最终转换为目标字典类型
|
classesScoreThresholds = jObjectC.ToObject<Dictionary<string, double>>();
|
|
}
|
else if (classesScoreThresholdsObj is Object)
|
{
|
classesScoreThresholds = classesScoreThresholdsObj as Dictionary<string, double>;
|
}
|
else
|
{
|
//// 处理类型不符的异常情况(可选,增强健壮性)
|
//throw new System.Exception("classesScoreThresholds的实际类型不是JObject,转换失败");
|
classesScoreThresholds = new Dictionary<string, double>();
|
}
|
//Dictionary<string, double> areaThresholds = ((SegmentTool)Subject).Params.Inputs["AreaThresholds"] as Dictionary<string, double> ?? new Dictionary<string, double>();
|
//Dictionary<string, double> longSideThresholds = ((SegmentTool)Subject).Params.Inputs["LongSideThresholds"] as Dictionary<string, double> ?? new Dictionary<string, double>();
|
//Dictionary<string, double> shortSideThresholds = ((SegmentTool)Subject).Params.Inputs["ShortSideThresholds"] as Dictionary<string, double> ?? new Dictionary<string, double>();
|
//Dictionary<string, double> classesScoreThresholds = ((SegmentTool)Subject).Params.Inputs["ClassesScoreThresholds"] as Dictionary<string, double> ?? new Dictionary<string, double>();
|
|
//// 收集所有类别名称(合并所有字典的Key)
|
//var allClassNames = new HashSet<string>();
|
//foreach (var key in areaThresholds.Keys) allClassNames.Add(key);
|
//foreach (var key in longSideThresholds.Keys) allClassNames.Add(key);
|
//foreach (var key in shortSideThresholds.Keys) allClassNames.Add(key);
|
//foreach (var key in classesScoreThresholds.Keys) allClassNames.Add(key);
|
|
// 构建DataGridView数据源
|
var dataSource = new BindingList<ThresholdItem>();
|
foreach (var className in SegFeatures)
|
{
|
dataSource.Add(new ThresholdItem
|
{
|
ClassName = className,
|
AreaThreshold = areaThresholds.TryGetValue(className, out double area) ? area : 0.0,
|
LongSideThreshold = longSideThresholds.TryGetValue(className, out double longSide) ? longSide : 0.0,
|
ShortSideThreshold = shortSideThresholds.TryGetValue(className, out double shortSide) ? shortSide : 0.0,
|
ClassesScoreThreshold = classesScoreThresholds.TryGetValue(className, out double score) ? score : 0.0
|
});
|
}
|
|
// 绑定数据源
|
dataGridView1.DataSource = dataSource;
|
dataGridView1.ForeColor = Color.Black;
|
}
|
|
/// <summary>
|
/// 将DataGridView中的参数更新到SegmentTool的Params.Inputs
|
/// </summary>
|
public void UpdateInputs()
|
{
|
if (dataGridView1.DataSource == null)
|
{
|
return;
|
}
|
|
// 初始化新的阈值字典
|
Dictionary<string, double> areaThresholds = new Dictionary<string, double>();
|
Dictionary<string, double> longSideThresholds = new Dictionary<string, double>();
|
Dictionary<string, double> shortSideThresholds = new Dictionary<string, double>();
|
Dictionary<string, double> classesScoreThresholds = new Dictionary<string, double>();
|
|
// 遍历表格行,更新到字典
|
BindingList<ThresholdItem> dataSource = (BindingList<ThresholdItem>)dataGridView1.DataSource;
|
foreach (var item in dataSource)
|
{
|
if (string.IsNullOrWhiteSpace(item.ClassName))
|
{
|
continue; // 跳过空类别
|
}
|
areaThresholds[item.ClassName] = item.AreaThreshold;
|
longSideThresholds[item.ClassName] = item.LongSideThreshold;
|
shortSideThresholds[item.ClassName] = item.ShortSideThreshold;
|
classesScoreThresholds[item.ClassName] = item.ClassesScoreThreshold;
|
}
|
|
// 更新到SegmentTool的输入参数
|
((SegmentTool)Subject).Params.Inputs["AreaThresholds"] = areaThresholds;
|
((SegmentTool)Subject).Params.Inputs["LongSideThresholds"] = longSideThresholds;
|
((SegmentTool)Subject).Params.Inputs["ShortSideThresholds"] = shortSideThresholds;
|
((SegmentTool)Subject).Params.Inputs["ClassesScoreThresholds"] = classesScoreThresholds;
|
}
|
#endregion
|
|
#region 数据模型:DataGridView行项
|
/// <summary>
|
/// 阈值参数行模型
|
/// </summary>
|
public class ThresholdItem
|
{
|
/// <summary>
|
/// 类别名称
|
/// </summary>
|
public string ClassName { get; set; }
|
|
/// <summary>
|
/// 面积阈值
|
/// </summary>
|
public double AreaThreshold { get; set; }
|
|
/// <summary>
|
/// 长边阈值
|
/// </summary>
|
public double LongSideThreshold { get; set; }
|
|
/// <summary>
|
/// 短边阈值
|
/// </summary>
|
public double ShortSideThreshold { get; set; }
|
|
/// <summary>
|
/// 类别置信度阈值
|
/// </summary>
|
public double ClassesScoreThreshold { get; set; }
|
}
|
#endregion
|
|
|
private void SegmentToolEdit_Load(object sender, EventArgs e)
|
{
|
//按钮使能初始化
|
|
pnlInputImage.Controls.Add(inputImageHSmartWindowControl);
|
inputImageHSmartWindowControl.Dock = DockStyle.Fill;
|
|
pnlRecordImage.Controls.Add(recordImageHSmartWindowControl);
|
recordImageHSmartWindowControl.Dock = DockStyle.Fill;
|
|
//遍历可以选择的Roi类型枚举
|
foreach (var value in Enum.GetValues(typeof(RoiType)))
|
{
|
this.cmbTypeRoi.Items.Add(value.ToString());
|
}
|
|
//遍历可以选择的模型类型枚举
|
foreach (var value in DiskInfoHelper.GetGpuInfoWithCudaIndex())
|
{
|
if (value.IsNvidia)
|
{
|
this.cobGPUDeviceID.Items.Add(value.CudaIndex.ToString());
|
}
|
}
|
|
cmbTypeRoi.Text = RoiType.None.ToString();
|
LoadParas();
|
|
if (Subject.Result)
|
{
|
lblResult.BackColor = Color.Green;
|
lblResult.Text = "True";
|
}
|
else
|
{
|
lblResult.BackColor = Color.Red;
|
lblResult.Text = "False";
|
}
|
|
lblMsg.Text = Msg.Length > 50 ? Msg.Substring(0, 50) : Msg;
|
lblMsgToolTip.SetToolTip(BtmStatusStrip, Msg);
|
lblRunTime.Text = $"{Subject.RunTime}ms";
|
}
|
List<string> SegFeatures;
|
/// <summary>
|
/// 更新运行参数
|
/// </summary>
|
public override void UpdataInputs()
|
{
|
//设置运行参数
|
int iResult = 0;
|
double dResult = 0;
|
|
|
|
string nPath = this.txtModelPath.Text;
|
string oPath = Subject.Params.Inputs["ModelPath"]?.ToString();
|
|
bool nIsUseGPU = this.rbIsUseGPU.Checked;
|
bool oIsUseGPU = Convert.ToBoolean(Subject.Params.Inputs["UseGpu"]?.ToString());
|
|
int nModelID = Convert.ToInt32(this.txtModelID.Text);
|
int oModelID = Convert.ToInt32(Subject.Params.Inputs["ModelID"]?.ToString());
|
|
int.TryParse(this.cobGPUDeviceID.Text, out int nGPUDeviceID);
|
int oGPUDeviceID = Convert.ToInt32(Subject.Params.Inputs["DeviceId"]);
|
|
int.TryParse(this.txtBatchSize.Text, out int nBatchSize);
|
double oBatchSize = Convert.ToDouble(Subject.Params.Inputs["BatchSize"]);
|
|
double.TryParse(this.txtMaxTimeOut.Text, out double nMaxTimeOut);
|
double oMaxTimeOut = Convert.ToDouble(Subject.Params.Inputs["MaxTimeOut"]);
|
|
//if (nPath != oPath || nIsUseGPU != oIsUseGPU || nModelID != oModelID
|
// || nGPUDeviceID != oGPUDeviceID || nBatchSize != oBatchSize)
|
//{
|
// //模型输入
|
// Subject.Params.Inputs.Add("ModuleId", nModelID);
|
// Subject.Params.Inputs.Add("UseGpu", nIsUseGPU);
|
// Subject.Params.Inputs.Add("DeviceId", nGPUDeviceID);
|
// Subject.Params.Inputs.Add("BatchSize", nBatchSize);
|
// Subject.Params.Inputs.Add("ModelPath", nPath);
|
// UpdateInputs();
|
// ////面积阈值
|
// //Subject.Params.Inputs.Add("AreaThresholds", new Dictionary<string, Int32>());
|
|
// ////长边过滤阈值
|
// //Subject.Params.Inputs.Add("LongSideThresholds", new Dictionary<string, double>());
|
|
// ////短边过滤阈值
|
// //Subject.Params.Inputs.Add("ShortSideThresholds", new Dictionary<string, double>());
|
|
// ////类别置信度阈值
|
// //Subject.Params.Inputs.Add("ClassesScoreThresholds", new Dictionary<string, double>());
|
|
// if (!((SegmentTool)Subject).LoadModel())
|
// {
|
// Debug.WriteLine("模型加载失败,请检查模型路径");
|
// }
|
// else
|
// {
|
// SegFeatures = ((SegmentTool)Subject).SegFeatures;
|
// }
|
// LoadParamsToDataGridView();
|
//}
|
|
Subject.Params.Inputs.Add("ModuleId", nModelID);
|
Subject.Params.Inputs.Add("UseGpu", nIsUseGPU);
|
Subject.Params.Inputs.Add("DeviceId", nGPUDeviceID);
|
Subject.Params.Inputs.Add("BatchSize", nBatchSize);
|
Subject.Params.Inputs.Add("ModelPath", nPath);
|
Subject.Params.Inputs.Add("MaxTimeOut", nMaxTimeOut);
|
UpdateInputs();
|
|
if (!((SegmentTool)Subject).LoadModel(/*(Subject.Params.Inputs["ModelPath"])?.ToString()*/))
|
{
|
Debug.WriteLine("模型加载失败,请检查模型路径");
|
}
|
else
|
{
|
SegFeatures = ((SegmentTool)Subject).SegFeatures;
|
}
|
LoadParamsToDataGridView();
|
|
Type type = inputImageHSmartWindowControl.oRoi?.GetType();
|
switch (type)
|
{
|
case Type t when t == typeof(HRectangle2):
|
{
|
HRectangle2 hRectangle2 = (HRectangle2)inputImageHSmartWindowControl.oRoi;
|
Subject.Params.ROI
|
= new HRectangle2(hRectangle2.X - Subject.Params.Fixture.X, hRectangle2.Y - Subject.Params.Fixture.Y
|
, hRectangle2.Phi - Subject.Params.Fixture.Phi, hRectangle2.Width, hRectangle2.Height);
|
break;
|
}
|
case Type t when t == typeof(HCircle):
|
{
|
HCircle hCircle = (HCircle)inputImageHSmartWindowControl.oRoi;
|
Subject.Params.ROI
|
= new HCircle(hCircle.X - Subject.Params.Fixture.X, hCircle.Y - Subject.Params.Fixture.Y, hCircle.Radius);
|
break;
|
}
|
case Type t when t == typeof(HSegment):
|
{
|
HSegment hSegment = (HSegment)inputImageHSmartWindowControl.oRoi;
|
Subject.Params.ROI
|
= new HSegment(hSegment.StartX - Subject.Params.Fixture.X, hSegment.StartY - Subject.Params.Fixture.Y
|
, hSegment.EndX - Subject.Params.Fixture.X, hSegment.EndY - Subject.Params.Fixture.Y);
|
break;
|
}
|
default:
|
{
|
Subject.Params.ROI = new ROI();
|
break;
|
}
|
}
|
}
|
|
/// <summary>
|
/// 加载运行参数
|
/// </summary>
|
public override void LoadParas()
|
{
|
this.Invoke(new Action(() =>
|
{
|
this.txtModelPath.Text = Subject.Params.Inputs["ModelPath"]?.ToString();
|
|
this.txtModelID.Text = Subject.Params.Inputs["ModuleId"]?.ToString();
|
this.txtBatchSize.Text = Subject.Params.Inputs["BatchSize"]?.ToString();
|
this.rbIsUseGPU.Checked = Convert.ToBoolean(Subject.Params.Inputs["UseGpu"]);
|
this.cobGPUDeviceID.Text = Subject.Params.Inputs["DeviceId"]?.ToString();
|
this.txtMaxTimeOut.Text= Subject.Params.Inputs["MaxTimeOut"]?.ToString();
|
if (!string.IsNullOrEmpty(this.txtModelPath.Text))
|
{
|
if (!((SegmentTool)Subject).LoadModel(/*(Subject.Params.Inputs["ModelPath"])?.ToString()*/))
|
{
|
Debug.WriteLine("模型加载失败,请检查模型路径");
|
}
|
else
|
{
|
SegFeatures = ((SegmentTool)Subject).SegFeatures;
|
}
|
}
|
|
LoadParamsToDataGridView();
|
|
if (Subject.InputImage != null && Subject.InputImage is Mat)
|
{
|
TAlgorithm.Mat2HObject((Mat)Subject.InputImage, out HObject image);
|
inputImageHSmartWindowControl.ShowHoImage(image);
|
}
|
|
Type type = Subject.Params.ROI?.GetType();
|
if (Subject.Params.ROI != null)
|
{
|
switch (type)
|
{
|
case Type t when t == typeof(HRectangle2):
|
{
|
cmbTypeRoi.Text = RoiType.Rectangle2.ToString();
|
break;
|
}
|
case Type t when t == typeof(HCircle):
|
{
|
cmbTypeRoi.Text = RoiType.Circle.ToString();
|
break;
|
}
|
case Type t when t == typeof(HSegment):
|
{
|
cmbTypeRoi.Text = RoiType.Segment.ToString();
|
break;
|
}
|
default:
|
{
|
cmbTypeRoi.Text = RoiType.None.ToString();
|
break;
|
}
|
}
|
if (cmbTypeRoi.Text.ToString() != "None")
|
{
|
ckbDrawRoi.Checked = true;
|
}
|
else
|
{
|
ckbDrawRoi.Checked = false;
|
}
|
inputImageHSmartWindowControl.oRoi = Subject.Params.ROI;
|
}
|
}));
|
}
|
|
/// <summary>
|
/// 更新输出结果
|
/// </summary>
|
public override void UpdataOutputs()
|
{
|
this.BeginInvoke(new Action(() =>
|
{
|
//存在反序列化错乱的情况需要使用自定义的转换器
|
stxtCodeStrings.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["CodeStrings"]);
|
dtxtCount.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Count"]);
|
}));
|
}
|
|
/// <summary>
|
/// 点击运行
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
public override void btnRun_Click(object sender, EventArgs e)
|
{
|
if (Subject.InputImage != null)
|
{
|
InputImage = Subject.InputImage;
|
}
|
|
//运行前需要更新输入参数Paras
|
UpdataInputs();
|
DateTime StartTime = DateTime.Now;
|
Subject.Run();
|
|
//更新日志与结果
|
this.BeginInvoke(new Action(() =>
|
{
|
if (Subject.Result)
|
{
|
lblResult.BackColor = Color.Green;
|
lblResult.Text = "True";
|
recordImageHSmartWindowControl.SetColor("green");
|
}
|
else
|
{
|
lblResult.BackColor = Color.Red;
|
lblResult.Text = "False";
|
recordImageHSmartWindowControl.SetColor("red");
|
}
|
|
lblMsg.Text = Msg.Length > 50 ? Msg.Substring(0, 50) : Msg;
|
lblMsgToolTip.SetToolTip(BtmStatusStrip, Msg);
|
lblRunTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms";
|
|
UpdataOutputs();
|
imgTabControl.SelectedTab = tabPageRecordImage;
|
|
//if (Subject.OutputImage != null && Subject.OutputImage is HObject ho_image)
|
// recordImageHSmartWindowControl.ShowHoImage(ho_image);
|
|
if (Subject.InputImage != null)
|
{
|
if (Subject.InputImage is HObject ho_image && ho_image.IsInitialized())
|
{
|
recordImageHSmartWindowControl.ShowHoImage(ho_image);
|
}
|
else if (Subject.InputImage is Bitmap)
|
{
|
TAlgorithm.Bitmap2HObject((Bitmap)Subject.InputImage, out HObject image);
|
recordImageHSmartWindowControl.ShowHoImage(image);
|
}
|
else if (Subject.InputImage is Mat)
|
{
|
TAlgorithm.Mat2HObject((Mat)Subject.InputImage, out HObject image);
|
recordImageHSmartWindowControl.ShowHoImage(image);
|
}
|
}
|
|
//先判断子类再判断父类
|
if (Subject.Record != null && Subject.Record is MsgRecord msgRecord)
|
{
|
recordImageHSmartWindowControl.DispObj(msgRecord.RecordObject_OK, true);
|
recordImageHSmartWindowControl.DispObj(msgRecord.RecordObject_NG, false);
|
|
for (int i = 0; i < msgRecord.Msg.Length; i++)
|
{
|
recordImageHSmartWindowControl.ShowMsg(msgRecord.Msg[i]
|
, 1 == msgRecord.Result[i] ? true : false, msgRecord.Column[i], msgRecord.Row[i]);
|
}
|
}
|
else if (Subject.Record != null && Subject.Record is ObjectRecord objRecord)
|
{
|
recordImageHSmartWindowControl.DispObj(objRecord.RecordObject_OK, true);
|
recordImageHSmartWindowControl.DispObj(objRecord.RecordObject_NG, false);
|
}
|
|
GC.Collect();
|
}));
|
}
|
|
private new void btnLoadImage_Click(object sender, EventArgs e)
|
{
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
// 设置文件对话框的属性
|
openFileDialog.Multiselect = false; // 不允许多选
|
// 设置文件过滤器,支持多种文件类型
|
openFileDialog.Filter = "Image Files (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp|All Files (*.*)|*.*";
|
// 显示文件对话框
|
DialogResult result = openFileDialog.ShowDialog();
|
|
// 处理对话框返回结果
|
if (result == DialogResult.OK)
|
{
|
// 获取用户选择的文件名
|
string[] selectedFiles = openFileDialog.FileNames;
|
if (selectedFiles.Length > 0)
|
{
|
Mat src = Cv2.ImRead(selectedFiles[0]);
|
InputImage = src.Clone();
|
if (((Mat)InputImage) == null)
|
{
|
lblResult.BackColor = Color.Red;
|
lblResult.Text = "False";
|
lblMsg.Text = $"图片导入失败,路径为{selectedFiles[0]}";
|
}
|
imgTabControl.SelectedTab = tabPageInputImage;
|
}
|
}
|
}
|
|
public override void btnSaveParas_Click(object sender, EventArgs e)
|
{
|
//保存前需要更新输入参数Inputs
|
UpdataInputs();
|
|
// 创建 SaveFileDialog 实例
|
using (SaveFileDialog saveFileDialog = new SaveFileDialog())
|
{
|
// 设置对话框标题
|
saveFileDialog.Title = "保存文件";
|
|
// 设置默认路径
|
saveFileDialog.InitialDirectory = Application.StartupPath;
|
|
// 设置文件类型过滤器
|
saveFileDialog.Filter = "文本文件 (*.json)|*.json|所有文件 (*.*)|*.*";
|
|
// 设置默认文件名
|
saveFileDialog.FileName = Subject.strProcessName + ".json";
|
|
// 显示对话框并检查用户是否点击了保存按钮
|
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
{
|
// 获取用户选择的文件路径
|
string fullPath = saveFileDialog.FileName;
|
Debug.WriteLine("选择的文件路径是: " + fullPath);
|
Subject.strProcessName = Path.GetFileNameWithoutExtension(fullPath);
|
Subject.Save(Path.GetDirectoryName(fullPath));
|
}
|
}
|
}
|
|
public override void ckbDrawRoi_CheckedChanged(object sender, EventArgs e)
|
{
|
if (ckbDrawRoi.Checked)
|
{
|
inputImageHSmartWindowControl.bAollowDraw = true;
|
imgTabControl.SelectedTab = tabPageInputImage;
|
}
|
else
|
{
|
inputImageHSmartWindowControl.bAollowDraw = false;
|
Subject.Params.ROI = new ROI();
|
}
|
}
|
|
public override void cmbTypeRoi_SelectedIndexChanged(object sender, EventArgs e)
|
{
|
try
|
{
|
if (Enum.TryParse(cmbTypeRoi.Text.ToString(), out RoiType type))
|
{
|
HTuple hv_imageWidth = 100;
|
HTuple hv_imageHeight = 100;
|
if (InputImage != null && InputImage is Mat mat)
|
{
|
hv_imageWidth = mat.Width;
|
hv_imageHeight = mat.Height;
|
}
|
|
switch (type)
|
{
|
case RoiType.Rectangle2:
|
{
|
inputImageHSmartWindowControl.oRoi = new HRectangle2(hv_imageWidth.TupleReal() / 2, hv_imageHeight.TupleReal() / 2, 0
|
, hv_imageWidth.TupleReal() / 4, hv_imageHeight.TupleReal() / 4);
|
break;
|
}
|
case RoiType.Circle:
|
{
|
inputImageHSmartWindowControl.oRoi = new HCircle(hv_imageWidth.TupleReal() / 2, hv_imageHeight.TupleReal() / 2
|
, hv_imageWidth.TupleReal() / 4);
|
break;
|
}
|
case RoiType.None:
|
default:
|
{
|
inputImageHSmartWindowControl.oRoi = null;
|
break;
|
}
|
}
|
}
|
}
|
catch { }
|
}
|
|
private void btnChoseModel_Click(object sender, EventArgs e)
|
{
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
// 设置文件对话框的属性
|
openFileDialog.Multiselect = false; // 不允许多选
|
// 设置文件过滤器,支持多种文件类型
|
openFileDialog.Filter = "Vimosln Files (*.vimosln)|*.vimosln";
|
// 显示文件对话框
|
DialogResult result = openFileDialog.ShowDialog();
|
|
// 处理对话框返回结果
|
if (result == DialogResult.OK)
|
{
|
// 获取用户选择的文件名
|
string[] selectedFiles = openFileDialog.FileNames;
|
if (selectedFiles.Length > 0)
|
{
|
this.txtModelPath.Text = selectedFiles[0];
|
}
|
}
|
}
|
}
|
}
|