using Bro.Common.Helper; using Bro.UI.Config.Helper; using Bro.UI.Config.MenuForms; using Bro.UI.Model.Winform; using HalconDotNet; using HDisplay; using HDisplay.ViewROI; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace Bro.UI.Config { [MenuNode("EditModel", "模板编辑", 4, "View2", true)] public partial class FrmEditModel : MenuFrmBase { CanvasImage canvas = new CanvasImage(); HTuple modelId = null; HalconDisplay hDisplay = new HalconDisplay(); CreateShapeModelConfig modelConfig = new CreateShapeModelConfig(); FindShapeModelConfig findConfig = new FindShapeModelConfig(); public FrmEditModel() { InitializeComponent(); //canvas.Dock = DockStyle.Fill; //plImage.Controls.Clear(); //plImage.Controls.Add(canvas); hDisplay.Dock = DockStyle.Fill; plImage.Controls.Clear(); plImage.Controls.Add(hDisplay); pgCreateModel.SelectedObject = modelConfig; pgFindConfig.SelectedObject = findConfig; dgvImages.AutoGenerateColumns = false; } private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) { if (tabControl1.SelectedIndex == 1) { canvas.Elements.Clear(); } } private void btnLoadImage_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Multiselect = false; ofd.Filter = "图片文件|*.bmp;*.png;*.jpg;*.jpeg;*.tif|所有文件|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { //Bitmap map = (Bitmap)Bitmap.FromFile(ofd.FileName); //canvas.LoadImage(map); LoadImage(ofd.FileName); } } private void LoadImage(string imgFileName) { hDisplay.ClearDisplay(); hDisplay.Image?.Dispose(); HImage hImage = new HImage(); hImage.ReadImage(imgFileName); hDisplay.Image = hImage; hDisplay.Refresh(); } private void btnCreateModel_Click(object sender, EventArgs e) { if (hDisplay.Image == null) { MessageBox.Show("请先载入产品图片"); return; } if (hDisplay.ROIController.ROIList.Count != 1) { MessageBox.Show("请仅设置一个矩阵ROI"); return; } HOperatorSet.ClearAllShapeModels(); modelId = null; HObject rectObj = null; HOperatorSet.HomMat2dIdentity(out HTuple identityMatrix); HTuple transformMatrix = null; if (hDisplay.ROIController.ROIList[0] is ROIRectangle1 rect1) { HOperatorSet.GenRectangle1(out rectObj, rect1.Row1, rect1.Col1, rect1.Row2, rect1.Col2); HOperatorSet.HomMat2dTranslate(identityMatrix, (rect1.Row1 + rect1.Row2) / 2.0, (rect1.Col1 + rect1.Col2) / 2.0, out transformMatrix); } else if (hDisplay.ROIController.ROIList[0] is ROIRectangle2 rect2) { HOperatorSet.GenRectangle2(out rectObj, rect2.MidR, rect2.MidC, rect2.Phi, rect2.Length1, rect2.Length2); HOperatorSet.HomMat2dTranslate(identityMatrix, rect2.MidR, rect2.MidC, out transformMatrix); } else { MessageBox.Show("请仅设置一个矩阵ROI"); return; } HOperatorSet.ReduceDomain(hDisplay.Image, rectObj, out HObject imageReduced); HTuple config = modelConfig.GetHTuple(); HOperatorSet.CreateShapeModel(imageReduced, config[0], config[1], config[2], config[3], config[4], config[5], config[6], config[7], out modelId); HOperatorSet.GetShapeModelContours(out HObject modelContours, modelId, 1); HOperatorSet.AffineTransContourXld(modelContours, out HObject countoursAffinTrans, transformMatrix); hDisplay.ClearGraphicStack(); hDisplay.AddObjectToGraphicStack(hDisplay.Image); hDisplay.AddObjectToGraphicStack(countoursAffinTrans); hDisplay.Refresh(); MessageBox.Show("模板创建成功"); } private void btnSaveModel_Click(object sender, EventArgs e) { if (modelId == null) { MessageBox.Show("模板句柄为空,无法保存"); return; } SaveFileDialog sfd = new SaveFileDialog(); sfd.SupportMultiDottedExtensions = false; sfd.Filter = "模板文件|*.shm"; sfd.DefaultExt = "shm"; if (sfd.ShowDialog() == DialogResult.OK) { HOperatorSet.WriteShapeModel(modelId, sfd.FileName); MessageBox.Show("模板保存完成"); } } private void btnLoadModel_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "模板文件|*.shm"; ofd.Multiselect = false; if (ofd.ShowDialog() == DialogResult.OK) { lblModel.Text = ""; HOperatorSet.ReadShapeModel(ofd.FileName, out modelId); lblModel.Text = ofd.FileName; } } private void btnLoadImageFolder_Click(object sender, EventArgs e) { FolderBrowserDialog fbd = new FolderBrowserDialog(); fbd.ShowNewFolderButton = false; if (fbd.ShowDialog() == DialogResult.OK) { lblImageFolder.Text = fbd.SelectedPath; DirectoryInfo dir = new DirectoryInfo(fbd.SelectedPath); List suffixList = new List() { "bmp", "png", "jpg", "jpeg", "tif" }; var imgFileNames = dir.GetFiles().ToList().Where(u => suffixList.Any(s => u.Name.ToLower().EndsWith(s))) .Select(u => { TestCase tc = new TestCase(); tc.Name = u.Name; tc.FullName = u.FullName; tc.ModelMatchNum = 0; return tc; }).ToList(); dgvImages.DataSource = imgFileNames; } } private void dgvImages_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { if (dgvImages.Rows[e.RowIndex].DataBoundItem is TestCase tc) { LoadImage(tc.FullName); } } private void btnTestCurrent_Click(object sender, EventArgs e) { if (!CheckBeforeTest()) { return; } RunSelected(); } private bool RunSelected(int step = 0) { int selectedIndex = dgvImages.SelectedRows[0].Index; if (step != 0) { int afterIndex = selectedIndex + step; if (afterIndex < 0) { //MessageBox.Show("当前已经是第一项"); return false; } if (afterIndex >= dgvImages.Rows.Count) { //MessageBox.Show("当前已经是最后一项"); return false; } dgvImages.Rows[selectedIndex].Selected = false; dgvImages.Rows[afterIndex].Selected = true; dgvImages.FirstDisplayedScrollingRowIndex = afterIndex; } TestCase tc = dgvImages.SelectedRows[0].DataBoundItem as TestCase; LoadImage(tc.FullName); HTuple findConfigTuple = findConfig.GetHTuple(); HOperatorSet.FindShapeModel(hDisplay.Image, modelId, findConfigTuple[0], findConfigTuple[1], findConfigTuple[2], findConfigTuple[3], findConfigTuple[4], findConfigTuple[5], findConfigTuple[6], findConfigTuple[7], out HTuple rows, out HTuple cols, out HTuple angles, out HTuple scores); tc.ModelMatchNum = scores.Length; HOperatorSet.GetShapeModelContours(out HObject modelContours, modelId, 1); HOperatorSet.CountObj(modelContours, out HTuple objCount); HOperatorSet.HomMat2dIdentity(out HTuple identityMatrix); for (int i = 0; i < tc.ModelMatchNum; i++) { HOperatorSet.CopyObj(modelContours, out HObject model, 1, objCount); HOperatorSet.HomMat2dRotate(identityMatrix, angles[i], 0, 0, out HTuple transformMatrix); HOperatorSet.HomMat2dTranslate(transformMatrix, rows[i], cols[i], out transformMatrix); HOperatorSet.AffineTransContourXld(model, out HObject affinedContour, transformMatrix); hDisplay.AddObjectToGraphicStack(affinedContour); } hDisplay.Refresh(); dgvImages.Invalidate(); return true; } private bool CheckBeforeTest() { if (modelId == null) { MessageBox.Show("当前未编辑或者载入模板,请创建模板或者选择模板文件载入"); return false; } if (dgvImages.SelectedRows.Count == 0) { MessageBox.Show("当前图片列表未选择测试项,请选择需要测试的图片"); return false; } return true; } private void btnTestNext_Click(object sender, EventArgs e) { if (!CheckBeforeTest()) { return; } if (!RunSelected(1)) { MessageBox.Show("当前已经是最后一项"); } } private void btnTestAll_Click(object sender, EventArgs e) { if (dgvImages.Rows.Count <= 0) { MessageBox.Show("当前无待检测图片"); return; } dgvImages.FirstDisplayedScrollingRowIndex = 0; dgvImages.Rows[0].Selected = true; bool flag = RunSelected(0); while (flag) { flag = RunSelected(1); } MessageBox.Show("检测完成"); } } public class TestCase { public string Name { get; set; } public string FullName { get; set; } public int ModelMatchNum { get; set; } = 0; } #region Halcon Model public abstract class StrictedListConvert : StringConverter { public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { return true; } public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) { return true; } public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { List portNames = GetSupportedValueList(); return new StandardValuesCollection(portNames); } protected abstract List GetSupportedValueList(); } public abstract class ModelConfig { public abstract HTuple GetHTuple(); protected void IntCheck(ref ArrayList list, string desc) { if (int.TryParse(desc, out int convertValue)) { list.Add(convertValue); } else { list.Add(desc); } } protected void DoubleCheck(ref ArrayList list, string desc) { if (double.TryParse(desc, out double convertValue)) { list.Add(convertValue); } else { list.Add(desc); } } } #region Create Model public class NumLevelsConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "auto", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; } } public class AngleStartConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "-3.14", "-1.57", "-0.79", "-0.39", "-0.20", "0.0" }; } } public class AngleExtentConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "6.29", "3.14", "1.57", "0.79", "0.39" }; } } public class AngleStepConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "auto", "0.0175", "0.0349", "0.0524", "0.0698", "0.0873" }; } } public enum Optimization { auto, no_pregeneration, none, point_reduction_high, point_reduction_low, point_reduction_medium, pregeneration, } public enum Metric { use_polarity, ignore_color_polarity, ignore_global_polarity, ignore_local_polarity, } public class ContrastConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "auto", "auto_contrast", "auto_contrast_hyst", "auto_min_size", "10", "20", "30", "40", "60", "80", "100", "120", "140", "160" }; } } public class MinContrastConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "auto", "1", "2", "3", "5", "7", "10", "20", "30", "40" }; } } public class CreateShapeModelConfig : ModelConfig { [Category("建立模板配置")] [DisplayName("层次数量")] [TypeConverter(typeof(NumLevelsConvert))] public string NumLevles { get; set; } = "auto"; [Category("建立模板配置")] [DisplayName("起始角度")] [TypeConverter(typeof(AngleStartConvert))] public string AngleStart { get; set; } = "-0.39"; [Category("建立模板配置")] [DisplayName("角度范围")] [TypeConverter(typeof(AngleExtentConvert))] public string AngleExtent { get; set; } = "0.79"; [Category("建立模板配置")] [DisplayName("角度步长")] [TypeConverter(typeof(AngleStepConvert))] public string AngleStep { get; set; } = "auto"; [Category("建立模板配置")] [DisplayName("最优化选择")] public Optimization Optimization { get; set; } = Optimization.auto; [Category("建立模板配置")] [DisplayName("极性")] public Metric Metric { get; set; } = Metric.use_polarity; [Category("建立模板配置")] [DisplayName("对比度")] [TypeConverter(typeof(ContrastConvert))] public string Contrast { get; set; } = "auto"; [Category("建立模板配置")] [DisplayName("最小对比度")] [TypeConverter(typeof(MinContrastConvert))] public string MinContrast { get; set; } = "auto"; public override HTuple GetHTuple() { ArrayList list = new ArrayList(); IntCheck(ref list, NumLevles); DoubleCheck(ref list, AngleStart); DoubleCheck(ref list, AngleExtent); DoubleCheck(ref list, AngleStep); list.Add(Optimization.ToString()); list.Add(Metric.ToString()); IntCheck(ref list, Contrast); IntCheck(ref list, MinContrast); HTuple hTuple = new HTuple(list.ToArray()); return hTuple; } } #endregion #region Find Model public class AngleStartConvert_Find : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "-3.14", "-1.57", "-0.78", "-0.39", "-0.20", "0.0" }; } } public class AngleExtentConvert_Find : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "6.29", "3.14", "1.57", "0.78", "0.39", "0.0" }; } } public class MinScoreConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0" }; } } public class NumMatchesConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "0", "1", "2", "3", "4", "5", "10", "20" }; } } public class MaxOverlapConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "0.0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0" }; } } public enum SubPixel { interpolation, least_squares, least_squares_high, least_squares_very_high, [Description("max_deformation 1")] max_deformation_1, [Description("max_deformation 2")] max_deformation_2, [Description("max_deformation 3")] max_deformation_3, [Description("max_deformation 4")] max_deformation_4, [Description("max_deformation 5")] max_deformation_5, [Description("max_deformation 6")] max_deformation_6, none, } public class NumLevelsConvert_Find : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; } } public class GreedinessConvert : StrictedListConvert { protected override List GetSupportedValueList() { return new List() { "0.0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0" }; } } public class FindShapeModelConfig : ModelConfig { [Category("定位模板配置")] [DisplayName("起始角度")] [TypeConverter(typeof(AngleStartConvert_Find))] public string AngleStart { get; set; } = "-0.39"; [Category("定位模板配置")] [DisplayName("角度范围")] [TypeConverter(typeof(AngleExtentConvert_Find))] public string AngleExtent { get; set; } = "0.78"; [Category("定位模板配置")] [DisplayName("最小得分")] [TypeConverter(typeof(MinScoreConvert))] public string MinScore { get; set; } = "0.7"; [Category("定位模板配置")] [DisplayName("匹配数量")] [TypeConverter(typeof(NumMatchesConvert))] public string NumMatches { get; set; } = "0"; [Category("定位模板配置")] [DisplayName("最大重叠设置")] [TypeConverter(typeof(MaxOverlapConvert))] public string MaxOverlap { get; set; } = "0.5"; [Category("定位模板配置")] [DisplayName("亚像素设置")] public SubPixel SubPixel { get; set; } = SubPixel.least_squares; [Category("定位模板配置")] [DisplayName("层次数量")] [TypeConverter(typeof(NumLevelsConvert_Find))] public string NumLevles { get; set; } = "0"; [Category("定位模板配置")] [DisplayName("Greediness")] [TypeConverter(typeof(GreedinessConvert))] public string Greediness { get; set; } = "0.9"; public override HTuple GetHTuple() { ArrayList list = new ArrayList(); DoubleCheck(ref list, AngleStart); DoubleCheck(ref list, AngleExtent); DoubleCheck(ref list, MinScore); IntCheck(ref list, NumMatches); DoubleCheck(ref list, MaxOverlap); list.Add(SubPixel.GetEnumDescription()); IntCheck(ref list, NumLevles); DoubleCheck(ref list, Greediness); HTuple hTuple = new HTuple(list.ToArray()); return hTuple; } } #endregion #endregion }