合并修改

This commit is contained in:
2025-04-30 16:13:13 +08:00
294 changed files with 60700 additions and 6623 deletions

View File

@ -0,0 +1,399 @@
using System;
using System.ComponentModel;
using System.Drawing.Imaging;
using AntdUI;
using DH.Commons.Enums;
using DVPCameraType;
using HalconDotNet;
using OpenCvSharp;
namespace DH.Commons.Base
{
public class MatSet
{
public DateTime ImageTime { get; set; } = DateTime.Now;
private string id = "";
public string Id
{
get
{
if (string.IsNullOrWhiteSpace(id))
{
id = ImageTime.ToString("HHmmssfff");
}
return id;
}
set
{
id = value;
}
}
public string CameraId { get; set; }
public Mat _mat { get; set; } = null;
public ImageFormat _imageFormat { get; set; } = ImageFormat.Jpeg;
public virtual void Dispose()
{
_mat?.Dispose();
_mat = null;
}
}
public class CameraBase : NotifyProperty
{
// public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
// 私有字段 + 带通知的属性与DetectionLabel风格一致
private bool _isEnabled = false;
private bool _isallPicEnabled = true;//默认全画幅
private bool _isRGBEnabled = true;//默认彩色
private bool _isContinueMode = false;
private bool _isSavePicEnabled = false;
private bool _isZoomCamera = false;
private string _imageSaveDirectory;
private EnumCamType _CamType;
private dvpStreamFormat _dvpstreamFormat = dvpStreamFormat.S_RGB24;
private ImageFormat _imageFormat = ImageFormat.Jpeg;
private bool _isHardwareTrigger = true;
private string _serialNumber = string.Empty;
private string _cameraName = string.Empty;
private string _cameraIP = string.Empty;
private string _computerIP = string.Empty;
private bool _isDirectHardwareTrigger = false;
private float _gain =6;
private int _rotateImage = 0;
private float _exposure = 200;
private float _triggerDelay = 0;
private decimal _roiX = 0;
private decimal _roiY = 0;
private decimal _roiW = 2448;
private decimal _roiH = 2048;
private int _lineDebouncerTime = 0;
public volatile int SnapshotCount = 0;
[Category("相机设置")]
[DisplayName("图像格式")]
[Description("相机采集图像格式")]
public dvpStreamFormat DvpImageFormat
{
get => _dvpstreamFormat;
set
{
if (_dvpstreamFormat == value) return;
_dvpstreamFormat = value;
OnPropertyChanged(nameof(DvpImageFormat));
}
}
[Category("采图模式")]
[DisplayName("连续模式")]
[Description("是否连续模式。true连续模式采图false触发模式采图")]
public bool IsContinueMode
{
get => _isContinueMode;
set
{
if (_isContinueMode == value) return;
_isContinueMode = value;
OnPropertyChanged(nameof(IsContinueMode));
}
}
public bool IsZoomCamera
{
get => _isZoomCamera;
set
{
if (_isZoomCamera == value) return;
_isZoomCamera = value;
OnPropertyChanged(nameof(IsZoomCamera));
}
}
public virtual bool IsEnabled
{
get => _isEnabled;
set
{
if (_isEnabled == value) return;
_isEnabled = value;
OnPropertyChanged(nameof(IsEnabled));
}
}
public virtual bool IsAllPicEnabled
{
get => _isallPicEnabled;
set
{
if (_isallPicEnabled == value) return;
_isallPicEnabled = value;
OnPropertyChanged(nameof(IsAllPicEnabled));
}
}
public virtual bool IsSavePicEnabled
{
get => _isSavePicEnabled;
set
{
if (_isSavePicEnabled == value) return;
_isSavePicEnabled = value;
OnPropertyChanged(nameof(IsSavePicEnabled));
}
}
[Category("图片保存")]
[DisplayName("图片保存文件夹")]
[Description("图片保存文件夹")]
public virtual string ImageSaveDirectory
{
get => _imageSaveDirectory;
set
{
if (_imageSaveDirectory == value) return;
_imageSaveDirectory = value;
OnPropertyChanged(nameof(ImageSaveDirectory));
}
}
[Category("图片保存")]
[DisplayName("图片保存格式")]
[Description("图片保存格式")]
public ImageFormat ImageFormat
{
get => _imageFormat;
set
{
if (_imageFormat == value) return;
_imageFormat = value;
OnPropertyChanged(nameof(ImageFormat));
}
}
[Category("设备配置")]
[DisplayName("相机类型")]
[Description("相机类型")]
public EnumCamType CamType
{
get => _CamType;
set
{
if (_CamType == value) return;
_CamType = value;
OnPropertyChanged(nameof(CamType));
}
}
[Category("采图模式")]
[DisplayName("硬触发")]
[Description("是否硬触发模式。true硬触发false软触发")]
public bool IsHardwareTrigger
{
get => _isHardwareTrigger;
set
{
if (_isHardwareTrigger == value) return;
_isHardwareTrigger = value;
OnPropertyChanged(nameof(IsHardwareTrigger));
}
}
public string SerialNumber
{
get => _serialNumber;
set
{
if (_serialNumber == value) return;
_serialNumber = value;
OnPropertyChanged(nameof(SerialNumber));
}
}
public string CameraName
{
get => _cameraName;
set
{
if (_cameraName == value) return;
_cameraName = value;
OnPropertyChanged(nameof(CameraName));
}
}
public string CameraIP
{
get => _cameraIP;
set
{
if (_cameraIP == value) return;
_cameraIP = value;
OnPropertyChanged(nameof(CameraIP));
}
}
public string ComputerIP
{
get => _computerIP;
set
{
if (_computerIP == value) return;
_computerIP = value;
OnPropertyChanged(nameof(ComputerIP));
}
}
[Category("采图模式")]
[DisplayName("是否传感器直接硬触发")]
[Description("是否传感器直接硬触发。true传感器硬触发不通过软件触发false通过软件触发IO 的硬触发模式")]
public bool IsDirectHardwareTrigger
{
get => _isDirectHardwareTrigger;
set
{
if (_isDirectHardwareTrigger == value) return;
_isDirectHardwareTrigger = value;
OnPropertyChanged(nameof(IsDirectHardwareTrigger));
}
}
[Category("相机设置")]
[DisplayName("增益")]
[Description("Gain增益,-1:不设置不同型号相机的增益请参考mvs")]
public float Gain
{
get => _gain;
set
{
if (_gain.Equals(value)) return;
_gain = value;
OnPropertyChanged(nameof(Gain));
}
}
[Category("图像旋转")]
[DisplayName("默认旋转")]
[Description("默认旋转,相机开启后默认不旋转")]
public virtual int RotateImage
{
get => _rotateImage;
set
{
if (_rotateImage.Equals(value)) return;
_rotateImage = value;
OnPropertyChanged(nameof(RotateImage));
}
}
[Category("取像配置")]
[DisplayName("曝光")]
[Description("曝光")]
public virtual float Exposure
{
get => _exposure;
set
{
if (_exposure.Equals(value)) return;
_exposure = value;
OnPropertyChanged(nameof(Exposure));
}
}
[Category("相机设置")]
[DisplayName("硬触发后的延迟")]
[Description("TriggerDelay:硬触发后的延迟,单位us 微秒")]
public float TriggerDelay
{
get => _triggerDelay;
set
{
if (_triggerDelay.Equals(value)) return;
_triggerDelay = value;
OnPropertyChanged(nameof(TriggerDelay));
}
}
public decimal ROIX
{
get => _roiX;
set
{
if (_roiX == value) return;
_roiX = value;
OnPropertyChanged(nameof(ROIX));
}
}
public decimal ROIY
{
get => _roiY;
set
{
if (_roiY == value) return;
_roiY = value;
OnPropertyChanged(nameof(ROIY));
}
}
public decimal ROIW
{
get => _roiW;
set
{
if (_roiW == value) return;
_roiW = value;
OnPropertyChanged(nameof(ROIW));
}
}
public decimal ROIH
{
get => _roiH;
set
{
if (_roiH == value) return;
_roiH = value;
OnPropertyChanged(nameof(ROIH));
}
}
[Category("相机设置")]
[DisplayName("滤波时间")]
[Description("LineDebouncerTimeI/O去抖时间 单位us")]
public int LineDebouncerTime
{
get => _lineDebouncerTime;
set
{
if (_lineDebouncerTime == value) return;
_lineDebouncerTime = value;
OnPropertyChanged(nameof(LineDebouncerTime));
}
}
// 其他方法保持原有逻辑
public MatSet CopyImageSet(MatSet srcSet)
{
MatSet imageSet = new MatSet
{
Id = srcSet.Id,
_mat = srcSet._mat.Clone(),
// ImageSaveOption = srcSet.ImageSaveOption.Copy(),
ImageTime = srcSet.ImageTime
};
return imageSet;
}
public Action<DateTime, CameraBase, MatSet> OnHImageOutput { get; set; }
public virtual bool CameraConnect() { return false; }
public virtual bool CameraDisConnect() { return false; }
public virtual void SetExposure(int exposureTime, string cameraName) { }
public virtual void SetGain(int gain, string cameraName) { }
internal virtual void SetAcquisitionMode(int mode) { }
internal virtual void SetAcqRegion(int offsetV, int offsetH, int imageH, int imageW, string cameraName) { }
}
}

View File

