2026-01-26 18:56:53 +09:00

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);
}
}
}