using System;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Plugins.Vpp.Converters;
using Plugins.Vpp.Views;
using TeamAAS.Camera.Images;
using TeamAAS.Vision;
using TeamAAS.Vision.Calibration.Interfaces;
namespace Plugins.Vpp.Engines
{
///
/// VisionPro 引擎:基于 UCDispVpp 多画面控件(VppWindow 网格 + 双击放大)。
/// 实现 TeamAAS.Vision.IVisualEngine 抽象契约;引擎 SDK(Cognex)只被本插件引用。
/// 同时实现 :为标定算法提供"给图取特征点"能力,
/// 通过一个 Cognex (约定输入 InputImage、输出 Found/Point)完成。
///
public class VisionProEngine : IVisualEngine, ICalibrationVisionProvider
{
public string EngineName => "VisionPro9.0";
// 标定工具(Cognex ToolBlock)与其持久化引用(.vpp 路径)。
private CogToolBlock _calibTool;
private string _toolRef;
public FrameworkElement GetMainView()
{
return UCDispVpp.Instance;
}
public void ApplyHomeLayout(int frameCount, int arrange)
{
// RowColNumber:{画面总数, 排列方式}——内部按最优行列铺设 VppWindow 网格
// frameCount=0 时清空画面区(主页面不显示画面框)
UCDispVpp.Instance.RowColNumber = new[] { frameCount, arrange };
}
public FrameworkElement GetCalibrationView()
{
return new VppCalibrationPage();
}
/// 设置指定画面框的标题(画面名称);index 越界时静默忽略。
public void SetFrameCaption(int index, string name)
{
if (index < 0 || UCDispVpp.Instance.vppWindow.Count <= index) return;
UCDispVpp.Instance.vppWindow[index].SetCaption(name);
}
/// 设置指定画面框的状态圆点显隐;index 越界时静默忽略。
public void SetFrameDotVisible(int index, bool visible)
{
if (index < 0 || UCDispVpp.Instance.vppWindow.Count <= index) return;
UCDispVpp.Instance.vppWindow[index].SetStatusDotVisible(visible);
}
#region ICalibrationVisionProvider
/// 当前标定工具句柄(Cognex CogToolBlock)。
public object CurrentTool => _calibTool;
/// 标定工具持久化引用(.vpp 路径)。
public string ToolRef
{
get { return _toolRef; }
set { _toolRef = value; }
}
///
/// 在图像上运行标定 ToolBlock,返回特征点像素坐标。
/// 约定:ToolBlock 输入终端 "InputImage",输出终端 "Found"(bool)、"Point"(字符串 "x,y[,angle]")。
///
public Task<(bool found, double px, double py, double angle)> FindCalibPoint(GenImage image)
{
return Task.Run(() =>
{
try
{
if (_calibTool == null || image == null) return (false, 0d, 0d, 0d);
ICogImage cog = GenImageConverter.ToCogImage(image);
if (cog == null) return (false, 0d, 0d, 0d);
var input = _calibTool.Inputs["InputImage"];
if (input != null) input.Value = cog;
_calibTool.Run();
CogToolBlockTerminalCollection outputs = _calibTool.Outputs;
var foundTerminal = outputs["Found"];
bool found = foundTerminal != null && foundTerminal.Value != null && Convert.ToBoolean(foundTerminal.Value);
if (!found) return (false, 0d, 0d, 0d);
double px = 0, py = 0, angle = 0;
var pointTerminal = outputs["Point"];
if (pointTerminal != null && pointTerminal.Value != null)
{
ParsePoint(pointTerminal.Value, ref px, ref py, ref angle);
}
return (true, px, py, angle);
}
catch
{
return (false, 0d, 0d, 0d);
}
});
}
/// 畸变校正:VisionPro 引擎暂原样返回(如需棋盘格校正后续在此接入)。
public Task Undistort(GenImage image)
{
return Task.FromResult(image);
}
/// 从 .vpp 引用加载标定 ToolBlock;引用为空或加载失败时新建空 ToolBlock。
public void LoadTool(string toolRef)
{
_toolRef = toolRef;
_calibTool = null;
try
{
if (!string.IsNullOrEmpty(toolRef) && File.Exists(toolRef))
{
_calibTool = CogSerializer.LoadObjectFromFile(toolRef) as CogToolBlock;
}
}
catch
{
_calibTool = null;
}
if (_calibTool == null) _calibTool = new CogToolBlock();
}
/// 将当前标定 ToolBlock 保存到目录下的 CalibTool.vpp,返回该路径作为持久化引用。
public string SaveTool(string directory)
{
if (_calibTool == null) return _toolRef;
try
{
if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
string path = Path.Combine(directory, "CalibTool.vpp");
CogSerializer.SaveObjectToFile(_calibTool, path);
_toolRef = path;
return path;
}
catch
{
return _toolRef;
}
}
private static void ParsePoint(object value, ref double px, ref double py, ref double angle)
{
string s = value.ToString();
if (string.IsNullOrWhiteSpace(s)) return;
string[] items = s.Split(',');
if (items.Length >= 2
&& double.TryParse(items[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double x)
&& double.TryParse(items[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double y))
{
px = x; py = y;
}
if (items.Length >= 3
&& double.TryParse(items[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double a))
{
angle = a;
}
}
#endregion
}
}