diff --git a/DH.Commons/DH.Commons.csproj b/DH.Commons/DH.Commons.csproj index 1c2b199..9d1c41f 100644 --- a/DH.Commons/DH.Commons.csproj +++ b/DH.Commons/DH.Commons.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - AnyCPU;X64 + AnyCPU;x64 diff --git a/DH.Devices.Camera/DH.Devices.Camera.csproj b/DH.Devices.Camera/DH.Devices.Camera.csproj index af2ea5b..ea384fe 100644 --- a/DH.Devices.Camera/DH.Devices.Camera.csproj +++ b/DH.Devices.Camera/DH.Devices.Camera.csproj @@ -19,7 +19,7 @@ - ..\X64\Debug\DVPCameraCS64.dll + ..\x64\Debug\DVPCameraCS64.dll diff --git a/DH.Devices.PLC/DH.Devices.PLC.csproj b/DH.Devices.PLC/DH.Devices.PLC.csproj index 15e4ceb..74bc23a 100644 --- a/DH.Devices.PLC/DH.Devices.PLC.csproj +++ b/DH.Devices.PLC/DH.Devices.PLC.csproj @@ -22,7 +22,7 @@ - ..\X64\Debug\HslCommunication.dll + ..\x64\Debug\HslCommunication.dll diff --git a/DH.Devices.Vision/DH.Devices.Vision.csproj b/DH.Devices.Vision/DH.Devices.Vision.csproj index 6473332..9ff2894 100644 --- a/DH.Devices.Vision/DH.Devices.Vision.csproj +++ b/DH.Devices.Vision/DH.Devices.Vision.csproj @@ -11,6 +11,9 @@ AnyCPU;x64 + + + diff --git a/DH.Devices.Vision/DetectionConfig.cs b/DH.Devices.Vision/DetectionConfig.cs new file mode 100644 index 0000000..9cea844 --- /dev/null +++ b/DH.Devices.Vision/DetectionConfig.cs @@ -0,0 +1,666 @@ +using OpenCvSharp; +using System.ComponentModel; +using System.Drawing; +using static OpenCvSharp.AgastFeatureDetector; +using System.Text.RegularExpressions; +using System.Text; +using System.Drawing.Design; + +namespace DH.Devices.Vision +{ + public enum MLModelType + { + [Description("图像分类")] + ImageClassification = 1, + [Description("目标检测")] + ObjectDetection = 2, + //[Description("图像分割")] + //ImageSegmentation = 3 + [Description("语义分割")] + SemanticSegmentation = 3, + [Description("实例分割")] + InstanceSegmentation = 4, + [Description("目标检测GPU")] + ObjectGPUDetection = 5 + } + public class ModelLabel + { + public string LabelId { get; set; } + + + [Category("模型标签")] + [DisplayName("模型标签索引")] + [Description("模型识别的标签索引")] + public int LabelIndex { get; set; } + + + [Category("模型标签")] + [DisplayName("模型标签")] + [Description("模型识别的标签名称")] + public string LabelName { get; set; } + + + + + //[Category("模型配置")] + //[DisplayName("模型参数配置")] + //[Description("模型参数配置集合")] + + //public ModelParamSetting ModelParamSetting { get; set; } = new ModelParamSetting(); + + + public string GetDisplayText() + { + return $"{LabelId}-{LabelName}"; + } + } + public class MLRequest + { + public int ImageChannels = 3; + public Mat mImage; + public int ResizeWidth; + public int ResizeHeight; + + public float confThreshold; + + public float iouThreshold; + + //public int ImageResizeCount; + public bool IsCLDetection; + public int ProCount; + public string in_node_name; + + public string out_node_name; + + public string in_lable_path; + + public int ResizeImageSize; + public int segmentWidth; + public int ImageWidth; + + // public List OkClassTxtList; + + + public List LabelNames; + + + + } + public enum ResultState + { + + [Description("检测NG")] + DetectNG = -3, + + //[Description("检测不足TBD")] + // ShortageTBD = -2, + [Description("检测结果TBD")] + ResultTBD = -1, + [Description("OK")] + OK = 1, + // [Description("NG")] + // NG = 2, + //统计结果 + [Description("A类NG")] + A_NG = 25, + [Description("B类NG")] + B_NG = 26, + [Description("C类NG")] + C_NG = 27, + } + /// + /// 深度学习 识别结果明细 面向业务:detect 面向深度学习:Recongnition、Inference + /// + public class DetectionResultDetail + { + public string LabelBGR { get; set; }//识别到对象的标签BGR + + + public int LabelNo { get; set; } // 识别到对象的标签索引 + + public string LabelName { get; set; }//识别到对象的标签名称 + + public double Score { get; set; }//识别目标结果的可能性、得分 + + public string LabelDisplay { get; set; }//识别到对象的 显示信息 + + public double Area { get; set; }//识别目标的区域面积 + + public Rectangle Rect { get; set; }//识别目标的外接矩形 + + public RotatedRect MinRect { get; set; }//识别目标的最小外接矩形(带角度) + + public ResultState InferenceResult { get; set; }//只是模型推理 label的结果 + + public double DistanceToImageCenter { get; set; } //计算矩形框到图像中心的距离 + + + + public ResultState FinalResult { get; set; }//模型推理+其他视觉、逻辑判断后 label结果 + } + public class MLResult + { + public bool IsSuccess = false; + public string ResultMessage; + public Bitmap ResultMap; + public List ResultDetails = new List(); + } + public class MLInit + { + public string ModelFile; + public string InferenceDevice; + + + public int InferenceWidth; + public int InferenceHeight; + + public string InputNodeName; + + + public int SizeModel; + + public bool bReverse;//尺寸测量正反面 + //目标检测Gpu + public bool IsGPU; + public int GPUId; + public float Score_thre; + public MLInit(string modelFile, bool isGPU, int gpuId, float score_thre) + { + ModelFile = modelFile; + IsGPU = isGPU; + GPUId = gpuId; + Score_thre = score_thre; + } + + public MLInit(string modelFile, string inputNodeName, string inferenceDevice, int inferenceWidth, int inferenceHeight) + { + ModelFile = modelFile; + InferenceDevice = inferenceDevice; + + InferenceWidth = inferenceWidth; + InferenceHeight = inferenceHeight; + InputNodeName = inputNodeName; + + + } + } + public class DetectStationResult + { + public string Pid { get; set; } + + public string TempPid { get; set; } + + /// + /// 检测工位名称 + /// + public string DetectName { get; set; } + + + /// + /// 深度学习 检测结果 + /// + public List DetectDetails = new List(); + + + /// + /// 工位检测结果 + /// + public ResultState ResultState { get; set; } = ResultState.ResultTBD; + + + public double FinalResultfScore { get; set; } = 0.0; + + + public string ResultLabel { get; set; } = "";// 多个ng时,根据label优先级,设定当前检测项的label + + public string ResultLabelCategoryId { get; set; } = "";// 多个ng时,根据label优先级,设定当前检测项的label + + public int PreTreatState { get; set; } + public bool IsPreTreatDone { get; set; } = true; + + public bool IsAfterTreatDone { get; set; } = true; + + public bool IsMLDetectDone { get; set; } = true; + + /// + /// 预处理阶段已经NG + /// + public bool IsPreTreatNG { get; set; } = false; + + /// + /// 目标检测NG + /// + public bool IsObjectDetectNG { get; set; } = false; + + public DateTime EndTime { get; set; } + + public int StationDetectElapsed { get; set; } + public static string NormalizeAndClean(string input) + { + if (input == null) return null; + + // Step 1: 标准化字符编码为 Form C (规范组合) + string normalizedString = input.Normalize(NormalizationForm.FormC); + + // Step 2: 移除所有空白字符,包括制表符和换行符 + string withoutWhitespace = Regex.Replace(normalizedString, @"\s+", ""); + + // Step 3: 移除控制字符 (Unicode 控制字符,范围 \u0000 - \u001F 和 \u007F) + string withoutControlChars = Regex.Replace(withoutWhitespace, @"[\u0000-\u001F\u007F]+", ""); + + // Step 4: 移除特殊的不可见字符(如零宽度空格等) + string cleanedString = Regex.Replace(withoutControlChars, @"[\u200B\u200C\u200D\uFEFF]+", ""); + + return cleanedString; + } + + } + public class RelatedCamera + { + + [Category("关联相机")] + [DisplayName("关联相机")] + [Description("关联相机描述")] + + //[TypeConverter(typeof(CollectionCountConvert))] + public string CameraSourceId { get; set; } = ""; + + public RelatedCamera() + { + + } + public RelatedCamera(string cameraSourceId) + { + CameraSourceId = cameraSourceId; + + } + } + public class DetectionConfig + { + [ReadOnly(true)] + public string Id { get; set; } = Guid.NewGuid().ToString(); + + + [Category("检测配置")] + [DisplayName("检测配置名称")] + [Description("检测配置名称")] + public string Name { get; set; } + + [Category("关联相机")] + [DisplayName("关联相机")] + [Description("关联相机描述")] + + + public string CameraSourceId { get; set; } = ""; + + + [Category("关联相机集合")] + [DisplayName("关联相机集合")] + [Description("关联相机描述")] + //[TypeConverter(typeof(DeviceIdSelectorConverter))] + + public List CameraCollects { get; set; } = new List(); + + + [Category("启用配置")] + [DisplayName("是否启用GPU检测")] + [Description("是否启用GPU检测")] + public bool IsEnableGPU { get; set; } = false; + + [Category("启用配置")] + [DisplayName("是否混料模型")] + [Description("是否混料模型")] + public bool IsMixModel { get; set; } = false; + + + + [Category("启用配置")] + [DisplayName("是否启用该检测")] + [Description("是否启用该检测")] + public bool IsEnabled { get; set; } + + [Category("启用配置")] + [DisplayName("是否加入检测工位")] + [Description("是否加入检测工位")] + public bool IsAddStation { get; set; } = true; + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型类型")] + [Description("模型类型:ImageClassification-图片分类;ObjectDetection:目标检测;Segmentation-图像分割")] + //[TypeConverter(typeof(EnumDescriptionConverter))] + public MLModelType ModelType { get; set; } = MLModelType.ObjectDetection; + + //[Category("2.中检测(深度学习)")] + //[DisplayName("中检测-GPU索引")] + //[Description("GPU索引")] + //public int GPUIndex { get; set; } = 0; + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型文件路径")] + [Description("中处理 深度学习模型文件路径,路径中不可含有中文字符,一般情况可以只配置中检测模型,当需要先用预检测过滤一次时,请先配置好与预检测相关配置")] + + public string ModelPath { get; set; } + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型宽度")] + [Description("中处理-模型宽度")] + + public int ModelWidth { get; set; } = 640; + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型高度")] + [Description("中处理-模型高度")] + + public int ModelHeight { get; set; } = 640; + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型节点名称")] + [Description("中处理-模型节点名称")] + + public string ModeloutNodeName { get; set; } = "output0"; + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型置信度")] + [Description("中处理-模型置信度")] + + public float ModelconfThreshold { get; set; } = 0.5f; + + [Category("2.中检测(深度学习)")] + [DisplayName("中检测-模型标签路径")] + [Description("中处理-模型标签路径")] + + public string in_lable_path { get; set; } + + [Category("4.最终过滤(逻辑过滤)")] + [DisplayName("过滤器集合")] + [Description("最后的逻辑过滤:可根据 识别出对象的 宽度、高度、面积、得分来设置最终检测结果,同一识别目标同一判定,多项过滤器之间为“或”关系")] + + public List DetectionFilterList { get; set; } = new List(); + + //[Category("深度学习配置")] + //[DisplayName("检测配置标签")] + //[Description("检测配置标签关联")] + + //public List DetectConfigLabelList { get; set; } = new List(); + + + public DetectionConfig() + { + + } + + public DetectionConfig(string name, MLModelType modelType, string modelPath, bool isEnableGPU,string sCameraSourceId) + { + ModelPath = modelPath ?? string.Empty; + Name = name; + ModelType = modelType; + IsEnableGPU = isEnableGPU; + Id = Guid.NewGuid().ToString(); + CameraSourceId = sCameraSourceId; + + } + } + /// + /// 识别目标定义 class:分类信息 Detection Segmentation:要识别的对象 + /// + public class RecongnitionLabel //: IComplexDisplay + { + [Category("检测标签定义")] + [Description("检测标签编码")] + [ReadOnly(true)] + public string Id { get; set; } = Guid.NewGuid().ToString(); + + [Category("检测标签定义")] + [DisplayName("检测标签名称")] + [Description("检测标签名称")] + public string LabelName { get; set; } = ""; + + [Category("检测标签定义")] + [DisplayName("检测标签描述")] + [Description("检测标签描述,中文描述")] + public string LabelDescription { get; set; } = ""; + + [Category("检测标签定义")] + [DisplayName("检测标签分类")] + [Description("检测标签分类id")] + //[TypeConverter(typeof(LabelCategoryConverter))] + public string LabelCategory { get; set; } = ""; + + + + + } + + /// + /// 检测项识别对象 + /// + public class DetectConfigLabel //: IComplexDisplay + { + [Category("检测项标签")] + [DisplayName("检测项标签")] + [Description("检测标签Id")] + //[TypeConverter(typeof(DetectionLabelConverter))] + public string LabelId { get; set; } + + [Browsable(false)] + //public string LabelName { get => GetLabelName(); } + + [Category("检测项标签")] + [DisplayName("检测标签优先级")] + [Description("检测标签优先级,值越小,优先级越高")] + public int LabelPriority { get; set; } = 0; + + //[Category("检测项标签")] + //[DisplayName("标签BGR值")] + //[Description("检测标签BGR值,例如:0,128,0")] + //public string LabelBGR { get; set; } + + //[Category("模型配置")] + //[DisplayName("模型参数配置")] + //[Description("模型参数配置集合")] + //[TypeConverter(typeof(ComplexObjectConvert))] + //[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))] + //public ModelParamSetting ModelParamSetting { get; set; } = new ModelParamSetting(); + + //public string GetDisplayText() + //{ + // string dName = ""; + // if (!string.IsNullOrWhiteSpace(LabelId)) + // { + // using (var scope = GlobalVar.Container.BeginLifetimeScope()) + // { + // IProcessConfig config = scope.Resolve(); + + // var mlBase = config.DeviceConfigs.FirstOrDefault(c => c is VisionEngineInitialConfigBase) as VisionEngineInitialConfigBase; + // if (mlBase != null) + // { + // var targetLabel = mlBase.RecongnitionLabelList.FirstOrDefault(u => u.Id == LabelId); + // if (targetLabel != null) + // { + // dName = targetLabel.GetDisplayText(); + // } + // } + // } + // } + // return dName; + //} + //public string GetLabelName() + //{ + // var name = ""; + + + // var mlBase = iConfig.DeviceConfigs.FirstOrDefault(c => c is VisionEngineInitialConfigBase) as VisionEngineInitialConfigBase; + // if (mlBase != null) + // { + // var label = mlBase.RecongnitionLabelList.FirstOrDefault(u => u.Id == LabelId); + // if (label != null) + // { + // name = label.LabelName; + // } + // } + + + // return name; + //} + } + + /// + /// 识别对象定义分类信息 A类B类 + /// + public class RecongnitionLabelCategory //: IComplexDisplay + { + [Category("检测标签分类")] + [Description("检测标签分类")] + [ReadOnly(true)] + public string Id { get; set; } = Guid.NewGuid().ToString(); + + [Category("检测标签分类")] + [DisplayName("检测标签分类名称")] + [Description("检测标签分类名称")] + public string CategoryName { get; set; } = "A-NG"; + + [Category("检测标签分类")] + [DisplayName("检测标签分类优先级")] + [Description("检测标签分类优先级,值越小,优先级越高")] + public int CategoryPriority { get; set; } = 0; + + public string GetDisplayText() + { + return CategoryPriority + ":" + CategoryName; + } + } + + /// + /// 检测过滤 + /// + public class DetectionFilter ///: IComplexDisplay + { + [Category("过滤器基础信息")] + [DisplayName("检测标签")] + [Description("检测标签信息")] + //[TypeConverter(typeof(DetectionLabelConverter))] + public string LabelId { get; set; } + + // [Browsable(false)] + public string LabelName { get; set; } + + [Category("过滤器基础信息")] + [DisplayName("是否启用过滤器")] + [Description("是否启用过滤器")] + public bool IsEnabled { get; set; } + + [Category("过滤器判定信息")] + [DisplayName("判定结果")] + [Description("过滤器默认判定结果")] + public ResultState ResultState { get; set; } = ResultState.ResultTBD; + + [Category("过滤条件")] + [DisplayName("过滤条件集合")] + [Description("过滤条件集合,集合之间为“且”关系")] + //[TypeConverter(typeof(CollectionCountConvert))] + // [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] + public List FilterConditionsCollection { get; set; } = new List(); + + + + public bool FilterOperation(DetectionResultDetail recongnitionResult) + { + return FilterConditionsCollection.All(u => + { + return u.FilterConditionCollection.Any(c => + { + double compareValue = 0; + + switch (c.FilterPropperty) + { + case DetectionFilterProperty.Width: + compareValue = recongnitionResult.Rect.Width; + break; + case DetectionFilterProperty.Height: + compareValue = recongnitionResult.Rect.Height; + break; + case DetectionFilterProperty.Area: + compareValue = recongnitionResult.Area; + break; + case DetectionFilterProperty.Score: + compareValue = recongnitionResult.Score; + break; + //case RecongnitionTargetFilterProperty.Uncertainty: + // compareValue = 0; + // //defect.Uncertainty; + // break; + } + + return compareValue >= c.MinValue && compareValue <= c.MaxValue; + }); + }); + } + } + + public class FilterConditions //: IComplexDisplay + { + [Category("过滤条件")] + [DisplayName("过滤条件集合")] + [Description("过滤条件集合,集合之间为“或”关系")] + //[TypeConverter(typeof(CollectionCountConvert))] + //[Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] + public List FilterConditionCollection { get; set; } = new List(); + + //public string GetDisplayText() + //{ + // if (FilterConditionCollection.Count == 0) + // { + // return "空"; + // } + // else + // { + // var desc = string.Join(" OR ", FilterConditionCollection.Select(u => u.GetDisplayText())); + + // if (FilterConditionCollection.Count > 1) + // { + // desc = $"({desc})"; + // } + + // return desc; + // } + //} + } + + public class FilterCondition //: IComplexDisplay + { + [Category("识别目标属性")] + [DisplayName("过滤属性")] + [Description("识别目标过滤针对的属性")] + //[TypeConverter(typeof(EnumDescriptionConverter))] + public DetectionFilterProperty FilterPropperty { get; set; } = DetectionFilterProperty.Width; + + [Category("过滤值")] + [DisplayName("最小值")] + [Description("最小值")] + public double MinValue { get; set; } = 1; + + [Category("过滤值")] + [DisplayName("最大值")] + [Description("最大值")] + public double MaxValue { get; set; } = 99999999; + + //public string GetDisplayText() + //{ + // return $"{FilterPropperty.GetEnumDescription()}:{MinValue}-{MaxValue}"; + //} + } + + public enum DetectionFilterProperty + { + [Description("宽度")] + Width = 1, + [Description("高度")] + Height = 2, + [Description("面积")] + Area = 3, + [Description("得分")] + Score = 4, + //[Description("不确定性")] + //Uncertainty = 5, + } +} diff --git a/DH.Devices.Vision/SimboDetection.cs b/DH.Devices.Vision/SimboDetection.cs new file mode 100644 index 0000000..d579cf8 --- /dev/null +++ b/DH.Devices.Vision/SimboDetection.cs @@ -0,0 +1,244 @@ +#define USE_MULTI_THREAD + +using OpenCvSharp; +using OpenCvSharp.Extensions; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using System.Security.Cryptography.Xml; +using System.Runtime.InteropServices; +using Newtonsoft.Json; + + + +namespace DH.Devices.Vision +{ + + + /// + /// 目标检测 GPU + /// + public class SimboDetection : SimboVisionMLBase + { + + public override bool Load(MLInit mLInit) + { + bool res = false; + try + { + Model = MLGPUEngine.InitModel(mLInit.ModelFile, 1, mLInit.Score_thre, mLInit.GPUId, 3, 8); + + //Model = MLEngine.InitModel(mLInit.ModelFile, 1, 0.45f, 0, 3); + + res = true; + +#if USE_MULTI_THREAD + IsCreated = true; + if (IsCreated) + { + _runHandleBefore ??= new AutoResetEvent(false); + _runHandleAfter ??= new ManualResetEvent(false); + + _runTask ??= Task.Factory.StartNew(() => + { + while (IsCreated) + { + _runHandleBefore.WaitOne(); + + if (IsCreated) + { + _result = RunInferenceFixed(_req); + _runHandleAfter.Set(); + } + } + }, TaskCreationOptions.LongRunning); + } +#endif + } + catch (Exception ex) + { + throw ex; + } + return res; + } +#if USE_MULTI_THREAD + MLRequest _req = null; + MLResult _result = null; + public bool IsCreated { get; set; } = false; + Task _runTask = null; + AutoResetEvent _runHandleBefore = new AutoResetEvent(false); + ManualResetEvent _runHandleAfter = new ManualResetEvent(false); + object _runLock = new object(); +#endif + [HandleProcessCorruptedStateExceptions] + public override MLResult RunInference(MLRequest req) + { +#if USE_MULTI_THREAD + MLResult mlResult = null; + lock (_runLock) + { + _result = new MLResult(); + + _req = req; + + _runHandleAfter.Reset(); + _runHandleBefore.Set(); + _runHandleAfter.WaitOne(); + + mlResult = _result; + } + + return mlResult; +#else + return RunInferenceFixed(req); +#endif + } + private void ConvertJsonResult(string json, ref MLResult result) + { + // json = "{\"FastDetResult\":[{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654843,\"rect\":[175,99,110,594]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654589,\"rect\":[2608,19,104,661]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654285,\"rect\":[1275,19,104,662]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.620762,\"rect\":[1510,95,107,600]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.617812,\"rect\":[2844,93,106,602]}]}"; + // + Console.WriteLine("检测结果JSON:" + json); + HYoloResult detResult = JsonConvert.DeserializeObject(json); + if (detResult == null) + { + return; + } + + int iNum = detResult.HYolo.Count; + int IokNum = 0; + for (int ix = 0; ix < iNum; ix++) + { + var det = detResult.HYolo[ix]; + + var rect = det.rect; + DetectionResultDetail detectionResultDetail = new DetectionResultDetail(); + // detectionResultDetail.LabelNo = det.classId; + //todo: 标签名相对应 + detectionResultDetail.LabelDisplay = det.classname; + detectionResultDetail.Rect = new Rectangle(rect[0], rect[1], rect[2], rect[3]); + detectionResultDetail.Score = det.fScore; + detectionResultDetail.LabelName = det.classname; + detectionResultDetail.Area = rect[2] * rect[3]; + detectionResultDetail.InferenceResult = ResultState.DetectNG; + + result.ResultDetails.Add(detectionResultDetail); + + + } + + } + + [HandleProcessCorruptedStateExceptions] + public MLResult RunInferenceFixed(MLRequest req) + { + MLResult mlResult = new MLResult(); + Mat originMat = new Mat(); + Mat detectMat = new Mat(); + + try + { + if (req.mImage == null) + { + mlResult.IsSuccess = false; + mlResult.ResultMessage = "异常:mat为null,无法执行推理!"; + return mlResult; + } + + // resize + detectMat = req.mImage;//1ms + + + + int iWidth = detectMat.Cols; + int iHeight = detectMat.Rows; + + // 如果是单通道图像,转换为三通道 RGB 格式 + if (detectMat.Channels() == 1) + { + // 将灰度图像转换为RGB格式(三通道) + + Cv2.CvtColor(detectMat, originMat, ColorConversionCodes.GRAY2BGR); + + } + else if (detectMat.Channels() == 3) + { + // 如果已经是三通道(BGR),则直接转换为RGB + + Cv2.CvtColor(detectMat, originMat, ColorConversionCodes.BGR2RGB); + + } + + //输入数据转化为字节 + var inputByte = new byte[originMat.Total() * 3];//这里必须乘以通道数,不然数组越界,也可以用w*h*c,差不多 + Marshal.Copy(originMat.Data, inputByte, 0, inputByte.Length); + + byte[] labellist = new byte[40960]; //新建字节数组:label1_str label2_str + + byte[] outputByte = new byte[originMat.Total() * 3]; + + Stopwatch sw = new Stopwatch(); + sw.Start(); + + //mlResult.IsSuccess = true; + unsafe + { + //mlResult.IsSuccess = MLGPUEngine.Inference(Model, inputByte, iWidth, iHeight, 3, req.in_lable_path, ref outputByte[0], ref labellist[0]); + + mlResult.IsSuccess = MLGPUEngine.Inference2(Model, inputByte, iWidth, iHeight, 3, req.in_lable_path, ref labellist[0]); + } + + sw.Stop(); + + + if (mlResult.IsSuccess) + { + mlResult.ResultMessage = $"深度学习推理成功,耗时:{sw.ElapsedMilliseconds} ms"; + + //将字节数组转换为字符串 + mlResult.ResultMap = originMat.ToBitmap();//4ms + string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); + + if (strGet == null) + { + mlResult.ResultMessage = $"异常:深度学习执行推理失败!"; + return mlResult; + } + + ConvertJsonResult(strGet, ref mlResult); + + return mlResult; + } + else + { + mlResult.ResultMessage = $"异常:深度学习执行推理失败!"; + return mlResult; + } + } + catch (Exception ex) + { + mlResult.ResultMessage = $"深度学习执行推理异常"; + return mlResult; + } + finally + { + + originMat?.Dispose(); + originMat = null; + //maskMat?.Dispose(); + // maskMat = null; + detectMat?.Dispose(); + detectMat = null; + // maskWeighted?.Dispose(); + // maskWeighted = null; + // GC.Collect(); + } + } + + + } +} diff --git a/DH.Devices.Vision/SimboInstanceSegmentation.cs b/DH.Devices.Vision/SimboInstanceSegmentation.cs new file mode 100644 index 0000000..f0a751d --- /dev/null +++ b/DH.Devices.Vision/SimboInstanceSegmentation.cs @@ -0,0 +1,264 @@ +//#define USE_MULTI_THREAD + +using OpenCvSharp; +using OpenCvSharp.Extensions; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using Newtonsoft.Json; + + +namespace DH.Devices.Vision +{ + + /// + /// 实例分割 maskrcnn + /// + public class SimboInstanceSegmentation : SimboVisionMLBase + { + public override bool Load(MLInit mLInit) + { + bool res = false; + try + { + + + Model = MLEngine.InitModel(mLInit.ModelFile, + mLInit.InferenceDevice, + mLInit.InputNodeName, + 1, 3, + mLInit.InferenceWidth, + mLInit.InferenceHeight,5); + res = true; + +#if USE_MULTI_THREAD + + IsCreated = true; + if (IsCreated) + { + if (_runHandleBefore == null) + { + _runHandleBefore = new AutoResetEvent(false); + } + + if (_runHandleAfter == null) + { + _runHandleAfter = new ManualResetEvent(false); + } + + if (_runTask == null) + { + _runTask = Task.Factory.StartNew(() => + { + while (IsCreated) + { + _runHandleBefore.WaitOne(); + + if (IsCreated) + { + _result = RunInferenceFixed(_req); + _runHandleAfter.Set(); + } + } + }, TaskCreationOptions.LongRunning); + } + } +#endif + } + catch (Exception ex) + { + throw ex; + } + return res; + } + + + +#if USE_MULTI_THREAD + MLRequest _req = null; + MLResult _result = null; + + + public bool IsCreated { get; set; } = false; + Task _runTask = null; + AutoResetEvent _runHandleBefore = new AutoResetEvent(false); + ManualResetEvent _runHandleAfter = new ManualResetEvent(false); + object _runLock = new object(); +#endif + + [HandleProcessCorruptedStateExceptions] + public override MLResult RunInference(MLRequest req) + { +#if USE_MULTI_THREAD + MLResult mlResult = null; + lock (_runLock) + { + _result = new MLResult(); + + _req = req; + + _runHandleAfter.Reset(); + _runHandleBefore.Set(); + _runHandleAfter.WaitOne(); + + mlResult = _result; + } + + return mlResult; +#else + return RunInferenceFixed(req); +#endif + + + + + } + + + private void ConvertJsonResult(string json, ref MLResult result) + { + // json = "{\"FastDetResult\":[{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654843,\"rect\":[175,99,110,594]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654589,\"rect\":[2608,19,104,661]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654285,\"rect\":[1275,19,104,662]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.620762,\"rect\":[1510,95,107,600]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.617812,\"rect\":[2844,93,106,602]}]}"; + // + Console.WriteLine("检测结果JSON:" + json); + SegResult detResult = JsonConvert.DeserializeObject(json); + if (detResult == null) + { + return; + } + + int iNum = detResult.SegmentResult.Count; + int IokNum = 0; + for (int ix = 0; ix < iNum; ix++) + { + var det = detResult.SegmentResult[ix]; + + var rect = det.rect; + DetectionResultDetail detectionResultDetail = new DetectionResultDetail(); + detectionResultDetail.LabelNo = det.classId; + //todo: 标签名相对应 + detectionResultDetail.LabelDisplay = det.classname; + detectionResultDetail.Rect = new Rectangle(rect[0], rect[1], rect[2], rect[3]); + detectionResultDetail.Score = det.fScore; + detectionResultDetail.LabelName = det.classname; + detectionResultDetail.Area = det.area; + detectionResultDetail.InferenceResult = ResultState.DetectNG; + + result.ResultDetails.Add(detectionResultDetail); + + + } + + } + + + + + [HandleProcessCorruptedStateExceptions] + public MLResult RunInferenceFixed(MLRequest req) + { + MLResult mlResult = new MLResult(); + Mat originMat = new Mat(); + Mat detectMat = new Mat(); + + try + { + if (req.mImage == null) + { + mlResult.IsSuccess = false; + mlResult.ResultMessage = "异常:mat为null,无法执行推理!"; + return mlResult; + } + + // resize + detectMat = req.mImage;//1ms + + + + int iWidth = detectMat.Cols; + int iHeight = detectMat.Rows; + + // 如果是单通道图像,转换为三通道 RGB 格式 + if (detectMat.Channels() == 1) + { + // 将灰度图像转换为RGB格式(三通道) + + Cv2.CvtColor(detectMat, originMat, ColorConversionCodes.GRAY2BGR); + + } + else if (detectMat.Channels() == 3) + { + // 如果已经是三通道(BGR),则直接转换为RGB + + Cv2.CvtColor(detectMat, originMat, ColorConversionCodes.BGR2RGB); + + } + + //输入数据转化为字节 + var inputByte = new byte[originMat.Total() * 3];//这里必须乘以通道数,不然数组越界,也可以用w*h*c,差不多 + Marshal.Copy(originMat.Data, inputByte, 0, inputByte.Length); + + byte[] labellist = new byte[40960]; //新建字节数组:label1_str label2_str + + byte[] outputByte = new byte[originMat.Total() * 3]; + + Stopwatch sw = new Stopwatch(); + sw.Start(); + unsafe + { + + mlResult.IsSuccess = MLEngine.seg_ModelPredict(Model, inputByte, iWidth, iHeight, 3, + req.in_lable_path, req.confThreshold, req.iouThreshold, req.confThreshold, req.segmentWidth, ref outputByte[0], ref labellist[0]); + //mlResult.IsSuccess = true; + } + sw.Stop(); + + if (mlResult.IsSuccess) + { + mlResult.ResultMessage = $"深度学习推理成功,耗时:{sw.ElapsedMilliseconds} ms"; + + //将字节数组转换为字符串 + mlResult.ResultMap = originMat.ToBitmap();//4ms + string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); + + + Console.WriteLine("strGet:", strGet); + + + ConvertJsonResult(strGet, ref mlResult); + + + + //解析json字符串 + + return mlResult; + } + else + { + mlResult.ResultMessage = $"异常:深度学习执行推理失败!"; + return mlResult; + } + } + catch (Exception ex) + { + mlResult.ResultMessage = $"深度学习执行推理异常"; + return mlResult; + } + finally + { + + originMat?.Dispose(); + originMat = null; + + + // GC.Collect(); + } + } + + } +} diff --git a/DH.Devices.Vision/SimboObjectDetection.cs b/DH.Devices.Vision/SimboObjectDetection.cs index 21cf262..9ef5e57 100644 --- a/DH.Devices.Vision/SimboObjectDetection.cs +++ b/DH.Devices.Vision/SimboObjectDetection.cs @@ -17,23 +17,7 @@ using Newtonsoft.Json; namespace DH.Devices.Vision { - //public class SegResult - //{ - // public List SegmentResult; - // public class Result - // { - // public double fScore; - // public int classId; - // public string classname; - - // public double area; - // public List rect; - - - // } - - //} @@ -157,7 +141,6 @@ namespace DH.Devices.Vision } int iNum = detResult.SegmentResult.Count; - int IokNum = 0; for (int ix = 0; ix < iNum; ix++) { var det = detResult.SegmentResult[ix]; @@ -188,7 +171,7 @@ namespace DH.Devices.Vision { MLResult mlResult = new MLResult(); Mat originMat=new Mat() ; - Mat tempMat; + Mat detectMat; try { if (req.mImage == null) @@ -199,26 +182,26 @@ namespace DH.Devices.Vision } // resize - tempMat = req.mImage;//1ms + detectMat = req.mImage;//1ms - int iWidth = tempMat.Cols; - int iHeight = tempMat.Rows; + int iWidth = detectMat.Cols; + int iHeight = detectMat.Rows; // 如果是单通道图像,转换为三通道 RGB 格式 - if (tempMat.Channels() == 1) + if (detectMat.Channels() == 1) { // 将灰度图像转换为RGB格式(三通道) - Cv2.CvtColor( tempMat,originMat, ColorConversionCodes.GRAY2BGR); + Cv2.CvtColor( detectMat,originMat, ColorConversionCodes.GRAY2BGR); } - else if (tempMat.Channels() == 3) + else if (detectMat.Channels() == 3) { // 如果已经是三通道(BGR),则直接转换为RGB - Cv2.CvtColor( tempMat,originMat, ColorConversionCodes.BGR2RGB); + Cv2.CvtColor( detectMat,originMat, ColorConversionCodes.BGR2RGB); } @@ -250,9 +233,6 @@ namespace DH.Devices.Vision { mlResult.ResultMessage = $"深度学习推理成功,耗时:{sw.ElapsedMilliseconds} ms"; - //Mat maskWeighted = new Mat(iHeight, iWidth, MatType.CV_8UC3, outputByte); - - //mlResult.ResultMap = BitmapConverter.ToBitmap(maskWeighted);//4ms //将字节数组转换为字符串 mlResult.ResultMap = originMat.ToBitmap();//4ms string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); @@ -261,9 +241,6 @@ namespace DH.Devices.Vision ConvertJsonResult(strGet, ref mlResult); - //maskWeighted?.Dispose(); - //maskWeighted = null; - // 解析json字符串 return mlResult; } diff --git a/DH.Devices.Vision/SimboVisionDriver.cs b/DH.Devices.Vision/SimboVisionDriver.cs new file mode 100644 index 0000000..378cecf --- /dev/null +++ b/DH.Devices.Vision/SimboVisionDriver.cs @@ -0,0 +1,18 @@ +using OpenCvSharp; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace DH.Devices.Vision +{ + public class SimboVisionDriver + { + + + } +} diff --git a/DH.Devices.Vision/SimboVisionMLBase.cs b/DH.Devices.Vision/SimboVisionMLBase.cs index 1f76fe1..0164094 100644 --- a/DH.Devices.Vision/SimboVisionMLBase.cs +++ b/DH.Devices.Vision/SimboVisionMLBase.cs @@ -44,6 +44,31 @@ namespace DH.Devices.Vision // ColorLut = new Mat(1, 256, MatType.CV_8UC3, ColorMap); } } + public class HYoloResult + { + //{ + // "HYolo": [{ + // "fScore": "0.687012", + // "classId": 0, + // "classname": "quejiao", + // "rect": [421, 823, 6, 8] + // }] + //} + public List HYolo; + public class Result + { + + public double fScore; + public int classId; + public string classname; + + //public double area; + public List rect; + + + } + + } public class SegResult { public List SegmentResult; diff --git a/DH.Devices.Vision/VisionEngine.cs b/DH.Devices.Vision/VisionEngine.cs deleted file mode 100644 index 8556658..0000000 --- a/DH.Devices.Vision/VisionEngine.cs +++ /dev/null @@ -1,299 +0,0 @@ -using OpenCvSharp; -using System.ComponentModel; -using System.Drawing; -using static OpenCvSharp.AgastFeatureDetector; -using System.Text.RegularExpressions; -using System.Text; - -namespace DH.Devices.Vision -{ - public enum MLModelType - { - [Description("图像分类")] - ImageClassification = 1, - [Description("目标检测")] - ObjectDetection = 2, - //[Description("图像分割")] - //ImageSegmentation = 3 - [Description("语义分割")] - SemanticSegmentation = 3, - [Description("实例分割")] - InstanceSegmentation = 4, - [Description("目标检测GPU")] - ObjectGPUDetection = 5 - } - public class MLRequest - { - public int ImageChannels = 3; - public Mat mImage; - public int ResizeWidth; - public int ResizeHeight; - - public float confThreshold; - - public float iouThreshold; - - //public int ImageResizeCount; - public bool IsCLDetection; - public int ProCount; - public string in_node_name; - - public string out_node_name; - - public string in_lable_path; - - public int ResizeImageSize; - public int segmentWidth; - public int ImageWidth; - - // public List OkClassTxtList; - - - // public List LabelNames; - - public float Score; - - } - public enum ResultState - { - - [Description("检测NG")] - DetectNG = -3, - - //[Description("检测不足TBD")] - // ShortageTBD = -2, - [Description("检测结果TBD")] - ResultTBD = -1, - [Description("OK")] - OK = 1, - // [Description("NG")] - // NG = 2, - //统计结果 - [Description("A类NG")] - A_NG = 25, - [Description("B类NG")] - B_NG = 26, - [Description("C类NG")] - C_NG = 27, - } - /// - /// 深度学习 识别结果明细 面向业务:detect 面向深度学习:Recongnition、Inference - /// - public class DetectionResultDetail - { - public string LabelBGR { get; set; }//识别到对象的标签BGR - - - public int LabelNo { get; set; } // 识别到对象的标签索引 - - public string LabelName { get; set; }//识别到对象的标签名称 - - public double Score { get; set; }//识别目标结果的可能性、得分 - - public string LabelDisplay { get; set; }//识别到对象的 显示信息 - - public double Area { get; set; }//识别目标的区域面积 - - public Rectangle Rect { get; set; }//识别目标的外接矩形 - - public RotatedRect MinRect { get; set; }//识别目标的最小外接矩形(带角度) - - public ResultState InferenceResult { get; set; }//只是模型推理 label的结果 - - public double DistanceToImageCenter { get; set; } //计算矩形框到图像中心的距离 - - - - public ResultState FinalResult { get; set; }//模型推理+其他视觉、逻辑判断后 label结果 - } - public class MLResult - { - public bool IsSuccess = false; - public string ResultMessage; - public Bitmap ResultMap; - public List ResultDetails = new List(); - } - public class MLInit - { - public string ModelFile; - public string InferenceDevice; - - - public int InferenceWidth; - public int InferenceHeight; - - public string InputNodeName; - - - public int SizeModel; - - public bool bReverse;//尺寸测量正反面 - //目标检测Gpu - public bool IsGPU; - public int GPUId; - public float Score_thre; - public MLInit(string modelFile, bool isGPU, int gpuId, float score_thre) - { - ModelFile = modelFile; - IsGPU = isGPU; - GPUId = gpuId; - Score_thre = score_thre; - } - - public MLInit(string modelFile, string inputNodeName, string inferenceDevice, int inferenceWidth, int inferenceHeight) - { - ModelFile = modelFile; - InferenceDevice = inferenceDevice; - - InferenceWidth = inferenceWidth; - InferenceHeight = inferenceHeight; - InputNodeName = inputNodeName; - - - } - } - public class DetectStationResult - { - public string Pid { get; set; } - - public string TempPid { get; set; } - - /// - /// 检测工位名称 - /// - public string DetectName { get; set; } - - - /// - /// 深度学习 检测结果 - /// - public List DetectDetails = new List(); - - - /// - /// 工位检测结果 - /// - public ResultState ResultState { get; set; } = ResultState.ResultTBD; - - - public double FinalResultfScore { get; set; } = 0.0; - - - public string ResultLabel { get; set; } = "";// 多个ng时,根据label优先级,设定当前检测项的label - - public string ResultLabelCategoryId { get; set; } = "";// 多个ng时,根据label优先级,设定当前检测项的label - - public int PreTreatState { get; set; } - public bool IsPreTreatDone { get; set; } = true; - - public bool IsAfterTreatDone { get; set; } = true; - - public bool IsMLDetectDone { get; set; } = true; - - /// - /// 预处理阶段已经NG - /// - public bool IsPreTreatNG { get; set; } = false; - - /// - /// 目标检测NG - /// - public bool IsObjectDetectNG { get; set; } = false; - - public DateTime EndTime { get; set; } - - public int StationDetectElapsed { get; set; } - public static string NormalizeAndClean(string input) - { - if (input == null) return null; - - // Step 1: 标准化字符编码为 Form C (规范组合) - string normalizedString = input.Normalize(NormalizationForm.FormC); - - // Step 2: 移除所有空白字符,包括制表符和换行符 - string withoutWhitespace = Regex.Replace(normalizedString, @"\s+", ""); - - // Step 3: 移除控制字符 (Unicode 控制字符,范围 \u0000 - \u001F 和 \u007F) - string withoutControlChars = Regex.Replace(withoutWhitespace, @"[\u0000-\u001F\u007F]+", ""); - - // Step 4: 移除特殊的不可见字符(如零宽度空格等) - string cleanedString = Regex.Replace(withoutControlChars, @"[\u200B\u200C\u200D\uFEFF]+", ""); - - return cleanedString; - } - - } - public class RelatedCamera - { - - [Category("关联相机")] - [DisplayName("关联相机")] - [Description("关联相机描述")] - - //[TypeConverter(typeof(CollectionCountConvert))] - public string CameraSourceId { get; set; } = ""; - - - - } - public class VisionEngine - { - [ReadOnly(true)] - public string Id { get; set; } = Guid.NewGuid().ToString(); - - - [Category("检测配置")] - [DisplayName("检测配置名称")] - [Description("检测配置名称")] - public string Name { get; set; } - - [Category("关联相机")] - [DisplayName("关联相机")] - [Description("关联相机描述")] - - - public string CameraSourceId { get; set; } = ""; - - - [Category("关联相机集合")] - [DisplayName("关联相机集合")] - [Description("关联相机描述")] - //[TypeConverter(typeof(DeviceIdSelectorConverter))] - - public List CameraCollects { get; set; } = new List(); - - - [Category("启用配置")] - [DisplayName("是否启用GPU检测")] - [Description("是否启用GPU检测")] - public bool IsEnableGPU { get; set; } = false; - - [Category("2.中检测(深度学习)")] - [DisplayName("中检测-模型类型")] - [Description("模型类型:ImageClassification-图片分类;ObjectDetection:目标检测;Segmentation-图像分割")] - //[TypeConverter(typeof(EnumDescriptionConverter))] - public MLModelType ModelType { get; set; } = MLModelType.ObjectDetection; - - //[Category("2.中检测(深度学习)")] - //[DisplayName("中检测-GPU索引")] - //[Description("GPU索引")] - //public int GPUIndex { get; set; } = 0; - - [Category("2.中检测(深度学习)")] - [DisplayName("中检测-模型文件路径")] - [Description("中处理 深度学习模型文件路径,路径中不可含有中文字符,一般情况可以只配置中检测模型,当需要先用预检测过滤一次时,请先配置好与预检测相关配置")] - - public string ModelPath { get; set; } - - public VisionEngine(string name, MLModelType modelType, string modelPath, bool isEnableGPU,string sCameraSourceId) - { - ModelPath = modelPath ?? string.Empty; - Name = name; - ModelType = modelType; - IsEnableGPU = isEnableGPU; - Id = Guid.NewGuid().ToString(); - CameraSourceId = sCameraSourceId; - - } - } -} diff --git a/DHSoftware.sln b/DHSoftware.sln index b48051f..500edbf 100644 --- a/DHSoftware.sln +++ b/DHSoftware.sln @@ -17,60 +17,60 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Commons", "Commons", "{0AB4 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DH.Commons", "DH.Commons\DH.Commons.csproj", "{027373EC-C5CB-4161-8D43-AB6009371FDE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DH.Devices.Vision", "DH.Devices.Vision\DH.Devices.Vision.csproj", "{97B55FCF-54A3-449E-8437-735E65C35291}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DH.Devices.Vision", "DH.Devices.Vision\DH.Devices.Vision.csproj", "{97B55FCF-54A3-449E-8437-735E65C35291}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DH.Devices.Camera", "DH.Devices.Camera\DH.Devices.Camera.csproj", "{1378A932-1C25-40EF-BA31-A3463B23F4E5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DH.Devices.Camera", "DH.Devices.Camera\DH.Devices.Camera.csproj", "{1378A932-1C25-40EF-BA31-A3463B23F4E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DH.Devices.PLC", "DH.Devices.PLC\DH.Devices.PLC.csproj", "{458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DH.Devices.PLC", "DH.Devices.PLC\DH.Devices.PLC.csproj", "{458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|X64 = Debug|X64 + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU - Release|X64 = Release|X64 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Debug|X64.ActiveCfg = Debug|X64 - {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Debug|X64.Build.0 = Debug|X64 + {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Debug|x64.ActiveCfg = Debug|x64 + {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Debug|x64.Build.0 = Debug|x64 {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Release|Any CPU.Build.0 = Release|Any CPU - {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Release|X64.ActiveCfg = Release|X64 - {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Release|X64.Build.0 = Release|X64 + {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Release|x64.ActiveCfg = Release|x64 + {17CC10DC-9132-4A03-AADA-2D1070418C9B}.Release|x64.Build.0 = Release|x64 {027373EC-C5CB-4161-8D43-AB6009371FDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {027373EC-C5CB-4161-8D43-AB6009371FDE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {027373EC-C5CB-4161-8D43-AB6009371FDE}.Debug|X64.ActiveCfg = Debug|X64 - {027373EC-C5CB-4161-8D43-AB6009371FDE}.Debug|X64.Build.0 = Debug|X64 + {027373EC-C5CB-4161-8D43-AB6009371FDE}.Debug|x64.ActiveCfg = Debug|x64 + {027373EC-C5CB-4161-8D43-AB6009371FDE}.Debug|x64.Build.0 = Debug|x64 {027373EC-C5CB-4161-8D43-AB6009371FDE}.Release|Any CPU.ActiveCfg = Release|Any CPU {027373EC-C5CB-4161-8D43-AB6009371FDE}.Release|Any CPU.Build.0 = Release|Any CPU - {027373EC-C5CB-4161-8D43-AB6009371FDE}.Release|X64.ActiveCfg = Release|X64 - {027373EC-C5CB-4161-8D43-AB6009371FDE}.Release|X64.Build.0 = Release|X64 + {027373EC-C5CB-4161-8D43-AB6009371FDE}.Release|x64.ActiveCfg = Release|x64 + {027373EC-C5CB-4161-8D43-AB6009371FDE}.Release|x64.Build.0 = Release|x64 {97B55FCF-54A3-449E-8437-735E65C35291}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {97B55FCF-54A3-449E-8437-735E65C35291}.Debug|Any CPU.Build.0 = Debug|Any CPU - {97B55FCF-54A3-449E-8437-735E65C35291}.Debug|X64.ActiveCfg = Debug|X64 - {97B55FCF-54A3-449E-8437-735E65C35291}.Debug|X64.Build.0 = Debug|X64 + {97B55FCF-54A3-449E-8437-735E65C35291}.Debug|x64.ActiveCfg = Debug|x64 + {97B55FCF-54A3-449E-8437-735E65C35291}.Debug|x64.Build.0 = Debug|x64 {97B55FCF-54A3-449E-8437-735E65C35291}.Release|Any CPU.ActiveCfg = Release|Any CPU {97B55FCF-54A3-449E-8437-735E65C35291}.Release|Any CPU.Build.0 = Release|Any CPU - {97B55FCF-54A3-449E-8437-735E65C35291}.Release|X64.ActiveCfg = Release|X64 - {97B55FCF-54A3-449E-8437-735E65C35291}.Release|X64.Build.0 = Release|X64 + {97B55FCF-54A3-449E-8437-735E65C35291}.Release|x64.ActiveCfg = Release|x64 + {97B55FCF-54A3-449E-8437-735E65C35291}.Release|x64.Build.0 = Release|x64 {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Debug|X64.ActiveCfg = Debug|x64 - {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Debug|X64.Build.0 = Debug|x64 + {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Debug|x64.ActiveCfg = Debug|x64 + {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Debug|x64.Build.0 = Debug|x64 {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Release|Any CPU.Build.0 = Release|Any CPU - {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Release|X64.ActiveCfg = Release|x64 - {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Release|X64.Build.0 = Release|x64 + {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Release|x64.ActiveCfg = Release|x64 + {1378A932-1C25-40EF-BA31-A3463B23F4E5}.Release|x64.Build.0 = Release|x64 {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Debug|X64.ActiveCfg = Debug|x64 - {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Debug|X64.Build.0 = Debug|x64 + {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Debug|x64.ActiveCfg = Debug|x64 + {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Debug|x64.Build.0 = Debug|x64 {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Release|Any CPU.Build.0 = Release|Any CPU - {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Release|X64.ActiveCfg = Release|x64 - {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Release|X64.Build.0 = Release|x64 + {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Release|x64.ActiveCfg = Release|x64 + {458B2CF6-6F1B-4B8B-BB85-C6FD7F453A5D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DHSoftware/DHSoftware.csproj b/DHSoftware/DHSoftware.csproj index 2b98a95..dbb3345 100644 --- a/DHSoftware/DHSoftware.csproj +++ b/DHSoftware/DHSoftware.csproj @@ -25,7 +25,7 @@ - ..\X64\Debug\DVPCameraCS64.dll + ..\x64\Debug\DVPCameraCS64.dll diff --git a/DHSoftware/MainWindow.cs b/DHSoftware/MainWindow.cs index dd1a0db..1a26d3e 100644 --- a/DHSoftware/MainWindow.cs +++ b/DHSoftware/MainWindow.cs @@ -13,6 +13,7 @@ using System; using System.CodeDom; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; @@ -258,41 +259,111 @@ namespace DHSoftware public volatile int ProductNum_Total = 0; public volatile int ProductNum_OK = 0; private readonly object _cameraSummaryLock = new object(); + List detectionList = new List(); + public List RecongnitionLabelList { get; set; } = new List(); public DateTime sraerttime; private void HandleStartButton() { CurrentMachine = true; - List detectionList = new List(); - detectionList.Add(new VisionEngine("相机1", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam1")); - detectionList.Add(new VisionEngine("相机2", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam2")); - detectionList.Add(new VisionEngine("相机3", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam3")); - detectionList.Add(new VisionEngine("相机4", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam4")); + //[Category("深度学习检测配置")] + //[DisplayName("检测标签定义集合")] + //[Description("定义检测标签的集合,例如:Seg/Detection模式:断裂、油污、划伤...;Class模式:ok、ng、上面、下面、套环、正常...")] + //[TypeConverter(typeof(CollectionCountConvert))] + //[Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] + RecongnitionLabel recongnition=new RecongnitionLabel + { + LabelName="youwu", + LabelDescription="油污", + LabelCategory="A_NG" + }; + RecongnitionLabel recongnition2 = new RecongnitionLabel + { + LabelName = "youwu", + LabelDescription = "油污", + LabelCategory = "A_NG" + }; + RecongnitionLabel recongnition3 = new RecongnitionLabel + { + LabelName = "youwu", + LabelDescription = "油污", + LabelCategory = "A_NG" + }; + RecongnitionLabelList.Add(recongnition); + RecongnitionLabelList.Add(recongnition2); + RecongnitionLabelList.Add(recongnition3); + var det1 = new DetectionConfig("相机1", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam1"); + var det2 = new DetectionConfig("相机2", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam2"); + var det3 = new DetectionConfig("相机3", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam3"); + var det4 = new DetectionConfig("相机4", MLModelType.ObjectDetection, @"D:\DHSoftware\DHSoftware\Models\yolov3.cfg", false, "Cam4"); + List CameraCollects=new List(); + CameraCollects.Add(new RelatedCamera("Cam1")); + List CameraCollects2 = new List(); + CameraCollects2.Add(new RelatedCamera("Cam2")); + List CameraCollects3 = new List(); + CameraCollects3.Add(new RelatedCamera("Cam3")); + List CameraCollects4 = new List(); + CameraCollects4.Add(new RelatedCamera("Cam4")); + List CameraCollects5 = new List(); + CameraCollects5.Add(new RelatedCamera("Cam5")); + float Conf = 0.5f; + det1.CameraCollects = CameraCollects; + det1.ModelconfThreshold = Conf; + det1.ModelWidth = 640; + det1.ModelHeight = 640; + det1.in_lable_path = " D:\\PROJECTS\\MaodingTest1\\Vision\\cam1.txt"; + + + det2.CameraCollects = CameraCollects2; + det1.ModelconfThreshold = Conf; + det1.ModelWidth = 640; + det1.ModelHeight = 640; + det1.in_lable_path = " D:\\PROJECTS\\MaodingTest1\\Vision\\cam2.txt"; + + det3.CameraCollects = CameraCollects3; + det1.ModelconfThreshold = Conf; + det1.ModelWidth = 640; + det1.ModelHeight = 640; + det1.in_lable_path = " D:\\PROJECTS\\MaodingTest1\\Vision\\cam3.txt"; + + det4.CameraCollects = CameraCollects4; + det1.ModelconfThreshold = Conf; + det1.ModelWidth = 640; + det1.ModelHeight = 640; + det1.in_lable_path = " D:\\PROJECTS\\MaodingTest1\\Vision\\cam4.txt"; + + detectionList.Add(det1); + detectionList.Add(det2); + detectionList.Add(det3); + detectionList.Add(det4); + Cameras.Clear(); + Dectection.Clear(); _cameraRelatedDetectionDict = new(); + detectionList.ForEach(detection => { - // detection.CameraCollects.ForEach(cam => + detection.CameraCollects.ForEach(cam => { List Dets = new List { detection.Id }; - if (!_cameraRelatedDetectionDict.ContainsKey(detection.CameraSourceId)) + if (!_cameraRelatedDetectionDict.ContainsKey(cam.CameraSourceId)) { - _cameraRelatedDetectionDict.Add(detection.CameraSourceId, Dets); + _cameraRelatedDetectionDict.Add(cam.CameraSourceId, Dets); } else { - _cameraRelatedDetectionDict[detection.CameraSourceId].Add(detection.Id); + _cameraRelatedDetectionDict[cam.CameraSourceId].Add(detection.Id); } } - //); + ); }); //Add the code for the "启动" button click here @@ -310,10 +381,7 @@ namespace DHSoftware do3ThinkCamera2.CameraConnect(); do3ThinkCamera1.OnHImageOutput += OnCameraHImageOutput; do3ThinkCamera2.OnHImageOutput += OnCameraHImageOutput; - var simbo1 = new SimboObjectDetection - { - - }; + var simbo1 = new SimboObjectDetection(); MLInit mLInit; string inferenceDevice = "CPU"; @@ -321,12 +389,11 @@ namespace DHSoftware simbo1.Load(mLInit); - Dectection.Add(do3ThinkCamera1.CameraName, simbo1); + - var simbo2 = new SimboObjectDetection - { + Dectection.Add(det1.Id, simbo1); - }; + var simbo2 = new SimboObjectDetection(); MLInit mLInit2; string inferenceDevice2 = "CPU"; @@ -334,7 +401,11 @@ namespace DHSoftware simbo2.Load(mLInit2); - Dectection.Add(do3ThinkCamera2.CameraName, simbo2); + for(int i = 0;i { - this.BeginInvoke(new MethodInvoker(delegate () { richTextBox1.AppendText("入料成功" + PieceCount); })); - - }); + int index = PieceNumberToIndex(pieceNumber); // productDatas.Add(pData); //转盘2 的物料是不是重新覆盖之前的pDta @@ -387,6 +455,11 @@ namespace DHSoftware ProductData pData = new ProductData("", pieceNumber, ProductBaseCount); _productLists[index][pieceNumber] = pData; } + string logStr = $"时间:{DateTime.Now} 轴{axisIndex}新产品{pieceNumber}加入队列{index}----入料计数{PieceCount}\n"; + Task.Run(() => { + this.BeginInvoke(new MethodInvoker(delegate () { richTextBox1.AppendText(logStr); })); + + }); DateTime dtNow = DateTime.Now; UpdateCT(null, (float)(dtNow - _ctTime).TotalSeconds); _ctTime = dtNow; @@ -472,28 +545,173 @@ namespace DHSoftware for (int i = 0; i < detectionDict.Count; i++) { - string d = detectionDict[i]; + string detectionId = detectionDict[i]; try { + DetectionConfig detectConfig = null; + //找到对应的配置 + if (!string.IsNullOrWhiteSpace(detectionId)) + { + detectConfig = detectionList.FirstOrDefault(u => u.Id == detectionId); + } + else + { + detectConfig = detectionList.FirstOrDefault(u => u.CameraSourceId == camera.CameraName); + } - // LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 推理进度1.3,产品{productNumber}"); + if (detectConfig == null) + { + + //未能获得检测配置 + return ; + } + + + #region 1.预处理 + #endregion + #region 2.深度学习推理 var req = new MLRequest(); req.mImage = imageSet.Clone(); - req.ResizeWidth = 640; - req.ResizeHeight = 640; - req.confThreshold = 0.5f; + req.ResizeWidth = detectConfig.ModelWidth; + req.ResizeHeight = detectConfig.ModelHeight; + req.confThreshold = detectConfig.ModelconfThreshold; req.iouThreshold = 0.3f; - req.out_node_name = "output0"; - req.in_lable_path = "D:\\PROJECTS\\MaodingTest1\\Vision\\cam1.txt"; + req.out_node_name = detectConfig.ModeloutNodeName; + req.in_lable_path = detectConfig.in_lable_path; //req.LabelNames = dc.GetLabelNames(); - req.Score = 0.5f; + //HOperatorSet.WriteImage(req.HImage, "png", 0, @"D:\\666.png"); - var result = Dectection[camera.CameraName].RunInference(req); + Stopwatch + sw = new Stopwatch(); + sw.Start(); + + + var result = Dectection[detectionId].RunInference(req); + sw.Stop(); + //LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 推理进度1.1,产品{productNumber},耗时{sw.ElapsedMilliseconds}ms"); + #endregion + #region 3.后处理 + DetectStationResult detectResult = new DetectStationResult(); + if (result == null || (result != null && !result.IsSuccess)) + { + detectResult.IsMLDetectDone = false; + } + if (result != null && result.IsSuccess) + { + detectResult.DetectDetails = result.ResultDetails; + if (detectResult.DetectDetails != null) + { + } + else + { + detectResult.IsMLDetectDone = false; + } + } + #endregion + #region 3.后处理 + #endregion + //根据那些得分大于阈值的推理结果,判断产品是否成功 + #region 4.最终过滤(逻辑过滤) + detectResult.DetectDetails?.ForEach(d => + { - this.BeginInvoke(new MethodInvoker(delegate () { - pictureBox1.Image = result.ResultMap; richTextBox1.AppendText("推理成功" + productNumber+ result.IsSuccess+ "\n"); })); + //当前检测项的 过滤条件 + //var conditionList = detectConfig.DetectionFilterList + // .Where(u => u.IsEnabled && u.LabelName == d.LabelName) + // .GroupBy(u => u.ResultState) + // .OrderBy(u => u.Key) + // .ToList(); + //当前检测项的 过滤条件 + var conditionList = detectConfig.DetectionFilterList + .Where(u => u.IsEnabled && u.LabelName == d.LabelName) + .GroupBy(u => u.ResultState) + .OrderBy(u => u.Key) + .ToList(); + + if (conditionList.Count == 0) + { + + if (d.LabelName.ToLower() == "ok") + { + d.FinalResult = d.InferenceResult = ResultState.OK; + } + else + { + d.FinalResult = d.InferenceResult = ResultState.DetectNG; + } + } + else + { + if (detectConfig.IsMixModel) + { + d.FinalResult = d.InferenceResult = ResultState.A_NG; + } + else + { + //将所有已将筛选出来的缺陷进行过滤 + d.FinalResult = d.InferenceResult = ResultState.OK; + } + + + } + + + foreach (IGrouping group in conditionList) + { + bool b = group.ToList().Any(f => + { + return f.FilterOperation(d); + }); + + + if (b) + { + d.FinalResult = group.Key; + break; + } + //else + //{ + // d.FinalResult = d.InferenceResult = ResultState.OK; + //} + } + }); + #endregion + #region 5.统计缺陷过滤结果或预处理直接NG + if (detectResult.DetectDetails?.Count > 0) + { + detectResult.ResultState = detectResult.DetectDetails.GroupBy(u => u.FinalResult).OrderBy(u => u.Key).First().First().FinalResult; + detectResult.ResultLabel = detectResult.ResultLabel; + detectResult.ResultLabelCategoryId = detectResult.ResultLabel;//TODO:设置优先级 + //////根据优先级设置ResultLabel + //if (detectionLabels.Count > 0) + //{ + // foreach (var l in detectionLabels) + // { + // var isExist = DetectDetails.Any(o => NormalizeAndClean(o.LabelName) == NormalizeAndClean(l.LabelName) && o.FinalResult == ResultState.DetectNG); + // if (isExist) + // { + + // ResultLabelCategoryId = l.LabelCategoryId; + // break; + // } + // } + //} + + return; + } + #endregion + + + resultStates.Add(detectResult.ResultState); + + product.ResultCollection.Add(detectResult); + this.BeginInvoke(new MethodInvoker(delegate () + { + pictureBox1.Image = result.ResultMap; richTextBox1.AppendText($"推理成功{productNumber},{result.IsSuccess} 推理耗时{sw.ElapsedMilliseconds}ms,总推理耗时\n"); + + })); //DetectStationResult temp; ////LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 推理进度1.4,产品{productNumber}"); //// 检测结果 @@ -541,10 +759,7 @@ namespace DHSoftware if (!product.InferenceFinished()) { - //if (!(camera.Name == "Cam8")) - //{ - // return; - //} + return; } ProductNum_Total++; @@ -559,6 +774,30 @@ namespace DHSoftware richTextBox1.SelectionStart = richTextBox1.TextLength; richTextBox1.ScrollToCaret(); })); + #region 6.统计产品结果 + if (product.ResultCollection.Any(u => u.ResultState != ResultState.OK)) + { + //检测结果TBD + // CurTrigger = TriggerSettings.FirstOrDefault(u => u.TriggerType == TriggerType.B_NG); + product.ProductResult = ResultState.B_NG; + product.ProductLabelCategory = ResultState.B_NG.GetEnumDescription(); + product.ProductLabel = ResultState.B_NG.GetEnumDescription(); + + + } + else + { + // CurTrigger = TriggerSettings.FirstOrDefault(u => u.TriggerType == TriggerType.OK); + product.ProductResult = ResultState.OK; + product.ProductLabelCategory = ResultState.OK.GetEnumDescription(); + product.ProductLabel = ResultState.OK.GetEnumDescription(); + } + #endregion + #region 7.产品吹气 + + #endregion + + //LogAsync(DateTime.Now, LogLevel.Information, $"推理完成,产品{product.PieceNumber}获取结果"); @@ -661,9 +900,19 @@ namespace DHSoftware if (isSuccess) { - // LogAsync(DateTime.Now, LogLevel.Assist, $"产品{productNumber}出列成功:{isSuccess}," + - //$"产品结果:{temp.ProductResult.GetEnumDescription()}," + - //$"当前队列产品数量:{tmpDic.Count}"); + string logStr =$"{DateTime.Now}产品{productNumber}出列成功:{isSuccess}," + + $"产品结果:{temp.ProductResult.GetEnumDescription()}," + + $"当前队列产品数量:{tmpDic.Count}"; + this.BeginInvoke(new MethodInvoker(delegate () { + + int currentScrollPosition = richTextBox1.GetPositionFromCharIndex(richTextBox1.TextLength).Y; + + richTextBox1.AppendText(logStr); + + // 设置回原来的滚动位置 + richTextBox1.SelectionStart = richTextBox1.TextLength; + richTextBox1.ScrollToCaret(); + })); } tryTimes--; Thread.Sleep(1); @@ -703,6 +952,29 @@ namespace DHSoftware } }); } + public void SetResult() + { + + + + + + //// detectResult.IsPreTreatDone = detectResult.VisionImageSet.PreTreatedFlag + ////2024-02-29 目标检测不能全是NG + //if (IsPreTreatNG || IsObjectDetectNG) + //{ + // return; + //} + + + + //if (IsPreTreatDone && IsMLDetectDone && IsAfterTreatDone) + //{ + // ResultState = ResultState.OK; + // ResultLabel = ResultState.OK.GetEnumDescription(); + //} + + } private void HandleStopButton() { Cameras.Clear();