2026-06-05 13:44:39 +09:00

624 lines
26 KiB
C#

using Aurora;
using Aurora.Api;
using Aurora.View;
using Hermes;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace VisionCommon {
public abstract class PatternAgentBase : IDisposable {
protected object _lockObj = new object();
protected Logger _logger = null;
protected SubSysInfo _subSysInfo;
protected Dictionary<PatternInfo, IPatternFinder> _patterns = new Dictionary<PatternInfo, IPatternFinder>();
public PatternAgentBase() {
}
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) {
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;
}
public PatternResult Find(
PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult = null) {
if (PatternConstants.IsPatternBlock(patternInfo.PatternType)) {
return FindPatternBlock(patternInfo, image, cameraDisplay, fixtureResult);
}
return FindPatterns(patternInfo, image, cameraDisplay, fixtureResult);
}
public PatternResult FindPatterns(
PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult = null) {
var allPatternInfos = GetMainSubPatterns(patternInfo);
//[SR] tack우선 인가(Fastest), 스코어 우선인가(BestFind)를 구분할 필요는 현재 없음
// MultiLine만 모두 다 찾는 것으로 분기 하고 기타 로직은 이전과 같음.
if(patternInfo.PatternType == ePatternType.MultiLineFinder) {
//[SR] multi의 경우 다 찾는다
var returnResult = new List<PatternResult>();
Parallel.ForEach(allPatternInfos, curPatternInfo => {
returnResult.Add(FindPattern(curPatternInfo, image, cameraDisplay, fixtureResult));
});
var orderResult = returnResult.OrderBy(result => result.PatternIndex.PatternSubId).ToList();
var foundResult = orderResult.FirstOrDefault()?.Clone();
List<LineFinderResult> resultsList = new List<LineFinderResult>();
foreach (var lineFinderResult in orderResult) {
if (lineFinderResult != null) {
var temp = lineFinderResult.Results as List<LineFinderResult>;
if (temp.Count > 0) {
temp[0].AddFoundStatus(lineFinderResult.Status);
resultsList.Add(temp[0]);
}
else {
var notfound = new LineFinderResult();
//[SR] MultiPattern의 경우 못찾은경우에도 결과를 넣어줘야하기때문에
notfound.AddFoundStatus(lineFinderResult.Status);
notfound.AddFoundStatus(lineFinderResult.FindRoi);
resultsList.Add(notfound);
}
}
}
foundResult.Results = resultsList;
return foundResult;
}
else{
//[SR] 일반패턴의 로직은 그대로 유지한다.
var patternResult = new PatternResult();
foreach (var curPatternInfo in allPatternInfos) {
patternResult = FindPattern(curPatternInfo, image, cameraDisplay, fixtureResult);
if (patternResult.Status == eFoundStatus.FoundOK) {
break;
}
}
return patternResult;
}
}
public abstract PatternResult FindPattern(
PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult);
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);
}
#warning [SR] FindPattern 우선 구현
return FindPattern(patternInfo, image, findRoi);
}
public abstract PatternResult FindPattern(PatternInfo patternInfo, object image, ROI findRoi = null);
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 GetFindNumber(PatternInfo patternInfo);
public abstract bool IsTrainPattern(PatternInfo patternInfo);
public void Dispose() {
ClearPatterns(_patterns);
}
}
}