上传视觉检测模块

This commit is contained in:
2025-03-07 16:29:38 +08:00
parent af2e65dd58
commit 4df6b668bf
14 changed files with 1570 additions and 400 deletions

View File

@ -11,6 +11,9 @@
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20241108" />

View File

@ -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<labelStringBase> OkClassTxtList;
public List<ModelLabel> 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,
}
/// <summary>
/// 深度学习 识别结果明细 面向业务detect 面向深度学习Recongnition、Inference
/// </summary>
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<DetectionResultDetail> ResultDetails = new List<DetectionResultDetail>();
}
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; }
/// <summary>
/// 检测工位名称
/// </summary>
public string DetectName { get; set; }
/// <summary>
/// 深度学习 检测结果
/// </summary>
public List<DetectionResultDetail> DetectDetails = new List<DetectionResultDetail>();
/// <summary>
/// 工位检测结果
/// </summary>
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;
/// <summary>
/// 预处理阶段已经NG
/// </summary>
public bool IsPreTreatNG { get; set; } = false;
/// <summary>
/// 目标检测NG
/// </summary>
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<CameraBase>))]
public List<RelatedCamera> CameraCollects { get; set; } = new List<RelatedCamera>();
[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<MLModelType>))]
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<DetectionFilter> DetectionFilterList { get; set; } = new List<DetectionFilter>();
//[Category("深度学习配置")]
//[DisplayName("检测配置标签")]
//[Description("检测配置标签关联")]
//public List<DetectConfigLabel> DetectConfigLabelList { get; set; } = new List<DetectConfigLabel>();
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;
}
}
/// <summary>
/// 识别目标定义 class分类信息 Detection Segmentation要识别的对象
/// </summary>
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; } = "";
}
/// <summary>
/// 检测项识别对象
/// </summary>
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<IProcessConfig>();
// 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;
//}
}
/// <summary>
/// 识别对象定义分类信息 A类B类
/// </summary>
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;
}
}
/// <summary>
/// 检测过滤
/// </summary>
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<FilterConditions>), typeof(UITypeEditor))]
public List<FilterConditions> FilterConditionsCollection { get; set; } = new List<FilterConditions>();
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<FilterCondition>), typeof(UITypeEditor))]
public List<FilterCondition> FilterConditionCollection { get; set; } = new List<FilterCondition>();
//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<DetectionFilterProperty>))]
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,
}
}

View File

@ -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
{
/// <summary>
/// 目标检测 GPU
/// </summary>
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<HYoloResult>(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();
}
}
}
}

View File

@ -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
{
/// <summary>
/// 实例分割 maskrcnn
/// </summary>
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<SegResult>(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();
}
}
}
}

View File

@ -17,23 +17,7 @@ using Newtonsoft.Json;
namespace DH.Devices.Vision
{
//public class SegResult
//{
// public List<Result> SegmentResult;
// public class Result
// {
// public double fScore;
// public int classId;
// public string classname;
// public double area;
// public List<int> 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;
}

View File

@ -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
{
}
}

View File

@ -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<Result> HYolo;
public class Result
{
public double fScore;
public int classId;
public string classname;
//public double area;
public List<int> rect;
}
}
public class SegResult
{
public List<Result> SegmentResult;

View File

@ -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<labelStringBase> OkClassTxtList;
// public List<ModelLabel> 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,
}
/// <summary>
/// 深度学习 识别结果明细 面向业务detect 面向深度学习Recongnition、Inference
/// </summary>
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<DetectionResultDetail> ResultDetails = new List<DetectionResultDetail>();
}
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; }
/// <summary>
/// 检测工位名称
/// </summary>
public string DetectName { get; set; }
/// <summary>
/// 深度学习 检测结果
/// </summary>
public List<DetectionResultDetail> DetectDetails = new List<DetectionResultDetail>();
/// <summary>
/// 工位检测结果
/// </summary>
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;
/// <summary>
/// 预处理阶段已经NG
/// </summary>
public bool IsPreTreatNG { get; set; } = false;
/// <summary>
/// 目标检测NG
/// </summary>
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<CameraBase>))]
public List<RelatedCamera> CameraCollects { get; set; } = new List<RelatedCamera>();
[Category("启用配置")]
[DisplayName("是否启用GPU检测")]
[Description("是否启用GPU检测")]
public bool IsEnableGPU { get; set; } = false;
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型类型")]
[Description("模型类型ImageClassification-图片分类ObjectDetection目标检测Segmentation-图像分割")]
//[TypeConverter(typeof(EnumDescriptionConverter<MLModelType>))]
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;
}
}
}