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 参数加载/更新核心方法 /// /// 加载参数到DataGridView /// private void LoadParamsToDataGridView() { if (SegFeatures == null) return; Dictionary areaThresholds = null; Dictionary longSideThresholds = null; Dictionary shortSideThresholds = null; Dictionary classesScoreThresholds = null; // 获取SegmentTool中的阈值字典 var areaThresholdsObj = ((SegmentTool)Subject).Params.Inputs["AreaThresholds"]; if (areaThresholdsObj is JObject jObject) { // 最终转换为目标字典类型 areaThresholds = jObject.ToObject>(); } else if (areaThresholdsObj is Object) { areaThresholds = areaThresholdsObj as Dictionary; } else { //// 处理类型不符的异常情况(可选,增强健壮性) //throw new System.Exception("AreaThresholds的实际类型不是JObject,转换失败"); areaThresholds = new Dictionary(); } var longSideThresholdsObj = ((SegmentTool)Subject).Params.Inputs["LongSideThresholds"]; if (longSideThresholdsObj is JObject jObjectL) { // 最终转换为目标字典类型 longSideThresholds = jObjectL.ToObject>(); } else if (longSideThresholdsObj is Object) { longSideThresholds = longSideThresholdsObj as Dictionary; } else { //// 处理类型不符的异常情况(可选,增强健壮性) //throw new System.Exception("LongSideThresholds的实际类型不是JObject,转换失败"); longSideThresholds = new Dictionary(); } var shortSideThresholdsObj = ((SegmentTool)Subject).Params.Inputs["ShortSideThresholds"]; if (shortSideThresholdsObj is JObject jObjectS) { // 最终转换为目标字典类型 shortSideThresholds = jObjectS.ToObject>(); } else if (shortSideThresholdsObj is Object) { shortSideThresholds = shortSideThresholdsObj as Dictionary; } else { //// 处理类型不符的异常情况(可选,增强健壮性) //throw new System.Exception("shortSideThresholds的实际类型不是JObject,转换失败"); shortSideThresholds = new Dictionary(); } var classesScoreThresholdsObj = ((SegmentTool)Subject).Params.Inputs["ClassesScoreThresholds"]; if (classesScoreThresholdsObj is JObject jObjectC) { // 最终转换为目标字典类型 classesScoreThresholds = jObjectC.ToObject>(); } else if (classesScoreThresholdsObj is Object) { classesScoreThresholds = classesScoreThresholdsObj as Dictionary; } else { //// 处理类型不符的异常情况(可选,增强健壮性) //throw new System.Exception("classesScoreThresholds的实际类型不是JObject,转换失败"); classesScoreThresholds = new Dictionary(); } //Dictionary areaThresholds = ((SegmentTool)Subject).Params.Inputs["AreaThresholds"] as Dictionary ?? new Dictionary(); //Dictionary longSideThresholds = ((SegmentTool)Subject).Params.Inputs["LongSideThresholds"] as Dictionary ?? new Dictionary(); //Dictionary shortSideThresholds = ((SegmentTool)Subject).Params.Inputs["ShortSideThresholds"] as Dictionary ?? new Dictionary(); //Dictionary classesScoreThresholds = ((SegmentTool)Subject).Params.Inputs["ClassesScoreThresholds"] as Dictionary ?? new Dictionary(); //// 收集所有类别名称(合并所有字典的Key) //var allClassNames = new HashSet(); //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(); 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; } /// /// 将DataGridView中的参数更新到SegmentTool的Params.Inputs /// public void UpdateInputs() { if (dataGridView1.DataSource == null) { return; } // 初始化新的阈值字典 Dictionary areaThresholds = new Dictionary(); Dictionary longSideThresholds = new Dictionary(); Dictionary shortSideThresholds = new Dictionary(); Dictionary classesScoreThresholds = new Dictionary(); // 遍历表格行,更新到字典 BindingList dataSource = (BindingList)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行项 /// /// 阈值参数行模型 /// public class ThresholdItem { /// /// 类别名称 /// public string ClassName { get; set; } /// /// 面积阈值 /// public double AreaThreshold { get; set; } /// /// 长边阈值 /// public double LongSideThreshold { get; set; } /// /// 短边阈值 /// public double ShortSideThreshold { get; set; } /// /// 类别置信度阈值 /// 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 SegFeatures; /// /// 更新运行参数 /// 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()); // ////长边过滤阈值 // //Subject.Params.Inputs.Add("LongSideThresholds", new Dictionary()); // ////短边过滤阈值 // //Subject.Params.Inputs.Add("ShortSideThresholds", new Dictionary()); // ////类别置信度阈值 // //Subject.Params.Inputs.Add("ClassesScoreThresholds", new Dictionary()); // 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; } } } /// /// 加载运行参数 /// 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; } })); } /// /// 更新输出结果 /// public override void UpdataOutputs() { this.BeginInvoke(new Action(() => { //存在反序列化错乱的情况需要使用自定义的转换器 stxtCodeStrings.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["CodeStrings"]); dtxtCount.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Count"]); })); } /// /// 点击运行 /// /// /// 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]; } } } } }