using HalconDotNet;
|
using Newtonsoft.Json;
|
using OpenCvSharp;
|
using OpenCvSharp.Extensions;
|
using System.Collections.Concurrent;
|
using System.Diagnostics;
|
using System.Text;
|
using static LB_VisionProcesses.Alogrithms.OpenCvSharp.FindModelTool;
|
using Point = OpenCvSharp.Point;
|
using Size = OpenCvSharp.Size;
|
|
namespace LB_VisionProcesses.Alogrithms.OpenCvSharp
|
{
|
public class FindModelTool : TAlgorithm
|
{
|
public enum ModelType { 灰度匹配 };
|
|
public OModel ModelID = new OModel();
|
|
public FindModelTool()
|
{
|
strProcessClass = "LB_VisionProcesses.Alogrithms.OpenCvSharp.FindModelTool";
|
strProcessName = "OpenCvSharp_模板匹配工具";
|
|
Params.Inputs.Add("ModelType", ModelType.灰度匹配);
|
|
//AngleStart:搜索时的起始角度[需要转换为弧度]
|
Params.Inputs.Add("AngleStart", -5.0);
|
//AngleExtent:搜索时的角度范围,0表示无角度搜索[需要转换为弧度]
|
Params.Inputs.Add("AngleExtent", 10.0);
|
//AngleStep:角度步长--弧度[角度步长 >= 0和角度步长 <= pi / 16]
|
Params.Inputs.Add("AngleStep", "auto");
|
Params.Inputs.Add("ScaleRMin", 0.9);
|
Params.Inputs.Add("ScaleRMax", 1.1);
|
Params.Inputs.Add("ScaleCMin", 0.9);
|
Params.Inputs.Add("ScaleCMax", 1.1);
|
//MinScore:被找到的模板最小分数
|
Params.Inputs.Add("MinScore", 0.5);
|
//NumMatches:要找到的模板最多的实例数,0则找到所有可能的匹配
|
Params.Inputs.Add("NumMatches", 0);
|
//MaxOverlap:允许找到的模型实例的最大重叠比例, 建议值:0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0
|
Params.Inputs.Add("MaxOverlap", 0.2);
|
//SubPixel:计算精度的设置
|
//'none' 不适用亚像素,最大误差为半个像素
|
//'interpolation' 差值得到亚像素精度
|
//'least_squares', 'least_squares_high', 'least_squares_very_high'
|
//'max_deformation 1', 'max_deformation 2', 'max_deformation 3', 'max_deformation 4'
|
Params.Inputs.Add("SubPixel", "none");
|
//NumLevels:搜索时金字塔的层级,0表示不使用金字塔
|
Params.Inputs.Add("NumLevels", 0);
|
//Greediness:贪婪度,搜索启发式,一般都设为2,越小速度越快,容易出现找不到的情况
|
Params.Inputs.Add("Greediness", 2);
|
Params.Inputs.Add("ResultType", "");
|
|
Params.Inputs.Add("MinCount", 0);
|
Params.Inputs.Add("MaxCount", 9999);
|
|
Params.Outputs.Add("CenterX", new List<double>());
|
Params.Outputs.Add("CenterY", new List<double>());
|
Params.Outputs.Add("Phi", new List<double>());
|
Params.Outputs.Add("Score", new List<double>());
|
Params.Outputs.Add("Count", 0);
|
}
|
|
private static readonly object lockObj = new object();
|
/// <summary>
|
/// 运行算子
|
/// </summary>
|
public override void TAlgorithmMain()
|
{
|
lock (lockObj)
|
{
|
try
|
{
|
if (InputImage == null)
|
{
|
Msg = "输入图片为空";
|
Result = false;
|
return;
|
}
|
if (InputImage is Bitmap)
|
{
|
try
|
{
|
using (Mat hImage = ((Bitmap)InputImage).ToMat())
|
{
|
//((Bitmap)InputImage).Dispose();
|
InputImage = null;
|
InputImage = hImage.Clone();
|
}
|
}
|
catch (Exception ex)
|
{
|
}
|
}
|
if (!(InputImage is Mat))
|
{
|
Msg = "输入图片格式不为Mat";
|
Result = false;
|
return;
|
}
|
|
#region 裁剪区域
|
object DomainImage = null;
|
|
if (!ReduceDomainImage(InputImage, ref DomainImage))
|
{
|
Msg = "裁剪区域失败";
|
Result = false;
|
return;
|
}
|
|
Mat hoDomainImage = DomainImage as Mat;
|
//判断是否为灰度图
|
try
|
{
|
if (hoDomainImage.Channels() != 1)
|
Cv2.CvtColor(hoDomainImage, hoDomainImage, ColorConversionCodes.RGB2GRAY);
|
|
//转换后再次检查是否为灰度图
|
if (hoDomainImage.Channels() != 1)
|
{
|
Msg = "输入图片不为灰度图";
|
Result = false;
|
return;
|
}
|
}
|
catch
|
{
|
Msg = "输入图片不为灰度图且转换失败";
|
Result = false;
|
return;
|
}
|
#endregion
|
|
//判断是否有模板
|
if (ModelID.hoImage == null || ModelID.hoImage.Empty())
|
{
|
Msg = "未创建模板";
|
Result = false;
|
return;
|
}
|
|
#region 算子逻辑
|
Record = new ObjectRecord();
|
ModelType type = ModelID.Type;
|
int ho_ModelWidth = ModelID.Width;
|
int ho_ModelHeight = ModelID.Height;
|
|
double AngleStart = Convert.ToDouble(Params.Inputs["AngleStart"]);
|
double AngleExtent = Convert.ToDouble(Params.Inputs["AngleExtent"]);
|
double MinScore = Convert.ToDouble(Params.Inputs["MinScore"]);
|
int NumMatches = ProcessParams.ConvertToInt32(Params.Inputs["NumMatches"]);
|
double MaxOverlap = Convert.ToDouble(Params.Inputs["MaxOverlap"]);
|
string SubPixel = ProcessParams.ConvertToString(Params.Inputs["SubPixel"]);
|
string NumLevels = ProcessParams.ConvertToString(Params.Inputs["NumLevels"]);
|
double Greediness = Convert.ToDouble(Params.Inputs["Greediness"]);
|
|
double ScaleRMin = Convert.ToDouble(Params.Inputs["ScaleRMin"]);
|
double ScaleRMax = Convert.ToDouble(Params.Inputs["ScaleRMax"]);
|
double ScaleCMin = Convert.ToDouble(Params.Inputs["ScaleCMin"]);
|
double ScaleCMax = Convert.ToDouble(Params.Inputs["ScaleCMax"]);
|
|
double ScaleMin = ScaleCMin > ScaleRMin ? ScaleRMin : ScaleCMin;
|
double ScaleMax = ScaleCMax > ScaleRMax ? ScaleRMax : ScaleCMax;
|
double ScaleStep = (ScaleMax - ScaleMin) / Greediness;
|
|
List<RotatedRect> results = new List<RotatedRect>();
|
switch (type)
|
{
|
case ModelType.灰度匹配:
|
// 执行灰度匹配
|
results = MultiAngleTemplateMatch(hoDomainImage, ModelID.hoImage, AngleStart, AngleStart + AngleExtent, AngleExtent / Greediness
|
, ScaleMin, ScaleMax, ScaleStep, MinScore, MaxOverlap);
|
|
break;
|
default:
|
Msg = "不支持的模板";
|
Result = false;
|
return;
|
}
|
#endregion
|
|
#region 结果处理
|
List<double> CenterX = new List<double>();
|
List<double> CenterY = new List<double>();
|
List<double> Phi = new List<double>();
|
List<double> Score = new List<double>();
|
for (int i = 0; i < results.Count; i++)
|
{
|
CenterX.Add(results[i].Center.X);
|
CenterY.Add(results[i].Center.Y);
|
Phi.Add(results[i].Angle / 180 * Math.PI);
|
|
HOperatorSet.GenRectangle2(out HObject hRectangle, CenterY[i], CenterX[i], Phi[i], ho_ModelWidth / 2, ho_ModelHeight / 2);
|
((ObjectRecord)Record).AddRecord(hRectangle);
|
}
|
|
Params.Outputs["CenterX"] = CenterX;
|
Params.Outputs["CenterY"] = CenterY;
|
Params.Outputs["Phi"] = Phi;
|
Params.Outputs["Score"] = Score;
|
Params.Outputs["Count"] = Score.Count;
|
#endregion
|
|
#region 生成OutputImage给后续处理
|
try
|
{
|
OutputImage = hoDomainImage;
|
}
|
catch (Exception ex)
|
{
|
Msg = "生成OutputImage失败,原因是:" + ex.ToString();
|
Result = false;
|
return;
|
}
|
#endregion
|
|
if (Msg == "运行超时")
|
{
|
Result = false;
|
Record.ChangeAll2False();
|
return;
|
}
|
|
int MinCount = ProcessParams.ConvertToInt32(Params.Inputs["MinCount"]);
|
int MaxCount = ProcessParams.ConvertToInt32(Params.Inputs["MaxCount"]);
|
|
if (CenterX.Count < MinCount || CenterX.Count > MaxCount)
|
{
|
Msg = string.Format("结果个数超出范围({0},{1})", MinCount, MaxCount);
|
Record.ChangeAll2False();
|
Result = false;
|
return;
|
}
|
|
Msg = "运行成功";
|
Result = true;
|
return;
|
}
|
catch (Exception ex)
|
{
|
Msg = "运行失败,原因是:" + ex.ToString().TrimEnd();
|
OutputImage = null;
|
Result = false;
|
return;
|
}
|
finally
|
{
|
if (!Result)
|
{
|
Params.Outputs["CenterX"] = 0;
|
Params.Outputs["CenterY"] = 0;
|
Params.Outputs["Phi"] = 0;
|
Params.Outputs["Score"] = 0;
|
Params.Outputs["Count"] = 0;
|
}
|
bCompleted = true;
|
#region 内存释放
|
|
#endregion
|
}
|
}
|
}
|
|
/// <summary>
|
/// 带角度的灰度匹配
|
/// </summary>
|
/// <param name="source"></param>
|
/// <param name="template"></param>
|
/// <param name="startAngle"></param>
|
/// <param name="endAngle"></param>
|
/// <param name="angleStep"></param>
|
/// <param name="scaleStart"></param>
|
/// <param name="scaleEnd"></param>
|
/// <param name="scaleStep"></param>
|
/// <param name="threshold"></param>
|
/// <param name="NMS"></param>
|
/// <returns></returns>
|
public static List<RotatedRect> MultiAngleTemplateMatch(
|
Mat source,
|
Mat template,
|
double startAngle = 0,
|
double endAngle = 360,
|
double angleStep = 10,
|
double scaleStart = 0.5,
|
double scaleEnd = 2.0,
|
double scaleStep = 0.1,
|
double threshold = 0.8,
|
double NMS = 0.3)
|
{
|
var allMatches = new List<MatchResult>();
|
|
// 生成角度序列
|
var angles = GenerateAngleSequence(startAngle, endAngle, angleStep);
|
|
// 生成缩放序列
|
var scales = GenerateScaleSequence(scaleStart, scaleEnd, scaleStep);
|
|
// 多线程加速方法[存在匹配结果不一致的情况]
|
//allMatches = MultiScaleAngleTemplateMatchFullParallel(source, template, scales, angles, threshold);
|
|
foreach (double scale in scales)
|
{
|
// 缩放模板
|
Mat scaledTemplate = new Mat();
|
if (scale != 1.0)
|
{
|
Cv2.Resize(template, scaledTemplate,
|
new Size(template.Width * scale, template.Height * scale));
|
}
|
else
|
scaledTemplate = template.Clone();
|
|
if (scaledTemplate.Width > source.Width || scaledTemplate.Height > source.Height)
|
continue;
|
|
foreach (double angle in angles)
|
{
|
// 旋转模板
|
using (Mat rotatedTemplate = RotateImageForTemplateMatching(scaledTemplate, angle))
|
{
|
if (rotatedTemplate.Empty()) continue;
|
|
using (Mat resultMatrix = new Mat())
|
{
|
Cv2.MatchTemplate(source, rotatedTemplate, resultMatrix,
|
TemplateMatchModes.CCoeffNormed);
|
|
// 查找最佳匹配位置
|
double minVal, maxVal;
|
Point minLoc, maxLoc;
|
Cv2.MinMaxLoc(resultMatrix, out minVal, out maxVal, out minLoc, out maxLoc);
|
|
if (maxVal >= threshold)
|
{
|
var rotatedRect = new RotatedRect(
|
new Point2f(maxLoc.X + rotatedTemplate.Width / 2.0f,
|
maxLoc.Y + rotatedTemplate.Height / 2.0f),
|
new Size2f(rotatedTemplate.Width, rotatedTemplate.Height),
|
(float)angle);
|
|
allMatches.Add(new MatchResult
|
{
|
RotatedRect = rotatedRect,
|
Score = maxVal,
|
Scale = scale
|
});
|
}
|
}
|
}
|
}
|
}
|
|
// 应用旋转矩形的非极大值抑制
|
return ApplyRotatedNMS(allMatches, NMS);
|
}
|
|
public static List<MatchResult> MultiScaleAngleTemplateMatchFullParallel(
|
Mat source,
|
Mat template,
|
double[] scales,
|
double[] angles,
|
double threshold = 0.8)
|
{
|
var allMatches = new ConcurrentBag<MatchResult>();
|
|
// 预处理源图像
|
// 创建所有尺度-角度组合
|
var combinations = from scale in scales
|
from angle in angles
|
select new { Scale = scale, Angle = angle };
|
|
Parallel.ForEach(combinations, combination =>
|
{
|
try
|
{
|
ProcessScaleAngleCombination(source, template,
|
combination.Scale, combination.Angle, threshold, allMatches);
|
}
|
catch (Exception ex)
|
{
|
Debug.WriteLine($"处理尺度 {combination.Scale}, 角度 {combination.Angle} 时出错: {ex.Message}");
|
}
|
});
|
|
return allMatches.ToList();
|
}
|
|
private static void ProcessScaleAngleCombination(Mat source, Mat template,
|
double scale, double angle, double threshold, ConcurrentBag<MatchResult> allMatches)
|
{
|
Mat scaledTemplate = new Mat();
|
// 缩放
|
if (scale != 1.0)
|
{
|
Cv2.Resize(template, scaledTemplate,
|
new Size(template.Width * scale, template.Height * scale));
|
}
|
else
|
{
|
scaledTemplate = template.Clone();
|
}
|
|
if (scaledTemplate.Width > source.Width || scaledTemplate.Height > source.Height)
|
return;
|
|
// 旋转
|
using (Mat rotatedTemplate = RotateImageForTemplateMatching(scaledTemplate, angle))
|
{
|
if (rotatedTemplate.Empty()) return;
|
|
using (Mat resultMatrix = new Mat())
|
{
|
Cv2.MatchTemplate(source, rotatedTemplate, resultMatrix,
|
TemplateMatchModes.CCoeffNormed);
|
|
double minVal, maxVal;
|
Point minLoc, maxLoc;
|
Cv2.MinMaxLoc(resultMatrix, out minVal, out maxVal, out minLoc, out maxLoc);
|
|
if (maxVal >= threshold)
|
{
|
var rotatedRect = new RotatedRect(
|
new Point2f(maxLoc.X + rotatedTemplate.Width / 2.0f,
|
maxLoc.Y + rotatedTemplate.Height / 2.0f),
|
new Size2f(rotatedTemplate.Width, rotatedTemplate.Height),
|
(float)angle);
|
|
allMatches.Add(new MatchResult
|
{
|
RotatedRect = rotatedRect,
|
Score = maxVal,
|
Scale = scale
|
});
|
}
|
}
|
}
|
}
|
|
public static Mat RotateImageForTemplateMatching(Mat template, double angle, double scale = 1.0)
|
{
|
if (template.Empty())
|
return new Mat();
|
|
try
|
{
|
double radians = angle * Math.PI / 180.0;
|
double sin = Math.Abs(Math.Sin(radians));
|
double cos = Math.Abs(Math.Cos(radians));
|
|
int newWidth = (int)Math.Ceiling((template.Width * cos + template.Height * sin) * scale);
|
int newHeight = (int)Math.Ceiling((template.Width * sin + template.Height * cos) * scale);
|
|
// 确保使用相同的类型创建画布
|
Mat canvas = new Mat(newHeight, newWidth, template.Type(), Scalar.Black);
|
|
int xOffset = (newWidth - template.Width) / 2;
|
int yOffset = (newHeight - template.Height) / 2;
|
|
Rect roi = new Rect(xOffset, yOffset, template.Width, template.Height);
|
using (Mat canvasRoi = new Mat(canvas, roi))
|
{
|
template.CopyTo(canvasRoi);
|
}
|
|
Point2f center = new Point2f(newWidth / 2.0f, newHeight / 2.0f);
|
|
using (Mat rotationMatrix = Cv2.GetRotationMatrix2D(center, angle, scale))
|
{
|
Mat rotated = new Mat();
|
Cv2.WarpAffine(canvas, rotated, rotationMatrix, new Size(newWidth, newHeight),
|
InterpolationFlags.Linear, BorderTypes.Constant, Scalar.Black);
|
|
// 确保输出类型与输入一致
|
if (rotated.Type() != template.Type())
|
{
|
Mat converted = new Mat();
|
rotated.ConvertTo(converted, template.Type());
|
rotated.Dispose();
|
canvas.Dispose();
|
return converted;
|
}
|
|
canvas.Dispose();
|
return rotated;
|
}
|
}
|
catch (Exception ex)
|
{
|
Debug.WriteLine($"旋转图像时出错: {ex.Message}");
|
return new Mat();
|
}
|
}
|
|
private static List<RotatedRect> ApplyRotatedNMS(List<MatchResult> matches, double overlapThreshold)
|
{
|
var results = new List<RotatedRect>();
|
var remainingMatches = new List<MatchResult>(matches);
|
|
while (remainingMatches.Count > 0)
|
{
|
// 取分数最高的匹配
|
var bestMatch = remainingMatches[0];
|
results.Add(bestMatch.RotatedRect);
|
remainingMatches.RemoveAt(0);
|
|
// 移除与最佳匹配重叠度高的其他匹配
|
for (int i = remainingMatches.Count - 1; i >= 0; i--)
|
{
|
double overlap = CalculateRotatedOverlap(bestMatch.RotatedRect,
|
remainingMatches[i].RotatedRect);
|
|
if (overlap > overlapThreshold)
|
{
|
remainingMatches.RemoveAt(i);
|
}
|
}
|
}
|
|
return results;
|
}
|
|
public class MatchResult
|
{
|
public RotatedRect RotatedRect { get; set; }
|
public double Score { get; set; }
|
public double Scale { get; set; }
|
}
|
|
private static double CalculateRotatedOverlap(RotatedRect rect1, RotatedRect rect2)
|
{
|
// 计算两个旋转矩形的交并比
|
Point2f[] vertices1 = rect1.Points();
|
Point2f[] vertices2 = rect2.Points();
|
|
// 使用轮廓面积计算重叠度
|
using (Mat img1 = new Mat(1000, 1000, MatType.CV_8UC1, Scalar.Black))
|
using (Mat img2 = new Mat(1000, 1000, MatType.CV_8UC1, Scalar.Black))
|
{
|
// 绘制第一个矩形
|
Point[] points1 = vertices1.Select(p => new Point(p.X + 500, p.Y + 500)).ToArray();
|
Cv2.FillConvexPoly(img1, points1, Scalar.White);
|
|
// 绘制第二个矩形
|
Point[] points2 = vertices2.Select(p => new Point(p.X + 500, p.Y + 500)).ToArray();
|
Cv2.FillConvexPoly(img2, points2, Scalar.White);
|
|
// 计算交集
|
using (Mat intersection = new Mat())
|
{
|
Cv2.BitwiseAnd(img1, img2, intersection);
|
|
double intersectionArea = Cv2.CountNonZero(intersection);
|
double unionArea = Cv2.CountNonZero(img1) + Cv2.CountNonZero(img2) - intersectionArea;
|
|
return intersectionArea / unionArea;
|
}
|
}
|
}
|
|
private static double[] GenerateAngleSequence(double start, double end, double step)
|
{
|
var angles = new List<double>();
|
for (double angle = start; angle < end; angle += step)
|
{
|
angles.Add(angle);
|
}
|
return angles.ToArray();
|
}
|
|
private static double[] GenerateScaleSequence(double start, double end, double step)
|
{
|
var scales = new List<double>();
|
for (double scale = start; scale <= end; scale += step)
|
{
|
scales.Add(scale);
|
}
|
return scales.ToArray();
|
}
|
|
public bool CreateModel(Mat Template, ModelType modelType = ModelType.灰度匹配, string NumLevels = "auto"
|
, double AngleStart = -5, double AngleExtent = 10, string AngleStep = "auto"
|
, double ScaleRMin = 0.9, double ScaleRMax = 1.1, string ScaleRStep = "auto"
|
, double ScaleCMin = 1.1, double ScaleCMax = 0.9, string ScaleCStep = "auto"
|
, string Optimization = "none", string Metric = "ignore_local_polarity"
|
, string Contrast = "auto", int MinContrast = 10)
|
{
|
try
|
{
|
if (Template == null || Template.Empty())
|
Template = new Mat();
|
|
#region 参数介绍
|
//Template: : //reduce_domain后的模板图像
|
//NumLevels ,//金字塔的层数,可设为“auto”或0—10的整数
|
//AngleStart ,//模板旋转的起始角度
|
//AngleExtent ,//模板旋转角度范围, >=0
|
//AngleStep ,//旋转角度的步长, >=0 and <=pi/16
|
//Optimization ,//设置模板优化和模板创建方法
|
//Metric , //匹配方法设置
|
//Contrast ,//设置对比度
|
//MinContrast // 设置最小对比度
|
#endregion
|
switch (modelType)
|
{
|
case ModelType.灰度匹配:
|
//HOperatorSet.CreateLocalDeformableModel(Template, NumLevels == "auto" ? NumLevels : Convert.ToInt16(NumLevels)
|
// , AngleStart, AngleExtent, AngleStep == "auto" ? AngleStep : Convert.ToDouble(AngleStep)
|
// , ScaleRMin, ScaleRMax, ScaleRStep == "auto" ? ScaleRStep : Convert.ToDouble(ScaleRStep)
|
// , ScaleCMin, ScaleCMax, ScaleCStep == "auto" ? ScaleCStep : Convert.ToDouble(ScaleCStep)
|
// , Optimization, Metric
|
// , Contrast, MinContrast
|
// , new HTuple(), new HTuple()
|
// , out ModelID.hvModel);
|
ModelID.hoImage = Template.Clone();
|
ModelID.Type = ModelType.灰度匹配;
|
return true;
|
default:
|
//HOperatorSet.CreateAnisoShapeModel(Template, NumLevels == "auto" ? NumLevels : Convert.ToInt16(NumLevels)
|
// , AngleStart, AngleExtent, AngleStep == "auto" ? AngleStep : Convert.ToDouble(AngleStep)
|
// , ScaleRMin, ScaleRMax, ScaleRStep == "auto" ? ScaleRStep : Convert.ToDouble(ScaleRStep)
|
// , ScaleCMin, ScaleCMax, ScaleCStep == "auto" ? ScaleCStep : Convert.ToDouble(ScaleCStep)
|
// , Optimization, Metric
|
// , Contrast, MinContrast, out ModelID.hvModel);
|
ModelID.hoImage = Template.Clone();
|
ModelID.Type = ModelType.灰度匹配;
|
return true;
|
}
|
}
|
catch { return false; }
|
}
|
|
/// <summary>
|
/// 加载算法
|
/// </summary>
|
/// <param name="fullPath">完整路径带.json</param>
|
/// <returns></returns>
|
public override bool Load(string fullPath)
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(fullPath))
|
return false;
|
|
if (!fullPath.Contains(".json"))
|
{
|
Debug.WriteLine("文件路径不完整");
|
return false;
|
}
|
|
if (fullPath.StartsWith(".\\"))
|
{
|
// 判断原字符串长度是否大于等于2,避免越界
|
if (fullPath.Length >= 2)
|
{
|
// 替换开头两个字符
|
fullPath = Application.StartupPath + fullPath.Substring(2);
|
Debug.WriteLine($"修改后的字符串: {fullPath}");
|
}
|
}
|
|
// 获取不带文件名的目录路径
|
string directoryPath = Path.GetDirectoryName(fullPath);
|
strProcessName = Path.GetFileNameWithoutExtension(fullPath);
|
// 修正真实路径,模板匹配工具其路径为一个文件夹,而不是一个文件
|
fullPath = directoryPath + "\\" + strProcessName + "\\" + strProcessName + ".json";
|
|
if (!File.Exists(fullPath))
|
{
|
Debug.WriteLine("文件不存在创建空文件");
|
ModelID = new OModel(fullPath, ModelType.灰度匹配, strProcessName);
|
Save(directoryPath);
|
ModelID.Save(fullPath, ModelID.Type);
|
return true;
|
}
|
|
string strJson = string.Empty;
|
using (StreamReader streamReader = new StreamReader(fullPath, Encoding.UTF8))
|
{
|
strJson = streamReader.ReadToEnd();
|
streamReader.Close();
|
}
|
Params = JsonConvert.DeserializeObject<ProcessParams>(strJson);
|
if (Params == null)
|
return false;
|
|
// 反序列化后修复数据
|
Params.FixDeserializedData();
|
strProcessName = Path.GetFileNameWithoutExtension(fullPath);
|
|
if (!Enum.TryParse(Params.Inputs["ModelType"].ToString(), out ModelType modelType))
|
return false;
|
|
if (!ModelID.Load(fullPath, modelType))
|
return false;
|
|
return true;
|
}
|
catch { return false; }
|
}
|
|
/// <summary>
|
/// 保存算法
|
/// </summary>
|
/// <param name="filePath">不带.json</param>
|
/// <returns></returns>
|
public override bool Save(string filePath)
|
{
|
try
|
{
|
// 修正真实路径,模板匹配工具其路径为一个文件夹,而不是一个文件
|
filePath += ("\\" + strProcessName);
|
Params.Inputs.Add("ModelType", ModelID.Type.ToString());
|
if (!base.Save(filePath)
|
|| !ModelID.Save(filePath + "\\" + strProcessName + ".json", ModelID.Type))
|
return false;
|
|
return true;
|
}
|
catch { return false; }
|
}
|
}
|
|
public class OModel
|
{
|
public OModel(string modelName = "") { ModelName = modelName; }
|
|
public OModel(string modelFullPath, ModelType modelType, string modelName)
|
{
|
ModelFullPath = modelFullPath;
|
ModelName = modelName;
|
Type = modelType;
|
switch (modelType)
|
{
|
case ModelType.灰度匹配:
|
Load(ModelFullPath, modelType);
|
break;
|
default:
|
Load(ModelFullPath, modelType);
|
break;
|
}
|
}
|
|
/// <summary>
|
/// 模板路径
|
/// </summary>
|
public string ModelFullPath = "C:\\LB_SmartVisionModel\\ModelName.temp";
|
|
/// <summary>
|
/// 模板名称
|
/// </summary>
|
public string ModelName
|
{
|
get { return Path.GetFileNameWithoutExtension(ModelFullPath); }
|
set
|
{
|
// 获取文件的扩展名(包括点)
|
string fileExtension = Path.GetExtension(ModelFullPath);
|
|
// 获取文件所在的文件夹路径
|
string directoryPath = Path.GetDirectoryName(ModelFullPath);
|
|
ModelFullPath = directoryPath + "\\" + value + fileExtension;
|
}
|
}
|
|
/// <summary>
|
/// 模板图片
|
/// </summary>
|
public Mat hoImage;
|
|
public int Width
|
{
|
get
|
{
|
if (hoImage == null || hoImage.Empty())
|
return 0;
|
return hoImage.Width;
|
}
|
}
|
|
public int Height
|
{
|
get
|
{
|
if (hoImage == null || hoImage.Empty())
|
return 0;
|
return hoImage.Height;
|
}
|
}
|
|
/// <summary>
|
/// 模板类型
|
/// </summary>
|
public ModelType Type = ModelType.灰度匹配;
|
|
/// <summary>
|
/// 加载模板(带.json)
|
/// </summary>
|
/// <param name="fullPath">完整路径带.json</param>
|
/// <returns></returns>
|
public bool Load(string fullPath, ModelType modelType)
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(fullPath))
|
return false;
|
|
string filePath = Path.GetDirectoryName(fullPath);
|
ModelName = Path.GetFileNameWithoutExtension(fullPath);
|
ModelFullPath = filePath + "\\" + ModelName;
|
ModelFullPath += ".model";
|
Type = modelType;
|
//switch (modelType)
|
//{
|
// case ModelType.局部变形模板:
|
// ModelFullPath += ".dfm";
|
// if (File.Exists(ModelFullPath))
|
// HOperatorSet.ReadDeformableModel(ModelFullPath, out hvModel);
|
// break;
|
// case ModelType.各向异形模板:
|
// default:
|
// if (File.Exists(ModelFullPath))
|
// HOperatorSet.ReadShapeModel(ModelFullPath, out hvModel);
|
// break;
|
//}
|
|
string ImageFileName = Path.GetFileNameWithoutExtension(fullPath);
|
string ImageFullPath = filePath + "\\" + ImageFileName + ".bmp";
|
if (File.Exists(ImageFullPath))
|
hoImage = Cv2.ImRead(ImageFullPath);
|
|
if (hoImage == null || hoImage.Empty())
|
return false;
|
|
if (hoImage.Channels() != 1)
|
Cv2.CvtColor(hoImage, hoImage, ColorConversionCodes.RGB2GRAY);
|
|
return true;
|
}
|
catch { Type = ModelType.灰度匹配; return false; }
|
}
|
|
/// <summary>
|
/// 保存模板(路径带.model)
|
/// </summary>
|
/// <param name="fullPath">带.model</param>
|
/// <returns></returns>
|
public bool Save(string fullPath)
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(fullPath))
|
return false;
|
|
string filePath = Path.GetDirectoryName(fullPath);
|
//判断文件夹是否存在
|
if (!Directory.Exists(filePath))
|
{
|
try
|
{
|
Directory.CreateDirectory(filePath);
|
}
|
catch (Exception)
|
{ }
|
}
|
|
ModelName = Path.GetFileNameWithoutExtension(fullPath);
|
// 使用 Path.GetExtension 提取扩展名
|
//switch (Type)
|
//{
|
// case ModelType.局部变形模板:
|
// HOperatorSet.WriteDeformableModel(hvModel, fullPath);
|
// break;
|
// case ModelType.各向异形模板:
|
// default:
|
// HOperatorSet.WriteShapeModel(hvModel, fullPath);
|
// break;
|
//}
|
|
string ImageFileName = Path.GetFileNameWithoutExtension(fullPath);
|
string ImageFullPath = filePath + "\\" + ImageFileName + ".bmp";
|
Cv2.ImWrite(ImageFullPath, hoImage);
|
//HOperatorSet.WriteImage(hoImage, "bmp", 0, ImageFullPath);
|
return true;
|
}
|
catch { return false; }
|
}
|
|
/// <summary>
|
/// 保存模板(路径带.json)
|
/// </summary>
|
/// <param name="fullPath">带.json</param>
|
/// <returns></returns>
|
public bool Save(string fullPath, ModelType modelType)
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(fullPath))
|
return false;
|
|
string filePath = Path.GetDirectoryName(fullPath);
|
//判断文件夹是否存在
|
if (!Directory.Exists(filePath))
|
{
|
try
|
{
|
Directory.CreateDirectory(filePath);
|
}
|
catch (Exception)
|
{ }
|
}
|
|
ModelName = Path.GetFileNameWithoutExtension(fullPath);
|
ModelFullPath = filePath + "\\" + ModelName + ".model";
|
Type = modelType;
|
//switch (modelType)
|
//{
|
// case ModelType.各向异形模板:
|
// HOperatorSet.WriteDeformableModel(hvModel, ModelFullPath);
|
// break;
|
// default:
|
// HOperatorSet.WriteShapeModel(hvModel, ModelFullPath);
|
// break;
|
//}
|
|
string ImageFileName = Path.GetFileNameWithoutExtension(fullPath);
|
string ImageFullPath = filePath + "\\" + ImageFileName + ".bmp";
|
Cv2.ImWrite(ImageFullPath, hoImage);
|
return true;
|
}
|
catch { return false; }
|
}
|
}
|
}
|