@ -9,27 +9,14 @@ using AntdUI;
using System.Text.Json.Serialization;
using static DH.Commons.Enums.EnumHelper;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
using DH.Commons.Enums;
using System.Drawing.Imaging;
namespace DH.Commons.Enums
namespace DH.Commons.Base
{
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 class ModelLabel
{
public string LabelId { get; set; }
@ -45,7 +32,7 @@ namespace DH.Commons.Enums
[Description("模型识别的标签名称")]
public string LabelName { get; set; }
//[Category("模型配置")]
@ -74,28 +61,28 @@ namespace DH.Commons.Enums
//public int ImageResizeCount;
public bool IsCLDetection;
public int ProCount;
public string in_node_name;
public string in_node_name;
public string out_node_name;
public string out_node_name;
public string in_lable_path;
public string in_lable_path;
public int ResizeImageSize;
public int segmentWidth;
public int ImageWidth;
// public List<labelStringBase> OkClassTxtList;
// public List<labelStringBase> OkClassTxtList;
public List<ModelLabel> LabelNames;
public List<ModelLabel> LabelNames;
}
public enum ResultState
{
[Description("检测NG")]
DetectNG = -3,
@ -120,20 +107,20 @@ namespace DH.Commons.Enums
/// </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; }//识别到对象的 显示信息
@ -154,10 +141,10 @@ namespace DH.Commons.Enums
public class MLResult
{
public bool IsSuccess = false;
public string ResultMessage;
public Bitmap ResultMap;
public List<DetectionResultDetail> ResultDetails = new List<DetectionResultDetail>();
@ -181,8 +168,7 @@ namespace DH.Commons.Enums
public bool IsGPU;
public int GPUId;
public float Score_thre;
public MLInit(string modelFile, bool isGPU, int gpuId, float score_thre)
@ -205,31 +191,48 @@ namespace DH.Commons.Enums
}
}
public class DetectStationResult
public class DetectStationResult
{
public DateTime ImageTime { get; set; } = DateTime.Now;
private string id = "";
public string Id
{
get
{
if (string.IsNullOrWhiteSpace(id))
{
id = ImageTime.ToString("HHmmssfff");
}
return id;
}
set
{
id = value;
}
}
public string Pid { get; set; }
public string TempPid { get; set; }
public string TempPid { get; set; }
/// <summary>
/// 检测工位名称
/// </summary>
public string DetectName { get; set; }
/// <summary>
/// 深度学习 检测结果
/// </summary>
public List<DetectionResultDetail> DetectDetails = new List<DetectionResultDetail>();
public List<IShapeElement> DetectionResultShapes = new List<IShapeElement>();
/// <summary>
/// 视觉测量结果集合
/// </summary>
public List<IndexedSpec> realSpecs { get; set; } = new List<IndexedSpec>();
/// <summary>
/// 工位检测结果
/// </summary>
@ -254,36 +257,25 @@ namespace DH.Commons.Enums
/// 预处理阶段已经NG
/// </summary>
public bool IsPreTreatNG { get; set; } = false;
/// <summary>
/// 检测原图
/// </summary>
public Bitmap DetectionOriginImage { get; set; }
/// <summary>
/// 目标检测NG
/// </summary>
public bool IsObjectDetectNG { get; set; } = false;
public ImageFormat ImageFormat { get; set; } = ImageFormat.Jpeg;
public DateTime EndTime { get; set; }
public string ImageSaveDirectory { get; set; }
public int StationDetectElapsed { get; set; }
public static string NormalizeAndClean(string input)
{
#pragma warning disable CS8603 // 可能返回 null 引用
if (input == null) return null;
#pragma warning restore CS8603 // 可能返回 null 引用
public bool SaveOKOriginal = false;
public bool SaveNGOriginal = false;
public bool SaveOKDetect = false;
public bool SaveNGDetect = false;
// 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 : NotifyProperty
{
@ -406,7 +398,7 @@ namespace DH.Commons.Enums
public static double GetDistance(CustomizedPoint p1, CustomizedPoint p2)
{
return Math.Sqrt(Math.Pow((p1.X - p2.X), 2) + Math.Pow((p1.Y - p2.Y), 2));
return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
}
public override string ToString()
@ -447,13 +439,13 @@ namespace DH.Commons.Enums
public int CompareTo(CustomizedPoint other)
{
return (X == other.X && Y == other.Y) ? 0 : 1;
return X == other.X && Y == other.Y ? 0 : 1;
}
public override int GetHashCode()
{
//return (int)(X * 10 + Y);
return (new Tuple<double, double>(X, Y)).GetHashCode();
return new Tuple<double, double>(X, Y).GetHashCode();
}
public static CustomizedPoint operator -(CustomizedPoint p1, CustomizedPoint p2)
@ -476,7 +468,7 @@ namespace DH.Commons.Enums
// [Category("预处理参数")]
// [DisplayName("参数名称")]
// [Description("参数名称")]
//
//#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
// public string Name { get; set; }
@ -488,7 +480,7 @@ namespace DH.Commons.Enums
// [Category("预处理参数")]
// [DisplayName("参数值")]
// [Description("参数值")]
//
//#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
// public string Value { get; set; }
@ -496,48 +488,135 @@ namespace DH.Commons.Enums
// }
public class DetectionConfig : NotifyProperty
{
#region
[JsonPropertyName("id")]
#region
private string _id = Guid.NewGuid().ToString();
private string _name;
private EnumDetectionType _detectionType= EnumDetectionType.;
private string _cameraSourceId = "";
private List<RelatedCamera> _cameraCollects = new List<RelatedCamera>();
private bool _isEnableGPU;
private bool _isMixModel;
private bool _isPreEnabled;
private bool _isEnabled;
private bool _isAddStation = true;
private string _halconAlgorithemPath_Pre;
private AntList<PreTreatParam> _preTreatParams = new AntList<PreTreatParam>();
private AntList<PreTreatParam> _outPreTreatParams = new AntList<PreTreatParam>();
private ModelType _modelType = ModelType.;
private string _modelPath;
private int _modelWidth = 640;
private int _modelHeight = 640;
private string _modeloutNodeName = "output0";
private float _modelconfThreshold = 0.5f;
private string _in_lable_path;
private AntList<DetectionLable> _detectionLableList = new AntList<DetectionLable>();
private AntList<SizeTreatParam> _sizeTreatParamList = new AntList<SizeTreatParam>();
private CustomizedPoint _showLocation = new CustomizedPoint();
private string _imageSaveDirectory= "D://PROJECTS//Images//";
private bool _saveOKOriginal = false;
private bool _saveNGOriginal = false;
private bool _saveOKDetect = false;
private bool _saveNGDetect = false;
#endregion
#region
[ReadOnly(true)]
public string Id { get; private set; } = Guid.NewGuid().ToString();
public string Id
{
get => _id;
set
{
if (_id == value) return;
_id = value;
OnPropertyChanged(nameof(Id));
}
}
[Category("检测配置")]
[DisplayName("检测配置名称")]
[Description("检测配置名称")]
[JsonPropertyName("name")]
public string Name { get; set; }
#endregion
#region
[Category("关联相机")]
[DisplayName("关联相机")]
[Description("关联相机描述")]
[JsonPropertyName("camera_source_id")]
public string CameraSourceId { get; set; } = "";
public string Name
{
get => _name;
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged(nameof(Name));
}
}
[Category("关联相机集合")]
[DisplayName("关联相机集合")]
[Description("关联相机描述")]
[JsonPropertyName("camera_Collects")]
public List<RelatedCamera> CameraCollects { get; set; } = new();
#endregion
public List<RelatedCamera> CameraCollects
{
get => _cameraCollects;
set
{
if (_cameraCollects == value) return;
_cameraCollects = value;
OnPropertyChanged(nameof(CameraCollects));
}
}
#region
[Category("启用配置")]
[DisplayName("是否启用GPU检测")]
[JsonPropertyName("is_enable_gpu")]
public bool IsEnableGPU { get; set; }
[Description("是否启用GPU检测")]
public bool IsEnableGPU
{
get => _isEnableGPU;
set
{
if (_isEnableGPU == value) return;
_isEnableGPU = value;
OnPropertyChanged(nameof(IsEnableGPU));
}
}
[Category("启用配置")]
[DisplayName("是否混料模型")]
[JsonPropertyName("is_mixModel")]
public bool IsMixModel { get; set; }
[Description("是否混料模型")]
public bool IsMixModel
{
get => _isMixModel;
set
{
if (_isMixModel == value) return;
_isMixModel = value;
OnPropertyChanged(nameof(IsMixModel));
}
}
[Category("启用配置")]
[DisplayName("是否启用预处理")]
[Description("是否启用预处理")]
public bool IsPreEnabled
{
get => _isPreEnabled;
set
{
if (_isPreEnabled == value) return;
_isPreEnabled = value;
OnPropertyChanged(nameof(IsPreEnabled));
}
}
[Category("启用配置")]
[DisplayName("是否启用该检测")]
[JsonPropertyName("is_enabled")]
public bool IsEnabled { get; set; }
[Description("是否启用该检测")]
public bool IsEnabled
{
get => _isEnabled;
set
{
if (_isEnabled == value) return;
_isEnabled = value;
OnPropertyChanged(nameof(IsEnabled));
}
}
[Category("启用配置")]
[DisplayName("是否启用预处理")]
@ -548,133 +627,293 @@ namespace DH.Commons.Enums
private bool _isAddStation;
[Category("启用配置")]
[DisplayName("是否加入检测工位")]
[JsonPropertyName("is_addstation")]
[Description("是否加入检测工位")]
public bool IsAddStation
{
get => _isAddStation;
set
{
if (_isAddStation != value)
{
_isAddStation = value;
OnPropertyChanged(nameof(IsAddStation));
}
if (_isAddStation == value) return;
_isAddStation = value;
OnPropertyChanged(nameof(IsAddStation));
}
}
[Category("图片保存")]
[DisplayName("图片保存文件夹")]
[Description("图片保存文件夹")]
public virtual string ImageSaveDirectory
{
get => _imageSaveDirectory;
set
{
if (_imageSaveDirectory == value) return;
_imageSaveDirectory = value;
OnPropertyChanged(nameof(ImageSaveDirectory));
}
}
#endregion
#region
[Category("1.预处理(视觉算子)")]
[DisplayName("预处理-算法文件路径")]
[JsonPropertyName("halcon_algorithemPath_pre")]
public string HalconAlgorithemPath_Pre { get; set; }
public string HalconAlgorithemPath_Pre
{
get => _halconAlgorithemPath_Pre;
set
{
if (_halconAlgorithemPath_Pre == value) return;
_halconAlgorithemPath_Pre = value;
OnPropertyChanged(nameof(HalconAlgorithemPath_Pre));
}
}
[Category("1.预处理(视觉算子)")]
[DisplayName("预处理-参数列表")]
[JsonPropertyName("pre_treatParams")]
public List<PreTreatParam> PreTreatParams { get; set; } = new();
[Category("1.预处理(视觉算子)")]
[DisplayName("预处理-输出参数列表")]
[JsonPropertyName("out_preTreatParams")]
public List<PreTreatParam> OUTPreTreatParams { get; set; } = new();
#endregion
#region
[Category("2.中检测(深度学习)")]
[DisplayName("模型类型")]
[JsonPropertyName("model_Type")]
public MLModelType ModelType { get; set; } = MLModelType.ObjectDetection;
[Category("2.中检测(深度学习)")]
[DisplayName("模型文件路径")]
[JsonPropertyName("model_Path")]
public string ModelPath { get; set; }
[Category("2.中检测(深度学习)")]
[DisplayName("模型宽度")]
[JsonPropertyName("model_Width")]
public int ModelWidth { get; set; } = 640;
[Category("2.中检测(深度学习)")]
[DisplayName("模型高度")]
[JsonPropertyName("model_Height")]
public int ModelHeight { get; set; } = 640;
[Category("2.中检测(深度学习)")]
[DisplayName("模型节点名称")]
[JsonPropertyName("model_outNodeName")]
public string ModeloutNodeName { get; set; } = "output0";
[Category("2.中检测(深度学习)")]
[DisplayName("模型置信度")]
[JsonPropertyName("model_confThreshold")]
public float ModelconfThreshold { get; set; } = 0.5f;
[Category("2.中检测(深度学习)")]
[DisplayName("模型标签路径")]
[JsonPropertyName("in_lablepath")]
public string in_lable_path { get; set; }
#endregion
#region
// public List<SizeTreatParam> PreTreatCollects { get; set; } = new();
private List<SizeTreatParam> _preTreatParams = new();
[Category("1.尺寸测量集合")]
[DisplayName("尺寸测量集合")]
[JsonPropertyName("Pre_TreatCollects")]
public List<SizeTreatParam> PreTreatCollects
[Description("预处理-参数列表")]
public AntList<PreTreatParam> PreTreatParams
{
get => _preTreatParams;
set
{
if (_preTreatParams != value)
{
_preTreatParams = value;
OnPropertyChanged(nameof(PreTreatCollects));
}
if (_preTreatParams == value) return;
_preTreatParams = value;
OnPropertyChanged(nameof(PreTreatParams));
}
}
#endregion
[Category("1.预处理(视觉算子)")]
[DisplayName("预处理-输出参数列表")]
[Description("预处理-输出参数列表")]
public AntList<PreTreatParam> OUTPreTreatParams
{
get => _outPreTreatParams;
set
{
if (_outPreTreatParams == value) return;
_outPreTreatParams = value;
OnPropertyChanged(nameof(OUTPreTreatParams));
}
}
#region
[Category("4.最终过滤(逻辑过滤)")]
[DisplayName("过滤器集合")]
[JsonPropertyName("detection_filterList")]
public List<DetectionFilter> DetectionFilterList { get; set; } = new();
#endregion
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型类型")]
[Description("模型类型ImageClassification-图片分类ObjectDetection目标检测Segmentation-图像分割")]
public ModelType ModelType
{
get => _modelType;
set
{
if (_modelType == value) return;
_modelType = value;
OnPropertyChanged(nameof(ModelType));
}
}
#region
[JsonPropertyName("Detection_LableList")]
public List<DetectionLable> DetectionLableList { get; set; } = new();
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型文件路径")]
[Description("中处理 深度学习模型文件路径")]
public string ModelPath
{
get => _modelPath;
set
{
if (_modelPath == value) return;
_modelPath = value;
OnPropertyChanged(nameof(ModelPath));
}
}
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型宽度")]
[Description("中处理-模型宽度")]
public int ModelWidth
{
get => _modelWidth;
set
{
if (_modelWidth == value) return;
_modelWidth = value;
OnPropertyChanged(nameof(ModelWidth));
}
}
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型高度")]
[Description("中处理-模型高度")]
public int ModelHeight
{
get => _modelHeight;
set
{
if (_modelHeight == value) return;
_modelHeight = value;
OnPropertyChanged(nameof(ModelHeight));
}
}
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型节点名称")]
[Description("中处理-模型节点名称")]
public string ModeloutNodeName
{
get => _modeloutNodeName;
set
{
if (_modeloutNodeName == value) return;
_modeloutNodeName = value;
OnPropertyChanged(nameof(ModeloutNodeName));
}
}
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型置信度")]
[Description("中处理-模型置信度")]
public float ModelconfThreshold
{
get => _modelconfThreshold;
set
{
if (_modelconfThreshold == value) return;
_modelconfThreshold = value;
OnPropertyChanged(nameof(ModelconfThreshold));
}
}
[Category("2.中检测(深度学习)")]
[DisplayName("中检测-模型标签路径")]
[Description("中处理-模型标签路径")]
public string In_lable_path
{
get
{
if (string.IsNullOrEmpty(ModelPath) || string.IsNullOrWhiteSpace(ModelPath))
{
return string.Empty;
}
string dir = Path.GetDirectoryName(ModelPath);
string file = $"{Path.GetFileNameWithoutExtension(ModelPath)}.txt";
return Path.Combine(dir, file);
}
set
{
if (_in_lable_path == value) return;
_in_lable_path = value;
OnPropertyChanged(nameof(In_lable_path));
}
}
[Category("检测配置")]
[DisplayName("检测类型")]
[Description("检测类型")]
public EnumDetectionType DetectionType
{
get => _detectionType;
set
{
if (_detectionType == value) return;
_detectionType = value;
OnPropertyChanged(nameof(DetectionType));
}
}
[Category("显示配置")]
[DisplayName("显示位置")]
[JsonPropertyName("Show_Location")]
public CustomizedPoint ShowLocation { get; set; } = new();
#endregion
//public event PropertyChangedEventHandler PropertyChanged;
[Description("检测信息显示位置")]
public CustomizedPoint ShowLocation
{
get => _showLocation;
set
{
if (_showLocation == value) return;
_showLocation = value;
OnPropertyChanged(nameof(ShowLocation));
}
}
//protected virtual void OnPropertyChanged(string propertyName)
//{
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
//}
/// <summary>
/// 标签集合需确保DetectionLable也实现INotifyPropertyChanged
/// </summary>
public AntList<DetectionLable> DetectionLableList
{
get => _detectionLableList;
set
{
if (_detectionLableList == value) return;
_detectionLableList = value;
OnPropertyChanged(nameof(DetectionLableList));
}
}
public AntList<SizeTreatParam> SizeTreatParamList
{
get => _sizeTreatParamList;
set
{
if (_sizeTreatParamList == value) return;
_sizeTreatParamList = value;
OnPropertyChanged(nameof(SizeTreatParamList));
}
}
public bool SaveOKOriginal
{
get => _saveOKOriginal;
set
{
if (_saveOKOriginal == value) return;
_saveOKOriginal = value;
OnPropertyChanged(nameof(SaveOKOriginal));
}
}
public bool SaveNGOriginal
{
get => _saveNGOriginal;
set
{
if (_saveNGOriginal == value) return;
_saveNGOriginal = value;
OnPropertyChanged(nameof(SaveNGOriginal));
}
}
public bool SaveOKDetect
{
get => _saveOKDetect;
set
{
if (_saveOKDetect == value) return;
_saveOKDetect = value;
OnPropertyChanged(nameof(SaveOKDetect));
}
}
public bool SaveNGDetect
{
get => _saveNGDetect;
set
{
if (_saveNGDetect == value) return;
_saveNGDetect = value;
OnPropertyChanged(nameof(SaveNGDetect));
}
}
#endregion
#region
public DetectionConfig() { }
public DetectionConfig(string name, MLModelType modelType, string modelPath, bool isEnableGPU, string sCameraSourceId)
public DetectionConfig(
string name,
ModelType modelType,
string modelPath,
bool isEnableGPU,
string sCameraSourceId)
{
// 通过属性赋值触发通知
ModelPath = modelPath ?? string.Empty;
Name = name;
ModelType = modelType;
ModelPath = modelPath ?? string.Empty;
IsEnableGPU = isEnableGPU;
CameraSourceId = sCameraSourceId;
Id = Guid.NewGuid().ToString();
}
#endregion
}
@ -727,6 +966,7 @@ namespace DH.Commons.Enums
}
private CellLink[] cellLinks;
[JsonIgnore]
public CellLink[] CellLinks
{
get {
@ -747,17 +987,18 @@ namespace DH.Commons.Enums
public class DetectionLable : NotifyProperty
{
private bool _selected = false;
private string _labelId;
private string _labelName;
private double _maxSource;
private double _minSource;
private double _maxScore;
private double _minScore;
private double _maxArea;
private double _minArea;
private ResultState _resultState = ResultState.ResultTBD;
public bool Selected
{
get { return _selected; }
@ -792,27 +1033,26 @@ namespace DH.Commons.Enums
OnPropertyChanged(nameof(LabelName));
}
}
[JsonPropertyName("maxSource")]
public double MaxSource
public double MaxScore
{
get { return _maxSource; }
get { return _maxScore; }
set
{
if (_maxSource.Equals(value)) return;
_maxSource = value;
OnPropertyChanged(nameof(MaxSource));
if (_maxScore.Equals(value)) return;
_maxScore = value;
OnPropertyChanged(nameof(MaxScore));
}
}
[JsonPropertyName("minSource")]
public double MinSource
public double MinScore
{
get { return _minSource; }
get { return _minScore; }
set
{
if (_minSource.Equals(value)) return;
_minSource = value;
OnPropertyChanged(nameof(MinSource));
if (_minScore.Equals(value)) return;
_minScore = value;
OnPropertyChanged(nameof(MinScore));
}
}
[JsonPropertyName("maxArea")]
@ -850,6 +1090,7 @@ namespace DH.Commons.Enums
}
private CellLink[] cellLinks;
[JsonIgnore]
public CellLink[] CellLinks
{
get {
@ -862,6 +1103,15 @@ namespace DH.Commons.Enums
OnPropertyChanged(nameof(CellLinks));
}
}
public bool FilterOperation(DetectionResultDetail recongnitionResult)
{
double compareValue = recongnitionResult.Area;
double compareScoreValue = recongnitionResult.Score;
return (compareValue >= MinArea && compareValue <= MaxArea)&& (compareScoreValue >= MinScore && compareScoreValue <= MaxScore);
}
}
public class PreTreatCollect
{
@ -999,7 +1249,7 @@ namespace DH.Commons.Enums
_resultShow = value;
OnPropertyChanged(nameof(ResultShow));
}
}
public string OutResultShow
@ -1013,19 +1263,20 @@ namespace DH.Commons.Enums
}
}
//public string PrePath
//{
// get { return _prePath; }
// set
// {
// if (_prePath.Equals(value)) return;
// _prePath = value;
// OnPropertyChanged(nameof(PrePath));
// }
//}
public string PrePath
{
get { return _prePath; }
set
{
if (_prePath.Equals(value)) return;
_prePath = value;
OnPropertyChanged(nameof(PrePath));
}
}
private CellLink[] cellLinks;
[JsonIgnore]
public CellLink[] CellLinks
{
get { return cellLinks; }
@ -1063,9 +1314,9 @@ namespace DH.Commons.Enums
//[TypeConverter(typeof(LabelCategoryConverter))]
public string LabelCategory { get; set; } = "";
}
/// <summary>
@ -1126,8 +1377,8 @@ namespace DH.Commons.Enums
//public string GetLabelName()
//{
// var name = "";
// var mlBase = iConfig.DeviceConfigs.FirstOrDefault(c => c is VisionEngineInitialConfigBase) as VisionEngineInitialConfigBase;
// if (mlBase != null)
// {
@ -1138,7 +1389,7 @@ namespace DH.Commons.Enums
// }
// }
// return name;
//}
}
@ -1199,11 +1450,11 @@ namespace DH.Commons.Enums
[DisplayName("过滤条件集合")]
[Description("过滤条件集合,集合之间为“且”关系")]
//[TypeConverter(typeof(CollectionCountConvert))]
// [Editor(typeof(ComplexCollectionEditor<FilterConditions>), typeof(UITypeEditor))]
// [Editor(typeof(ComplexCollectionEditor<FilterConditions>), typeof(UITypeEditor))]
public List<FilterConditions> FilterConditionsCollection { get; set; } = new List<FilterConditions>();
public bool FilterOperation(DetectionResultDetail recongnitionResult)
{
return FilterConditionsCollection.All(u =>

View File

@ -0,0 +1,389 @@

using DH.Commons.Enums;
using OpenCvSharp.Internal;
using System;
using System.ComponentModel;
using System.IO;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using static DH.Commons.Enums.EnumHelper;
using Timer = System.Threading.Timer;
namespace DH.Commons.Base
{
public abstract class DeviceBase : IDisposable
{
#region Event
[JsonIgnore]
[Browsable(false)]
public Action<DateTime, Exception> OnExceptionOccured { get; set; }
//public event Action<DateTime, LogLevel, string> OnLog;
public event Action<LogMsg> OnLog;
// public event Action<IDevice, DeviceState> OnDeviceStateChanged;
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region field
int RetryTime = 3;
/// <summary>
/// 和设备暂停状态关联的信号量
/// </summary>
private readonly ManualResetEvent pauseHandle = new ManualResetEvent(true);
readonly Timer stateChangedTimer;
#endregion
#region Property
#region State
private EnumHelper.DeviceState _currentStateToBe = EnumHelper.DeviceState.DSUninit;
/// <summary>
/// 当前设备状态
/// </summary>
[JsonIgnore]
internal EnumHelper.DeviceState CurrentStateToBe
{
get
{
return _currentStateToBe;
}
set
{
if (value != _currentStateToBe)
{
var initialState = _currentStateToBe;
_currentStateToBe = value;
if (_currentStateToBe != EnumHelper.DeviceState.DSExcept)
{
// OnStateChanged(initialState);
}
else
{
stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
}
//private EnumHelper.DeviceState initialState = EnumHelper.DeviceState.DSUninit;
private EnumHelper.DeviceState _currentState = EnumHelper.DeviceState.DSUninit;
public EnumHelper.DeviceState CurrentState
{
get
{
return _currentState;
}
set
{
_currentState = value;
if (value != EnumHelper.DeviceState.TBD)
{
// OnDeviceStateChanged?.Invoke(this, _currentState);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState"));
}
//else
//{
// initialState = _currentState;
//}
}
}
#endregion
/// <summary>
/// 设备标识符 从数据库获取
/// </summary>
public string Id { get; set; }
/// <summary>
/// 设备名称 从数据库获取
/// </summary>
public string Name { get; set; }
//private IInitialConfig initialConfig = null;
///// <summary>
///// 设备初始化配置 从数据库获取
///// </summary>
//public virtual IInitialConfig InitialConfig
//{
// get => initialConfig;
// set
// {
// initialConfig = value;
// Id = initialConfig.Id;
// Name = initialConfig.Name;
// LoggerHelper.LogPath = initialConfig.LogPath;
// LoggerHelper.LogPrefix = initialConfig.Name;
// }
//}
#endregion
#region
public DeviceBase()
{
RegisterFileWriterException();
// stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite);
}
#endregion
#region
protected virtual void Init()
{
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}初始化完成");
}
protected virtual void Start()
{
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}启动");
}
protected virtual void Stop()
{
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}停止");
}
//public abstract void AttachToProcess(IProcess process);
#endregion
/// <summary>
/// 常用操作封装方法
/// </summary>
/// <param name="opConfig"></param>
/// <returns></returns>
//public virtual ResponseMessage RunWrap(IOperationConfig opConfig)
//{
// ResponseMessage msg = new ResponseMessage();
// msg.Message = "设备基类默认操作";
// return msg;
//}
#region
//[DeviceExceptionAspect]
//public void StateChange(EnumHelper.DeviceState stateToBe)
//{
// if (CurrentState == stateToBe)
// {
// return;
// }
// if (!stateToBe.CheckPreStateValid((int)CurrentStateToBe))
// {
// string currentStateStr = CurrentStateToBe.GetEnumDescription();
// string stateToBeStr = stateToBe.GetEnumDescription();
// throw new ProcessException($"{InitialConfig.Name}设备的当前状态为{currentStateStr},无法切换至{stateToBeStr}");
// }
// CurrentState = EnumHelper.DeviceState.TBD;
// CurrentStateToBe = stateToBe;
//}
//[DeviceExceptionAspect]
//private void OnStateChanged(EnumHelper.DeviceState initialState)
//{
// try
// {
// if (CurrentStateToBe != EnumHelper.DeviceState.DSExcept)
// {
// }
// else
// {
// if (CurrentState == EnumHelper.DeviceState.DSExcept)
// {
// return;
// }
// else
// {
// throw new ProcessException($"{InitialConfig.Name}设备操作超时");
// }
// }
// if (RetryTime >= 0)
// {
// if (initialState == CurrentStateToBe)
// {
// CurrentState = CurrentStateToBe;
// return;
// }
// #region 状态切换操作
// switch (CurrentStateToBe)
// {
// case EnumHelper.DeviceState.DSInit:
// if (initialState == EnumHelper.DeviceState.DSOpen)
// {
// return;
// }
// else
// {
// Init();
// }
// break;
// case EnumHelper.DeviceState.DSOpen:
// if (initialState == EnumHelper.DeviceState.DSInit)
// {
// Start();
// }
// else if (initialState == EnumHelper.DeviceState.DSPause)
// {
// Resume();
// pauseHandle.Set();
// }
// break;
// case EnumHelper.DeviceState.DSPause:
// pauseHandle.Reset();
// Pause();
// break;
// case EnumHelper.DeviceState.DSClose:
// if (initialState != DeviceState.DSUninit)
// {
// Stop();
// }
// break;
// default:
// break;
// }
// RetryTime = 3;
// CurrentState = CurrentStateToBe;
// #endregion
// }
// stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
// }
// catch (Exception ex)
// {
// RetryTime--;
// if (RetryTime > 0)
// {
// OnStateChanged(initialState);
// }
// else
// {
// if (CurrentState != EnumHelper.DeviceState.DSExcept)
// {
// RetryTime = 3;
// throw new ProcessException($"设备{InitialConfig.Name}的{CurrentStateToBe.GetEnumDescription()}操作重复3次失败", ex, ExceptionLevel.Warning);
// }
// }
// }
//}
//private void CheckDeviceOpTimeOut(object state)
//{
// stateChangedTimer?.Change(Timeout.Infinite, Timeout.Infinite);
// if (CurrentState != EnumHelper.DeviceState.DSExcept)
// {
// StateChange(EnumHelper.DeviceState.DSExcept);
// }
//}
#endregion
#region
private void RegisterFileWriterException()
{
LoggerHelper.OnLogExceptionRaised -= LoggerHelper_OnLogExceptionRaised;
// CSVHelper.OnCSVExceptionRaised -= LoggerHelper_OnLogExceptionRaised;
LoggerHelper.OnLogExceptionRaised += LoggerHelper_OnLogExceptionRaised;
// CSVHelper.OnCSVExceptionRaised += LoggerHelper_OnLogExceptionRaised;
}
// public CSVHelper CSVHelper { get; set; } = new CSVHelper();
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
public virtual void LogAsync(LogMsg msg)
{
msg.MsgSource = Name;
msg.ThreadId = Thread.CurrentThread.ManagedThreadId;
//OnLog?.BeginInvoke(msg, null, null);
OnLog?.Invoke(msg);
//if (InitialConfig.IsEnableLog)
//{
LoggerHelper.LogAsync(msg);
//}
}
public virtual void LogAsync(DateTime dt, LogLevel logLevel, string msg)
{
LogAsync(new LogMsg(dt, logLevel, msg));
}
private void LoggerHelper_OnLogExceptionRaised(DateTime dt, string msg)
{
OnLog?.Invoke(new LogMsg(dt, LogLevel.Error, msg));
}
/// <summary>
/// CSV异步数据输出
/// </summary>
/// <param name="csvFile">CSV输出文件的文件全路径</param>
/// <param name="csvData">CSV输出数据</param>
/// <param name="csvHead">CSV文件表头</param>
public virtual void CSVRecordAsync(string csvFile, string csvData, string csvHead = "")
{
// CSVHelper.CSVOutputAsync(csvFile, csvData, csvHead);
}
#endregion
#region
//object _alarmLock = new object();
//protected virtual async void SaveAlarmCSVAsync(DateTime now, string deviceName, IWarningSet ws)
//{
// await Task.Run(() =>
// {
// LogAsync(now, LogLevel.Warning, $"{ws.WarningCode}-{ws.WarningDescription} {(ws.CurrentStatus ? "发生" : "取消")}");
// if (string.IsNullOrWhiteSpace(this.InitialConfig.LogPath) || !InitialConfig.IsEnableCSV)
// return;
// string path = Path.Combine(InitialConfig.LogPath, $"Alarm_{Name}_{now.ToString("yyyyMMdd")}.csv");
// string head = "Time,Source,AlarmCode,AlarmDescription,AlarmStatus";
// string data = $"{now.ToString("HH:mm:ss.fff")},{deviceName},{ws.WarningCode},{ws.WarningDescription},{(ws.CurrentStatus ? "报警发生" : "报警取消")}";
// CSVRecordAsync(path, data, head);
// });
//}
#endregion
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
//释放托管状态(托管对象)。
stateChangedTimer?.Dispose();
pauseHandle?.Dispose();
}
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。
disposedValue = true;
}
}
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
// ~DeviceBase()
// {
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
// Dispose(false);
// }
// 添加此代码以正确实现可处置模式。
public void Dispose()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(true);
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
// GC.SuppressFinalize(this);
}
#endregion
}
}

