2025-03-21 08:51:20 +08:00
|
|
|
|
using DH.Commons.Base;
|
|
|
|
|
using DH.Commons.Enums;
|
2025-04-01 18:15:30 +08:00
|
|
|
|
using DH.Commons.Helper;
|
2025-03-16 13:11:08 +08:00
|
|
|
|
using DH.UI.Model.Winform;
|
|
|
|
|
using HalconDotNet;
|
|
|
|
|
using OpenCvSharp;
|
|
|
|
|
using OpenCvSharp.Extensions;
|
2025-03-07 16:29:38 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
2025-04-02 18:26:34 +08:00
|
|
|
|
using System.Diagnostics.Eventing.Reader;
|
|
|
|
|
using System.Drawing.Imaging;
|
2025-03-07 16:29:38 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.ExceptionServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
2025-03-16 13:11:08 +08:00
|
|
|
|
using System.Windows.Forms;
|
2025-03-07 16:29:38 +08:00
|
|
|
|
using System.Xml.Linq;
|
2025-03-16 13:11:08 +08:00
|
|
|
|
using XKRS.UI.Model.Winform;
|
|
|
|
|
using static DH.Commons.Enums.EnumHelper;
|
2025-04-01 18:15:30 +08:00
|
|
|
|
using LogLevel = DH.Commons.Enums.EnumHelper.LogLevel;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
using ResultState = DH.Commons.Base.ResultState;
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
2025-03-07 16:29:38 +08:00
|
|
|
|
|
|
|
|
|
namespace DH.Devices.Vision
|
|
|
|
|
{
|
2025-03-16 13:11:08 +08:00
|
|
|
|
public class SimboVisionDriver : VisionEngineBase
|
2025-03-07 16:29:38 +08:00
|
|
|
|
{
|
2025-03-16 13:11:08 +08:00
|
|
|
|
public Dictionary<string, HDevEngineTool> HalconToolDict = new Dictionary<string, HDevEngineTool>();
|
|
|
|
|
|
|
|
|
|
public List<SimboStationMLEngineSet> SimboStationMLEngineList = new List<SimboStationMLEngineSet>();
|
|
|
|
|
|
|
|
|
|
public void Init()
|
|
|
|
|
{
|
|
|
|
|
//InitialQueue();
|
|
|
|
|
InitialHalconTools();
|
|
|
|
|
InitialSimboMLEnginesAsync();
|
|
|
|
|
|
|
|
|
|
// ImageSaveHelper.OnImageSaveExceptionRaised -= ImageSaveHelper_OnImageSaveExceptionRaised;
|
|
|
|
|
// ImageSaveHelper.OnImageSaveExceptionRaised += ImageSaveHelper_OnImageSaveExceptionRaised;
|
|
|
|
|
// base.Init();
|
|
|
|
|
}
|
2025-03-27 18:03:07 +08:00
|
|
|
|
public void Stop()
|
|
|
|
|
{
|
|
|
|
|
SimboStationMLEngineList.ToList().ForEach(sm =>
|
|
|
|
|
{
|
|
|
|
|
if (sm.IsUseGPU)
|
|
|
|
|
{
|
|
|
|
|
sm.StationMLEngine.Dispose();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sm.StationMLEngine.Dispose2();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-03-16 13:11:08 +08:00
|
|
|
|
//private void ImageSaveHelper_OnImageSaveExceptionRaised(DateTime dt, string msg)
|
|
|
|
|
//{
|
|
|
|
|
// LogAsync(new LogMsg(dt, LogLevel.Error, msg));
|
|
|
|
|
//}
|
|
|
|
|
public override DetectStationResult RunInference(Mat originImgSet, string detectionId = null)
|
|
|
|
|
{
|
|
|
|
|
DetectStationResult detectResult = new DetectStationResult();
|
|
|
|
|
DetectionConfig detectConfig = null;
|
|
|
|
|
//找到对应的配置
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(detectionId))
|
|
|
|
|
{
|
|
|
|
|
detectConfig = DetectionConfigs.FirstOrDefault(u => u.Id == detectionId);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//detectConfig = DetectionConfigs.FirstOrDefault(u => u.CameraSourceId == camera.CameraName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (detectConfig == null)
|
|
|
|
|
{
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"异常:未能获取检测配置");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
//未能获得检测配置
|
|
|
|
|
return detectResult;
|
|
|
|
|
}
|
2025-04-02 18:26:34 +08:00
|
|
|
|
detectResult.DetectName = detectConfig.Name;
|
2025-04-02 14:41:26 +08:00
|
|
|
|
detectResult.ImageSaveDirectory=detectConfig.ImageSaveDirectory;
|
|
|
|
|
detectResult.SaveNGDetect=detectConfig.SaveNGDetect;
|
|
|
|
|
detectResult.SaveNGOriginal=detectConfig.SaveNGOriginal;
|
|
|
|
|
detectResult.SaveOKDetect=detectConfig.SaveOKDetect;
|
|
|
|
|
detectResult.SaveOKOriginal=detectConfig.SaveOKOriginal;
|
2025-04-02 18:26:34 +08:00
|
|
|
|
//detectResult.DetectionOriginImage = originImgSet.Clone().ToBitmap();
|
2025-04-01 18:15:30 +08:00
|
|
|
|
Stopwatch sw = new Stopwatch();
|
2025-03-16 13:11:08 +08:00
|
|
|
|
#region 1.预处理
|
2025-04-01 18:15:30 +08:00
|
|
|
|
sw.Start();
|
2025-03-16 13:11:08 +08:00
|
|
|
|
using (Mat PreTMat = originImgSet.Clone())
|
|
|
|
|
{
|
|
|
|
|
PreTreated(detectConfig, detectResult, PreTMat);
|
2025-04-01 18:15:30 +08:00
|
|
|
|
PreTreated2(detectConfig, detectResult, PreTMat);
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
2025-04-01 18:15:30 +08:00
|
|
|
|
sw.Stop();
|
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Information, $"产品:{detectResult.Pid} {detectConfig.Name}预处理耗时:{sw.ElapsedMilliseconds}ms。SpecsResults:{string.Join(";", detectResult.realSpecs.Select(u => $"{u.Code} {u.ActualValue}"))}");
|
|
|
|
|
// 工位2尺寸测量
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
if (detectResult.IsPreTreatNG)
|
|
|
|
|
{
|
|
|
|
|
detectResult.ResultState = ResultState.DetectNG;
|
|
|
|
|
detectResult.IsPreTreatDone = true;
|
|
|
|
|
detectResult.IsMLDetectDone = false;
|
|
|
|
|
return detectResult;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(detectConfig.ModelPath) && detectConfig.IsEnabled)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SimboStationMLEngineSet mlSet = null;
|
|
|
|
|
mlSet = SimboStationMLEngineList.FirstOrDefault(t => t.DetectionId == detectConfig.Id);
|
|
|
|
|
if (mlSet == null)
|
|
|
|
|
{
|
|
|
|
|
// LogAsync(DateTime.Now, LogLevel.Exception, $"异常:{detectConfig.Name}未能获取对应配置的模型检测工具");
|
|
|
|
|
detectResult.IsMLDetectDone = false;
|
|
|
|
|
|
|
|
|
|
//HandleDetectDone(detectResult, detectConfig);
|
|
|
|
|
return detectResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 2.深度学习推理
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Information, $"{detectConfig.Name} 产品{detectResult.TempPid} 模型检测执行");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(detectConfig.ModelPath))
|
|
|
|
|
{
|
|
|
|
|
Stopwatch mlWatch = new Stopwatch();
|
|
|
|
|
var req = new MLRequest();
|
|
|
|
|
//之前的检测图片都是相机存储成HImage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
req.ResizeWidth = (int)detectConfig.ModelWidth;
|
|
|
|
|
req.ResizeHeight = (int)detectConfig.ModelHeight;
|
|
|
|
|
// req.LabelNames = detectConfig.GetLabelNames();
|
|
|
|
|
// req.Score = IIConfig.Score;
|
|
|
|
|
req.mImage = originImgSet.Clone();
|
|
|
|
|
|
2025-03-21 08:51:20 +08:00
|
|
|
|
req.in_lable_path = detectConfig.In_lable_path;
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
req.confThreshold = detectConfig.ModelconfThreshold;
|
|
|
|
|
req.iouThreshold = 0.3f;
|
|
|
|
|
req.segmentWidth = 320;
|
|
|
|
|
req.out_node_name = "output0";
|
|
|
|
|
switch (detectConfig.ModelType)
|
|
|
|
|
{
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.图像分类:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.目标检测:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.语义分割:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.实例分割:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.目标检测GPU:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LogAsync(DateTime.Now, LogLevel.Information, $"{detectConfig.Name} 产品{detectResult.TempPid} RunInference BEGIN");
|
|
|
|
|
mlWatch.Start();
|
|
|
|
|
//20230802改成多线程推理 RunInferenceFixed
|
2025-03-27 17:51:07 +08:00
|
|
|
|
// MLResult result = new MLResult();
|
|
|
|
|
var result = mlSet.StationMLEngine.RunInference(req);
|
2025-03-16 13:11:08 +08:00
|
|
|
|
// var result = mlSet.StationMLEngine.RunInferenceFixed(req);
|
|
|
|
|
mlWatch.Stop();
|
|
|
|
|
// LogAsync(DateTime.Now, LogLevel.Information, $"{detectConfig.Name} 产品{detectResult.TempPid} RunInference END");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var req = new MLRequest();
|
|
|
|
|
|
|
|
|
|
//req.mImage = inferenceImage;
|
|
|
|
|
|
|
|
|
|
//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 = detectConfig.in_lable_path;
|
|
|
|
|
|
|
|
|
|
//Stopwatch sw = Stopwatch.StartNew();
|
|
|
|
|
//var result = Dectection[detectionId].RunInference(req);
|
|
|
|
|
//sw.Stop();
|
|
|
|
|
//LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 推理进度1.1,产品{productNumber},耗时{sw.ElapsedMilliseconds}ms");
|
|
|
|
|
|
|
|
|
|
//this.BeginInvoke(new MethodInvoker(delegate ()
|
|
|
|
|
//{
|
|
|
|
|
// // pictureBox1.Image?.Dispose(); // 释放旧图像
|
|
|
|
|
// // pictureBox1.Image = result.ResultMap;
|
|
|
|
|
// richTextBox1.AppendText($"推理成功 {productNumber}, {result.IsSuccess}相机名字{camera.CameraName} 耗时 {mlWatch.ElapsedMilliseconds}ms\n");
|
|
|
|
|
//}));
|
|
|
|
|
//req.mImage?.Dispose();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result == null || (result != null && !result.IsSuccess))
|
|
|
|
|
{
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"CoreInx:{mlSet.GPUNo} 产品:{detectResult.Pid} {detectConfig.Name} 模型检测异常,{result?.ResultMessage}");
|
|
|
|
|
|
2025-03-16 13:11:08 +08:00
|
|
|
|
detectResult.IsMLDetectDone = false;
|
|
|
|
|
}
|
|
|
|
|
if (result != null && result.IsSuccess)
|
|
|
|
|
{
|
|
|
|
|
detectResult.DetectDetails = result.ResultDetails;
|
|
|
|
|
if (detectResult.DetectDetails != null)
|
|
|
|
|
{
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Information, $"CoreInx:{mlSet.GPUNo} 产品:{detectResult.Pid} {detectResult.DetectName} 模型检测总耗时:{mlWatch.ElapsedMilliseconds} ms {result.ResultMessage},{string.Join(";", detectResult.DetectDetails.Select(u => $"{u.LabelName} X:{u.Rect.X} Y:{u.Rect.Y} Area:{u.Area.ToString("f2")} W:{u.Rect.Width} H:{u.Rect.Height}"))}");
|
|
|
|
|
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"CoreInx:{mlSet.GPUNo} 产品:{detectResult.Pid} {detectConfig.Name} 模型检测异常返回 null");
|
|
|
|
|
|
2025-03-16 13:11:08 +08:00
|
|
|
|
detectResult.IsMLDetectDone = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 3.后处理
|
|
|
|
|
#endregion
|
|
|
|
|
//根据那些得分大于阈值的推理结果,判断产品是否成功
|
|
|
|
|
#region 4.最终过滤(逻辑过滤)
|
|
|
|
|
detectResult.DetectDetails?.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
2025-03-24 15:21:16 +08:00
|
|
|
|
// 当前检测项的 过滤条件
|
|
|
|
|
var conditionList = detectConfig.DetectionLableList
|
|
|
|
|
.Where(u=>u.LabelName == d.LabelName)
|
|
|
|
|
.GroupBy(u => u.ResultState)
|
|
|
|
|
.OrderBy(u => u.Key)
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (conditionList.Count == 0)
|
|
|
|
|
{
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
2025-03-24 15:21:16 +08:00
|
|
|
|
d.FinalResult = d.LabelName.ToLower() == "ok"
|
|
|
|
|
? ResultState.OK
|
|
|
|
|
: ResultState.DetectNG;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d.FinalResult = detectConfig.IsMixModel
|
|
|
|
|
? ResultState.A_NG
|
|
|
|
|
: ResultState.OK;
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
|
2025-03-24 15:21:16 +08:00
|
|
|
|
}
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
//foreach (IGrouping<ResultState, DetectionFilter> group in conditionList)
|
|
|
|
|
//{
|
|
|
|
|
// bool b = group.ToList().Any(f =>
|
|
|
|
|
// {
|
|
|
|
|
// return f.FilterOperation(d);
|
|
|
|
|
// });
|
2025-03-24 15:21:16 +08:00
|
|
|
|
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
// if (b)
|
|
|
|
|
// {
|
|
|
|
|
// d.FinalResult = group.Key;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
2025-03-24 15:21:16 +08:00
|
|
|
|
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
//}
|
2025-03-16 13:11:08 +08:00
|
|
|
|
});
|
|
|
|
|
#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:设置优先级
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
detectResult.ResultState = detectResult.DetectDetails?
|
|
|
|
|
.GroupBy(u => u.FinalResult)
|
|
|
|
|
.OrderBy(u => u.Key)
|
|
|
|
|
.FirstOrDefault()?.Key ?? ResultState.OK;
|
|
|
|
|
detectResult.ResultLabel = detectResult.ResultLabel;
|
|
|
|
|
detectResult.ResultLabelCategoryId = detectResult.ResultLabel;//TODO:设置优先级
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Information, $"{detectConfig.Name} 检测结果:{detectResult.ResultState.GetEnumDescription()}");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DisplayDetectionResult(detectResult, originImgSet.Clone(), detectionId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return detectResult;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化深度学习工具
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool InitialSimboMLEnginesAsync()
|
|
|
|
|
{
|
|
|
|
|
//深度学习 模型加载
|
|
|
|
|
var resultOK = MLLoadModel();
|
|
|
|
|
return resultOK;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 深度学习 模型加载
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private bool MLLoadModel()
|
|
|
|
|
{
|
|
|
|
|
bool resultOK = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// SimboStationMLEngineList = new List<SimboStationMLEngineSet>();
|
|
|
|
|
// _cameraRelatedDetectionDict = IConfig.DetectionConfigs.Select(t => t.ModelPath).Distinct().ToList();
|
|
|
|
|
DetectionConfigs.ForEach(dc =>
|
|
|
|
|
//_cameraRelatedDetectionDict.ForEach(dc =>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (dc.IsEnabled && !string.IsNullOrWhiteSpace(dc.ModelPath))
|
|
|
|
|
{
|
|
|
|
|
if (dc.IsEnableGPU)
|
|
|
|
|
{
|
|
|
|
|
//if (IIConfig.IsLockGPU)
|
|
|
|
|
//{
|
|
|
|
|
//foreach (var validGPU in ValidGPUList2)
|
|
|
|
|
//{
|
|
|
|
|
// if (validGPU.DetectionIds.Contains(dc.Id))
|
|
|
|
|
// {
|
|
|
|
|
var engine = SingleMLLoadModel(dc, true, 0);
|
|
|
|
|
SimboStationMLEngineList.Add(engine);
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
//}
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// foreach (var validGPU in ValidGPUList)
|
|
|
|
|
// {
|
|
|
|
|
// //var validGPU = ValidGPUList.FirstOrDefault(u => u.DetectionIds.Contains(dc.Id));
|
|
|
|
|
// if (validGPU.DetectionId == dc.Id)
|
|
|
|
|
// {
|
|
|
|
|
// var engine = SingleMLLoadModel(dc, true, validGPU.GPUNo);
|
|
|
|
|
// SimboStationMLEngineList.Add(engine);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//for (int i = 0; i < IConfig.CPUNums; i++)
|
|
|
|
|
for (int i = 0; i < 1; i++)
|
|
|
|
|
{
|
|
|
|
|
//var engine = SingleMLLoadModel(dc, false, i);
|
|
|
|
|
var engine = SingleMLLoadModel(dc, false, i);
|
|
|
|
|
SimboStationMLEngineList.Add(engine);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
resultOK = true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
// LogAsync(DateTime.Now, LogLevel.Exception, $"异常:模型并发加载异常:{ex.GetExceptionMessage()}");
|
|
|
|
|
resultOK = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resultOK;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 单个模型加载
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="dc"></param>
|
|
|
|
|
/// <param name="gpuNum"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private SimboStationMLEngineSet SingleMLLoadModel(DetectionConfig dc, bool isGPU, int coreInx)
|
|
|
|
|
{
|
|
|
|
|
SimboStationMLEngineSet mLEngineSet = new SimboStationMLEngineSet();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
mLEngineSet.IsUseGPU = isGPU;
|
|
|
|
|
if (isGPU)
|
|
|
|
|
{
|
|
|
|
|
mLEngineSet.GPUNo = coreInx;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mLEngineSet.CPUNo = coreInx;
|
|
|
|
|
}
|
|
|
|
|
mLEngineSet.DetectionId = dc.Id;
|
|
|
|
|
mLEngineSet.DetectionName = dc.Name;
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(dc.ModelPath))
|
|
|
|
|
{
|
|
|
|
|
// 根据算法类型创建不同的实例
|
|
|
|
|
switch (dc.ModelType)
|
|
|
|
|
{
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.图像分类:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.目标检测:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
mLEngineSet.StationMLEngine = new SimboObjectDetection();
|
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.语义分割:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.实例分割:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
mLEngineSet.StationMLEngine = new SimboInstanceSegmentation();
|
|
|
|
|
break;
|
2025-03-21 08:51:20 +08:00
|
|
|
|
case ModelType.目标检测GPU:
|
2025-03-16 13:11:08 +08:00
|
|
|
|
mLEngineSet.StationMLEngine = new SimboDetection();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
MLInit mLInit;
|
|
|
|
|
string inferenceDevice = "CPU";
|
|
|
|
|
if (dc.IsEnableGPU)
|
|
|
|
|
{
|
|
|
|
|
inferenceDevice = "GPU";
|
|
|
|
|
mLInit = new MLInit(dc.ModelPath, isGPU, coreInx, dc.ModelconfThreshold);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mLInit = new MLInit(dc.ModelPath, "images", inferenceDevice, (int)dc.ModelWidth, (int)dc.ModelHeight);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isSuccess = mLEngineSet.StationMLEngine.Load(mLInit);
|
|
|
|
|
if (!isSuccess)
|
|
|
|
|
{
|
|
|
|
|
// throw new ProcessException("异常:模型加载异常", null);
|
|
|
|
|
}
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Information, $"模型加载成功;是否GPU:{isGPU} CoreInx:{coreInx} - {dc.Name}" + $" {dc.ModelType.GetEnumDescription()}:{dc.ModelPath}");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2025-04-02 18:26:34 +08:00
|
|
|
|
// LogAsync(DateTime.Now, LogLevel.Error, $"模型加载成功;是否GPU:{isGPU} CoreInx:{coreInx} - {dc.Name}" + $" {dc.ModelType.GetEnumDescription()}:{dc.ModelPath}");
|
2025-04-01 18:15:30 +08:00
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
throw new ProcessException($"异常:是否GPU:{isGPU} CoreInx:{coreInx} - {dc.Name}模型加载异常:{ex.GetExceptionMessage()}");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
|
|
|
|
return mLEngineSet;
|
|
|
|
|
}
|
|
|
|
|
private void InitialHalconTools()
|
|
|
|
|
{
|
|
|
|
|
HOperatorSet.SetSystem("parallelize_operators", "true");
|
|
|
|
|
HOperatorSet.SetSystem("reentrant", "true");
|
|
|
|
|
HOperatorSet.SetSystem("global_mem_cache", "exclusive");
|
|
|
|
|
|
|
|
|
|
HalconToolDict = new Dictionary<string, HDevEngineTool>();
|
|
|
|
|
|
|
|
|
|
DetectionConfigs.ForEach(c =>
|
|
|
|
|
{
|
|
|
|
|
if (!c.IsEnabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (c.HalconAlgorithemPath_Pre != null)
|
|
|
|
|
LoadHalconTool(c.HalconAlgorithemPath_Pre);
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LoadHalconTool(string path)
|
|
|
|
|
{
|
|
|
|
|
if (!HalconToolDict.ContainsKey(path))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string algorithemPath = path;
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(algorithemPath))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
string directoryPath = Path.GetDirectoryName(algorithemPath);
|
|
|
|
|
string fileName = Path.GetFileNameWithoutExtension(algorithemPath);
|
|
|
|
|
|
|
|
|
|
HDevEngineTool tool = new HDevEngineTool(directoryPath);
|
|
|
|
|
tool.LoadProcedure(fileName);
|
|
|
|
|
|
|
|
|
|
HalconToolDict[path] = tool;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 预处理
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="detectConfig"></param>
|
|
|
|
|
/// <param name="detectResult"></param>
|
|
|
|
|
public void PreTreated(DetectionConfig detectConfig, DetectStationResult detectResult, Mat MhImage)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// detectResult.VisionImageSet.DetectionOriginImage = detectResult.VisionImageSet.HImage.ConvertHImageToBitmap();
|
|
|
|
|
//detectResult.VisionImageSet.PreTreatedBitmap = detectResult.VisionImageSet.HImage.ConvertHImageToBitmap();
|
|
|
|
|
//detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.PreTreatedBitmap?.CopyBitmap();
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(detectConfig.HalconAlgorithemPath_Pre))
|
|
|
|
|
{
|
|
|
|
|
HObject obj = OpenCVHelper.MatToHImage(MhImage);
|
|
|
|
|
HImage hImage = HalconHelper.ConvertHObjectToHImage(obj);
|
|
|
|
|
string toolKey = detectConfig.HalconAlgorithemPath_Pre;
|
|
|
|
|
if (!HalconToolDict.ContainsKey(toolKey))
|
|
|
|
|
{
|
|
|
|
|
// LogAsync(DateTime.Now, LogLevel.Exception, $"{detectConfig.Name}未获取预处理算法");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//Mean_Thre Deviation_Thre Mean_standard Deviation_standard
|
|
|
|
|
var tool = HalconToolDict[toolKey];
|
|
|
|
|
|
|
|
|
|
////tool.InputTupleDic["Mean_Thre"] = 123;
|
|
|
|
|
for (int i = 0; i < detectConfig.PreTreatParams.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var param = detectConfig.PreTreatParams[i];
|
|
|
|
|
tool.InputTupleDic[param.Name] = double.Parse(param.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// tool.InputTupleDic["fCricularity"] = 200;
|
|
|
|
|
|
|
|
|
|
tool.InputImageDic["INPUT_Image"] = hImage;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!tool.RunProcedure(out string errorMsg, out _))
|
|
|
|
|
{
|
|
|
|
|
// detectResult.PreTreatedFlag = false;
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"{detectConfig.Name}预处理异常,{errorMsg}");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
detectResult.IsPreTreatDone = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var preTreatRet = tool.GetResultTuple("OUTPUT_Flag").I;
|
|
|
|
|
|
|
|
|
|
//var fRCricularity = tool.GetResultTuple("fRCricularity");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// detectResult.IsPreTreatDone = detectResult.VisionImageSet.PreTreatedFlag = preTreatRet == 1;
|
|
|
|
|
//detectResult.IsPreTreatDone = detectResult.VisionImageSet.PreTreatedFlag = true;
|
|
|
|
|
// detectResult.VisionImageSet.PreTreatedTime = DateTime.Now;
|
2025-04-01 18:15:30 +08:00
|
|
|
|
switch (preTreatRet)
|
2025-03-16 13:11:08 +08:00
|
|
|
|
{
|
2025-04-01 18:15:30 +08:00
|
|
|
|
case 0: // 预处理算法无异常
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < detectConfig.OUTPreTreatParams.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var param = detectConfig.OUTPreTreatParams[i];
|
|
|
|
|
|
|
|
|
|
var Value = tool.GetResultTuple(param.Name);
|
|
|
|
|
|
|
|
|
|
// 显示结果
|
|
|
|
|
IndexedSpec specRCricularity = new()
|
|
|
|
|
{
|
|
|
|
|
Code = param.Name,
|
|
|
|
|
ActualValue = Value
|
|
|
|
|
};
|
|
|
|
|
detectResult.realSpecs.Add(specRCricularity);
|
|
|
|
|
}
|
|
|
|
|
detectResult.IsPreTreatNG = false;
|
|
|
|
|
detectResult.IsPreTreatDone = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case -111: // 检测结果为NG
|
|
|
|
|
{
|
|
|
|
|
/// detectResult.VisionImageSet.DetectionResultImage =
|
|
|
|
|
// tool.GetResultObject("OUTPUT_PreTreatedImage").ConvertHImageToBitmap();
|
|
|
|
|
for (int i = 0; i < detectConfig.OUTPreTreatParams.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var param = detectConfig.OUTPreTreatParams[i];
|
|
|
|
|
|
|
|
|
|
var Value = tool.GetResultTuple(param.Name);
|
|
|
|
|
|
|
|
|
|
// 显示结果
|
|
|
|
|
IndexedSpec specRCricularity = new()
|
|
|
|
|
{
|
|
|
|
|
Code = param.Name,
|
|
|
|
|
ActualValue = Value
|
|
|
|
|
};
|
|
|
|
|
detectResult.realSpecs.Add(specRCricularity);
|
|
|
|
|
}
|
|
|
|
|
// 结果为NG
|
|
|
|
|
detectResult.ResultState = ResultState.DetectNG;
|
|
|
|
|
detectResult.IsPreTreatNG = true;
|
|
|
|
|
detectResult.IsPreTreatDone = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
case -999: // 算法异常
|
|
|
|
|
{
|
|
|
|
|
// 算法异常时,结果图
|
|
|
|
|
// detectResult.VisionImageSet.DetectionResultImage =
|
|
|
|
|
// tool.GetResultObject("OUTPUT_PreTreatedImage").ConvertHImageToBitmap();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < detectConfig.OUTPreTreatParams.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var param = detectConfig.OUTPreTreatParams[i];
|
|
|
|
|
// 显示结果
|
|
|
|
|
IndexedSpec specRCricularity = new()
|
|
|
|
|
{
|
|
|
|
|
Code = param.Name,
|
|
|
|
|
ActualValue = -1,
|
|
|
|
|
};
|
|
|
|
|
detectResult.realSpecs.Add(specRCricularity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 结果保持TBD
|
|
|
|
|
detectResult.IsPreTreatDone = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
2025-04-01 18:15:30 +08:00
|
|
|
|
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2023/10/16 新增预处理结果反馈,如果预处理结果为NG,直接返回
|
|
|
|
|
if (preTreatRet != 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.ResultState = ResultState.DetectNG;
|
|
|
|
|
|
|
|
|
|
detectResult.IsPreTreatNG = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (detectResult.VisionImageSet.PreTreatedFlag)
|
|
|
|
|
{
|
|
|
|
|
//detectResult.VisionImageSet.MLImage = tool.GetResultObject("OUTPUT_PreTreatedImage");
|
|
|
|
|
//DetectionResultImage
|
|
|
|
|
// detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.MLImage.ConvertHImageToBitmap();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.MLImage.ConvertHImageToBitmap();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2025-04-01 18:15:30 +08:00
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"{detectConfig.Name}预处理异常:{ex.GetExceptionMessage()}");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
//detectResult.VisionImageSet.HImage?.Dispose();
|
|
|
|
|
//detectResult.VisionImageSet.HImage = null;
|
|
|
|
|
// MhImage?.Dispose();
|
|
|
|
|
//MhImage = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2025-04-01 18:15:30 +08:00
|
|
|
|
public void PreTreated2(DetectionConfig detectConfig, DetectStationResult detectResult,Mat MhImage)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (detectConfig.SizeTreatParamList != null && detectConfig.SizeTreatParamList.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (var preTreat in detectConfig.SizeTreatParamList)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(preTreat.PrePath))
|
|
|
|
|
{
|
|
|
|
|
string toolKey = preTreat.PrePath;
|
|
|
|
|
if (!HalconToolDict.ContainsKey(toolKey))
|
|
|
|
|
{
|
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"{detectConfig.Name}未获取预处理{preTreat.PreName}算法");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//Mean_Thre Deviation_Thre Mean_standard Deviation_standard
|
|
|
|
|
var tool = HalconToolDict[toolKey];
|
|
|
|
|
|
|
|
|
|
//tool.InputTupleDic["Mean_Thre"] = 123;
|
|
|
|
|
List<PreTreatParam> PreParams = new List<PreTreatParam>();
|
|
|
|
|
preoutparms(PreParams, preTreat.ResultShow);
|
|
|
|
|
for (int i = 0; i < PreParams.Count(); i++)
|
|
|
|
|
{
|
|
|
|
|
var param = PreParams[i];
|
|
|
|
|
if (param.Value.Contains(","))
|
|
|
|
|
{
|
|
|
|
|
string[] strings = param.Value.Split(",");
|
|
|
|
|
float[] array = strings.Select(s => float.Parse(s)).ToArray();
|
|
|
|
|
HTuple hTupleArray = new HTuple(array);
|
|
|
|
|
|
|
|
|
|
tool.InputTupleDic[param.Name] = hTupleArray;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tool.InputTupleDic[param.Name] = double.Parse(param.Value);// param.Value.ToInt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IndexedSpec spec1 = new IndexedSpec();
|
|
|
|
|
|
|
|
|
|
switch (preTreat.PreType)
|
|
|
|
|
{
|
|
|
|
|
case SizeEnum.线线测量:
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.线圆测量:
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.圆形测量:
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.高度测量:
|
|
|
|
|
spec1.Code = $"in-{param.Name}";
|
|
|
|
|
spec1.ActualValue = double.Parse(param.Value);
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.直线测量:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
detectResult.realSpecs.Add(spec1);
|
|
|
|
|
}
|
|
|
|
|
//// 指定保存路径
|
|
|
|
|
//string filePath = @"D:\saved_image.jpg"; // 你可以根据需要更改路径和文件名
|
|
|
|
|
|
|
|
|
|
//// 使用WriteImage保存图像
|
|
|
|
|
//detectResult.VisionImageSet.HImage.WriteImage("jpeg", 0, filePath); // "jpeg" 表示图像格式,0表示不使用压缩
|
|
|
|
|
HObject obj = OpenCVHelper.MatToHImage(MhImage);
|
|
|
|
|
HImage hImage = HalconHelper.ConvertHObjectToHImage(obj);
|
|
|
|
|
tool.InputImageDic["INPUT_Image"] = hImage;
|
|
|
|
|
if (!tool.RunProcedure(out string errorMsg, out _))
|
|
|
|
|
{
|
|
|
|
|
// detectResult.VisionImageSet.PreTreatedFlag = false;
|
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"{detectConfig.Name}预处理异常,{errorMsg}");
|
|
|
|
|
detectResult.IsPreTreatDone = false;
|
|
|
|
|
|
|
|
|
|
// HandleDetectDone(detectResult, detectConfig);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var preTreatRet = tool.GetResultTuple("OUTPUT_Flag").I;
|
|
|
|
|
//double MatchScore = 1;
|
|
|
|
|
//MatchScore = tool.GetResultTuple("MatchScore");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
detectResult.IsPreTreatDone = preTreatRet == 1;
|
|
|
|
|
// detectResult.IsPreTreatDone = detectResult.VisionImageSet.PreTreatedFlag = true;
|
|
|
|
|
// detectResult.VisionImageSet.PreTreatedTime = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//IndexedSpec spec1 = new IndexedSpec();
|
|
|
|
|
//spec1.Code = "score";
|
|
|
|
|
//spec1.ActualValue = MatchScore;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//detectResult.realSpecs.Add(spec1);
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2023/10/16 新增预处理结果反馈,如果预处理结果为NG,直接返回
|
|
|
|
|
if (preTreatRet != 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.ResultState = ResultState.DetectNG;
|
|
|
|
|
|
|
|
|
|
detectResult.IsPreTreatNG = true;
|
|
|
|
|
// detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.MLImage.ConvertHImageToBitmap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch (preTreat.PreType)
|
|
|
|
|
{
|
|
|
|
|
case SizeEnum.线线测量:
|
|
|
|
|
isPreOutparams(ref detectResult, preTreat, tool, ref preTreatRet);
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.线圆测量:
|
|
|
|
|
isPreOutparams(ref detectResult, preTreat, tool, ref preTreatRet);
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.圆形测量:
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.高度测量:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
isPreOutparams(ref detectResult, preTreat, tool, ref preTreatRet);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SizeEnum.直线测量:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"{detectConfig.Name}尺寸预处理异常:{ex.GetExceptionMessage()}");
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
//detectResult.VisionImageSet.HImage?.Dispose();
|
|
|
|
|
//detectResult.VisionImageSet.HImage = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void isPreOutparams(ref DetectStationResult detectResult, SizeTreatParam preTreat, HDevEngineTool tool, ref int preTreatRet)
|
|
|
|
|
{
|
|
|
|
|
List<PreTreatParam> PreParams = new List<PreTreatParam>();
|
|
|
|
|
preoutparms(PreParams, preTreat.OutResultShow);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < PreParams.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var param = PreParams[i];
|
|
|
|
|
double dParam = double.Parse(param.Value);
|
|
|
|
|
double heights = tool.GetResultTuple(param.Name).D;
|
|
|
|
|
switch (preTreat.PreType)
|
|
|
|
|
{
|
|
|
|
|
case SizeEnum.高度测量:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IndexedSpec spec2 = new IndexedSpec();
|
|
|
|
|
spec2.Code = $"out-{param.Name}";
|
|
|
|
|
spec2.ActualValue = Convert.ToDouble(param.Value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
detectResult.realSpecs.Add(spec2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IndexedSpec spec1 = new IndexedSpec();
|
|
|
|
|
spec1.Code = $"actual-{param.Name}";
|
|
|
|
|
spec1.ActualValue = heights;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
detectResult.realSpecs.Add(spec1);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((heights > dParam - preTreat.PrePix) && (heights < dParam + preTreat.PrePix))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
preTreatRet = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (preTreatRet != 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.ResultState = ResultState.DetectNG;
|
|
|
|
|
|
|
|
|
|
detectResult.IsPreTreatNG = true;
|
|
|
|
|
//detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.MLImage.ConvertHImageToBitmap();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.MLImage.ConvertHImageToBitmap();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void preoutparms(List<PreTreatParam> preTreatParams, string defectRows)
|
|
|
|
|
{
|
|
|
|
|
// 解析 ReslutShow 字符串,构建 PreTreatParam 列表
|
|
|
|
|
if (!string.IsNullOrEmpty(defectRows))
|
|
|
|
|
{
|
|
|
|
|
var keyValuePairs = defectRows.Split(';');
|
|
|
|
|
|
|
|
|
|
foreach (var pair in keyValuePairs)
|
|
|
|
|
{
|
|
|
|
|
var parts = pair.Split(':');
|
|
|
|
|
if (parts.Length == 2)
|
|
|
|
|
{
|
|
|
|
|
PreTreatParam param;
|
|
|
|
|
if (parts[1].Trim().Contains(","))
|
|
|
|
|
{
|
|
|
|
|
param = new PreTreatParam
|
|
|
|
|
{
|
|
|
|
|
Name = parts[0].Trim(), // 去除多余的空格
|
|
|
|
|
Value = parts[1].Trim() // 转换为 double,失败则为0
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
double dvalue = double.TryParse(parts[1].Trim(), out double value) ? value : 0;
|
|
|
|
|
|
|
|
|
|
param = new PreTreatParam
|
|
|
|
|
{
|
|
|
|
|
Name = parts[0].Trim(), // 去除多余的空格
|
|
|
|
|
Value = dvalue.ToString() // 转换为 double,失败则为0
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
preTreatParams.Add(param);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-16 13:11:08 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 显示检测结果
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="detectResult"></param>
|
|
|
|
|
private void DisplayDetectionResult(DetectStationResult detectResult,Mat result,string DetectionId)
|
|
|
|
|
{
|
|
|
|
|
//结果显示上传
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string displayTxt = detectResult.ResultState.ToString() + "\r\n";
|
|
|
|
|
if (detectResult.DetectDetails != null && detectResult.DetectDetails?.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.DetectDetails.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
displayTxt +=
|
|
|
|
|
$"{d.LabelName} score:{d.Score.ToString("f2")} area:{d.Area.ToString("f2")}\r\n";
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 14:41:26 +08:00
|
|
|
|
if (detectResult.realSpecs != null && detectResult.realSpecs?.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.realSpecs.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
displayTxt +=
|
|
|
|
|
$"{d.Code} :{d.ActualValue} \r\n";
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Bitmap resultMask =result.ToBitmap();
|
2025-03-16 13:11:08 +08:00
|
|
|
|
//if (detectResult.VisionImageSet.DetectionResultImage == null && detectResult.VisionImageSet.SizeResultImage == null)
|
|
|
|
|
//{
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
|
|
|
|
//else if (detectResult.VisionImageSet.DetectionResultImage == null && detectResult.VisionImageSet.SizeResultImage != null)
|
|
|
|
|
//{
|
|
|
|
|
// detectResult.VisionImageSet.DetectionResultImage = detectResult.VisionImageSet.SizeResultImage.CopyBitmap();
|
|
|
|
|
// resultMask = detectResult.VisionImageSet.DetectionResultImage.CopyBitmap();
|
|
|
|
|
//}
|
|
|
|
|
//else if (detectResult.VisionImageSet.DetectionResultImage != null && detectResult.VisionImageSet.SizeResultImage != null)
|
|
|
|
|
//{
|
|
|
|
|
// Mat img1 = ConvertBitmapToMat(detectResult.VisionImageSet.SizeResultImage.CopyBitmap()); // 第一张图片,已经带框
|
|
|
|
|
// Mat img2 = ConvertBitmapToMat(detectResult.VisionImageSet.DetectionResultImage.CopyBitmap()); // 第二张图片,已经带框
|
|
|
|
|
|
|
|
|
|
// // 合成两张图像:可以选择叠加或拼接
|
|
|
|
|
// Mat resultImg = new Mat();
|
|
|
|
|
// Cv2.AddWeighted(img1, 0.5, img2, 0.5, 0, resultImg); // 使用加权平均法合成图像
|
|
|
|
|
|
|
|
|
|
// resultMask = resultImg.ToBitmap();
|
|
|
|
|
//}
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// resultMask = detectResult.VisionImageSet.DetectionResultImage.CopyBitmap();
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
List<IShapeElement> detectionResultShapes =
|
|
|
|
|
new List<IShapeElement>(detectResult.DetectionResultShapes);
|
|
|
|
|
|
|
|
|
|
DetectResultDisplay resultDisplay = new DetectResultDisplay(detectResult, resultMask, displayTxt);
|
|
|
|
|
detectionResultShapes.Add(resultDisplay);
|
|
|
|
|
List<IShapeElement> detectionResultShapesClone = new List<IShapeElement>(detectionResultShapes);
|
|
|
|
|
|
|
|
|
|
DetectionDone(DetectionId, resultMask, detectionResultShapes);
|
2025-04-02 18:26:34 +08:00
|
|
|
|
detectResult.DetectionOriginImage = CopyBitmapWithLockBits(resultMask);
|
2025-04-02 14:41:26 +08:00
|
|
|
|
SaveDetectResultImageAsync(detectResult);
|
2025-03-16 13:11:08 +08:00
|
|
|
|
// SaveDetectResultCSVAsync(detectResult);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2025-04-02 18:26:34 +08:00
|
|
|
|
//LogAsync(DateTime.Now, LogLevel.Exception,
|
|
|
|
|
// $"{Name}显示{detectResult.DetectName}检测结果异常,{ex.GetExceptionMessage()}");
|
2025-03-16 13:11:08 +08:00
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-04-02 18:26:34 +08:00
|
|
|
|
public static Bitmap CopyBitmapWithLockBits(Bitmap original)
|
|
|
|
|
{
|
|
|
|
|
Bitmap copy = new Bitmap(original.Width, original.Height, original.PixelFormat);
|
|
|
|
|
BitmapData originalData = original.LockBits(
|
|
|
|
|
new Rectangle(0, 0, original.Width, original.Height),
|
|
|
|
|
ImageLockMode.ReadOnly,
|
|
|
|
|
original.PixelFormat
|
|
|
|
|
);
|
|
|
|
|
BitmapData copyData = copy.LockBits(
|
|
|
|
|
new Rectangle(0, 0, copy.Width, copy.Height),
|
|
|
|
|
ImageLockMode.WriteOnly,
|
|
|
|
|
copy.PixelFormat
|
|
|
|
|
);
|
|
|
|
|
int bytesPerPixel = Image.GetPixelFormatSize(original.PixelFormat) / 8;
|
|
|
|
|
int byteCount = originalData.Stride * original.Height;
|
|
|
|
|
byte[] buffer = new byte[byteCount];
|
|
|
|
|
System.Runtime.InteropServices.Marshal.Copy(originalData.Scan0, buffer, 0, byteCount);
|
|
|
|
|
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, copyData.Scan0, byteCount);
|
|
|
|
|
original.UnlockBits(originalData);
|
|
|
|
|
copy.UnlockBits(copyData);
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
2025-04-02 14:41:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
///图片异步保存
|
|
|
|
|
/// </summary>
|
2025-04-02 18:26:34 +08:00
|
|
|
|
public void SaveDetectResultImageAsync1(DetectStationResult detectResult)
|
2025-04-02 14:41:26 +08:00
|
|
|
|
{
|
|
|
|
|
string format = detectResult.ImageFormat.ToString().ToLower();
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
if(detectResult.ImageSaveDirectory!=null)
|
|
|
|
|
{
|
|
|
|
|
if (!Directory.Exists(detectResult.ImageSaveDirectory))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}else
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-04-02 14:41:26 +08:00
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
|
2025-04-02 14:41:26 +08:00
|
|
|
|
//根目录
|
|
|
|
|
string rootPath = Path.Combine(detectResult.ImageSaveDirectory,
|
2025-04-02 18:26:34 +08:00
|
|
|
|
DateTime.Now.ToString("yyyyMMdd"), detectResult.DetectName);
|
2025-04-02 14:41:26 +08:00
|
|
|
|
|
|
|
|
|
if (detectResult.ResultState != ResultState.OK)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// NG原图
|
|
|
|
|
if (detectResult.SaveNGOriginal && detectResult.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
string prefix = Path.Combine(rootPath, "NGRawImages", detectResult.ResultLabel);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{detectResult.Pid}_NGRawImage_{detectResult.DetectName}_{detectResult.Id}.{format}");
|
|
|
|
|
SaveImageAsync(fullname, detectResult.DetectionOriginImage, detectResult.ImageFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//NG结果图
|
|
|
|
|
if (detectResult.SaveOKDetect && detectResult.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
// 没有预处理,则保存原始图+检测结果图
|
|
|
|
|
// if (detectResult.VisionImageSet.PreTreatedBitmap == null)
|
|
|
|
|
{
|
|
|
|
|
//string displayTxt = detectResult.ResultState.ToString() + "\r\n";
|
|
|
|
|
string displayTxt = "";
|
|
|
|
|
detectResult.DetectDetails.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
displayTxt += $"{d.LabelName} score:{d.Score.ToString("f2")} area:{d.Area.ToString("f2")}\r\n";
|
|
|
|
|
});
|
|
|
|
|
if (detectResult.realSpecs != null && detectResult.realSpecs?.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.realSpecs.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
displayTxt +=
|
|
|
|
|
$"{d.Code} score:{d.ActualValue} \r\n";
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Bitmap resultMask = detectResult.DetectionOriginImage.CopyBitmap();
|
|
|
|
|
|
|
|
|
|
Bitmap preTreatedBitmap = detectResult.DetectionOriginImage.CopyBitmap();
|
|
|
|
|
|
|
|
|
|
List<IShapeElement> detectionResultShapes = new List<IShapeElement>(detectResult.DetectionResultShapes);
|
|
|
|
|
DetectResultDisplay resultDisplay = new DetectResultDisplay(detectResult, resultMask, displayTxt);
|
|
|
|
|
detectionResultShapes.Add(resultDisplay);
|
2025-03-07 16:29:38 +08:00
|
|
|
|
|
2025-04-02 14:41:26 +08:00
|
|
|
|
Bitmap resultMap = GetResultImage(resultMask, detectionResultShapes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resultDisplay.Dispose();
|
|
|
|
|
detectionResultShapes.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap detectionFitImage = StaticHelper.HConnectBitmap(preTreatedBitmap, resultMap);
|
|
|
|
|
|
|
|
|
|
string prefix = Path.Combine(rootPath, "NGFitImages", detectResult.ResultLabel);
|
2025-04-02 18:26:34 +08:00
|
|
|
|
Directory.CreateDirectory(prefix); // 自动创建所有缺失的目录
|
2025-04-02 14:41:26 +08:00
|
|
|
|
string fullname = Path.Combine(prefix, $"{detectResult.Pid}_NGFitImage_{detectResult.DetectName}_{detectResult.Id}.{format}");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
// SaveImageAsync(fullname, detectionFitImage, detectResult.ImageFormat);
|
|
|
|
|
// 使用回调或 Task.ContinueWith 确保保存完成后再释放资源
|
|
|
|
|
//SaveImageAsync(fullname, detectionFitImage, detectResult.ImageFormat)
|
|
|
|
|
// .ContinueWith(t =>
|
|
|
|
|
// {
|
|
|
|
|
// resultMask?.Dispose();
|
|
|
|
|
// preTreatedBitmap?.Dispose();
|
|
|
|
|
// resultMap?.Dispose();
|
|
|
|
|
// detectionFitImage?.Dispose();
|
|
|
|
|
// }, TaskScheduler.Default);
|
2025-04-02 14:41:26 +08:00
|
|
|
|
|
|
|
|
|
resultMask?.Dispose();
|
|
|
|
|
preTreatedBitmap?.Dispose();
|
|
|
|
|
resultMap?.Dispose();
|
|
|
|
|
detectionFitImage?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ // OK原图
|
|
|
|
|
if (detectResult.SaveOKOriginal && detectResult.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
string prefix = Path.Combine(rootPath, "OKRawImages", detectResult.ResultLabel);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{detectResult.Pid}_OKRawImage_{detectResult.DetectName}_{detectResult.Id}.{format}");
|
|
|
|
|
SaveImageAsync(fullname, detectResult.DetectionOriginImage, detectResult.ImageFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//ok结果图
|
|
|
|
|
if (detectResult.SaveOKDetect && detectResult.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
// 没有预处理,则保存原始图+检测结果图
|
|
|
|
|
// if (detectResult.VisionImageSet.PreTreatedBitmap == null)
|
|
|
|
|
{
|
|
|
|
|
//string displayTxt = detectResult.ResultState.ToString() + "\r\n";
|
|
|
|
|
string displayTxt = "";
|
|
|
|
|
detectResult.DetectDetails.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
displayTxt += $"{d.LabelName} score:{d.Score.ToString("f2")} area:{d.Area.ToString("f2")}\r\n";
|
|
|
|
|
});
|
|
|
|
|
if (detectResult.realSpecs != null && detectResult.realSpecs?.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
detectResult.realSpecs.ForEach(d =>
|
|
|
|
|
{
|
|
|
|
|
displayTxt +=
|
|
|
|
|
$"{d.Code} score:{d.ActualValue} \r\n";
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Bitmap resultMask = detectResult.DetectionOriginImage.CopyBitmap();
|
|
|
|
|
|
|
|
|
|
Bitmap preTreatedBitmap = detectResult.DetectionOriginImage.CopyBitmap();
|
|
|
|
|
|
|
|
|
|
List<IShapeElement> detectionResultShapes = new List<IShapeElement>(detectResult.DetectionResultShapes);
|
|
|
|
|
DetectResultDisplay resultDisplay = new DetectResultDisplay(detectResult, resultMask, displayTxt);
|
|
|
|
|
detectionResultShapes.Add(resultDisplay);
|
|
|
|
|
|
|
|
|
|
Bitmap resultMap = GetResultImage(resultMask, detectionResultShapes);
|
|
|
|
|
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
|
2025-04-02 14:41:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap detectionFitImage = StaticHelper.HConnectBitmap(preTreatedBitmap, resultMap);
|
|
|
|
|
|
|
|
|
|
string prefix = Path.Combine(rootPath, "OKFitImages", detectResult.ResultLabel);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{detectResult.Pid}_" +
|
|
|
|
|
$"OKFitImage_{detectResult.DetectName}_{detectResult.Id}.{format}");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SaveImageAsync(fullname, detectionFitImage, detectResult.ImageFormat);
|
|
|
|
|
|
2025-04-02 18:26:34 +08:00
|
|
|
|
//resultDisplay.Dispose();
|
|
|
|
|
//detectionResultShapes.Clear();
|
|
|
|
|
//resultMask?.Dispose();
|
|
|
|
|
//preTreatedBitmap?.Dispose();
|
|
|
|
|
//resultMap?.Dispose();
|
|
|
|
|
//detectionFitImage?.Dispose();
|
2025-04-02 14:41:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-04-02 18:26:34 +08:00
|
|
|
|
|
2025-04-02 14:41:26 +08:00
|
|
|
|
public virtual Bitmap GetResultImage(Bitmap baseImage, List<IShapeElement> eleList)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 重新生成画布 避免 无法从带有索引像素格式的图像创建graphics对象
|
|
|
|
|
Bitmap image = new Bitmap(baseImage.Width, baseImage.Height);
|
|
|
|
|
|
|
|
|
|
using (Graphics g = Graphics.FromImage(image))
|
|
|
|
|
{
|
|
|
|
|
g.DrawImage(baseImage, 0, 0);
|
|
|
|
|
|
|
|
|
|
eleList.ForEach(e =>
|
|
|
|
|
{
|
|
|
|
|
e.State = ElementState.Normal;
|
|
|
|
|
e.Draw(g);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LogAsync(DateTime.Now, LogLevel.Exception, $"获取叠加结果图片异常:{ex.GetExceptionMessage()}");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2025-04-02 18:26:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void SaveDetectResultImageAsync(DetectStationResult detectResult)
|
|
|
|
|
{
|
|
|
|
|
if (detectResult.ImageSaveDirectory == null) return;
|
|
|
|
|
|
|
|
|
|
string format = detectResult.ImageFormat.ToString().ToLower();
|
|
|
|
|
string rootPath = Path.Combine(detectResult.ImageSaveDirectory,
|
|
|
|
|
DateTime.Now.ToString("yyyyMMdd"), detectResult.DetectName);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (detectResult.ResultState != ResultState.OK)
|
|
|
|
|
{
|
|
|
|
|
SaveNGImages(detectResult, rootPath, format);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SaveOKImages(detectResult, rootPath, format);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
// Logger.Error($"保存检测结果失败: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private void SaveNGImages(DetectStationResult result, string rootPath, string format)
|
|
|
|
|
{
|
|
|
|
|
// NG 原图
|
|
|
|
|
if (result.SaveNGOriginal && result.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
string prefix = Path.Combine(rootPath, "NGRawImages", result.ResultLabel);
|
|
|
|
|
Directory.CreateDirectory(prefix);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{result.Pid}_NGRawImage_{result.DetectName}_{result.Id}.{format}");
|
|
|
|
|
SaveImageAsync(fullname, result.DetectionOriginImage, result.ImageFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NG 结果图
|
|
|
|
|
if (result.SaveOKDetect && result.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
string displayTxt = BuildDisplayText(result);
|
|
|
|
|
using (Bitmap resultMask = result.DetectionOriginImage.CopyBitmap())
|
|
|
|
|
using (Bitmap preTreatedBitmap = result.DetectionOriginImage.CopyBitmap())
|
|
|
|
|
{
|
|
|
|
|
var detectionResultShapes = new List<IShapeElement>(result.DetectionResultShapes)
|
|
|
|
|
{
|
|
|
|
|
new DetectResultDisplay(result, resultMask, displayTxt)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (Bitmap resultMap = GetResultImage(resultMask, detectionResultShapes))
|
|
|
|
|
using (Bitmap detectionFitImage = StaticHelper.HConnectBitmap(preTreatedBitmap, resultMap))
|
|
|
|
|
{
|
|
|
|
|
string prefix = Path.Combine(rootPath, "NGFitImages", result.ResultLabel);
|
|
|
|
|
Directory.CreateDirectory(prefix);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{result.Pid}_NGFitImage_{result.DetectName}_{result.Id}.{format}");
|
|
|
|
|
SaveImageAsync(fullname, detectionFitImage, result.ImageFormat);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private void SaveOKImages(DetectStationResult result, string rootPath, string format)
|
|
|
|
|
{
|
|
|
|
|
// OK 原图
|
|
|
|
|
if (result.SaveOKOriginal && result.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
string prefix = Path.Combine(rootPath, "OKRawImages", result.ResultLabel);
|
|
|
|
|
Directory.CreateDirectory(prefix);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{result.Pid}_OKRawImage_{result.DetectName}_{result.Id}.{format}");
|
|
|
|
|
SaveImageAsync(fullname, result.DetectionOriginImage, result.ImageFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OK 结果图
|
|
|
|
|
if (result.SaveOKDetect && result.DetectionOriginImage != null)
|
|
|
|
|
{
|
|
|
|
|
string displayTxt = BuildDisplayText(result);
|
|
|
|
|
using (Bitmap resultMask = result.DetectionOriginImage.CopyBitmap())
|
|
|
|
|
using (Bitmap preTreatedBitmap = result.DetectionOriginImage.CopyBitmap())
|
|
|
|
|
{
|
|
|
|
|
var detectionResultShapes = new List<IShapeElement>(result.DetectionResultShapes)
|
|
|
|
|
{
|
|
|
|
|
new DetectResultDisplay(result, resultMask, displayTxt)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (Bitmap resultMap = GetResultImage(resultMask, detectionResultShapes))
|
|
|
|
|
using (Bitmap detectionFitImage = StaticHelper.HConnectBitmap(preTreatedBitmap, resultMap))
|
|
|
|
|
{
|
|
|
|
|
string prefix = Path.Combine(rootPath, "OKFitImages", result.ResultLabel);
|
|
|
|
|
Directory.CreateDirectory(prefix);
|
|
|
|
|
string fullname = Path.Combine(prefix, $"{result.Pid}_OKFitImage_{result.DetectName}_{result.Id}.{format}");
|
|
|
|
|
SaveImageAsync(fullname, result.DetectionOriginImage, result.ImageFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string BuildDisplayText(DetectStationResult result)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
result.DetectDetails.ForEach(d => sb.AppendLine($"{d.LabelName} score:{d.Score:f2} area:{d.Area:f2}"));
|
|
|
|
|
if (result.realSpecs?.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
result.realSpecs.ForEach(d => sb.AppendLine($"{d.Code} score:{d.ActualValue}"));
|
|
|
|
|
}
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
2025-03-07 16:29:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|