模板匹配助手在保存模型时写入同名参考位姿 JSON。
训练 ROI 后记录基准中心和角度,保存模型时同步生成同名元数据文件,并在加载模型时自动回读,减少后续对齐配置的人工录入。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
@@ -47,6 +48,10 @@ public class TemplateMatchAssistantViewModel : BindableBase, IDisposable
|
||||
private bool _useSimd = true;
|
||||
private bool _useSubPixel;
|
||||
private bool _isModelReady;
|
||||
private bool _hasReferencePose;
|
||||
private double _referenceCenterX;
|
||||
private double _referenceCenterY;
|
||||
private double _referenceAngle;
|
||||
|
||||
public TemplateMatchAssistantViewModel(
|
||||
IEventAggregator eventAggregator,
|
||||
@@ -244,6 +249,10 @@ public class TemplateMatchAssistantViewModel : BindableBase, IDisposable
|
||||
}
|
||||
|
||||
IsModelReady = true;
|
||||
_hasReferencePose = true;
|
||||
_referenceCenterX = rx + rw * 0.5;
|
||||
_referenceCenterY = ry + rh * 0.5;
|
||||
_referenceAngle = 0.0;
|
||||
StatusMessage = $"模板已从 ROI 学习成功({rw}×{rh} 像素)。可保存模型或运行匹配。";
|
||||
_logger.Info("Template assistant: learned from ROI {0},{1},{2},{3}", rx, ry, rw, rh);
|
||||
}
|
||||
@@ -284,7 +293,19 @@ public class TemplateMatchAssistantViewModel : BindableBase, IDisposable
|
||||
_eventAggregator.GetEvent<TemplateMatchClearRoiOverlayEvent>().Publish();
|
||||
|
||||
IsModelReady = true;
|
||||
StatusMessage = $"已加载模型: {Path.GetFileName(dlg.FileName)}";
|
||||
if (TryLoadModelMetadata(dlg.FileName, out var metadata))
|
||||
{
|
||||
_hasReferencePose = true;
|
||||
_referenceCenterX = metadata.ReferencePose.CenterX;
|
||||
_referenceCenterY = metadata.ReferencePose.CenterY;
|
||||
_referenceAngle = metadata.ReferencePose.Angle;
|
||||
StatusMessage = $"已加载模型: {Path.GetFileName(dlg.FileName)}(已读取同名参考位姿 JSON)";
|
||||
}
|
||||
else
|
||||
{
|
||||
_hasReferencePose = false;
|
||||
StatusMessage = $"已加载模型: {Path.GetFileName(dlg.FileName)}";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -312,7 +333,14 @@ public class TemplateMatchAssistantViewModel : BindableBase, IDisposable
|
||||
lock (_matcherLock)
|
||||
ok = _matcher != null && _matcher.SaveModel(dlg.FileName);
|
||||
if (ok)
|
||||
StatusMessage = $"模型已保存: {dlg.FileName}";
|
||||
{
|
||||
if (TrySaveModelMetadata(dlg.FileName, out var metadataPath, out var metadataError))
|
||||
StatusMessage = $"模型已保存: {dlg.FileName};参考位姿已保存: {metadataPath}";
|
||||
else if (_hasReferencePose)
|
||||
StatusMessage = $"模型已保存: {dlg.FileName};参考位姿 JSON 保存失败: {metadataError}";
|
||||
else
|
||||
StatusMessage = $"模型已保存: {dlg.FileName};未生成参考位姿 JSON(当前无示教基准位姿)。";
|
||||
}
|
||||
else
|
||||
StatusMessage = "模型保存失败。";
|
||||
}
|
||||
@@ -485,6 +513,71 @@ public class TemplateMatchAssistantViewModel : BindableBase, IDisposable
|
||||
return image;
|
||||
}
|
||||
|
||||
private bool TrySaveModelMetadata(string modelPath, out string metadataPath, out string? errorMessage)
|
||||
{
|
||||
metadataPath = Path.ChangeExtension(modelPath, ".json");
|
||||
errorMessage = null;
|
||||
if (!_hasReferencePose)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
string modelFileName = Path.GetFileName(modelPath);
|
||||
string templateName = Path.GetFileNameWithoutExtension(modelPath);
|
||||
var metadata = new TemplateModelMetadata
|
||||
{
|
||||
TemplateName = templateName,
|
||||
ModelFileName = modelFileName,
|
||||
SavedAt = DateTime.Now,
|
||||
ReferencePose = new TemplateReferencePose
|
||||
{
|
||||
CenterX = _referenceCenterX,
|
||||
CenterY = _referenceCenterY,
|
||||
Angle = _referenceAngle
|
||||
}
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(metadata, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
File.WriteAllText(metadataPath, json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = ex.Message;
|
||||
Log.Error(ex, "Save template metadata failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryLoadModelMetadata(string modelPath, out TemplateModelMetadata metadata)
|
||||
{
|
||||
metadata = new TemplateModelMetadata();
|
||||
try
|
||||
{
|
||||
string metadataPath = Path.ChangeExtension(modelPath, ".json");
|
||||
if (!File.Exists(metadataPath))
|
||||
return false;
|
||||
|
||||
string json = File.ReadAllText(metadataPath);
|
||||
var parsed = JsonSerializer.Deserialize<TemplateModelMetadata>(json, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
if (parsed?.ReferencePose == null)
|
||||
return false;
|
||||
|
||||
metadata = parsed;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
@@ -505,3 +598,18 @@ public class TemplateMatchAssistantViewModel : BindableBase, IDisposable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TemplateModelMetadata
|
||||
{
|
||||
public string TemplateName { get; set; } = string.Empty;
|
||||
public string ModelFileName { get; set; } = string.Empty;
|
||||
public DateTime SavedAt { get; set; }
|
||||
public TemplateReferencePose ReferencePose { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class TemplateReferencePose
|
||||
{
|
||||
public double CenterX { get; set; }
|
||||
public double CenterY { get; set; }
|
||||
public double Angle { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user