View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using AntdUI;
namespace DH.Commons.Base
{
public class GlobalConfig : NotifyProperty
{
bool _EnableVibrator=false;
bool _EnableBelt = false;
int _ClearTime=0;
string _name;
private BindingList<PLCItem> _InitProcessList = new BindingList<PLCItem>();
private BindingList<PLCItem> _StartProcessList = new BindingList<PLCItem>();
private BindingList<PLCItem> _StopProcessList = new BindingList<PLCItem>();
private BindingList<PLCItem> _StartResetList = new BindingList<PLCItem>();
private BindingList<PLCItem> _StopResetList = new BindingList<PLCItem>();
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
}
public bool EnableBelt
{
get => _EnableBelt;
set
{
if (_EnableBelt != value)
{
_EnableBelt = value;
OnPropertyChanged(nameof(EnableBelt));
}
}
}
public bool EnableVibrator
{
get => _EnableVibrator;
set
{
if (_EnableVibrator != value)
{
_EnableVibrator = value;
OnPropertyChanged(nameof(EnableVibrator));
}
}
}
public int ClearTime
{
get => _ClearTime;
set
{
if (_ClearTime != value)
{
_ClearTime = value;
OnPropertyChanged(nameof(ClearTime));
}
}
}
public BindingList<PLCItem> InitProcessList
{
get => _InitProcessList;
set
{
if (_InitProcessList == value) return;
_InitProcessList = value;
OnPropertyChanged(nameof(InitProcessList));
}
}
public BindingList<PLCItem> StartProcessList
{
get => _StartProcessList;
set
{
if (_StartProcessList == value) return;
_StartProcessList = value;
OnPropertyChanged(nameof(StartProcessList));
}
}
public BindingList<PLCItem> StopProcessList
{
get => _StopProcessList;
set
{
if (_StopProcessList == value) return;
_StopProcessList = value;
OnPropertyChanged(nameof(StopProcessList));
}
}
public BindingList<PLCItem> StartResetList
{
get => _StartResetList;
set
{
if (_StartResetList == value) return;
_StartResetList = value;
OnPropertyChanged(nameof(StartResetList));
}
}
public BindingList<PLCItem> StopResetList
{
get => _StopResetList;
set
{
if (_StopResetList == value) return;
_StopResetList = value;
OnPropertyChanged(nameof(StopResetList));
}
}
string _imgSavePath;
string _dbSavePath;
string _configSavePath;
public string ImgSavePath
{
get => _imgSavePath;
set
{
if (_imgSavePath != value)
{
_imgSavePath = value;
OnPropertyChanged(nameof(ImgSavePath));
}
}
}
public string DbSavePath
{
get => _dbSavePath;
set
{
if (_dbSavePath != value)
{
_dbSavePath = value;
OnPropertyChanged(nameof(DbSavePath));
}
}
}
public string ConfigSavePath
{
get => _configSavePath;
set
{
if (_configSavePath != value)
{
_configSavePath = value;
OnPropertyChanged(nameof(ConfigSavePath));
}
}
}
}
}

378
DH.Commons/Base/PLCBase.cs Normal file
View File

