309 lines
9.8 KiB
C#
309 lines
9.8 KiB
C#
using Hawkeye.VisionBuilder.Workflow.Datatypes;
|
|
using Hawkeye.VisionBuilder.Workflow.Links;
|
|
using Hawkeye.VisionBuilder.Workflow.Operations.Attributes;
|
|
using Microsoft.Scripting.Hosting;
|
|
using Ninject.Infrastructure.Language;
|
|
using OpenCvSharp;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Runtime;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text.RegularExpressions;
|
|
using System.Xml;
|
|
using System.Xml.Linq;
|
|
using Serilog;
|
|
using RectangleElement = Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Rectangle.RectangleElement;
|
|
|
|
namespace Hawkeye.VisionBuilder.Workflow
|
|
{
|
|
public abstract class BaseOperation
|
|
{
|
|
private static readonly ScriptScope _scope;
|
|
private static readonly ScriptEngine _engine;
|
|
|
|
static BaseOperation()
|
|
{
|
|
_engine = IronPython.Hosting.Python.CreateEngine();
|
|
_scope = _engine.CreateScope();
|
|
}
|
|
protected BaseOperation()
|
|
{
|
|
TypeName = MakeOperationName(this.GetType().Name);
|
|
Label = MakeOperationName(this.GetType().Name,false);
|
|
|
|
|
|
}
|
|
|
|
public static void SetScriptValue<T>(string name, T value)
|
|
{
|
|
_scope.SetVariable(name,value);
|
|
}
|
|
|
|
public static T GetScriptValue<T>(ScriptValue scriptValue)
|
|
{
|
|
return _engine.Execute<T>(scriptValue.Script,_scope);
|
|
}
|
|
[NotForTool]
|
|
public bool CanHaveProcessingError { get; set; } = true;
|
|
[NotForTool]
|
|
public string Status { get; set; }
|
|
|
|
protected bool CheckImageExists(Context context)
|
|
{
|
|
if (context.ActiveImage == null)
|
|
{
|
|
Status = "No image available";
|
|
Result = false;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected bool CheckColorful(Context context)
|
|
{
|
|
if (context.ActiveImage.ImageData.Type() != MatType.CV_8UC3)
|
|
{
|
|
Status="Image is not colorful";
|
|
Result = false;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected bool CheckGrayscale(Context context)
|
|
{
|
|
if (context.ActiveImage.ImageData.Type() != MatType.CV_8UC1)
|
|
{
|
|
Status="Image is not grayscale";
|
|
Result = false;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
[NotForTool]
|
|
public bool NeedsUpdate { get; set; } = true;
|
|
[NotForTool]
|
|
public Guid Id { get; protected set; }= Guid.NewGuid();
|
|
public static string MakeOperationName(string typeName,bool useSpaces=true)
|
|
{
|
|
return Regex.Replace(typeName.Replace("Operation", ""), "(\\B[A-Z]+?(?=[A-Z][^A-Z])|\\B[A-Z]+?(?=[^A-Z]))", (useSpaces?" ":"")+"$1");
|
|
}
|
|
[NotForTool]
|
|
public bool Result { get; set; } = true;
|
|
[NotForTool]
|
|
public string ResultString
|
|
{
|
|
get
|
|
{
|
|
return this.ToString();
|
|
}
|
|
}
|
|
[NotForTool]
|
|
public string TypeName { get; private set; }
|
|
[NotForTool]
|
|
public string Label { get; set; }
|
|
|
|
[NotForTool]
|
|
public bool Enabled { get; set; } = true;
|
|
|
|
[NotForTool]
|
|
public TimeSpan ExecutionTime { get; set; }
|
|
[NotForTool]
|
|
public string ExecutionTimeString
|
|
{
|
|
get
|
|
{
|
|
return ((int)ExecutionTime.TotalMilliseconds) + " ms";
|
|
}
|
|
}
|
|
|
|
public void Interpret(Context context)
|
|
{
|
|
|
|
|
|
Result = true;
|
|
Status = "";
|
|
Stopwatch sw = Stopwatch.StartNew();
|
|
InterpretInternal(context);
|
|
sw.Stop();
|
|
ExecutionTime = sw.Elapsed;
|
|
_scope.SetVariable(Label,this);
|
|
|
|
}
|
|
|
|
protected abstract void InterpretInternal(Context context);
|
|
|
|
public Dictionary<string, object> GetParameters()
|
|
{
|
|
|
|
var props = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
.Where(x=>!x.HasAttribute(typeof(NotForToolAttribute)));
|
|
return props.ToDictionary(x => x.Name, x => x.GetValue(this)!);
|
|
}
|
|
|
|
public virtual void SetParameters(Dictionary<string, object> parameters)
|
|
{
|
|
foreach (KeyValuePair<string, object> pair in parameters)
|
|
{
|
|
this.GetType().GetProperty(pair.Key,
|
|
BindingFlags.Public | BindingFlags.Instance )
|
|
?.SetValue(this,pair.Value);
|
|
}
|
|
}
|
|
|
|
|
|
public virtual void SaveXML(XmlWriter writer)
|
|
{
|
|
writer.WriteAttributeString("Id", Id.ToString());
|
|
writer.WriteAttributeString("Label", Label);
|
|
|
|
// Save all public properties that are not marked with NotForTool
|
|
var properties = GetParameters();
|
|
foreach (var property in properties)
|
|
{
|
|
if (property.Value != null)
|
|
{
|
|
writer.WriteStartElement("Property");
|
|
writer.WriteAttributeString("Name", property.Key);
|
|
writer.WriteAttributeString("Type", property.Value.GetType().FullName);
|
|
|
|
// Handle different types appropriately
|
|
if (property.Value is string || property.Value.GetType().IsPrimitive || property.Value.GetType().IsEnum)
|
|
{
|
|
writer.WriteString(property.Value.ToString());
|
|
}
|
|
else if (property.Value is Guid guid)
|
|
{
|
|
writer.WriteString(guid.ToString());
|
|
}
|
|
else
|
|
{
|
|
// For complex types, convert to string representation
|
|
writer.WriteString(property.Value.ToString());
|
|
}
|
|
|
|
writer.WriteEndElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void LoadXML(XmlReader reader)
|
|
{
|
|
if (reader.GetAttribute("Id") != null)
|
|
Id = new Guid(reader.GetAttribute("Id"));
|
|
if (reader.GetAttribute("Label") != null)
|
|
Label = reader.GetAttribute("Label");
|
|
|
|
var properties = new Dictionary<string, object>();
|
|
|
|
while (reader.Read())
|
|
{
|
|
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Property")
|
|
{
|
|
string propertyName = reader.GetAttribute("Name");
|
|
string propertyType = reader.GetAttribute("Type");
|
|
string propertyValue = reader.ReadElementContentAsString();
|
|
|
|
if (!string.IsNullOrEmpty(propertyName) && !string.IsNullOrEmpty(propertyValue))
|
|
{
|
|
// Convert string value back to appropriate type
|
|
object convertedValue = ConvertFromString(propertyValue, propertyType);
|
|
if (convertedValue != null)
|
|
{
|
|
properties[propertyName] = convertedValue;
|
|
}
|
|
}
|
|
}
|
|
else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == GetOperationElementName())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (properties.Count > 0)
|
|
{
|
|
SetParameters(properties);
|
|
}
|
|
}
|
|
|
|
private string GetOperationElementName()
|
|
{
|
|
return this.GetType().Name;
|
|
}
|
|
|
|
private object ConvertFromString(string value, string typeName)
|
|
{
|
|
try
|
|
{
|
|
var type = Type.GetType(typeName);
|
|
if (type == null) return value;
|
|
|
|
if (type == typeof(string))
|
|
return value;
|
|
else if (type == typeof(int))
|
|
return int.Parse(value);
|
|
else if (type == typeof(double))
|
|
return double.Parse(value);
|
|
else if (type == typeof(float))
|
|
return float.Parse(value);
|
|
else if (type == typeof(bool))
|
|
return bool.Parse(value);
|
|
else if (type == typeof(Guid))
|
|
return new Guid(value);
|
|
else if (type.IsEnum)
|
|
return Enum.Parse(type, value);
|
|
else
|
|
return value; // Fallback to string
|
|
}
|
|
catch
|
|
{
|
|
return value; // Fallback to string if conversion fails
|
|
}
|
|
}
|
|
|
|
|
|
public override string ToString()
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
public virtual void Save(BinaryWriter bw)
|
|
{
|
|
bw.Write(Id.ToString());
|
|
bw.Write(Label);
|
|
}
|
|
|
|
public virtual void Load(BinaryReader br)
|
|
{
|
|
Id = new Guid(br.ReadString());
|
|
Label = br.ReadString();
|
|
}
|
|
|
|
public virtual void Save(Dictionary<string, object> dict)
|
|
{
|
|
dict[nameof(Id)] = Id.ToString();
|
|
dict[nameof(Label)] = Label;
|
|
dict[nameof(Enabled)] = Enabled;
|
|
}
|
|
|
|
public virtual void Load(Dictionary<string, object> dict)
|
|
{
|
|
if (dict.ContainsKey(nameof(Id)))
|
|
Id = new Guid(dict[nameof(Id)].ToString());
|
|
if (dict.ContainsKey(nameof(Label)))
|
|
Label = dict[nameof(Label)].ToString();
|
|
if (dict.ContainsKey(nameof(Enabled)))
|
|
Enabled = Convert.ToBoolean(dict[nameof(Enabled)]);
|
|
}
|
|
|
|
public void SetError(string eMessage)
|
|
{
|
|
Log.Information($"Processing error on {Label}:{eMessage}");
|
|
Status=eMessage;
|
|
Result = false;
|
|
}
|
|
}
|
|
} |