对算法输入参数非法情况进行过滤
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
using Emgu.CV;
|
using Emgu.CV;
|
||||||
using Emgu.CV.Structure;
|
using Emgu.CV.Structure;
|
||||||
using Emgu.CV.Util;
|
using Emgu.CV.Util;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace XP.ImageProcessing.Core;
|
namespace XP.ImageProcessing.Core;
|
||||||
|
|
||||||
@@ -164,11 +165,45 @@ public abstract class ImageProcessorBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public T GetParameter<T>(string name)
|
public T GetParameter<T>(string name)
|
||||||
{
|
{
|
||||||
if (Parameters.ContainsKey(name))
|
if (!Parameters.ContainsKey(name))
|
||||||
{
|
|
||||||
return (T)Convert.ChangeType(Parameters[name].Value, typeof(T))!;
|
|
||||||
}
|
|
||||||
throw new ArgumentException($"参数 {name} 不存在");
|
throw new ArgumentException($"参数 {name} 不存在");
|
||||||
|
|
||||||
|
var parameter = Parameters[name];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (parameter.Value is T typedValue)
|
||||||
|
return typedValue;
|
||||||
|
|
||||||
|
if (parameter.Value is string textValue)
|
||||||
|
{
|
||||||
|
var normalizedText = NormalizeText(textValue);
|
||||||
|
if (typeof(T) == typeof(string))
|
||||||
|
return (T)(object)textValue;
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(int) && int.TryParse(normalizedText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
|
||||||
|
return (T)(object)intValue;
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(double) && double.TryParse(normalizedText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
|
||||||
|
return (T)(object)doubleValue;
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(bool) && bool.TryParse(normalizedText, out var boolValue))
|
||||||
|
return (T)(object)boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)Convert.ChangeType(parameter.Value, typeof(T), CultureInfo.InvariantCulture)!;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
$"参数 {name} 的值 '{parameter.Value}' 无法转换为 {typeof(T).Name}",
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeText(string value)
|
||||||
|
{
|
||||||
|
return value.Trim().TrimEnd('、', ',', ',', '。', '.', ';', ';', ':', ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class SuperResolutionProcessor : ImageProcessorBase
|
|||||||
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
|
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
|
||||||
{
|
{
|
||||||
string model = GetParameter<string>("Model");
|
string model = GetParameter<string>("Model");
|
||||||
int scale = int.Parse(GetParameter<string>("Scale"));
|
int scale = GetParameter<int>("Scale");
|
||||||
|
|
||||||
// 查找模型文件
|
// 查找模型文件
|
||||||
string modelPath = FindModelFile(model, scale);
|
string modelPath = FindModelFile(model, scale);
|
||||||
|
|||||||
@@ -46,6 +46,19 @@ namespace XplorePlane.Services
|
|||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var node = enabledNodes[step];
|
var node = enabledNodes[step];
|
||||||
|
var invalidParameters = node.Parameters
|
||||||
|
.Where(p => !p.IsValueValid)
|
||||||
|
.Select(p => p.DisplayName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (invalidParameters.Count > 0)
|
||||||
|
{
|
||||||
|
throw new PipelineExecutionException(
|
||||||
|
$"算子 '{node.DisplayName}' 存在无效参数:{string.Join("、", invalidParameters)}",
|
||||||
|
node.Order,
|
||||||
|
node.OperatorKey);
|
||||||
|
}
|
||||||
|
|
||||||
var parameters = node.Parameters
|
var parameters = node.Parameters
|
||||||
.Where(p => p.IsValueValid)
|
.Where(p => p.IsValueValid)
|
||||||
.ToDictionary(p => p.Name, p => p.Value);
|
.ToDictionary(p => p.Name, p => p.Value);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Prism.Mvvm;
|
using Prism.Mvvm;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using XP.ImageProcessing.Core;
|
using XP.ImageProcessing.Core;
|
||||||
|
|
||||||
namespace XplorePlane.ViewModels
|
namespace XplorePlane.ViewModels
|
||||||
@@ -16,7 +18,8 @@ namespace XplorePlane.ViewModels
|
|||||||
_value = parameter.Value;
|
_value = parameter.Value;
|
||||||
MinValue = parameter.MinValue;
|
MinValue = parameter.MinValue;
|
||||||
MaxValue = parameter.MaxValue;
|
MaxValue = parameter.MaxValue;
|
||||||
ParameterType = parameter.ValueType?.Name?.ToLower() switch
|
Options = parameter.Options;
|
||||||
|
ParameterType = parameter.ValueType?.Name?.ToLowerInvariant() switch
|
||||||
{
|
{
|
||||||
"int32" or "int" => "int",
|
"int32" or "int" => "int",
|
||||||
"double" => "double",
|
"double" => "double",
|
||||||
@@ -30,6 +33,7 @@ namespace XplorePlane.ViewModels
|
|||||||
public string DisplayName { get; }
|
public string DisplayName { get; }
|
||||||
public object MinValue { get; }
|
public object MinValue { get; }
|
||||||
public object MaxValue { get; }
|
public object MaxValue { get; }
|
||||||
|
public string[]? Options { get; }
|
||||||
public string ParameterType { get; }
|
public string ParameterType { get; }
|
||||||
|
|
||||||
public bool IsValueValid
|
public bool IsValueValid
|
||||||
@@ -43,28 +47,160 @@ namespace XplorePlane.ViewModels
|
|||||||
get => _value;
|
get => _value;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (SetProperty(ref _value, value))
|
var normalizedValue = NormalizeValue(value);
|
||||||
ValidateValue(value);
|
if (SetProperty(ref _value, normalizedValue))
|
||||||
|
ValidateValue(normalizedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateValue(object value)
|
private void ValidateValue(object value)
|
||||||
{
|
{
|
||||||
if (value == null || MinValue == null || MaxValue == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
IsValueValid = true;
|
IsValueValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ParameterType == "int")
|
||||||
|
{
|
||||||
|
IsValueValid = TryConvertToInt(value, out var intValue) && IsWithinRange(intValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ParameterType == "double")
|
||||||
|
{
|
||||||
|
IsValueValid = TryConvertToDouble(value, out var doubleValue) && IsWithinRange(doubleValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ParameterType == "bool")
|
||||||
|
{
|
||||||
|
IsValueValid = TryConvertToBool(value, out _);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Options is { Length: > 0 })
|
||||||
|
{
|
||||||
|
var stringValue = Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty;
|
||||||
|
IsValueValid = Options.Contains(stringValue, StringComparer.OrdinalIgnoreCase);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsValueValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object NormalizeValue(object value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
if (ParameterType == "int" && TryConvertToInt(value, out var intValue))
|
||||||
|
return intValue;
|
||||||
|
|
||||||
|
if (ParameterType == "double" && TryConvertToDouble(value, out var doubleValue))
|
||||||
|
return doubleValue;
|
||||||
|
|
||||||
|
if (ParameterType == "bool" && TryConvertToBool(value, out var boolValue))
|
||||||
|
return boolValue;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsWithinRange(double value)
|
||||||
|
{
|
||||||
|
if (MinValue != null && TryConvertToDouble(MinValue, out var minValue) && value < minValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (MaxValue != null && TryConvertToDouble(MaxValue, out var maxValue) && value > maxValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeNumericText(string value)
|
||||||
|
{
|
||||||
|
return value.Trim().TrimEnd('、', ',', ',', '。', '.', ';', ';', ':', ':');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryConvertToInt(object value, out int result)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case int intValue:
|
||||||
|
result = intValue;
|
||||||
|
return true;
|
||||||
|
case string stringValue:
|
||||||
|
stringValue = NormalizeNumericText(stringValue);
|
||||||
|
return int.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)
|
||||||
|
|| int.TryParse(stringValue, NumberStyles.Integer, CultureInfo.CurrentCulture, out result);
|
||||||
|
default:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
double dVal = Convert.ToDouble(value);
|
result = Convert.ToInt32(value, CultureInfo.InvariantCulture);
|
||||||
double dMin = Convert.ToDouble(MinValue);
|
return true;
|
||||||
double dMax = Convert.ToDouble(MaxValue);
|
|
||||||
IsValueValid = dVal >= dMin && dVal <= dMax;
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
IsValueValid = true; // é�žæ•°å€¼ç±»åž‹ä¸�å�šèŒƒå›´æ ¡éª?
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryConvertToDouble(object value, out double result)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case double doubleValue:
|
||||||
|
result = doubleValue;
|
||||||
|
return true;
|
||||||
|
case float floatValue:
|
||||||
|
result = floatValue;
|
||||||
|
return true;
|
||||||
|
case int intValue:
|
||||||
|
result = intValue;
|
||||||
|
return true;
|
||||||
|
case long longValue:
|
||||||
|
result = longValue;
|
||||||
|
return true;
|
||||||
|
case string stringValue:
|
||||||
|
stringValue = NormalizeNumericText(stringValue);
|
||||||
|
return double.TryParse(stringValue, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out result)
|
||||||
|
|| double.TryParse(stringValue, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.CurrentCulture, out result);
|
||||||
|
default:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = Convert.ToDouble(value, CultureInfo.InvariantCulture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryConvertToBool(object value, out bool result)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case bool boolValue:
|
||||||
|
result = boolValue;
|
||||||
|
return true;
|
||||||
|
case string stringValue:
|
||||||
|
return bool.TryParse(stringValue.Trim(), out result);
|
||||||
|
default:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = Convert.ToBoolean(value, CultureInfo.InvariantCulture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,7 +319,7 @@
|
|||||||
telerik:ScreenTip.Title="模块"
|
telerik:ScreenTip.Title="模块"
|
||||||
Size="Medium"
|
Size="Medium"
|
||||||
SmallImage="/Assets/Icons/Module.png"
|
SmallImage="/Assets/Icons/Module.png"
|
||||||
Text="模块" />
|
Text="检测模块" />
|
||||||
<telerik:RadRibbonButton
|
<telerik:RadRibbonButton
|
||||||
telerik:ScreenTip.Title="全部保存"
|
telerik:ScreenTip.Title="全部保存"
|
||||||
Size="Medium"
|
Size="Medium"
|
||||||
@@ -331,12 +331,12 @@
|
|||||||
telerik:ScreenTip.Title="消息"
|
telerik:ScreenTip.Title="消息"
|
||||||
Size="Medium"
|
Size="Medium"
|
||||||
SmallImage="/Assets/Icons/message.png"
|
SmallImage="/Assets/Icons/message.png"
|
||||||
Text="消息" />
|
Text="消息弹窗" />
|
||||||
<telerik:RadRibbonButton
|
<telerik:RadRibbonButton
|
||||||
telerik:ScreenTip.Title="等待"
|
telerik:ScreenTip.Title="等待"
|
||||||
Size="Medium"
|
Size="Medium"
|
||||||
SmallImage="/Assets/Icons/wait.png"
|
SmallImage="/Assets/Icons/wait.png"
|
||||||
Text="等待" />
|
Text="插入等待" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</telerik:RadRibbonGroup>
|
</telerik:RadRibbonGroup>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user