@ -0,0 +1,378 @@
using System.ComponentModel;
using System.IO.Ports;
using System.Text.Json.Serialization;
using AntdUI;
using DH.Commons.Enums; // 请确保此命名空间包含EnumPLCType
namespace DH.Commons.Base
{
public class PLCBase : NotifyProperty
{
// 私有字段
private bool _enable;
private bool _connected;
private string _plcName;
private EnumPLCType _plcType;
private string _com = "COM1";
private int _baudRate = 9600;
private int _dataBit = 8;
private StopBits _stopBit = StopBits.One;
private Parity _parity = Parity.None;
private string _ip = "192.168.6.61";
private int _port = 502;
private BindingList<PLCItem> _PLCItemList = new BindingList<PLCItem>();
[Category("设备配置")]
[DisplayName("是否启用")]
[Description("是否启用")]
public bool Enable
{
get => _enable;
set
{
if (_enable == value) return;
_enable = value;
OnPropertyChanged(nameof(Enable));
}
}
[Category("状态监控")]
[DisplayName("连接状态")]
[Description("PLC连接状态")]
public bool Connected
{
get => _connected;
set
{
if (_connected == value) return;
_connected = value;
OnPropertyChanged(nameof(Connected));
}
}
[Category("设备配置")]
[DisplayName("PLC名称")]
[Description("PLC设备名称")]
public string PLCName
{
get => _plcName;
set
{
if (_plcName == value) return;
_plcName = value;
OnPropertyChanged(nameof(PLCName));
}
}
[Category("设备配置")]
[DisplayName("PLC类型")]
[Description("PLC通信协议类型")]
public EnumPLCType PLCType
{
get => _plcType;
set
{
if (_plcType == value) return;
_plcType = value;
OnPropertyChanged(nameof(PLCType));
}
}
[Category("串口配置")]
[DisplayName("COM端口")]
[Description("串口号如COM1")]
public string COM
{
get => _com;
set
{
if (_com == value) return;
_com = value;
OnPropertyChanged(nameof(COM));
}
}
[Category("串口配置")]
[DisplayName("波特率")]
[Description("串口通信波特率")]
public int BaudRate
{
get => _baudRate;
set
{
if (_baudRate == value) return;
_baudRate = value;
OnPropertyChanged(nameof(BaudRate));
}
}
[Category("串口配置")]
[DisplayName("数据位")]
[Description("数据位长度(5/6/7/8)")]
public int DataBit
{
get => _dataBit;
set
{
if (_dataBit == value) return;
_dataBit = value;
OnPropertyChanged(nameof(DataBit));
}
}
[Category("串口配置")]
[DisplayName("停止位")]
[Description("停止位设置")]
public StopBits StopBit
{
get => _stopBit;
set
{
if (_stopBit == value) return;
_stopBit = value;
OnPropertyChanged(nameof(StopBit));
}
}
[Category("串口配置")]
[DisplayName("校验位")]
[Description("奇偶校验方式")]
public Parity Parity
{
get => _parity;
set
{
if (_parity == value) return;
_parity = value;
OnPropertyChanged(nameof(Parity));
}
}
[Category("网络配置")]
[DisplayName("IP地址")]
[Description("PLC网络地址")]
public string IP
{
get => _ip;
set
{
if (_ip == value) return;
_ip = value;
OnPropertyChanged(nameof(IP));
}
}
[Category("网络配置")]
[DisplayName("端口号")]
[Description("网络通信端口")]
public int Port
{
get => _port;
set
{
if (_port == value) return;
_port = value;
OnPropertyChanged(nameof(Port));
}
}
[Category("点位配置")]
[DisplayName("点位配置")]
[Description("点位配置")]
public BindingList<PLCItem> PLCItemList
{
get => _PLCItemList;
set
{
if (_PLCItemList == value) return;
_PLCItemList = value;
OnPropertyChanged(nameof(PLCItemList));
}
}
public virtual bool PLCConnect()
{
Connected = true;
return true;
}
public virtual bool PLCDisConnect()
{
Connected = false;
return true;
}
public virtual Int16 ReadInt16(string address) { return 0; }
public virtual Int32 ReadInt32(string address) { return 0; }
public virtual UInt16 ReadUInt16(string address) { return 0; }
public virtual UInt32 ReadUInt32(string address) { return 0; }
public virtual float ReadFloat(string address) { return 0; }
public virtual bool ReadBool(string address) { return false; }
public virtual bool WriteInt16(string address, Int16 value, bool waitForReply = true) { return false; }
public virtual bool WriteInt32(string address, Int32 value, bool waitForReply = true) { return false; }
public virtual bool WriteUInt16(string address, UInt16 value, bool waitForReply = true) { return false; }
public virtual bool WriteUInt32(string address, UInt32 value, bool waitForReply = true) { return false; }
public virtual bool WriteFloat(string address, float value, bool waitForReply = true) { return false; }
public virtual bool WriteBool(string address, bool value, bool waitForReply = true) { return false; }
}
public class PLCItem : NotifyProperty
{
private bool _selected;
private string _name = string.Empty;
private EnumPLCDataType _type;
private string _value = string.Empty;
private bool _startexecute;
private int _startindex;
private string _address;
/// <summary>
/// 是否选中
/// </summary>
public bool Selected
{
get => _selected;
set
{
if (_selected != value)
{
_selected = value;
OnPropertyChanged(nameof(Selected));
}
}
}
/// <summary>
/// 参数名称
/// </summary>
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
}
public EnumPLCDataType Type
{
get => _type;
set
{
if (_type != value)
{
_type = value;
OnPropertyChanged(nameof(Type));
}
}
}
/// <summary>
/// 参数类型
/// </summary>
public string Address
{
get => _address;
set
{
if (_address != value)
{
_address = value;
OnPropertyChanged(nameof(Address));
}
}
}
/// <summary>
/// 参数值
/// </summary>
public string Value
{
get => _value;
set
{
if (_value != value)
{
_value = value;
OnPropertyChanged(nameof(Value));
}
}
}
/// <summary>
/// 启用状态
/// </summary>
public bool StartExecute
{
get => _startexecute;
set
{
if (_startexecute != value)
{
_startexecute = value;
OnPropertyChanged(nameof(StartExecute));
}
}
}
/// <summary>
/// 顺序
/// </summary>
public int StartIndex
{
get => _startindex;
set
{
if (_startindex != value)
{
_startindex = value;
OnPropertyChanged(nameof(StartIndex));
}
}
}
private CellLink[] cellLinks;
[JsonIgnore]
public CellLink[] CellLinks
{
get { return cellLinks; }
set
{
if (cellLinks == value) return;
cellLinks = value;
OnPropertyChanged(nameof(CellLinks));
}
}
//private CellTag[] cellTags;
//[JsonIgnore]
//public CellTag[] CellTags
//{
// get { return cellTags; }
// set
// {
// if (cellTags == value) return;
// cellTags = value;
// OnPropertyChanged(nameof(CellTags));
// }
//}
}
}

View File

@ -0,0 +1,78 @@
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using DH.Commons.Enums;
using DH.Commons.Helper;
using HalconDotNet;
using OpenCvSharp;
namespace DH.Commons.Base
{
/// <summary>
/// 视觉处理引擎1.传统视觉 2.深度学习
/// CV深度学习 四大领域
/// Image Classification 图像分类:判别图中物体是什么,比如是猫还是狗;
/// Semantic Segmentation 语义分割:对图像进行像素级分类,预测每个像素属于的类别,不区分个体;
/// Object Detection 目标检测:寻找图像中的物体并进行定位;
/// Instance Segmentation 实例分割:定位图中每个物体,并进行像素级标注,区分不同个体;
/// </summary>
public abstract class VisionEngineBase : DeviceBase
{
public List<DetectionConfig> DetectionConfigs = new List<DetectionConfig>();
#region event
public event Action<string, List<double>> OnCropParamsOutput;
public event Action<string, Bitmap, List<IShapeElement>> OnDetectionDone;
public event Action<string> OnDetectionWarningStop;//有无检测 需要报警停机
#endregion
//public VisionEngineInitialConfigBase IConfig
//{
// get => InitialConfig as VisionEngineInitialConfigBase;
//}
// public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
public string BatchNO { get; set; }
public HTuple hv_ModelID;
public abstract DetectStationResult RunInference(MatSet originImgSet, string detectionId = null);
//public abstract void SaveDetectResultAsync(DetectStationResult detectResult);
public virtual void DetectionDone(string detectionId, Bitmap image, List<IShapeElement> detectionResults)
{
OnDetectionDone?.Invoke(detectionId, image, detectionResults);
}
public virtual void DetectionWarningStop(string detectionDes)
{
OnDetectionWarningStop?.Invoke(detectionDes);
}
public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
public virtual void SaveImageAsync(string fullname, Bitmap saveMap, ImageFormat imageFormat)
{
if (saveMap != null)
{
ImageSaveSet imageSaveSet = new ImageSaveSet()
{
FullName = fullname,
SaveImage = saveMap.CopyBitmap(),
ImageFormat = imageFormat.DeepSerializeClone()
};
ImageSaveHelper.ImageSaveAsync(imageSaveSet);
}
}
}
}

View File

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
namespace DH.Commons.Base
{
public class VisualLocalization
{
// 配置属性
public string CameraName { get; set; }
public string ModelPath { get; set; }
public string ImgPath { get; set; }
public string Threshold { get; set; }
public string Direction { get; set; }
public string Speed { get; set; }
public string MSpeed { get; set; }
// 配置文件路径
private const string ConfigFile = "VisualConfigs.json";
private static readonly object _fileLock = new object();
/// <summary>
/// 保存当前配置(存在则更新,不存在则新增)
/// </summary>
public void Save()
{
lock (_fileLock)
{
var list = LoadAll();
var existing = list.FirstOrDefault(c => c.CameraName == CameraName);
if (existing != null)
{
// 更新现有配置
existing.ModelPath = ModelPath;
existing.ImgPath = ImgPath;
existing.Threshold = Threshold;
existing.Direction = Direction;
existing.Speed = Speed;
existing.MSpeed = MSpeed;
}
else
{
list.Add(this);
}
SaveAll(list);
}
}
/// <summary>
/// 获取全部配置列表
/// </summary>
public static List<VisualLocalization> LoadAll()
{
lock (_fileLock)
{
if (!File.Exists(ConfigFile)) return new List<VisualLocalization>();
var json = File.ReadAllText(ConfigFile);
return JsonSerializer.Deserialize<List<VisualLocalization>>(json)
?? new List<VisualLocalization>();
}
}
private static void SaveAll(List<VisualLocalization> list)
{
var options = new JsonSerializerOptions
{
WriteIndented = true,
IgnoreNullValues = true
};
File.WriteAllText(ConfigFile, JsonSerializer.Serialize(list, options));
}
}
}

View File

@ -13,15 +13,23 @@
<ItemGroup>
<PackageReference Include="AntdUI" Version="1.8.9" />
<PackageReference Include="hyjiacan.pinyin4net" Version="4.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20241108" />
<PackageReference Include="OpenCvSharp4.Extensions" Version="4.10.0.20241108" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.10.0.20241108" />
<PackageReference Include="System.IO.Ports" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="DVPCameraCS64">
<HintPath>..\X64\Debug\DVPCameraCS64.dll</HintPath>
</Reference>
<Reference Include="halcondotnet">
<HintPath>..\x64\Debug\halcondotnet.dll</HintPath>
</Reference>

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DH.Commons.Enums
{
public class CameraInfo
{
public string CamName { get; set; }
public string Serinum { get; set; }
public string IP { get; set; }
}
}

View File

