Files
HawkeyeVision/Hawkeye.VisionBuilder.Workflow/WorkflowList.cs
2025-07-19 15:57:59 +02:00

281 lines
9.5 KiB
C#

using Hawkeye.VisionBuilder.Workflow.Configuration;
using Hawkeye.VisionBuilder.Workflow.Links;
using OpenCvSharp;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Drawing;
using System.Reflection.PortableExecutable;
using System.Xml;
using VisionBuilder.UI.Common.RecipeProcessing;
using Size = OpenCvSharp.Size;
namespace Hawkeye.VisionBuilder.Workflow;
public class WorkflowList
{
public IImageSource ImageSource { get; set; }
public Mat? RecipeImage { get; set; }
public WorkflowConfiguration Configuration { get; set; } = new WorkflowConfiguration();
public List<BaseOperation> Operations { get; set; } = new List<BaseOperation>();
public Context Context { get; set; } = new Context();
private int _executionCounter = 0;
public void Execute()
{
Context.GraphicsElements.Clear();
UpdateConfigVariables();
long total = 0;
foreach (BaseOperation operation in Operations)
{
if (Context.CancellationToken.IsCancellationRequested) break;
operation.Interpret(Context);
}
_executionCounter++;
if (_executionCounter % 10 == 0)
GC.Collect();
}
public BaseOperation GetById(Guid originId)
{
var operation = Operations.FirstOrDefault(x =>
x.Id == originId);
if(operation==null)return NoOrigin.Instance;
return operation as BaseOperation;
}
public IHaveOrigin GetOriginById(Guid originId)
{
return GetById(originId) as IHaveOrigin ?? NoOrigin.Instance;
}
public void ExecuteTill(BaseOperation op)
{
Context.GraphicsElements.Clear();
UpdateConfigVariables();
foreach (BaseOperation operation in Operations)
{
if(operation == op) break;
operation.Interpret(Context);
}
}
public void ExecuteOne(BaseOperation operation)
{
Context.GraphicsElements.Clear();
UpdateConfigVariables();
try
{
operation.Interpret(Context);
}
catch (Exception e)
{
operation.SetError(e.Message);
}
}
void UpdateConfigVariables()
{
BaseOperation.SetScriptValue("config", Configuration);
}
public void Save(BinaryWriter bw)
{
Configuration.Save(bw);
bw.Write(Operations.Count);
foreach (BaseOperation operation in Operations)
{
bw.Write(operation.GetType().AssemblyQualifiedName);
operation.Save(bw);
}
if (RecipeImage == null)
{
var mat = new Mat(128, 128, MatType.CV_8UC3, Scalar.Gray);
var image = mat.ToBytes();
bw.Write(image.Length);
bw.Write(image);
}
else
{
var mat = RecipeImage;
var image = mat.Resize(new Size(128, 128)).ToBytes();
bw.Write(image.Length);
bw.Write(image);
}
}
public event Action PythonMissing=delegate { };
public void Load(BinaryReader br, OperationDiscoveryService operationDiscoveryService)
{
Configuration.Load(br);
if (!File.Exists(Configuration.PythonPath))
PythonMissing();
int count = br.ReadInt32();
Operations.Clear();
for (int i = 0; i < count; i++)
{
string operationType = br.ReadString();
var type=Type.GetType(operationType);
BaseOperation operation = operationDiscoveryService.CreateInstance(type);
operation.Load(br);
Operations.Add(operation);
}
int length = br.ReadInt32();
var image = br.ReadBytes(length);
RecipeImage = Mat.FromImageData(image);
}
public static WorkflowList LoadFromFile(string fileName)
{
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using (var br = new BinaryReader(fs))
{
var workflowList = new WorkflowList();
workflowList.Load(br, new OperationDiscoveryService(workflowList));
return workflowList;
}
}
public void SaveXML(XmlWriter writer)
{
writer.WriteStartElement("Workflow");
// Save Configuration
writer.WriteStartElement("Configuration");
writer.WriteAttributeString("RuntimeCameraType", Configuration.RuntimeCameraType.ToString());
writer.WriteAttributeString("DevelopmentCameraType", Configuration.DevelopmentCameraType.ToString());
writer.WriteAttributeString("Outputs", Configuration.Outputs.ToString());
writer.WriteAttributeString("EmulationPath", Configuration.EmulationPath);
writer.WriteAttributeString("PythonPath", Configuration.PythonPath);
writer.WriteAttributeString("ResultPin", Configuration.ResultPin.ToString());
writer.WriteAttributeString("SerialPort", Configuration.SerialPort);
writer.WriteAttributeString("Delay", Configuration.Delay.ToString());
writer.WriteEndElement(); // Configuration
// Save Operations
writer.WriteStartElement("Operations");
writer.WriteAttributeString("Count", Operations.Count.ToString());
foreach (BaseOperation operation in Operations)
{
writer.WriteStartElement("Operation");
writer.WriteAttributeString("Type", operation.GetType().AssemblyQualifiedName);
operation.SaveXML(writer);
writer.WriteEndElement(); // Operation
}
writer.WriteEndElement(); // Operations
// Save Recipe Image
writer.WriteStartElement("RecipeImage");
if (RecipeImage == null)
{
var mat = new Mat(128, 128, MatType.CV_8UC3, Scalar.Gray);
var image = mat.ToBytes();
writer.WriteAttributeString("Length", image.Length.ToString());
writer.WriteBase64(image, 0, image.Length);
}
else
{
var mat = RecipeImage;
var image = mat.Resize(new Size(128, 128)).ToBytes();
writer.WriteAttributeString("Length", image.Length.ToString());
writer.WriteBase64(image, 0, image.Length);
}
writer.WriteEndElement(); // RecipeImage
writer.WriteEndElement(); // Workflow
}
public void LoadXML(XmlReader reader, OperationDiscoveryService operationDiscoveryService)
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "Configuration":
LoadConfigurationXML(reader);
break;
case "Operations":
LoadOperationsXML(reader, operationDiscoveryService);
break;
case "RecipeImage":
LoadRecipeImageXML(reader);
break;
}
}
}
}
private void LoadConfigurationXML(XmlReader reader)
{
if (reader.GetAttribute("RuntimeCameraType") != null)
Configuration.RuntimeCameraType = Enum.Parse<ECameraType>(reader.GetAttribute("RuntimeCameraType"));
if (reader.GetAttribute("DevelopmentCameraType") != null)
Configuration.DevelopmentCameraType = Enum.Parse<ECameraType>(reader.GetAttribute("DevelopmentCameraType"));
if (reader.GetAttribute("Outputs") != null)
Configuration.Outputs = Enum.Parse<EOutputs>(reader.GetAttribute("Outputs"));
if (reader.GetAttribute("EmulationPath") != null)
Configuration.EmulationPath = reader.GetAttribute("EmulationPath");
if (reader.GetAttribute("PythonPath") != null)
Configuration.PythonPath = reader.GetAttribute("PythonPath");
if (reader.GetAttribute("ResultPin") != null)
Configuration.ResultPin = int.Parse(reader.GetAttribute("ResultPin"));
if (reader.GetAttribute("SerialPort") != null)
Configuration.SerialPort = reader.GetAttribute("SerialPort");
if (reader.GetAttribute("Delay") != null)
Configuration.Delay = int.Parse(reader.GetAttribute("Delay"));
}
private void LoadOperationsXML(XmlReader reader, OperationDiscoveryService operationDiscoveryService)
{
Operations.Clear();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Operation")
{
string operationType = reader.GetAttribute("Type");
var type = Type.GetType(operationType);
if (type != null)
{
BaseOperation operation = operationDiscoveryService.CreateInstance(type);
// go to child elements of Operation
operation.LoadXML(reader);
Operations.Add(operation);
}
}
else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Operations")
{
break;
}
}
}
private void LoadRecipeImageXML(XmlReader reader)
{
if (reader.GetAttribute("Length") != null)
{
int length = int.Parse(reader.GetAttribute("Length"));
byte[] imageData = new byte[length];
int bytesRead = reader.ReadElementContentAsBase64(imageData, 0, length);
if (bytesRead > 0)
{
RecipeImage = Mat.FromImageData(imageData);
}
}
}
}