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

643 lines
26 KiB
C#

/*
* Copyright (c) 2025 LG Electronics Inc.
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
*/
using Aurora.Api;
using Hermes;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace VisionCommon {
public abstract class PatternAgentBase : IDisposable {
protected object _lockObj = new object();
protected Logger _logger = null;
protected FovInfo _fovInfo;
protected eCamId _camId;
protected Dictionary<PatternInfo, IPatternFinder> _patterns = new Dictionary<PatternInfo, IPatternFinder>();
public PatternAgentBase(FovInfo fovInfo) {
_fovInfo = fovInfo;
_camId = VisionRecipeManager.GetCamRecipe(fovInfo).CamId;
if (VisionSettingManager.VisionSetting.UseCamPattern) {
_logger = new Logger($"PA_{fovInfo.GetKey()}");
}
else {
_logger = new Logger($"PA_{_camId}");
}
}
public abstract Dictionary<PatternInfo, IPatternFinder> GetPatterns();
public List<PatternInfo> GetMainPatterns(PatternInfo patternInfo) {
var fovIdxPrefix = patternInfo.GetPrefix();
return GetMainPatterns(fovIdxPrefix);
}
public List<PatternInfo> GetMainPatterns(PatternInfo patternInfo, ePatternType patternType) {
var fovIdxPrefix = patternInfo.GetPrefix();
return GetMainPatterns(fovIdxPrefix, patternType);
}
public abstract List<PatternInfo> GetMainPatterns(SubSysInfo subSysInfo, eFovId fovId);
public abstract List<PatternInfo> GetMainPatterns(FovInfo fovInfo);
public List<PatternInfo> GetMainPatterns(string fovIdxPrefix) {
return GetPatterns()
.Where(pi => pi.Key.IsMainPattern(fovIdxPrefix))
.Select(pi => pi.Key)
.OrderBy(pi => pi.GetFullId()) // 패턴 ID를 기준으로 오름차순 정렬
.ToList();
}
public List<PatternInfo> GetMainPatterns(string fovIdxPrefix, ePatternType patternType) {
return GetPatterns()
.Where(pi => pi.Key.IsMainPattern(fovIdxPrefix))
.Where(pi => pi.Key.PatternType == patternType)
.Select(pi => pi.Key)
.OrderBy(pi => pi.GetFullId()) // 패턴 ID를 기준으로 오름차순 정렬
.ToList();
}
public PatternInfo GetMainPatternInfo(PatternInfo subPatternInfo) {
return GetMainPatternInfo(subPatternInfo.GetPatternIndex());
}
public PatternInfo GetMainPatternInfo(PatternIndex subPatternIndex) {
var mainPatternIndex = subPatternIndex.Clone() as PatternIndex;
mainPatternIndex.PatternSubId = PatternConstants.MAIN_PATTERN_INDEX;
return GetPatternInfo(mainPatternIndex);
}
public bool HasSubPattern(PatternInfo patternInfo) {
var subPatternInfos = GetSubPatterns(patternInfo);
return subPatternInfos?.Count > 0;
}
public List<PatternInfo> GetSubPatterns(PatternInfo patternInfo) {
var patternIdPrefix = patternInfo.GetPatternIdPrefix();
return GetSubPatterns(patternIdPrefix);
}
public List<PatternInfo> GetSubPatterns(string patternIdPrefix) {
return GetPatterns()
.Where(pi => pi.Key.IsSubPattern(patternIdPrefix))
.Select(pi => pi.Key)
.OrderBy(pi => pi.GetFullId()) // 패턴 ID를 기준으로 오름차순 정렬
.ToList();
}
public List<PatternInfo> GetMainSubPatterns(PatternInfo patternInfo) {
var fovIdxPrefix = patternInfo.GetPrefix();
return GetPatterns()
.Where(pi => pi.Key.GetFullId().StartsWith(fovIdxPrefix))
.Where(pi => pi.Key.GetPatternId() == patternInfo.GetPatternId())
.Select(pi => pi.Key)
.OrderBy(pi => pi.GetPatternSubId()) // PatternSubId를 기준으로 오름차순 정렬
.ToList();
}
public List<PatternInfo> GetAllPatternsForFov(PatternInfo patternInfo) {
var fovIdxPrefix = patternInfo.GetPrefix();
return GetAllPatternsForFov(fovIdxPrefix);
}
public List<PatternInfo> GetAllPatternsForFov(string fovIdxPrefix) {
return GetPatterns()
.Where(pi => pi.Key.GetFullId().StartsWith(fovIdxPrefix))
.Select(pi => pi.Key)
.OrderBy(pi => pi.GetPatternId()) // 패턴 ID를 기준으로 오름차순 정렬
.ThenBy(pi => pi.GetPatternSubId())
.ToList();
}
public List<int> GetFixturePatternIndexListForFov(PatternInfo patternInfo) {
var patterns = GetMainPatterns(patternInfo);
return patterns
.Where(pi => PatternConstants.IsFixturePatternType(pi.PatternType))
.Where(pi => pi.GetPatternIdPrefix() != patternInfo.GetPatternIdPrefix())
.Select(pi => pi.GetPatternId()).ToList();
}
public bool IsPatternExist(FovInfo fovInfo, int patternId) {
return GetPatternInfo(fovInfo, patternId) != null;
}
public bool IsPatternExist(PatternIndex patternIndex) {
return GetPatternInfo(patternIndex) != null;
}
public abstract PatternInfo GetPatternInfo(FovInfo fovInfo, int patternId);
public PatternInfo GetPatternInfo(PatternIndex patternIndex) {
try {
var selectedInfos = GetPatterns().Where(
pi => pi.Key.GetFullId().Equals(patternIndex.GetFullId())).ToList();
if (selectedInfos.Count > 0) {
return selectedInfos[0].Key;
}
}
catch (Exception e) {
_logger.E(e.Message);
}
return null;
}
public IPatternFinder GetPattern(PatternIndex patternIndex) {
var patternInfo = GetPatternInfo(patternIndex);
return (patternInfo == null) ? null : GetPattern(patternInfo);
}
public IPatternFinder GetPattern(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
return GetPatterns()[patternInfo];
}
return null;
}
public int ReloadPattern(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
((IDisposable)GetPatterns()[patternInfo])?.Dispose();
}
var pattern = CreatePattern(patternInfo);
if (pattern != null) {
GetPatterns()[patternInfo] = pattern;
return E1.OK;
}
return E2.NOT_FOUND;
}
public int ClearPatterns(Dictionary<PatternInfo, IPatternFinder> patterns) {
foreach (var pattern in patterns) {
((IDisposable)pattern.Value)?.Dispose();
}
patterns.Clear();
return E1.OK;
}
public int MovePattern(PatternInfo sourcePatternInfo, PatternInfo dstPatternInfo) {
return MovePattern(sourcePatternInfo.GetPatternIndex(), dstPatternInfo.GetPatternIndex());
}
public int MovePattern(PatternIndex sourcePatternIndex, PatternIndex dstPatternIndex) {
if (E1.OK != CopyPattern(sourcePatternIndex, dstPatternIndex)) {
_logger.FuncE($"CopyPattern error");
return E1.GENERIC;
}
return Remove(sourcePatternIndex);
}
public int CopyPattern(PatternInfo sourcePatternInfo, PatternInfo dstPatternInfo) {
return CopyPattern(sourcePatternInfo.GetPatternIndex(), dstPatternInfo.GetPatternIndex());
}
public int CopyPatternFiles(string oldPatternPath, string newPatternPath) {
try {
if (!Directory.Exists(newPatternPath)) {
Directory.CreateDirectory(newPatternPath);
}
var sourceFiles = Directory.GetFiles(oldPatternPath, "*", SearchOption.TopDirectoryOnly);
foreach (var sourceFile in sourceFiles) {
var dstFile = Path.Combine(
newPatternPath, Path.GetFileName(sourceFile));
File.Copy(sourceFile, dstFile);
_logger.I($"{sourceFile} -> {dstFile}");
}
}
catch (Exception e) {
_logger.E(e.Message);
return E1.GENERIC;
}
return E1.OK;
}
public abstract string GetPatternInfoPath();
public abstract int LoadPatterns();
public int LoadPatterns(Dictionary<PatternInfo, IPatternFinder> patterns) {
var patternInfoList = GetPatternInfoListFromFiles(
GetPatternInfoPath());
foreach (var patternInfo in patternInfoList) {
patterns[patternInfo] = CreatePattern(patternInfo);
}
return E1.OK;
}
public abstract int CopyPattern(PatternIndex sourcePatternIndex, PatternIndex dstPatternIndex);
public int Train(PatternInfo patternInfo, ITrainParam trainParam) {
if (GetPatterns().ContainsKey(patternInfo)) {
((PatternBase)GetPatterns()[patternInfo]).SetDirty();
return ((IPatternTrain)GetPatterns()[patternInfo]).Train(trainParam);
}
return E2.NOT_FOUND;
}
public ITrainParam GetTrainParam(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
if (GetPatterns()[patternInfo] is IPatternTrain) {
return (GetPatterns()[patternInfo] as IPatternTrain).GetTrainParam();
}
}
return null;
}
public abstract object GetTool(PatternInfo patternInfo);
public ROI GetFindROI(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
return (GetPatterns()[patternInfo]).GetFindROI();
}
return null;
}
public int SetFindROI(PatternInfo patternInfo, ROI findRoi) {
if (GetPatterns().ContainsKey(patternInfo)) {
((PatternBase)GetPatterns()[patternInfo]).SetDirty();
return (GetPatterns()[patternInfo]).SetFindROI(findRoi);
}
return E1.GENERIC;
}
public IRunParam GetRunParam(PatternInfo patternInfo) {
var patterns = GetPatterns();
if (GetPatterns().ContainsKey(patternInfo)) {
return (GetPatterns()[patternInfo]).GetRunParam();
}
return null;
}
public int SetRunParam(PatternInfo patternInfo, IRunParam runParam) {
if (GetPatterns().ContainsKey(patternInfo)) {
((PatternBase)GetPatterns()[patternInfo]).SetDirty();
return (GetPatterns()[patternInfo]).SetRunParam(runParam);
}
return E1.GENERIC;
}
#region Multi Patterns
public List<PatternResult> FindMulti(
PatternInfo masterPatternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult = null) {
List<PatternInfo> slavePatternInfos = GetMainSubPatterns(masterPatternInfo);
var patternResults = new List<PatternResult>();
foreach (PatternInfo curPatternInfo in slavePatternInfos) {
if (curPatternInfo.IsActivated) {
// Multi Pattern의 경우 Slave 패턴들로만 찾아야 한다.
if (PatternConstants.IsMainPattern(curPatternInfo.PatternIndex)) {
continue;
}
patternResults.Add(FindPattern(curPatternInfo, image, cameraDisplay, fixtureResult));
}
}
List<PatternResult> sortedPatternResults = patternResults.OrderBy(result => result.PatternIndex.PatternSubId).ToList();
// 0 : Master 패턴, 1~9 : Slave 패턴 (Master 패턴은 실제 패턴이 아니고, Slave에 대한 대표자 역할만 해준다.)
// *Rule : Slave 패턴 중에 하나라도 NG이면, Master에 NG Status를 할당한다.
var masterPatternResult = new PatternResult() {
PatternIndex = masterPatternInfo.GetPatternIndex().Clone() as PatternIndex,
Status = eFoundStatus.FoundOK,
Results = new List<BaseResult>()
};
foreach (var patternResult in sortedPatternResults) {
if (patternResult.Status == eFoundStatus.NotFound) {
masterPatternResult.Status = eFoundStatus.NotFound;
break;
}
}
sortedPatternResults.Insert(0, masterPatternResult);
return sortedPatternResults;
}
#endregion
#region Single Pattern
public PatternResult Find(
PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult = null) {
if (PatternConstants.IsPatternBlock(patternInfo.PatternType)) {
return FindPatternBlock(patternInfo, image, cameraDisplay, fixtureResult);
}
var allPatternInfos = GetMainSubPatterns(patternInfo);
var patternResult = new PatternResult();
foreach (var curPatternInfo in allPatternInfos) {
patternResult = FindPattern(curPatternInfo, image, cameraDisplay, fixtureResult);
if (patternResult.Status == eFoundStatus.FoundOK) {
break;
}
}
return patternResult;
}
#endregion
public ROI GetFixtureROI(PatternInfo patternInfo, FixtureResult fixtureResult) {
if (fixtureResult != null) {
var curFindRoi = GetFindROI(patternInfo);
var fixtureRoi = Fixture.GetFixtureROI(patternInfo.PatternType, curFindRoi, fixtureResult);
_logger.I($"curFindRoi : {curFindRoi}");
_logger.I($"fixtureRoi : {fixtureRoi}");
return fixtureRoi;
}
return GetFindROI(patternInfo);
}
public PatternResult FindPatternBlock(
PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult = null) {
var patternResult = new PatternResult();
var allPatternInfos = GetMainSubPatterns(patternInfo);
foreach (var curPatternInfo in allPatternInfos) {
var pattern = GetPatterns()[curPatternInfo];
if (!curPatternInfo.IsActivated) {
_logger.I($"{curPatternInfo} : NOT activated");
patternResult = pattern.GetNotFoundPatternResult();
}
else {
var patternBlock = pattern as IPatternBlock;
var patternBlockResults = new List<PatternResult>();
double tatcTime = 0;
foreach (var patternId in patternBlock.GetPatternBlockIds()) {
var curPatternIndex = patternInfo.GetPatternIndex().Clone() as PatternIndex;
curPatternIndex.PatternId = patternId;
var patterBlockPatternInfo = GetPatternInfo(curPatternIndex);
var allSubPatternInfos = GetMainSubPatterns(patterBlockPatternInfo);
PatternResult curSubPatternResult = new PatternResult();
foreach (var curSubPatternInfo in allSubPatternInfos) {
curSubPatternResult = FindPattern(curSubPatternInfo, image, cameraDisplay, fixtureResult);
if (curSubPatternResult.Status == eFoundStatus.FoundOK) {
break;
}
}
patternBlockResults.Add(curSubPatternResult);
//tatcTime += curSubPatternResult.TactTimeInMilliSec;
tatcTime = curSubPatternResult.TactTimeInMilliSec; // 누적 택타임이 아닌 마지막 택타임으로 사용
}
patternResult = patternBlock.Find(patternBlockResults);
patternResult.TactTimeInMilliSec = tatcTime;
}
if (patternResult.Status == eFoundStatus.FoundOK) {
foreach (var reuslt in patternResult.Results) {
_logger.I($"{curPatternInfo} : {patternResult.Status} : {reuslt}");
}
break;
}
else {
_logger.I($"{curPatternInfo} : {patternResult.Status}");
}
}
SetPatternParams(patternInfo, patternResult);
return patternResult;
}
public PatternResult Find(PatternInfo patternInfo, object image, ROI findRoi = null) {
if (PatternConstants.IsPatternBlock(patternInfo.PatternType)) {
return FindPatternBlock(patternInfo, image, findRoi);
}
return FindPattern(patternInfo, image, findRoi);
}
// TestFind for Pattern Registration
public abstract PatternResult FindPattern(PatternInfo patternInfo, object image, ROI findRoi = null);
// Find for Sequence
public abstract PatternResult FindPattern(PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult);
public abstract PatternResult FindPatternBlock(PatternInfo patternInfo, object image, ROI findRoi = null);
public void SetPatternParams(PatternInfo patternInfo, PatternResult patternResult) {
patternResult.PatternType = patternInfo.PatternType;
patternResult.PatternName = patternInfo.PatternName;
patternResult.PatternIndex = patternInfo.GetPatternIndex().Clone() as PatternIndex;
}
public abstract void Draw(PatternInfo patternInfo, PatternResult patternResult, ICameraDisplay cameraDisplay, bool isFixturePattern = false);
public int Save(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
ReplacePatternInfo(patternInfo);
SavePatternInfoToFile(
patternInfo,
PatternConstants.GetSubPatternInfoFilePath(patternInfo));
if (GetPatterns()[patternInfo] != null) {
return GetPatterns()[patternInfo].Save();
}
}
return E2.NOT_FOUND;
}
public void ReplacePatternInfo(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
var pattern = GetPatterns()[patternInfo];
GetPatterns().Remove(patternInfo);
GetPatterns().Add(patternInfo, pattern);
}
}
public int Create(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
_logger.I($"Already exist : {patternInfo}");
return E1.GENERIC;
}
var pattern = CreatePattern(patternInfo);
if (pattern != null) {
GetPatterns()[patternInfo] = pattern;
return E1.OK;
}
return E2.NOT_FOUND;
}
public int Remove(PatternIndex patternIndex) {
if (!IsPatternExist(patternIndex)) {
_logger.I($"Pattern does NOT exist : {patternIndex}");
return E1.OK;
}
return Remove(GetPatternInfo(patternIndex));
}
public int Remove(PatternInfo patternInfo) {
if (patternInfo != null) {
if (GetPatterns().ContainsKey(patternInfo)) {
GetPatterns()[patternInfo].Remove(); // Remove Sub Pattern Directory
GetPatterns().Remove(patternInfo);
DeletePatternDirectory(patternInfo);
return E1.OK;
}
}
return E2.NOT_FOUND;
}
public abstract IPatternFinder CreatePattern(PatternInfo patternInfo);
public void DeletePatternDirectory(PatternInfo patternInfo) {
var patternDirPath = PatternConstants.GetPatternDirPath(patternInfo);
if (!Directory.Exists(patternDirPath)) {
return;
}
if (IsDirectoryEmpty(patternDirPath)) {
Directory.Delete(patternDirPath, recursive: true);
}
}
public bool IsDirectoryEmpty(string dirPath) {
var dirInfo = new DirectoryInfo(dirPath);
var dirs = dirInfo?.GetDirectories();
var files = dirInfo?.GetFiles();
return (dirs?.Length == 0 && files?.Length == 0);
}
public abstract List<PatternInfo> GetPatternInfoListFromFiles(string curRecipePath);
public int SavePatternInfoToFile(PatternInfo patternInfo, string filePath) {
var patternDirPath = Path.GetDirectoryName(filePath);
if (!Directory.Exists(patternDirPath)) {
Directory.CreateDirectory(patternDirPath);
}
using (var fs = File.Create(filePath))
using (var sw = new StreamWriter(fs))
using (var jtw = new JsonTextWriter(sw) {
Formatting = Formatting.Indented,
Indentation = 2,
}) {
(new JsonSerializer()).Serialize(jtw, patternInfo);
}
return E1.OK;
}
public static PatternIndex GetSubPatternIndex(PatternInfo mainPatternInfo, int subPatternId) {
var subPatternIndex = mainPatternInfo.GetPatternIndex().Clone() as PatternIndex;
subPatternIndex.PatternSubId = subPatternId;
return subPatternIndex;
}
public System.Drawing.Bitmap GetThumbnail(PatternInfo patternInfo) {
if (_patterns.ContainsKey(patternInfo)) {
if (PatternConstants.IsPatternBlock(patternInfo.PatternType)) {
return GetPatternBlockThumbnail(patternInfo);
}
var pattern = _patterns[patternInfo];
if (pattern != null) {
return pattern.GetThumbnail();
}
}
return ThumbnailUtil.GetDefaultImage();
}
public System.Drawing.Bitmap GetPatternBlockThumbnail(PatternInfo patternInfo) {
if (_patterns.ContainsKey(patternInfo)) {
if (PatternConstants.IsPatternBlock(patternInfo.PatternType)) {
var patternBlock = _patterns[patternInfo] as IPatternBlock;
var findRois = new List<ROI>();
foreach (var patternId in patternBlock.GetPatternBlockIds()) {
var curPatternIndex = patternInfo.GetPatternIndex().Clone() as PatternIndex;
curPatternIndex.PatternId = patternId;
var patterBlockPatternInfo = GetPatternInfo(curPatternIndex);
var findRoi = GetFindROI(patterBlockPatternInfo);
findRois.Add(findRoi);
}
return patternBlock.GetThumbnail(findRois);
}
}
return ThumbnailUtil.GetDefaultImage();
}
/// <summary>
/// C2_F4 or C4_F4에서 라인 교점으로 얼라인 하는 경우, 각 FOV들 간에 상관관계를 이용하여 라인 교점 알고리즘을 보상해주기 위해 라인 중점 저장
/// </summary>
/// <param name="patternResult">라인 결과</param>
/// <param name="patternInfo">패턴 정보</param>
/// <param name="cameraDisplay">카메라 디스플레이</param>
public void SetLineCenterPoint(PatternResult patternResult, PatternInfo patternInfo, ICameraDisplay cameraDisplay) {
var fovInfo = cameraDisplay.GetDisplayFovInfo();
var alignInfo = VisionRecipeManager.GetAlignInfo(fovInfo.UnitId, fovInfo.SubSysId, eAlignId.Align1);
var alignRecipe = VisionRecipeManager.GetAlignRecipe(alignInfo);
if (patternResult.Status == eFoundStatus.ForceOK) {
// 라인 교점
if (patternResult.PatternType == ePatternType.LineIntersection) {
var results = patternResult.Results.ToList();
var baseResult = results[0] as BaseResult;
var calibrator = CalAdapter.Instance.CalManager.GetCalibrator(fovInfo);
var cameraAgent = CameraAgentManager.GetCameraAgent(fovInfo);
var imageSize = cameraAgent.GetImageSize();
var calibratedPoint = CalAdapter.Instance.CalManager.TransformToCalibratedSpace(fovInfo, baseResult.ImagePosition, imageSize);
LineFittingManager.SetLineCenterPoint(fovInfo, eLineDirection.H, calibratedPoint);
LineFittingManager.SetLineCenterPoint(fovInfo, eLineDirection.V, calibratedPoint);
}
else {
// 싱글 라인
var results = patternResult.Results.ToList();
if (results.Count > 0) {
var baseResult = results[0] as BaseResult;
var lineType = Line<ImagePoint>.GetLineDirection(baseResult.Angle);
var calibrator = CalAdapter.Instance.CalManager.GetCalibrator(fovInfo);
var cameraAgent = CameraAgentManager.GetCameraAgent(fovInfo);
var imageSize = cameraAgent.GetImageSize();
var calibratedPoint = CalAdapter.Instance.CalManager.TransformToCalibratedSpace(fovInfo, baseResult.ImagePosition, imageSize);
LineFittingManager.SetLineCenterPoint(fovInfo, lineType, calibratedPoint);
}
}
}
}
public abstract int GetMilSystemId(eCamId camId);
public abstract int GetFindNumber(PatternInfo patternInfo);
public abstract bool IsTrainPattern(PatternInfo patternInfo);
public abstract bool IsDeletable(PatternInfo patternInfo, int patternIndex);
public void Dispose() {
ClearPatterns(_patterns);
}
}
}