@ -7,12 +7,62 @@ using System.Threading.Tasks;
namespace DH.Commons.Enums
{
public enum EnumStatus
{
,
,
,
,
}
public enum ModelType
{
= 1,
= 2,
= 3,
= 4,
GPU = 5
}
public enum SelectPicType
{
[Description("训练图片")]
train = 0,
[Description("测试图片")]
test
}
public enum NetModel
{
[Description("目标检测")]
training = 0,
[Description("语义分割")]
train_seg,
[Description("模型导出")]
emport,
[Description("推理预测")]
infernce
}
public enum EnumCamType
{
[Description("度申相机")]
Do3think = 0,
[Description("海康相机")]
hik ,
}
public enum EnumPLCType
{
XC_串口,
XC_网口,
XD_串口,
XD_网口
[Description("信捷XC串口")]
XC串口 = 0,
[Description("信捷XC网口")]
XC网口 = 1,
[Description("信捷XD串口")]
XD串口 = 2,
[Description("信捷XD网口")]
XD网口 = 3
}
@ -28,32 +78,84 @@ namespace DH.Commons.Enums
public enum EnumPLCOutputIO
{
=0,
=1,
使=2,
=3,
=4,
绿=5,
=6,
=7,
=8,
=9,
=10,
1=11,
2=12,
3=13,
4=14,
5=15,
OK料盒=16,
NG料盒=17,
OK吹气时间=18,
NG吹气时间=19,
=20,
=21,
=22,
=23,
=24,
=25
,
使,
,
,
绿,
,
,
,
,
,
1,
2,
3,
4,
5,
6 ,
7 ,
8 ,
9 ,
10 ,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
OK脉冲,
NG脉冲,
,
,
,
,
,
,
,
,
,
,
,
}
public enum EnumPLCDataType
{
,
,
,
}
public enum EnumBool
{
,
}
public enum EnumBool1
{
False,
True
}
public enum EnumDetectionType
{
,
}

View File

@ -0,0 +1,64 @@
using System;
using static DH.Commons.Enums.EnumHelper;
namespace DH.Commons.Helper
{
public enum ExceptionLevel
{
Info = 0,
Warning = 1,
Fatal = 2,
}
//public delegate void OnProcessExceptionRaisedDelegate(DateTime dt, ProcessException ex);
//[Serializable]
public class ProcessException : Exception
{
public ExceptionLevel Level { get; set; } = ExceptionLevel.Warning;
public ProcessException()
{
}
public ProcessException(Exception ex, ExceptionLevel lvl = ExceptionLevel.Warning) : base(ex.Message, ex)
{
Level = lvl;
ExceptionNotice();
}
public ProcessException(string error, Exception ex = null, ExceptionLevel lvl = ExceptionLevel.Warning) : base(error, ex)
{
Level = lvl;
ExceptionNotice();
}
public void ExceptionNotice()
{
//OnProcessExceptionRaised?.Invoke(DateTime.Now, this);
}
}
public static class ExceptionHelper
{
public static LogLevel LogLevel = LogLevel.Information;
public static string GetExceptionMessage(this Exception ex)
{
string msg = "异常信息:" + ex.Message;
if (ex.InnerException != null)
{
msg += "\t内部异常信息" + ex.InnerException.GetExceptionMessage();
}
if (LogLevel <= LogLevel.Assist)
{
msg += ("\r\n\t\tStackTrace:" + ex.StackTrace);
}
return msg;
}
}
public class AuthorityException : ProcessException
{
}
}

View File

@ -0,0 +1,162 @@
using DH.Commons.Enums;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using static DH.Commons.Enums.EnumHelper;
namespace DH.Commons.Enums
{
/// <summary>
/// 设备特性,指示该信息的设备类型,适用于设备信息和配置信息
/// </summary>
public class DeviceAttribute : Attribute
{
/// <summary>
/// 设备类型
/// </summary>
public string TypeCode { get; set; }
public string TypeDescription { get; set; }
/// <summary>
/// 特性修饰类别
/// </summary>
public DeviceAttributeType AttrType { get; set; }
public DeviceAttribute(string typeCode, string typeDesc, EnumHelper.DeviceAttributeType attrType)
{
TypeCode = typeCode;
TypeDescription = typeDesc;
AttrType = attrType;
}
}
/// <summary>
/// 预置状态特性 指定该修饰信息的前置状态允许范围
/// </summary>
public class PreStateAttribute : Attribute
{
public int PreState { get; set; }
public PreStateAttribute(int _preState)
{
PreState = _preState;
}
/// <summary>
/// 检查当前待执行操作的前置状态要求是否合法
/// </summary>
/// <param name="currentState"></param>
/// <returns></returns>
public bool CheckPreStateValid(int currentState)
{
return (currentState & PreState) == currentState;
}
}
public class ColorSelectAttribute : Attribute
{
public string SelectedColor { get; set; }
public ColorSelectAttribute(string selectedColor)
{
SelectedColor = selectedColor;
}
}
public class FontColorSelectAttribute : Attribute
{
public string SelectedColor { get; set; }
public FontColorSelectAttribute(string selectedColor)
{
SelectedColor = selectedColor;
}
}
public enum InvokeType
{
/// <summary>
/// 不公开调用
/// </summary>
[Description("不公开调用")]
NoneInvoke = 0,
/// <summary>
/// 测试调用
/// </summary>
[Description("测试调用")]
TestInvoke = 1,
/// <summary>
/// 标定调用
/// </summary>
[Description("标定调用")]
CalibInvoke = 2,
}
/// <summary>
/// 用来修饰对外开放的调用方法的特性
/// 调用方法参数顺序IOperationConfigInvokeDeviceSourceDevice
/// </summary>
public class ProcessMethodAttribute : Attribute
{
public string MethodCode { get; set; }
public string MethodDesc { get; set; }
/// <summary>
/// 是否提供人工调用测试
/// </summary>
public InvokeType InvokeType { get; set; }
public string DeviceType { get; set; }
public ProcessMethodAttribute(string deviceType, string code, string description, InvokeType invokeType)
{
DeviceType = deviceType;
MethodCode = code;
MethodDesc = description;
InvokeType = invokeType;
}
}
public class SwitchDisplayAttribute : Attribute
{
public string SwitchName { get; set; }
public bool SwithOnStatus { get; set; } = true;
public SwitchDisplayAttribute(string name, bool status)
{
SwitchName = name;
SwithOnStatus = status;
}
}
public class ElementAttribute : Attribute
{
public string Name { get; set; }
public string Desc { get; set; }
public string IconPath { get; set; }
public bool IsShowInToolBar { get; set; }
public ElementAttribute(string desc, string iconPath, bool isShowInToolBar = true, [CallerMemberName] string name = "")
{
Name = name;
Desc = desc;
IconPath = iconPath;
IsShowInToolBar = isShowInToolBar;
}
}
public class ProcessAttribute : Attribute
{
public string ProcessCode { get; set; }
public DeviceAttributeType AttrType { get; set; }
public ProcessAttribute(string stationCode, DeviceAttributeType attrType)
{
ProcessCode = stationCode;
AttrType = attrType;
}
}
}

View File

@ -0,0 +1,280 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using AntdUI;
using DH.Commons.Base;
using DH.Commons.Enums;
using DH.Commons.Models;
namespace DH.Commons.Helper
{
public static class ConfigHelper
{
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
IgnoreNullValues = true
};
/// <summary>
/// 配置存储根目录
/// </summary>
private static string ConfigsRoot => Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"configs");
/// <summary>
/// 获取当前方案的主配置文件路径
/// </summary>
private static string CurrentConfigPath
{
get
{
ValidateCurrentScheme();
return Path.Combine(
ConfigsRoot,
$"config_{SystemModel.CurrentScheme}.json");
}
}
/// <summary>
/// 获取当前方案的备份目录路径
/// </summary>
private static string CurrentBackupDir
{
get
{
ValidateCurrentScheme();
return Path.Combine(
ConfigsRoot,
$"bak_{SystemModel.CurrentScheme}");
}
}
/// <summary>
/// 初始化新方案(创建空文件)
/// </summary>
public static void InitializeScheme(string scheme)
{
SystemModel.CurrentScheme = scheme;
// 创建空配置文件
if (!File.Exists(CurrentConfigPath))
{
Directory.CreateDirectory(ConfigsRoot);
File.WriteAllText(CurrentConfigPath, "{}");
}
// 创建备份目录
Directory.CreateDirectory(CurrentBackupDir);
}
/// <summary>
/// 保存当前配置(自动备份)
/// </summary>
public static void SaveConfig()
{
ValidateCurrentScheme();
// 确保配置目录存在
Directory.CreateDirectory(ConfigsRoot);
// 备份现有配置
if (File.Exists(CurrentConfigPath))
{
var backupName = $"config_{SystemModel.CurrentScheme}_{DateTime.Now:yyyyMMddHHmmss}.json";
var backupPath = Path.Combine(CurrentBackupDir, backupName);
Directory.CreateDirectory(CurrentBackupDir);
File.Copy(CurrentConfigPath, backupPath);
}
//重置标签文件路径和内容
ConfigModel.DetectionList.ForEach(config =>
{
GenerateLabelFile(config);
});
// 序列化当前配置
var json = JsonSerializer.Serialize(new
{
ConfigModel.CameraBaseList,
ConfigModel.PLCBaseList,
ConfigModel.DetectionList,
ConfigModel.GlobalList,
}, _jsonOptions);
// 写入新配置
File.WriteAllText(CurrentConfigPath, json);
}
private static void GenerateLabelFile(DetectionConfig config)
{
try
{
if (config.DetectionLableList == null || string.IsNullOrEmpty(config.In_lable_path))
return;
// 确保目录存在
var directory = Path.GetDirectoryName(config.In_lable_path);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 写入文件内容
using (var writer = new StreamWriter(config.In_lable_path, false))
{
foreach (var label in config.DetectionLableList)
{
//是否假如判断标签为中文转为为英文
//string pinyinlabel = FileHelper.ConvertHanzitoPinyinWithNumbers(label.LabelName.ToString());
//if (FileHelper.IsAlphaNumericOnly(pinyinlabel))
//{
//}
// 根据实际需求格式化输出
writer.WriteLine(label.LabelName.ToString()); // 假设DetectionLable重写了ToString()
// 或者明确指定格式:
// writer.WriteLine($"{label.Id},{label.Name},{label.Confidence}");
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"生成标签文件失败: {ex.Message}");
// 可以考虑记录更详细的日志
}
}
/// <summary>
/// 加载当前方案配置
/// </summary>
public static void LoadConfig()
{
ValidateCurrentScheme();
if (!File.Exists(CurrentConfigPath))
{
InitializeScheme(SystemModel.CurrentScheme);
return;
}
var json = File.ReadAllText(CurrentConfigPath);
var data = JsonSerializer.Deserialize<ConfigData>(json, _jsonOptions);
ConfigModel.CameraBaseList = data?.Cameras ?? new List<CameraBase>();
ConfigModel.DetectionList = data?.Detections ?? new List<DetectionConfig>();
ConfigModel.PLCBaseList = data?.PLCs ?? new List<PLCBase>();
ConfigModel.GlobalList = data?.GlobalConfigs ?? new List<GlobalConfig>();
}
/// <summary>
/// 验证当前方案有效性
/// </summary>
private static void ValidateCurrentScheme()
{
if (string.IsNullOrWhiteSpace(SystemModel.CurrentScheme))
throw new InvalidOperationException("当前方案未设置");
}
/// <summary>
/// 派生新方案(基于当前方案创建副本)
/// </summary>
/// <param name="newSchemeName">新方案名称</param>
public static void DeriveScheme(string newSchemeName)
{
// 验证输入
if (string.IsNullOrWhiteSpace(newSchemeName))
{
throw new ArgumentException("新方案名称不能为空");
}
// 验证当前方案是否有效
ValidateCurrentScheme();
// 检查新方案是否已存在
var newConfigPath = Path.Combine(ConfigsRoot, $"config_{newSchemeName}.json");
if (File.Exists(newConfigPath))
{
throw new InvalidOperationException($"方案 {newSchemeName} 已存在");
}
// 保存当前配置确保最新
SaveConfig();
try
{
// 复制配置文件
File.Copy(CurrentConfigPath, newConfigPath);
// 创建备份目录
var newBackupDir = Path.Combine(ConfigsRoot, $"bak_{newSchemeName}");
Directory.CreateDirectory(newBackupDir);
// 可选:自动切换新方案
// SystemModel.CurrentScheme = newSchemeName;
}
catch (IOException ex)
{
throw new InvalidOperationException($"方案派生失败: {ex.Message}", ex);
}
}
/// <summary>
/// 删除指定方案的配置文件及备份目录
/// </summary>
/// <param name="schemeName">要删除的方案名称</param>
/// <exception cref="ArgumentException">当方案名称为空时抛出</exception>
/// <exception cref="IOException">文件操作失败时抛出</exception>
public static void DeleteSchemeConfig(string schemeName)
{
if (string.IsNullOrWhiteSpace(schemeName))
throw new ArgumentException("方案名称无效");
// 构造路径
var configPath = Path.Combine(ConfigsRoot, $"config_{schemeName}.json");
var backupDir = Path.Combine(ConfigsRoot, $"bak_{schemeName}");
try
{
// 删除配置文件
if (File.Exists(configPath))
{
File.Delete(configPath);
}
// 删除备份目录(递归删除)
if (Directory.Exists(backupDir))
{
Directory.Delete(backupDir, true);
}
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
throw new IOException($"删除方案 {schemeName} 的配置文件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 配置数据模型(内部类)
/// </summary>
private class ConfigData
{
[JsonPropertyName("cameraBaseList")]
public List<CameraBase> Cameras { get; set; } = new List<CameraBase>();
[JsonPropertyName("plcBaseList")]
public List<PLCBase> PLCs { get; set; } = new List<PLCBase>();
[JsonPropertyName("detectionList")]
public List<DetectionConfig> Detections { get; set; } = new List<DetectionConfig>();
[JsonPropertyName("globalList")]
public List<GlobalConfig> GlobalConfigs { get; set; } = new List<GlobalConfig>();
}
}
}

View File

@ -76,159 +76,83 @@ namespace DH.Commons.Enums
}
}
//public static System.Windows.Media.Color GetEnumSelectedMediaColor(this Enum enumObj)
//{
// Type t = enumObj.GetType();
// FieldInfo f = t.GetField(enumObj.ToString());
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
// if (attr != null)
// {
// var prop = typeof(System.Windows.Media.Colors).GetProperties().FirstOrDefault(p => p.Name == attr.SelectedColor);
// if (prop != null)
// {
// return (System.Windows.Media.Color)prop.GetValue(null);
// }
// }
// return System.Windows.Media.Colors.Transparent;
//}
//public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
//{
// Type t = enumObj.GetType();
// FieldInfo f = t.GetField(enumObj.ToString());
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
// if (attr != null)
// {
// return System.Drawing.Color.FromName(attr.SelectedColor);
// }
// else
// {
// return System.Drawing.Color.Transparent;
// }
//}
//public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
//{
// Type t = enumObj.GetType();
// FieldInfo f = t.GetField(enumObj.ToString());
// var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
// if (attr != null)
// {
// return System.Drawing.Color.FromName(attr.SelectedColor);
// }
// else
// {
// return System.Drawing.Color.Transparent;
// }
//}
//public static string GetEnumSelectedColorString(this Enum enumObj)
//{
// Type t = enumObj.GetType();
// FieldInfo f = t.GetField(enumObj.ToString());
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
// if (attr != null)
// {
// return attr.SelectedColor;
// }
// else
// {
// return "Transparent";
// }
//}
// 根据描述获取枚举值(泛型方法)
public static T GetEnumFromDescription<T>(string description) where T : Enum
{
Type enumType = typeof(T);
foreach (T value in Enum.GetValues(enumType))
{
string desc = GetEnumDescription(value);
if (desc == description)
{
return value;
}
}
throw new ArgumentException($"在枚举 {enumType.Name} 中未找到描述为 '{description}' 的值");
}
/// <summary>
/// 当枚举牵涉到状态变换,检查现状态是否满足待转换的状态的前置状态要求
/// 获取枚举类型的所有描述文本
/// </summary>
/// <param name="stateToBe"></param>
/// <param name="currentState"></param>
/// <returns></returns>
//public static bool CheckPreStateValid(this Enum stateToBe, int currentState)
//{
// Type t = stateToBe.GetType();
// FieldInfo f = t.GetField(stateToBe.ToString());
/// <param name="enumType">枚举类型</param>
/// <returns>描述文本列表</returns>
public static List<string> GetEnumDescriptions(Type enumType)
{
// 验证类型是否为枚举
if (!enumType.IsEnum)
throw new ArgumentException("传入的类型必须是枚举类型", nameof(enumType));
// PreStateAttribute attr = f.GetCustomAttribute<PreStateAttribute>();
// if (attr == null)
// {
// return true;
// }
// else
// {
// return attr.CheckPreStateValid(currentState);
// }
//}
var descriptions = new List<string>();
/// <summary>
/// 设备状态定义
/// 未初始化和异常状态无前置状态要求
/// 初始化操作前置状态必须是未初始化、关闭状态和异常状态
/// 打开前置必须是初始化和暂停
/// 关闭前置必须是打开和暂停和异常
/// 暂停前置必须是打开
/// </summary>
//public enum DeviceState
//{
// TBD = -1,
foreach (var value in Enum.GetValues(enumType))
{
var fieldInfo = enumType.GetField(value.ToString());
var attribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
descriptions.Add(attribute?.Description ?? value.ToString());
}
// [ColorSelect("Gray")]
// [FontColorSelect("Black")]
// [Description("未初始化")]
// DSUninit = 1,
return descriptions;
}
public static string GetEnumDescription1(Enum value)
{
var field = value.GetType().GetField(value.ToString());
var attribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
return attribute?.Description ?? value.ToString();
}
// [ColorSelect("Gold")]
// [FontColorSelect("White")]
// [PreState(1 + 2 + 4 + 8 + 32)]
// [Description("初始化")]
// DSInit = 2,
public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
{
Type t = enumObj.GetType();
FieldInfo f = t.GetField(enumObj.ToString());
// [ColorSelect("Lime")]
// [FontColorSelect("Black")]
// [PreState(2 + 4 + 16)]
// [Description("运行中")]
// DSOpen = 4,
ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
if (attr != null)
{
return System.Drawing.Color.FromName(attr.SelectedColor);
}
else
{
return System.Drawing.Color.Transparent;
}
}
// [ColorSelect("Gray")]
// [FontColorSelect("White")]
// [PreState(1 + 4 + 8 + 16 + 32)]
// [Description("关闭")]
// DSClose = 8,
public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
{
Type t = enumObj.GetType();
FieldInfo f = t.GetField(enumObj.ToString());
// [ColorSelect("Gold")]
// [FontColorSelect("White")]
// [PreState(4 + 16)]
// [Description("暂停")]
// DSPause = 16,
var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
if (attr != null)
{
return System.Drawing.Color.FromName(attr.SelectedColor);
}
else
{
return System.Drawing.Color.Transparent;
}
}
// [ColorSelect("Red")]
// [FontColorSelect("White")]
// [Description("异常")]
// DSExcept = 32
//}
///// <summary>
///// 工序状态
///// </summary>
//public enum RunState
//{
// [ColorSelect("Gold")]
// [Description("空闲")]
// Idle = 1,
// [ColorSelect("Lime")]
// [Description("运行中")]
// Running = 2,
// [ColorSelect("Gray")]
// [Description("停止")]
// Stop = 3,
// [ColorSelect("Red")]
// [Description("宕机")]
// Down = 99,
//}
[Flags]
public enum DeviceAttributeType
@ -361,7 +285,38 @@ namespace DH.Commons.Enums
[Description("测量结果")]
MeasureResult = 31,
}
public enum LogLevel
{
[Description("详细")]
[ColorSelect("White")]
[FontColorSelect("Green")]
Detail = 2,
[Description("信息")]
[ColorSelect("White")]
[FontColorSelect("Dark")]
Information = 3,
[Description("辅助")]
[ColorSelect("White")]
[FontColorSelect("Blue")]
Assist = 4,
[Description("动作")]
[ColorSelect("DarkGreen")]
[FontColorSelect("Yellow")]
Action = 5,
[Description("错误")]
[ColorSelect("Orange")]
[FontColorSelect("White")]
Error = 6,
[Description("警报")]
[ColorSelect("Brown")]
[FontColorSelect("White")]
Warning = 7,
[Description("异常")]
[ColorSelect("Red")]
[FontColorSelect("White")]
Exception = 8,
}
//public enum CameraDriverType
//{
// Halcon,
@ -382,6 +337,59 @@ namespace DH.Commons.Enums
// NG = -1,
// IGNORE = -999,
//}
public enum DeviceState
{
TBD = -1,
[ColorSelect("Gray")]
[FontColorSelect("Black")]
[Description("未初始化")]
DSUninit = 1,
[ColorSelect("Gold")]
[FontColorSelect("White")]
[PreState(1 + 2 + 4 + 8 + 32)]
[Description("初始化")]
DSInit = 2,
[ColorSelect("Lime")]
[FontColorSelect("Black")]
[PreState(2 + 4 + 16)]
[Description("运行中")]
DSOpen = 4,
[ColorSelect("Gray")]
[FontColorSelect("White")]
[PreState(1 + 4 + 8 + 16 + 32)]
[Description("关闭")]
DSClose = 8,
[ColorSelect("Gold")]
[FontColorSelect("White")]
[PreState(4 + 16)]
[Description("暂停")]
DSPause = 16,
[ColorSelect("Red")]
[FontColorSelect("White")]
[Description("异常")]
DSExcept = 32
}
public enum RunState
{
[ColorSelect("Gold")]
[Description("空闲")]
Idle = 1,
[ColorSelect("Lime")]
[Description("运行中")]
Running = 2,
[ColorSelect("Gray")]
[Description("停止")]
Stop = 3,
[ColorSelect("Red")]
[Description("宕机")]
Down = 99,
}
public enum PriorityDirection
{

View File

@ -0,0 +1,507 @@
using hyjiacan.py4n;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DH.Commons.Enums
{
public static class FileHelper
{
/// <summary>
/// 清理两个文件夹中的文件,保留文件名交集部分,其余文件删除。
/// </summary>
/// <param name="imagesFolder">图片文件夹路径</param>
/// <param name="labelsFolder">标签文件夹路径</param>
public static void CleanupFolders(string imagesFolder, string labelsFolder)
{
if (!Directory.Exists(imagesFolder))
{
Console.WriteLine($"Images folder does not exist: {imagesFolder}");
return;
}
if (!Directory.Exists(labelsFolder))
{
Console.WriteLine($"Labels folder does not exist: {labelsFolder}");
return;
}
// 获取文件名(不包含扩展名)
var imageFiles = Directory.GetFiles(imagesFolder)
.Select(Path.GetFileNameWithoutExtension)
.ToHashSet();
var labelFiles = Directory.GetFiles(labelsFolder)
.Select(Path.GetFileNameWithoutExtension)
.ToHashSet();
// 计算交集
var commonFiles = imageFiles.Intersect(labelFiles);
// 删除 images 文件夹中不在交集中的文件
foreach (var imagePath in Directory.GetFiles(imagesFolder))
{
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(imagePath);
if (!commonFiles.Contains(fileNameWithoutExt))
{
File.Delete(imagePath);
Console.WriteLine($"Deleted image file: {imagePath}");
}
}
// 删除 labels 文件夹中不在交集中的文件
foreach (var labelPath in Directory.GetFiles(labelsFolder))
{
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(labelPath);
if (!commonFiles.Contains(fileNameWithoutExt))
{
File.Delete(labelPath);
Console.WriteLine($"Deleted label file: {labelPath}");
}
}
Console.WriteLine("Folders cleaned successfully!");
}
/// <summary>
/// 获取文件夹中所有图片文件的个数
/// </summary>
/// <param name="folderPath">目标文件夹路径</param>
/// <param name="includeSubdirectories">是否包含子文件夹,默认不包含</param>
/// <returns>图片文件总数</returns>
public static int CountImageFiles(string folderPath, bool includeSubdirectories = false)
{
if (!Directory.Exists(folderPath))
{
throw new DirectoryNotFoundException($"The folder '{folderPath}' does not exist.");
}
// 支持的图片格式
string[] imageExtensions = { "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif" };
// 搜索选项
SearchOption searchOption = includeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
int fileCount = 0;
foreach (var ext in imageExtensions)
{
fileCount += Directory.GetFiles(folderPath, ext, searchOption).Length;
}
return fileCount;
}
/// <summary>
/// 删除一个目录所有子目录和文件
/// </summary>
/// <param name="path"></param>
public static void DeleteDirectoryAndContents(string path)
{
// 确保目录存在
if (Directory.Exists(path))
{
// 删除目录中的文件
string[] files = Directory.GetFiles(path);
foreach (var file in files)
{
File.Delete(file);
Console.WriteLine($"文件已删除: {file}");
}
// 删除目录中的子目录
string[] directories = Directory.GetDirectories(path);
foreach (var directory in directories)
{
DeleteDirectoryAndContents(directory); // 递归删除子目录
}
// 删除空目录
Directory.Delete(path);
Console.WriteLine($"目录已删除: {path}");
}
else
{
Console.WriteLine("目录不存在!");
}
}
/// <summary>
/// 将一个文件夹中的所有图片文件和 JSON 文件复制到另一个文件夹中
/// </summary>
/// <param name="sourceDirectory"></param>
/// <param name="destinationDirectory"></param>
public static void CopyImageAndJsonFiles(string sourceDirectory, string destinationDirectory)
{
// 确保目标文件夹存在,如果不存在则创建它
if (!Directory.Exists(destinationDirectory))
{
Directory.CreateDirectory(destinationDirectory);
}
// 获取源文件夹中的所有图片文件和 JSON 文件
string[] imageFiles = Directory.GetFiles(sourceDirectory, "*.*")
.Where(file => file.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".tiff", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".webp", StringComparison.OrdinalIgnoreCase))
.ToArray();
string[] jsonFiles = Directory.GetFiles(sourceDirectory, "*.json");
// 合并图片文件和 JSON 文件
string[] filesToCopy = imageFiles.Concat(jsonFiles).ToArray();
foreach (string file in filesToCopy)
{
try
{
// 获取文件名
string fileName = Path.GetFileName(file);
// 拼接目标文件的完整路径
string destinationFile = Path.Combine(destinationDirectory, fileName);
// 如果目标文件已存在,可以选择覆盖或跳过(这里我们选择跳过)
if (File.Exists(destinationFile))
{
Console.WriteLine($"文件 {fileName} 已存在,跳过复制.");
continue;
}
// 复制文件
File.Copy(file, destinationFile);
Console.WriteLine($"文件 {fileName} 已成功复制到 {destinationDirectory}");
}
catch (Exception ex)
{
Console.WriteLine($"复制文件 {file} 时出错: {ex.Message}");
}
}
}
/// <summary>
/// 遍历图片文件夹,检查对应的标签文件夹中是否有同名的 .txt 文件。
/// 如果没有,则创建一个空的 .txt 文件。
/// </summary>
/// <param name="imagesDirectory">图片文件夹路径</param>
/// <param name="labelsDirectory">标签文件夹路径</param>
public static void ProcessImageFiles(string imagesDirectory, string labelsDirectory)
{
// 检查 images 目录是否存在
if (!Directory.Exists(imagesDirectory))
{
throw new DirectoryNotFoundException($"目录 {imagesDirectory} 不存在.");
}
// 检查 labels 目录是否存在,如果不存在则创建
if (!Directory.Exists(labelsDirectory))
{
Directory.CreateDirectory(labelsDirectory);
Console.WriteLine($"目录 {labelsDirectory} 已创建.");
}
// 获取 images 目录中的所有文件(包括图片文件)
string[] imageFiles = Directory.GetFiles(imagesDirectory, "*.*", SearchOption.TopDirectoryOnly);
string[] validExtensions = { ".jpg", ".jpeg", ".png", ".bmp", ".gif" }; // 支持的图片格式
foreach (var imageFile in imageFiles)
{
// 检查文件扩展名是否为支持的图片格式
string extension = Path.GetExtension(imageFile).ToLower();
if (Array.Exists(validExtensions, ext => ext == extension))
{
// 获取图片文件的文件名(不包括扩展名)
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(imageFile);
// 生成对应的 txt 文件路径
string labelFilePath = Path.Combine(labelsDirectory, fileNameWithoutExtension + ".txt");
// 如果该 txt 文件不存在,则创建一个空白 txt 文件
if (!File.Exists(labelFilePath))
{
try
{
File.WriteAllText(labelFilePath, string.Empty); // 创建空白 txt 文件
Console.WriteLine($"创建空白文件: {labelFilePath}");
}
catch (Exception ex)
{
Console.WriteLine($"无法创建文件 {labelFilePath}: {ex.Message}");
}
}
}
}
}
// 封装的函数:删除没有对应 JSON 文件的图片
public static void DeleteUnmatchedImages(string labelsFolderPath, string imagesFolderPath)
{
try
{
// 获取 labels 文件夹中的所有 JSON 文件名(去除扩展名)
string[] jsonFiles = Directory.GetFiles(labelsFolderPath, "*.txt");
HashSet<string> jsonFileNames = new HashSet<string>();
foreach (string jsonFile in jsonFiles)
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(jsonFile);
jsonFileNames.Add(fileNameWithoutExtension);
}
// 获取 images 文件夹中的所有图片文件
string[] imageFiles = Directory.GetFiles(imagesFolderPath);
// 遍历图片文件,检查是否有对应的 JSON 文件
foreach (string imageFile in imageFiles)
{
string imageFileNameWithoutExtension = Path.GetFileNameWithoutExtension(imageFile);
// 如果图片文件名不在 labels 文件夹的 JSON 文件名集合中,则删除该图片
if (!jsonFileNames.Contains(imageFileNameWithoutExtension))
{
try
{
File.Delete(imageFile); // 删除图片
Console.WriteLine($"已删除图片: {Path.GetFileName(imageFile)}");
}
catch (Exception ex)
{
Console.WriteLine($"删除文件 {Path.GetFileName(imageFile)} 时出错: {ex.Message}");
}
}
else
{
Console.WriteLine($"图片 {Path.GetFileName(imageFile)} 有对应的 JSON 文件,不删除。");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"操作失败: {ex.Message}");
}
}
/// <summary>
/// 将 List<string> 保存到指定文件中,格式为 "项,标签"。
/// 标签是根据项的索引生成的。
/// </summary>
/// <param name="items">要保存的字符串列表</param>
/// <param name="filePath">保存文件的路径</param>
public static void SaveItemsToFile(List<string> items, string filePath)
{
// 使用 StreamWriter 写入文件
using (StreamWriter writer = new StreamWriter(filePath))
{
// 遍历 items 列表
for (int i = 0; i < items.Count; i++)
{
// 写入每一行,格式为 "项, 标签"
writer.WriteLine($"{items[i]},{i}");
}
}
}
public static void SaveItemsToFile(HashSet<string> items, string filePath)
{
// 使用 StreamWriter 写入文件
using (StreamWriter writer = new StreamWriter(filePath))
{
// 遍历 HashSet
int i = 0;
foreach (string item in items)
{
// 写入每一行,格式为 "项, 标签"
writer.WriteLine($"{item},{i}"); // 假设使用 item 的长度作为标签
i++;
}
}
}
static List<FileInformation> FileList = new List<FileInformation>();
/// <summary>
/// 递归获取指定文件夹下所有文件
/// </summary>
/// <param name="dir"></param>
/// <returns></returns>
public static List<FileInformation> GetAllFiles(DirectoryInfo dir)
{
FileInfo[] allFile = dir.GetFiles();
foreach (FileInfo fi in allFile)
{
FileList.Add(new FileInformation { FileName = fi.Name, FilePath = fi.FullName });
}
DirectoryInfo[] allDir = dir.GetDirectories();
foreach (DirectoryInfo d in allDir)
{
GetAllFiles(d);
}
return FileList;
}
/// <summary>
/// 判断字符串是否纯字母
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsAlphabetOnly(string input)
{
return Regex.IsMatch(input, "^[a-zA-Z]+$");
}
/// <summary>
/// 判断字符串是否仅包含大小写字母和数字
/// </summary>
/// <param name="input">待判断的字符串</param>
/// <returns>如果字符串仅包含字母和数字,返回 true否则返回 false</returns>
public static bool IsAlphaNumericOnly(string input)
{
return Regex.IsMatch(input, "^[a-zA-Z0-9]+$");
}
public static string ConvertHanzitoPinyinWithNumbers(string input)
{
// 正则表达式匹配汉字
string pattern = @"[\u4e00-\u9fa5]";
Regex regex = new Regex(pattern);
StringBuilder result = new StringBuilder();
int lastIndex = 0;
foreach (Match match in regex.Matches(input))
{
// 将非汉字部分保留为原样
result.Append(input.Substring(lastIndex, match.Index - lastIndex));
// 获取汉字并转换为拼音
string hanzi = match.Value;
string pinyin = ConvertHanziToPinyin(hanzi);
// 将拼音追加到结果中
result.Append(pinyin);
lastIndex = match.Index + match.Length;
}
// 添加最后的非汉字部分
result.Append(input.Substring(lastIndex));
return result.ToString();
}
public static string ConvertHanziToPinyin(string hanzi)
{
// 设置拼音格式去掉音调拼音小写ü保持为u:
PinyinFormat format = PinyinFormat.WITHOUT_TONE | PinyinFormat.LOWERCASE | PinyinFormat.WITH_U_AND_COLON;
// 获取拼音数组
List<PinyinItem> pinyinItems = Pinyin4Net.GetPinyinArray(hanzi, format);
StringBuilder pinyinBuilder = new StringBuilder();
foreach (var item in pinyinItems)
{
// 处理多音字:默认取第一个拼音
if (item.Count > 0)
{
string pinyin = item[0];
// 特殊处理ü的情况
pinyin = pinyin.Replace("u:", "v"); // 将u:转为v这是常见的拼音表示法
pinyinBuilder.Append(pinyin);
}
}
return pinyinBuilder.ToString();
}
/// <summary>
/// 汉字拼音转化
/// </summary>
/// <param name="hanzi"></param>
/// <returns></returns>
//public static string ConvertHanzitoPinyin(string hanzi)
//{
// PinyinFormat format = PinyinFormat.WITHOUT_TONE | PinyinFormat.LOWERCASE | PinyinFormat.WITH_U_UNICODE;
// // string hanzi = defectRow.LabelDescription;
// List<PinyinItem> pylist = Pinyin4Net.GetPinyinArray(hanzi, format);
// // 提取所有拼音并合并为一个字符串
// List<string> pinyinStrings = new List<string>();
// foreach (var item in pylist)
// {
// // 将PinyinItem中的每个拼音List<string>)合并为一个字符串
// string joinedPinyin = string.Join("", item); // 这里的item就是一个List<string>,其中存储了拼音
// pinyinStrings.Add(joinedPinyin); // 添加合并后的拼音
// }
// // 合并所有拼音为一个字符串
// string allPinyin = string.Join("", pinyinStrings);
// return allPinyin;
//}
/// <summary>
/// 递归获取指定文件夹下所有文件
/// </summary>
/// <param name="dir"></param>
/// <returns></returns>
public static List<FileInformation> GetAllFiles(string dir)
{
DirectoryInfo directoryInfo = new(dir);
return GetAllFiles(directoryInfo);
}
public static string OpenSlectDirDialog(string dirpath = "")
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.InitialDirectory = dirpath;
if (fbd.ShowDialog() == DialogResult.OK)
{
string targetDirPath = fbd.SelectedPath;
if (Directory.Exists(targetDirPath))
{
return targetDirPath;
}
else
return string.Empty;
//ImportDirImages(targetDirPath);
}
else
return string.Empty;
}
public static string OpenSlectfileDialog(string dirpath = "")
{
// 创建并配置 OpenFileDialog 实例
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Title = "选择文件"; // 对话框标题
openFileDialog.Filter = "所有文件 (*.pt)|*.*"; // 允许选择任何类型的文件
openFileDialog.InitialDirectory = @"C:\"; // 初始显示目录,可以根据需要修改
// 显示对话框
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
// 获取选中的文件路径
string selectedFilePath = openFileDialog.FileName;
Console.WriteLine("您选择的文件路径是: " + selectedFilePath);
return selectedFilePath;
}
else
{
Console.WriteLine("没有选择任何文件。");
return string.Empty;
MessageBox.Show("没有选择任何文件。");
}
}
}
public class FileInformation
{
public string FileName { get; set; }
public string FilePath { get; set; }
}
}

