325 lines
13 KiB
C#
325 lines
13 KiB
C#
/*
|
|
* Copyright (c) 2025 LG Electronics Inc.
|
|
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
|
|
*/
|
|
using Aurora.Api;
|
|
using CogCommon;
|
|
using VisionCommon;
|
|
using Hermes;
|
|
using Cognex.VisionPro;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Windows;
|
|
using Cognex.VisionPro.PMAlign;
|
|
using System.Diagnostics;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
|
|
namespace CogPattern {
|
|
public class ModelFinderRunParam : IRunParam, ICloneable {
|
|
public int FindNumber { get; set; } = 1;
|
|
public double Acceptance { get; set; } = 60;
|
|
public double Certainty { get; set; } = 90;
|
|
public Angle AngleTolerance { get; set; } = Angle.CreateWithDegree(2);
|
|
public eIgnorePolarity IgnorePolarity { get; set; } = eIgnorePolarity.ENABLED;
|
|
public double Score { get; set; } = 60; // 미사용
|
|
public ROI FindROI { get; set; } = new ROI();
|
|
|
|
public object Clone() {
|
|
return new ModelFinderRunParam() {
|
|
FindNumber = FindNumber,
|
|
Acceptance = Acceptance,
|
|
Certainty = Certainty,
|
|
AngleTolerance = AngleTolerance.Clone() as Angle,
|
|
IgnorePolarity = IgnorePolarity,
|
|
Score = Score,
|
|
FindROI = FindROI.Clone() as ROI,
|
|
};
|
|
}
|
|
}
|
|
|
|
internal static class MmfCommon {
|
|
public const double DEFAULT_ANGLE_TOLERANCE_DEGREE = 2.0;
|
|
public const double DEFAULT_SCALE_TOLERANCE = 0.1;
|
|
public const double DEFAULT_ACCEPT_THRESHOLD = 0.7;
|
|
public const double DEFAULT_TIME_OUT = 3000; // 3 sec
|
|
public const bool DEFAULT_SCORE_USING_CLUTTER = false;
|
|
|
|
private static Logger _Logger = new Logger(typeof(MmfCommon).Name);
|
|
|
|
public static CogPMAlignTool CreateTool() {
|
|
var cogPMAlignTool = new CogPMAlignTool();
|
|
SetAngleTolerance(cogPMAlignTool.RunParams);
|
|
SetScaleTolerance(cogPMAlignTool.RunParams);
|
|
cogPMAlignTool.RunParams.AcceptThreshold = DEFAULT_ACCEPT_THRESHOLD;
|
|
cogPMAlignTool.RunParams.ScoreUsingClutter = DEFAULT_SCORE_USING_CLUTTER;
|
|
cogPMAlignTool.RunParams.TimeoutEnabled = true;
|
|
cogPMAlignTool.RunParams.Timeout = DEFAULT_TIME_OUT;
|
|
|
|
return cogPMAlignTool;
|
|
}
|
|
|
|
public static CogPMAlignTool LoadTool(string filePath) {
|
|
return (CogPMAlignTool)CogSerializer.LoadObjectFromFile(
|
|
filePath,
|
|
typeof(BinaryFormatter),
|
|
CogSerializationOptionsConstants.Minimum);
|
|
}
|
|
|
|
public static int SaveTool(CogPMAlignTool cogPMAlignTool, string filePath) {
|
|
if (cogPMAlignTool != null && filePath != null) {
|
|
CogSerializer.SaveObjectToFile(
|
|
cogPMAlignTool,
|
|
filePath,
|
|
typeof(BinaryFormatter),
|
|
CogSerializationOptionsConstants.Minimum);
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
public static void FreeTool(CogPMAlignTool cogPMAlignTool) {
|
|
if (cogPMAlignTool != null) {
|
|
cogPMAlignTool = null;
|
|
}
|
|
}
|
|
|
|
public static bool IsTrained(CogPMAlignTool cogPMAlignTool) {
|
|
if (cogPMAlignTool == null ||
|
|
cogPMAlignTool.Pattern == null) {
|
|
return false;
|
|
}
|
|
|
|
return cogPMAlignTool.Pattern.Trained;
|
|
}
|
|
|
|
public static ROI GetFindROI(CogPMAlignTool cogPMAlignTool) {
|
|
if (cogPMAlignTool.SearchRegion == null) {
|
|
if (IsTrained(cogPMAlignTool)) {
|
|
var imageSize = CogEnvironment.GetImageSize(cogPMAlignTool.Pattern.TrainImage);
|
|
return RoiUtil.GetDefaultFindRoi(imageSize);
|
|
}
|
|
return new ROI();
|
|
}
|
|
return CogEnvironment.ConvertToRoi(cogPMAlignTool.SearchRegion as CogRectangleAffine);
|
|
}
|
|
|
|
public static int SetFindROI(CogPMAlignTool cogPMAlignTool, ROI findRoi) {
|
|
if (findRoi.Width > 0 && findRoi.Height > 0) {
|
|
if (cogPMAlignTool != null) {
|
|
cogPMAlignTool.SearchRegion = CogEnvironment.ConvertToCogRectangleAffine(findRoi);
|
|
}
|
|
}
|
|
else {
|
|
//ClearFindRoi(cogPMAlignTool);
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
//public static int ClearFindRoi(CogPMAlignTool cogPMAlignTool) {
|
|
// if (cogPMAlignTool != null) {
|
|
// cogPMAlignTool.SearchRegion = new CogRectangleAffine();
|
|
// }
|
|
|
|
// return E1.OK;
|
|
//}
|
|
|
|
public static ModelFinderRunParam GetRunParam(CogPMAlignTool cogPMAlignTool) {
|
|
var modelFinderRunParam = new ModelFinderRunParam();
|
|
modelFinderRunParam.FindNumber = cogPMAlignTool.RunParams.ApproximateNumberToFind;
|
|
modelFinderRunParam.Acceptance = CogEnvironment.ConvertToVisionScore(cogPMAlignTool.RunParams.AcceptThreshold);
|
|
modelFinderRunParam.Certainty = CogEnvironment.ConvertToCertainty(GetScaleTolerance(cogPMAlignTool.RunParams));
|
|
modelFinderRunParam.AngleTolerance = GetAngleTolerance(cogPMAlignTool.RunParams);
|
|
|
|
if (IsTrained(cogPMAlignTool)) {
|
|
modelFinderRunParam.IgnorePolarity = cogPMAlignTool.Pattern.IgnorePolarity? eIgnorePolarity.ENABLED : eIgnorePolarity.DISABLED;
|
|
modelFinderRunParam.FindROI = GetFindROI(cogPMAlignTool);
|
|
}
|
|
|
|
return modelFinderRunParam;
|
|
}
|
|
|
|
private static void SetAngleTolerance(CogPMAlignRunParams runParams, ModelFinderRunParam runParam = null) {
|
|
runParams.ZoneAngle.Configuration = CogPMAlignZoneConstants.LowHigh;
|
|
|
|
if (runParam != null) {
|
|
runParams.ZoneAngle.High = runParam.AngleTolerance.Radian;
|
|
runParams.ZoneAngle.Low = runParam.AngleTolerance.Radian * (-1);
|
|
}
|
|
else {
|
|
runParams.ZoneAngle.High = CogMisc.DegToRad(DEFAULT_ANGLE_TOLERANCE_DEGREE);
|
|
runParams.ZoneAngle.Low = CogMisc.DegToRad(DEFAULT_ANGLE_TOLERANCE_DEGREE) * (-1);
|
|
}
|
|
}
|
|
|
|
private static Angle GetAngleTolerance(CogPMAlignRunParams runParams) {
|
|
double angleToleranceMaxRad = Math.Max(Math.Abs(runParams.ZoneAngle.High), Math.Abs(runParams.ZoneAngle.Low));
|
|
double angleToleranceMaxDeg = CogMisc.RadToDeg(angleToleranceMaxRad);
|
|
|
|
return new Angle() {
|
|
Degree = angleToleranceMaxDeg,
|
|
Radian = angleToleranceMaxRad
|
|
};
|
|
}
|
|
|
|
private static void SetScaleTolerance(CogPMAlignRunParams runParams, ModelFinderRunParam runParam = null) {
|
|
runParams.ZoneScale.Configuration = CogPMAlignZoneConstants.LowHigh;
|
|
|
|
if (runParam != null) {
|
|
runParams.ZoneScale.High = 1.0 + (1.0 - CogEnvironment.ConvertToScale(runParam.Certainty));
|
|
runParams.ZoneScale.Low = 1.0 - (1.0 - CogEnvironment.ConvertToScale(runParam.Certainty));
|
|
}
|
|
else {
|
|
runParams.ZoneScale.High = 1.0 + DEFAULT_SCALE_TOLERANCE;
|
|
runParams.ZoneScale.Low = 1.0 - DEFAULT_SCALE_TOLERANCE;
|
|
}
|
|
}
|
|
|
|
private static double GetScaleTolerance(CogPMAlignRunParams runParams) {
|
|
double scaleMax = Math.Max(Math.Abs(runParams.ZoneScale.High), Math.Abs(runParams.ZoneScale.Low));
|
|
double scaleRatio = Math.Round(1.0 - Math.Abs(1.0 - scaleMax), 3); // scaleRatio : 0 ~ 1
|
|
|
|
return scaleRatio;
|
|
}
|
|
|
|
public static int SetRunParam(CogPMAlignTool cogPMAlignTool, IRunParam runParam) {
|
|
if (runParam is ModelFinderRunParam) {
|
|
var param = runParam as ModelFinderRunParam;
|
|
if (cogPMAlignTool != null) {
|
|
SetAngleTolerance(cogPMAlignTool.RunParams, param);
|
|
SetScaleTolerance(cogPMAlignTool.RunParams, param);
|
|
SetFindROI(cogPMAlignTool, param.FindROI);
|
|
cogPMAlignTool.RunParams.ApproximateNumberToFind = param.FindNumber;
|
|
cogPMAlignTool.RunParams.AcceptThreshold = CogEnvironment.ConvertToCogScore(param.Acceptance);
|
|
cogPMAlignTool.Pattern.IgnorePolarity = GetIgnorePolarity(param.IgnorePolarity);
|
|
//ClearFindRoi(cogPMAlignTool);
|
|
}
|
|
return E1.OK;
|
|
}
|
|
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
private static bool GetIgnorePolarity(eIgnorePolarity ignorePolarity) {
|
|
if (ignorePolarity == eIgnorePolarity.ENABLED) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static PatternResult Find(CogPMAlignTool cogPMAlignTool, ICogImage image, ROI findRoi) {
|
|
if (CogEnvironment.IsColorImage(image)) {
|
|
var grayImage = CogEnvironment.ConvertToGray(image);
|
|
var patternResult = FindInternal(cogPMAlignTool, grayImage, findRoi);
|
|
CogEnvironment.FreeImage(grayImage);
|
|
|
|
return patternResult;
|
|
}
|
|
return FindInternal(cogPMAlignTool, image, findRoi);
|
|
}
|
|
|
|
private static PatternResult FindInternal(CogPMAlignTool cogPMAlignTool, ICogImage image, ROI findRoi) {
|
|
var timeFind = new Stopwatch();
|
|
timeFind.Start();
|
|
|
|
var finderResult = new PatternResult();
|
|
var oldFindRoi = GetFindROI(cogPMAlignTool);
|
|
|
|
try {
|
|
if (IsTrained(cogPMAlignTool)) {
|
|
cogPMAlignTool.InputImage = image;
|
|
SetFindROI(cogPMAlignTool, findRoi);
|
|
cogPMAlignTool.Run();
|
|
finderResult = ExtractResults(cogPMAlignTool, CogEnvironment.GetImageCenter(image));
|
|
}
|
|
else {
|
|
finderResult = GetNotFoundPatternResult();
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
_Logger.FuncE(e.Message);
|
|
}
|
|
finally {
|
|
SetFindROI(cogPMAlignTool, oldFindRoi);
|
|
}
|
|
|
|
timeFind.Stop();
|
|
finderResult.TactTimeInMilliSec = timeFind.ElapsedMilliseconds;
|
|
|
|
return finderResult;
|
|
}
|
|
|
|
public static PatternResult GetNotFoundPatternResult() {
|
|
return new PatternResult() {
|
|
Status = eFoundStatus.NotFound,
|
|
Results = new List<ModelFinderResult>()
|
|
};
|
|
}
|
|
|
|
private static PatternResult ExtractResults(CogPMAlignTool cogPMAlignTool, ImagePoint imageCenter) {
|
|
var results = new List<ModelFinderResult>();
|
|
eFoundStatus status = eFoundStatus.NotFound;
|
|
|
|
foreach (CogPMAlignResult result in cogPMAlignTool.Results) {
|
|
double posX = result.GetPose().TranslationX;
|
|
double posY = result.GetPose().TranslationY;
|
|
double score = Math.Truncate(CogEnvironment.ConvertToVisionScore(result.Score));
|
|
double angleDeg = CogMisc.RadToDeg(result.GetPose().Rotation);
|
|
|
|
results.Add(new ModelFinderResult(
|
|
position: new ImagePoint(posX, posY),
|
|
offset: (new ImagePoint(posX, posY) - imageCenter) as ImagePoint,
|
|
angle: Angle.NormalizeAngle(Angle.CreateWithDegree(angleDeg)),
|
|
score: score));
|
|
|
|
if (results.Count == cogPMAlignTool.RunParams.ApproximateNumberToFind) {
|
|
status = eFoundStatus.FoundOK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return new PatternResult() {
|
|
Status = status,
|
|
Results = results
|
|
};
|
|
}
|
|
|
|
public static void Draw(
|
|
PatternResult patternResult, ICogCameraDisplay cogCameraDisplay, bool isFixturePattern) {
|
|
if (patternResult == null || patternResult.Results == null) {
|
|
return;
|
|
}
|
|
|
|
var crosses = new List<Cross>();
|
|
|
|
foreach (BaseResult baseResult in patternResult.Results) {
|
|
var result = baseResult as ModelFinderResult;
|
|
if (result.Score > 0) {
|
|
var color = GraphicColors.GetFindResultColor(patternResult.Status, isFixturePattern);
|
|
var cross = new Cross(result.ImagePosition.Clone() as ImagePoint, result.Angle, 50);
|
|
crosses.Add(cross);
|
|
|
|
cogCameraDisplay.SetPatternTracking(cross);
|
|
cogCameraDisplay.AddCross(cross, color);
|
|
|
|
var msgs = new List<string>();
|
|
msgs.Add(string.Format("I({0:0.0}, {1:0.0})", result.ImagePosition.X, result.ImagePosition.Y));
|
|
msgs.Add(result.ConvertMaterialPosition());
|
|
msgs.Add(string.Format("Angle : {0:0.00}", result.Angle.Degree));
|
|
msgs.Add(string.Format("Score : {0:0.00}", result.Score));
|
|
msgs.Add(string.Format("TactTime : {0} ms", Math.Round(patternResult.TactTimeInMilliSec)));
|
|
msgs.Add(string.Format("ID : {0}_{1}", patternResult.PatternIndex.PatternId, patternResult.PatternIndex.PatternSubId));
|
|
|
|
cogCameraDisplay.AddTextList(
|
|
color, new ImagePoint(result.ImagePosition.X, result.ImagePosition.Y), msgs);
|
|
}
|
|
}
|
|
cogCameraDisplay.DrawPatternTrackings(crosses);
|
|
}
|
|
}
|
|
}
|