View File

@ -0,0 +1,107 @@

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DH.Commons.Helper;
namespace DH.Commons.Enums
{
public class ImageSaveHelper
{
public event Action<DateTime, string> OnImageSaveExceptionRaised;
//private string baseDirectory = "";
//public string BaseDirectory
//{
// get => baseDirectory;
// set
// {
// baseDirectory = value;
// if (string.IsNullOrWhiteSpace(baseDirectory) || !Path.IsPathRooted(baseDirectory))
// {
// baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
// }
// }
//}
public bool EnableImageSave { get; set; } = true;
public ImageSaveHelper() { }
public ImageSaveHelper(bool enableImageSave = true)
{
EnableImageSave = enableImageSave;
}
object lockObj = new object();
////耗时操作从 _taskFactory分配线程
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
readonly ConcurrentQueue<ImageSaveSet> _imageQueue = new ConcurrentQueue<ImageSaveSet>();
Task _saveTask = null;
readonly object _saveLock = new object();
public async void ImageSaveAsync(ImageSaveSet set)
{
if (!EnableImageSave)
return;
await Task.Run(() =>
{
_imageQueue.Enqueue(set);
lock (_saveLock)
{
if (_saveTask == null)
{
_saveTask = Task.Run(async () =>
{
try
{
while (true)
{
while (_imageQueue.Count > 0)
{
if (_imageQueue.TryDequeue(out ImageSaveSet saveSet))
{
if (!Directory.Exists(Path.GetDirectoryName(saveSet.FullName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(saveSet.FullName));
}
if (saveSet.SaveImage != null)
{
saveSet.SaveImage.Save(saveSet.FullName, saveSet.ImageFormat);
saveSet.SaveImage.Dispose();
}
saveSet = null;
}
}
await Task.Delay(2000);
}
}
catch (Exception ex)
{
OnImageSaveExceptionRaised?.Invoke(DateTime.Now, $"图片保存异常:{ex.GetExceptionMessage()}");
}
});
}
}
});
}
}
public class ImageSaveSet
{
public string FullName { get; set; }//带后缀 全路径
public Bitmap SaveImage { get; set; }
public ImageFormat ImageFormat { get; set; } = ImageFormat.Jpeg;
}
}

View File

@ -0,0 +1,138 @@
using DH.Commons.Helper;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using static DH.Commons.Enums.EnumHelper;
namespace DH.Commons.Enums
{
public interface ILogOutput
{
event Action<LogMsg> OnLogMsgOutput;
void LogDisplay(LogMsg msg);
}
public interface ILogger
{
event Action<LogMsg> OnLog;
LoggerHelper LoggerHelper { get; set; }
//void LogAsync(DateTime dt, LogLevel loglevel, string msg);
void LogAsync(LogMsg msg);
}
public class LoggerHelper
{
public event Action<DateTime, string> OnLogExceptionRaised;
public string LogPath { get; set; }
public string LogPrefix { get; set; }
LogLevel LogLevel = LogLevel.Information;
public LoggerHelper() { }
public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information)
{
LogPath = logPath;
LogPrefix = logPrefix;
LogLevel = logLevel;
}
public void SetLogLevel(LogLevel logLevel)
{
if (LogLevel != logLevel)
LogLevel = logLevel;
}
////耗时操作从 _taskFactory分配线程
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>();
Task _logTask = null;
readonly object _logLock = new object();
public async void LogAsync(LogMsg msg)
{
await Task.Run(() =>
{
_logQueue.Enqueue(msg);
lock (_logLock)
{
if (_logTask == null)
{
_logTask = Task.Run(async () =>
{
string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt");
try
{
if (!StaticHelper.CheckFilesCanUse(filePath))
{
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用,无法写入");
return;
}
using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8))
{
while (true)
{
if (!Directory.Exists(LogPath))
{
Directory.CreateDirectory(LogPath);
}
while (_logQueue.Count > 0)
{
if (_logQueue.TryDequeue(out LogMsg log))
{
if (log.LogLevel >= LogLevel)
{
writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}\t{log.Msg}");
}
}
}
writer.Flush();
await Task.Delay(2000);
}
}
}
catch (Exception ex)
{
//OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常:/*{ex.GetExceptionMessage()*/}");
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常");
}
});
}
}
});
}
public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
{
LogAsync(new LogMsg(dt, logLevel, msg));
}
}
public class LogMsg
{
public DateTime LogTime { get; set; }
public LogLevel LogLevel { get; set; }
//public string Prefix { get; set; }
public string Msg { get; set; }
public string MsgSource { get; set; }
public int ThreadId { get; set; }
public LogMsg() { }
public LogMsg(DateTime dt, LogLevel logLevel, string msg)
{
LogTime = dt;
LogLevel = logLevel;
Msg = msg;
}
public override string ToString()
{
return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}";
}
}
}

View File

@ -0,0 +1,169 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
namespace DH.Commons.Helper
{
public static class SchemeHelper
{
private const string DefaultSchemeName = "默认方案";
private static readonly string ConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes.json");
/// <summary>
/// 方案配置数据结构
/// </summary>
private class SchemeConfig
{
public List<string> Schemes { get; set; } = new List<string>();
public string CurrentScheme { get; set; } = DefaultSchemeName;
}
/// <summary>
/// 初始化配置(首次运行时调用)
/// </summary>
public static void Initialize()
{
if (!File.Exists(ConfigFilePath))
{
var defaultConfig = new SchemeConfig
{
Schemes = new List<string> { DefaultSchemeName },
CurrentScheme = DefaultSchemeName
};
SaveConfig(defaultConfig);
}
}
/// <summary>
/// 获取所有方案
/// </summary>
public static List<string> GetAllSchemes()
{
var config = LoadConfig();
return config.Schemes ?? new List<string>();
}
/// <summary>
/// 添加新方案
/// </summary>
public static void AddScheme(string schemeName)
{
if (string.IsNullOrWhiteSpace(schemeName))
throw new ArgumentException("方案名称无效");
var config = LoadConfig();
if (config.Schemes.Contains(schemeName))
throw new InvalidOperationException($"方案 {schemeName} 已存在");
config.Schemes.Add(schemeName);
SaveConfig(config);
}
/// <summary>
/// 设置当前方案
/// </summary>
public static void SetCurrentScheme(string schemeName)
{
var config = LoadConfig();
if (!config.Schemes.Contains(schemeName))
throw new KeyNotFoundException($"方案 {schemeName} 不存在");
config.CurrentScheme = schemeName;
SaveConfig(config);
}
/// <summary>
/// 获取当前方案
/// </summary>
public static string GetCurrentScheme()
{
var config = LoadConfig();
return !string.IsNullOrEmpty(config.CurrentScheme)
? config.CurrentScheme
: DefaultSchemeName;
}
/// <summary>
/// 删除指定方案
/// </summary>
public static void DeleteScheme(string schemeName)
{
if (string.IsNullOrWhiteSpace(schemeName))
throw new ArgumentException("方案名称无效");
var config = LoadConfig();
if (!config.Schemes.Contains(schemeName))
throw new KeyNotFoundException($"方案 {schemeName} 不存在");
// 如果是当前方案,需要先切换
if (config.CurrentScheme == schemeName)
{
var otherScheme = config.Schemes.FirstOrDefault(s => s != schemeName);
if (otherScheme != null)
{
config.CurrentScheme = otherScheme;
}
else
{
config.CurrentScheme = DefaultSchemeName;
if (!config.Schemes.Contains(DefaultSchemeName))
{
config.Schemes.Add(DefaultSchemeName);
}
}
}
config.Schemes.Remove(schemeName);
SaveConfig(config);
}
/// <summary>
/// 加载配置文件
/// </summary>
private static SchemeConfig LoadConfig()
{
if (!File.Exists(ConfigFilePath))
{
Initialize();
}
try
{
string json = File.ReadAllText(ConfigFilePath);
return JsonConvert.DeserializeObject<SchemeConfig>(json) ?? new SchemeConfig();
}
catch
{
// 如果读取失败,返回默认配置
return new SchemeConfig
{
Schemes = new List<string> { DefaultSchemeName },
CurrentScheme = DefaultSchemeName
};
}
}
/// <summary>
/// 保存配置文件
/// </summary>
private static void SaveConfig(SchemeConfig config)
{
try
{
string json = JsonConvert.SerializeObject(config, Formatting.Indented);
File.WriteAllText(ConfigFilePath, json);
}
catch (Exception ex)
{
// 处理保存失败的情况
throw new InvalidOperationException("保存方案配置失败", ex);
}
}
}
}

View File

@ -0,0 +1,680 @@
using Microsoft.CSharp.RuntimeBinder;
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.Drawing.Imaging;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
namespace DH.Commons.Helper
{
public static class StaticHelper
{
/// <summary>
/// 数值转换为byte数组 高位在前,低位在后
/// </summary>
/// <param name="number"></param>
/// <param name="size"></param>
/// <returns></returns>
public static byte[] IntToBytes(this int number, int size = 2)
{
byte[] result = new byte[size];
int temp = size;
while (temp > 0)
{
result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff);
temp--;
}
return result;
}
public static T DeepSerializeClone<T>(this T t)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
}
/// <summary>
/// 字节数组转换为整数
/// </summary>
/// <param name="data">字节数组</param>
/// <param name="HtL">true:数组序号低的在高位 false数组序号低的在低位</param>
/// <returns></returns>
public static int BytesToInt(this byte[] data, bool HtL = true)
{
int res = 0;
for (int i = 0; i < data.Length; i++)
{
int index = i;
if (HtL)
{
index = data.Length - 1 - i;
}
res += data[index] << (8 * i);
}
return res;
}
/// <summary>
/// 获取一个类指定的属性值
/// </summary>
/// <param name="info">object对象</param>
/// <param name="field">属性名称</param>
/// <returns></returns>
public static object GetPropertyValue(object info, string field)
{
if (info == null) return null;
Type t = info.GetType();
IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
return property.First().GetValue(info, null);
}
/// <summary>
/// 将32位整形拆分为无符号16位整形
/// </summary>
/// <param name="num">需要拆分的32位整形</param>
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
/// <param name="HtL">true高位在前低位在后false高位在后低位在前</param>
/// <returns></returns>
public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false)
{
if (bitNum == 2)
{
ushort high = (ushort)(num >> 16);
ushort low = (ushort)num;
if (HtL)
{
return new List<ushort>() { high, low };
}
else
{
return new List<ushort>() { low, high };
}
}
else
{
if (num < 0)
{
num = ushort.MaxValue + 1 + num;
}
return new List<ushort>() { (ushort)num };
}
}
/// <summary>
/// 将32位整形数组拆分为无符号16位整形数组
/// </summary>
/// <param name="list">需要拆分的32位整形</param>
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
/// <param name="HtL">true高位在前低位在后false高位在后低位在前</param>
/// <returns></returns>
public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false)
{
return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList();
}
/// <summary>
/// 将ushort的集合转换为16位带符号整形
/// </summary>
/// <param name="numList"></param>
/// <param name="bitNum">合并的位数 1或者2</param>
/// <param name="HtL">true高位在前低位在后false高位在后低位在前</param>
/// <returns></returns>
public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false)
{
if (bitNum == 1)
{
return numList.ConvertAll(n =>
{
int num = n;
if (num > short.MaxValue)
{
num = num - ushort.MaxValue - 1;
}
return num;
});
}
else
{
List<int> list = new List<int>();
for (int i = 0; i < numList.Count; i += 2)
{
int high = HtL ? numList[i] : numList[i + 1];
int low = HtL ? numList[i + 1] : numList[i];
list.Add((high << 16) | low);
}
return list;
}
}
//public static T DeepSerializeClone<T>(this T t)
//{
// return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
//}
public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class
{
if (sourceT == null)
{
destT = null;
return;
}
PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray();
PropertyInfo[] propSource = sourceT.GetType().GetProperties();
Array.ForEach(propDest, prop =>
{
if (exceptionProps == null || !exceptionProps.Contains(prop.Name))
{
if (prop.CanWrite)
{
PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name);
if (propS != null && propS.CanRead)
{
prop.SetValue(destT, propS.GetValue(sourceT));
}
}
}
});
}
//RtlMoveMemory
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
[HandleProcessCorruptedStateExceptions]
//public static Bitmap CopyBitmap(this Bitmap source)
//{
// Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
// try
// {
// int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
// if (PixelSize == 1)
// {
// ColorPalette cp = clone.Palette;
// for (int i = 0; i < 256; i++)
// {
// cp.Entries[i] = Color.FromArgb(255, i, i, i);
// }
// clone.Palette = cp;
// }
// Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
// BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
// BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
// if (source.Width % 4 == 0)
// {
// unsafe
// {
// CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height));
// }
// }
// else
// {
// Parallel.For(0, source.Height, h =>
// {
// unsafe
// {
// CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width);
// }
// });
// }
// clone.UnlockBits(cloneData);
// source.UnlockBits(sourceData);
// }
// catch (Exception ex)
// {
// return clone;
// }
// return clone;
//}
public static Bitmap CopyBitmap(this Bitmap source)
{
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
try
{
int pixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
if (pixelSize == 1)
{
ColorPalette cp = clone.Palette;
for (int i = 0; i < 256; i++)
{
cp.Entries[i] = Color.FromArgb(255, i, i, i);
}
clone.Palette = cp;
}
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
BitmapData cloneData = clone.LockBits(rect, ImageLockMode.WriteOnly, source.PixelFormat);
int stride = sourceData.Stride;
int height = sourceData.Height;
if (stride % 4 == 0)
{
unsafe
{
CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(stride * height));
}
}
else
{
Parallel.For(0, height, h =>
{
unsafe
{
CopyMemory(cloneData.Scan0 + h * stride, sourceData.Scan0 + h * stride, (uint)stride);
}
});
}
source.UnlockBits(sourceData); clone.UnlockBits(cloneData);
}
catch (Exception ex)
{ // Handle or log exception if needed
} return clone; }
public static Bitmap BitmapDeepClone(Bitmap source)
{
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
try
{
int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
if (PixelSize == 1)
{
ColorPalette cp = clone.Palette;
for (int i = 0; i < 256; i++)
{
cp.Entries[i] = Color.FromArgb(255, i, i, i);
}
clone.Palette = cp;
}
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat);
int depth_width = source_bitmap.Width * PixelSize;
unsafe
{
byte* source_ptr = (byte*)source_bitmap.Scan0;
byte* destination_ptr = (byte*)destination_bitmap.Scan0;
int offset = source_bitmap.Stride - depth_width;
for (int i = 0; i < source_bitmap.Height; i++)
{
for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++)
{
*destination_ptr = *source_ptr;
}
source_ptr += offset;
destination_ptr += offset;
}
}
source.UnlockBits(source_bitmap);
clone.UnlockBits(destination_bitmap);
}
catch (Exception ex)
{
}
return clone;
}
public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2)
{
Bitmap connectImage = null;
if (map1 == null || map2 == null)
return null;
//横向拼接
int width = map1.Width + map2.Width;
//高度不变
int height = Math.Max(map1.Height, map2.Height);
connectImage = new Bitmap(width, height);
using (Graphics graph = Graphics.FromImage(connectImage))
{
graph.DrawImage(connectImage, width, height);
graph.Clear(System.Drawing.Color.White);
graph.DrawImage(map1, 0, 0);
graph.DrawImage(map2, map1.Width, 0);
}
return connectImage;
}
public static IntPtr FloatToIntptr(float[] bytes)
{
GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
return hObject.AddrOfPinnedObject();
}
// 将Btimap类转换为byte[]类函数
public static byte[] GetBGRValues(Bitmap bmp, out int stride)
{
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
stride = bmpData.Stride;
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
var imgBytes = bmp.Height * rowBytes;
byte[] rgbValues = new byte[imgBytes];
IntPtr ptr = bmpData.Scan0;
for (var i = 0; i < bmp.Height; i++)
{
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
ptr += bmpData.Stride;
}
bmp.UnlockBits(bmpData);
return rgbValues;
}
/// <summary>
/// 缺陷灰度图转彩色图像函数
/// </summary>
/// <param name="src">灰度图</param>
/// <returns>返回构造的伪彩色图像</returns>
public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null)
{
try
{
//Stopwatch sw = new Stopwatch();
//sw.Start();
Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
int destHeight = dest.Height;
int destWidth = dest.Width;
Rectangle rect = new Rectangle(0, 0, destWidth, destHeight);
BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
int strideDest = bmpDataDest.Stride;
int strideSrc = bmpDataSrc.Stride;
unsafe
{
byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer();
byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer();
Parallel.For(0, destHeight, y =>
{
Parallel.For(0, destWidth, x =>
{
int pixel = pSrc[y * strideSrc + x];
int startIndex = y * strideDest + x * 4;
if (pixel >= 0 && pixel <= 63)
{
Color color = Color.Red;
if (indexColorDict != null && indexColorDict.ContainsKey(pixel))
{
color = indexColorDict[pixel];
}
byte R = color.R;
byte G = color.G;
byte B = color.B;
pDest[startIndex] = B;
pDest[startIndex + 1] = G;
pDest[startIndex + 2] = R;
pDest[startIndex + 3] = 100;
}
else
{
pDest[startIndex] = 255;
pDest[startIndex + 1] = 255;
pDest[startIndex + 2] = 255;
pDest[startIndex + 3] = 0;
}
});
});
}
dest.UnlockBits(bmpDataDest);
src.UnlockBits(bmpDataSrc);
//sw.Stop();
//Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}");
return dest;
}
catch (Exception ex)
{
return null;
}
}
public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T>
{
List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序
for (int i = 0; i < sortedList.Count(); i++)
{
collection.Move(collection.IndexOf(sortedList[i]), i);
}
}
/// <summary>
/// 获得字符串中开始和结束字符串中间的值
/// </summary>
/// <param name="sourse"></param>
/// <param name="startstr"></param>
/// <param name="endstr"></param>
/// <returns></returns>
public static string GetMidString(string sourse, string startstr, string endstr)
{
string result = string.Empty;
int startindex, endindex;
try
{
startindex = sourse.IndexOf(startstr);
if (startindex == -1)
return result;
string tmpstr = sourse.Substring(startindex + startstr.Length);
endindex = tmpstr.IndexOf(endstr);
if (endindex == -1)
return result;
result = tmpstr.Remove(endindex);
}
catch (Exception ex)
{
return "";
}
return result;
}
/// <summary>
/// 获得字符串中开始和结束字符串中间的值
/// </summary>
/// <param name="t">字符串</param>
/// <param name="k">开始</param>
/// <param name="j">结束</param>
/// <returns></returns>
private static string GetMidString2(string sourse, string startstr, string endstr) //截取指定文本,和易语言的取文本中间差不多
{
try //异常捕捉
{
var kn = sourse.IndexOf(startstr, StringComparison.Ordinal) + startstr.Length;
var jn = sourse.IndexOf(endstr, kn, StringComparison.Ordinal);
return sourse.Substring(kn, jn - kn);
}
catch //如果发现未知的错误,比如上面的代码出错了,就执行下面这句代码
{
return ""; //返回空
}
}
// 布尔类型转换为整型
public static int ToInt(this object obj)
{
if (Convert.ToBoolean(obj) == true)
return 1;
else
return 0;
}
// 整型转换为布尔类型
public static bool ToBool(this object obj)
{
if (Convert.ToInt32(obj) == 1)
return true;
else
return false;
}
public static object GetProperty(this object o, string member)
{
if (o == null) throw new ArgumentNullException("o");
if (member == null) throw new ArgumentNullException("member");
Type scope = o.GetType();
IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
if (provider != null)
{
ParameterExpression param = Expression.Parameter(typeof(object));
DynamicMetaObject mobj = provider.GetMetaObject(param);
GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
DynamicMetaObject ret = mobj.BindGetMember(binder);
BlockExpression final = Expression.Block(
Expression.Label(CallSiteBinder.UpdateLabel),
ret.Expression
);
LambdaExpression lambda = Expression.Lambda(final, param);
Delegate del = lambda.Compile();
return del.DynamicInvoke(o);
}
else
{
return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
}
}
#region
[DllImport("kernel32.dll")]
private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hObject);
private const int OF_READWRITE = 2;
private const int OF_SHARE_DENY_NONE = 0x40;
private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
/// <summary>
/// 检测文件是否只读或被使用
/// </summary>
/// <param name="FileNames">要检测的文件</param>
/// <returns>true可用false在用或只读</returns>
public static bool CheckFilesCanUse(string fileName)
{
if (!File.Exists(fileName))
return true;//文件不存在
if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
return false; //文件只读
IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE);
if (vHandle == HFILE_ERROR)
{
CloseHandle(vHandle);
return false; //文件被占用
}
CloseHandle(vHandle); //文件没被占用
return true;
}
#endregion
/// <summary>
/// 获取指定文件夹下所有的文件名称
/// </summary>
/// <param name="folderName">指定文件夹名称,绝对路径</param>
/// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param>
/// <param name="isContainSubFolder">是否包含子文件夹</param>
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false)
{
List<FileInfo> resList = new List<FileInfo>();
try
{
DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录
FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件
foreach (FileInfo file in currFiles)
{
if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0)
{
resList.Add(file);
}
}
if (isContainSubFolder)
{
string[] subFolders = Directory.GetDirectories(folderName);
foreach (string subFolder in subFolders)
{
resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归
}
}
}
catch (Exception ex)
{
throw ex;
}
return resList;
}
/// <summary>
/// 获取指定文件夹下所有的文件名称,不过滤文件类型
/// </summary>
/// <param name="folderName">指定文件夹名称,绝对路径</param>
/// <param name="isContainSubFolder">是否包含子文件夹</param>
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder)
{
return GetAllFilesByFolder(folderName, "*", isContainSubFolder);
}
}
public class Compare<T, C> : IEqualityComparer<T>
{
private Func<T, C> _getField;
public Compare(Func<T, C> getfield)
{
_getField = getfield;
}
public bool Equals(T x, T y)
{
return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));
}
public int GetHashCode(T obj)
{
return EqualityComparer<C>.Default.GetHashCode(_getField(obj));
}
}
public static class ObjectExtensions
{
public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
{
return source.Distinct(new Compare<T, C>(getfield));
}
public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield)
{
return source.Distinct(new Compare<T, C>(getfield));
}
}
}

View File

@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace DH.Commons.Helper
{
/// <summary>
/// 配置文件操作工具类(自动定位主程序配置)
/// </summary>
public static class SystemConfigHelper
{
private static Configuration _mainConfig;
private static readonly object _lock = new object();
/// <summary>
/// 获取主程序配置对象
/// </summary>
private static Configuration MainConfiguration
{
get
{
if (_mainConfig == null)
{
lock (_lock)
{
if (_mainConfig == null)
{
// 获取主程序路径
string exePath = Assembly.GetEntryAssembly().Location;
var configFile = exePath + ".config";
// 加载主程序配置
var fileMap = new ExeConfigurationFileMap
{
ExeConfigFilename = configFile
};
_mainConfig = ConfigurationManager.OpenMappedExeConfiguration(
fileMap,
ConfigurationUserLevel.None
);
}
}
}
return _mainConfig;
}
}
/// <summary>
/// 检查配置项是否存在
/// </summary>
public static bool KeyExists(string key)
{
return MainConfiguration.AppSettings.Settings[key] != null;
}
/// <summary>
/// 读取配置项(带类型自动转换)
/// </summary>
public static T GetValue<T>(string key, T defaultValue = default)
{
try
{
var setting = MainConfiguration.AppSettings.Settings[key];
if (setting == null) return defaultValue;
return (T)Convert.ChangeType(setting.Value, typeof(T));
}
catch
{
return defaultValue;
}
}
/// <summary>
/// 写入配置项(自动保存)
/// </summary>
public static void SetValue(string key, object value)
{
var settings = MainConfiguration.AppSettings.Settings;
var stringValue = value?.ToString() ?? string.Empty;
if (settings[key] == null)
{
settings.Add(key, stringValue);
}
else
{
settings[key].Value = stringValue;
}
SaveChanges();
}
/// <summary>
/// 删除指定配置项
/// </summary>
public static void RemoveKey(string key)
{
if (KeyExists(key))
{
MainConfiguration.AppSettings.Settings.Remove(key);
SaveChanges();
}
}
/// <summary>
/// 保存配置修改
/// </summary>
private static void SaveChanges()
{
MainConfiguration.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
}
}

View File

@ -0,0 +1,109 @@

using System;
using System.ComponentModel;
using System.Drawing.Design;
namespace DH.Commons.Enums
{
/// <summary>
/// 标准配置
/// </summary>
public class Spec
{
[Category("通用配置")]
[Description("标准代码")]
public virtual string Code { get; set; }
[Category("通用配置")]
[Description("启用状态true启用false禁用")]
[DisplayName("启用状态")]
public bool IsEnabled { get; set; }
[Category("标准配置")]
[Description("标准值")]
[DisplayName("标准值")]
public double StandardValue { get; set; }
[Category("标准配置")]
[Description("正公差")]
[DisplayName("正公差")]
public double Tolrenance_Positive { get; set; }
[Category("标准配置")]
[Description("负公差")]
[DisplayName("负公差")]
public double Tolrenance_Negative { get; set; }
protected double? actualValue = null;
[Browsable(false)]
public virtual double? ActualValue
{
get
{
return actualValue;
}
set
{
//if (actualValue != value && value != null)
if (value != null)
{
if (value.Value >= (StandardValue - Tolrenance_Negative) && value.Value <= (StandardValue + Tolrenance_Positive))
{
MeasureResult = true;
}
else
{
MeasureResult = false;
}
}
actualValue = value;
}
}
[Browsable(false)]
public bool? MeasureResult { get; set; } = null;
public Spec Copy()
{
Spec spec = new Spec();
spec.Code = this.Code;
spec.IsEnabled = this.IsEnabled;
spec.StandardValue = this.StandardValue;
spec.Tolrenance_Positive = this.Tolrenance_Positive;
spec.Tolrenance_Negative = this.Tolrenance_Negative;
return spec;
}
}
public class IndexedSpec : Spec
{
[Category("数据源配置")]
[Description("数据源输出索引")]
[DisplayName("数据源输出索引")]
public int OutputIndex { get; set; }
public new IndexedSpec Copy()
{
IndexedSpec spec = new IndexedSpec();
spec.Code = this.Code;
spec.IsEnabled = this.IsEnabled;
spec.StandardValue = this.StandardValue;
spec.Tolrenance_Positive = this.Tolrenance_Positive;
spec.Tolrenance_Negative = this.Tolrenance_Negative;
spec.OutputIndex = this.OutputIndex;
return spec;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DH.Commons.Models
{
public class CameraSummary
{
public string CameraName { get; set; } // 相机名称
public int TiggerCount { get; set; } //触发数
public int OKCount { get; set; } // OK 数
public int NGCount { get; set; } // NG 数
public int TotalCount => OKCount + NGCount; // 总检测数量
public string YieldStr => $"{Yield:f2} %"; // 良率(字符串形式)
public double Yield => OKCount + NGCount > 0 ? (double)OKCount / (OKCount + NGCount) * 100 : 0;
}
public class ProductSummary
{
public int ProductAmount { get; set; }
public string ResultDesc { get; set; }
public string PercentStr { get; set; }
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DH.Commons.Base;
using DH.Commons.Enums;
namespace DH.Commons.Models
{
public static class SystemModel
{
/// <summary>
/// 当前方案
/// </summary>
public static string CurrentScheme=string.Empty;
/// <summary>
/// 当前状态
/// </summary>
public static EnumStatus CurrentStatus =EnumStatus.;
}
/// <summary>
/// 配置集合
/// </summary>
public static class ConfigModel
{
public static List<CameraBase> CameraBaseList = new List<CameraBase>();
public static List<PLCBase> PLCBaseList = new List<PLCBase>();
public static List<DetectionConfig> DetectionList = new List<DetectionConfig>();
public static List<GlobalConfig> GlobalList = new List<GlobalConfig>();
}
}