/* * Copyright (c) 2025 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora; using Aurora.Api; using CogCommon; using VisionCommon; using Hermes; using Cognex.VisionPro; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reactive.Linq; using Cognex.VisionPro.Display; using System.Windows; namespace CogPattern { /// /// Cognex 패턴 에이전트 /// public class CogPatternAgent : PatternAgentBase { /// /// 생성자 /// /// 서브시스템 정보 public CogPatternAgent( FovInfo fovInfo) : base(fovInfo) { LoadPatterns(); SetObservable(); } private void SetObservable() { var observable = VisionEventId.GetRecipeActivatedObservable(); observable.Subscribe(_ => LoadPatterns()); } /// /// 모든 패턴 Finder 객체 가져오기 /// /// 모든 패턴 Finder 객체 public override Dictionary GetPatterns() { return _patterns; } #region Main Patterns /// /// 메인 패턴 정보 리스트 가져오기 /// /// 서브시스템 정보 /// FOV ID /// 메인 패턴 정보 리스트 public override List GetMainPatterns(SubSysInfo subSysInfo, eFovId fovId) { var fovIdxPrefix = PatternIndex.GetPrefix(subSysInfo.UnitId, subSysInfo.SubSysId, fovId); return GetMainPatterns(fovIdxPrefix); } /// /// 메인 패턴 정보 리스트 가져오기 /// /// FOV 정보 /// 메인 패턴 정보 리스트 public override List GetMainPatterns(FovInfo fovInfo) { var fovIdxPrefix = PatternIndex.GetPrefix(fovInfo.UnitId, fovInfo.SubSysId, fovInfo.FovId); return GetMainPatterns(fovIdxPrefix); } #endregion /// /// 패턴 정보 가져오기 /// /// FOV 정보 /// 패턴 ID /// 패턴정보 public override PatternInfo GetPatternInfo(FovInfo fovInfo, int patternId) { return GetPatternInfo( new PatternIndex(fovInfo.UnitId, fovInfo.SubSysId, fovInfo.FovId, patternId)); } /// /// 패턴 루트 경로 가져오기 /// /// 패턴 루트 경로 public override string GetPatternInfoPath() { if (VisionSettingManager.VisionSetting.UseCamPattern) { return VisionEnv.VisionRootDataPath; } else { return PatternConstants.GetCurrentRecipeFilePath(); } } /// /// 패턴 가져오기 /// /// 패턴 public override int LoadPatterns() { if (E1.OK != ClearPatterns(_patterns)) { return E1.GENERIC; } if (E1.OK != LoadPatterns(_patterns)) { return E1.GENERIC; } return E1.OK; } /// /// 패턴 복사 /// /// 소스 패턴 인덱스 /// 타겟 패턴 인덱스 /// 성공 유무 public override int CopyPattern(PatternIndex sourcePatternIndex, PatternIndex dstPatternIndex) { // 1. Copy string curRecipePath = GetPatternInfoPath(); string sourcePatternPath = Path.Combine(new string[] { curRecipePath, PatternConstants.DIR_NAME_PATTERN, sourcePatternIndex.GetSubPatternDirectoryPath() }); string dstPatternPath = Path.Combine(new string[] { curRecipePath, PatternConstants.DIR_NAME_PATTERN, dstPatternIndex.GetSubPatternDirectoryPath() }); // 2. Remove old dst pattern if (E1.OK != Remove(dstPatternIndex)) { _logger.FuncE($"Remove error"); return E1.GENERIC; } // 3. Copy pattern files if (E1.OK != CopyPatternFiles(sourcePatternPath, dstPatternPath)) { _logger.FuncE($"CopyPatternFiles error"); return E1.GENERIC; } // 4. Reload copied pattern files var patternInfoFilePath = Path.Combine(dstPatternPath, PatternConstants.FILE_NAME_PATTERN_INFO); if (!File.Exists(patternInfoFilePath)) { _logger.FuncE($"patternInfoFilePath does NOT exist : {patternInfoFilePath}"); return E1.GENERIC; } var sourcePatternInfo = GetPatternInfo(sourcePatternIndex); var dstPatternInfo = LoadPatternInfoFromFile(patternInfoFilePath); dstPatternInfo.MilSystemId = sourcePatternInfo.MilSystemId; dstPatternInfo.PatternIndex = dstPatternIndex.Clone() as PatternIndex; return ReloadPattern(dstPatternInfo); } /// /// 패턴 Tool 가져오기 /// /// 패턴 정보 /// 패턴 Tool public override object GetTool(PatternInfo patternInfo) { if (GetPatterns().ContainsKey(patternInfo)) { return GetPatterns()[patternInfo].GetTool(); } return null; } #region Find for Sequence /// /// 패턴 찾기 /// /// 패턴 정보 /// 이미지 /// 카메라 디스플레이 /// 픽스쳐 결과 /// 패턴 결과 public override PatternResult FindPattern( PatternInfo patternInfo, object image, ICameraDisplay cameraDisplay, FixtureResult fixtureResult) { var findImage = (ICogImage)image; var patternResult = new PatternResult(); var pattern = _patterns[patternInfo]; if (((PatternBase)pattern).IsDirty()) { ((PatternBase)pattern).CleanDirty(); pattern.Load(); } ROI fixtureRoi = GetFixtureROI(patternInfo, fixtureResult); patternResult.FindRoi = fixtureRoi.Clone() as ROI; if (!patternInfo.IsActivated) { _logger.I($"{patternInfo} : NOT activated"); patternResult = pattern.GetNotFoundPatternResult(); } else { if (patternInfo.PreProcParam.Enabled()) { ICogImage preProcImage = null; try { preProcImage = findImage; // 임시 (전처리 구현 후, 아래 코드 사용 예정) //preProcImage = ImgPreProcessor.GetPreProcessedImage(findImage, patternInfo.PreProcParam); patternResult = Find(patternInfo, preProcImage, fixtureRoi); CopyImageToDisplay(cameraDisplay as ICogCameraDisplay, preProcImage); } catch (Exception e) { _logger.I($"{e.Message}"); } finally { CogEnvironment.FreeImage(preProcImage); } } else { patternResult = Find(patternInfo, findImage, fixtureRoi); } } if (patternResult.Status == eFoundStatus.FoundOK) { foreach (var reuslt in patternResult.Results) { _logger.I($"{patternInfo} : {patternResult.Status} : {reuslt}"); } } else { _logger.I($"{patternInfo} : {patternResult.Status}"); } SetPatternParams(patternInfo, patternResult); if (patternResult.PatternType == ePatternType.LineFinder) { SetLineCenterPoint(patternResult, patternInfo, cameraDisplay); } return patternResult; } private void CopyImageToDisplay(ICogCameraDisplay cogCameraDisplay, ICogImage preProcImage) { var displayImage = cogCameraDisplay.GetImage(); if (CogEnvironment.ImageSizeEquals(preProcImage, displayImage)) { CogEnvironment.CopyImage(preProcImage, ref displayImage); } } #endregion #region TestFind for Pattern Registration /// /// 패턴 찾기 /// /// 패턴 정보 /// 이미지 /// 찾기 영역 /// 패턴 결과 public override PatternResult FindPattern(PatternInfo patternInfo, object image, ROI findRoi = null) { var findImage = (ICogImage)image; var patternResult = new PatternResult() { PatternIndex = patternInfo.GetPatternIndex().Clone() as PatternIndex, }; if (_patterns.ContainsKey(patternInfo)) { if (patternInfo.IsActivated) { var pattern = _patterns[patternInfo]; if (findRoi == null) { patternResult = pattern.Find(findImage); } else { patternResult = pattern.Find(findImage, findRoi); } patternResult.FindRoi = (findRoi != null) ? findRoi : GetFindROI(patternInfo); } else { _logger.I($"Pattern is not activated."); } } else { _logger.I($"Pattern does not exist."); } SetPatternParams(patternInfo, patternResult); return patternResult; } /// /// 패턴 블록 찾기 /// /// 패턴 정보 /// 이미지 /// 찾기 영역 /// 패턴 결과 public override PatternResult FindPatternBlock(PatternInfo patternInfo, object image, ROI findRoi = null) { var findImage = (ICogImage)image; var patternResult = new PatternResult() { PatternIndex = patternInfo.GetPatternIndex().Clone() as PatternIndex, }; if (_patterns.ContainsKey(patternInfo)) { if (patternInfo.IsActivated) { var pattern = _patterns[patternInfo]; var patternBlock = pattern as IPatternBlock; var patternBlockResults = new List(); foreach (var patternId in patternBlock.GetPatternBlockIds()) { var curPatternIndex = patternInfo.GetPatternIndex().Clone() as PatternIndex; curPatternIndex.PatternId = patternId; var patterBlockPatternInfo = GetPatternInfo(curPatternIndex); var curPattern = GetPattern(patterBlockPatternInfo); PatternResult curPatternResult; if (findRoi == null) { curPatternResult = curPattern.Find(findImage); } else { curPatternResult = curPattern.Find(findImage, findRoi); } curPatternResult.FindRoi = (findRoi != null) ? findRoi : GetFindROI(patterBlockPatternInfo); SetPatternParams(patterBlockPatternInfo, curPatternResult); patternBlockResults.Add(curPatternResult); } patternResult = patternBlock.Find(patternBlockResults); patternResult.FindRoi = (findRoi != null) ? findRoi : GetFindROI(patternInfo); } else { _logger.I($"Pattern is not activated."); } } else { _logger.I($"Pattern does not exist."); } SetPatternParams(patternInfo, patternResult); return patternResult; } #endregion /// /// 패턴 결과 그리기 /// /// 패턴 정보 /// 패턴 결과 /// 카메라 디스플레이 /// 픽스쳐 패턴 여부 public override void Draw( PatternInfo patternInfo, PatternResult patternResult, ICameraDisplay cameraDisplay, bool isFixturePattern = false) { // Draw 택타임이 길어 비동기식으로 변경함. Application.Current.Dispatcher.BeginInvoke( new Action(() => { if (_patterns.ContainsKey(patternInfo)) { var cogCameraDisplay = cameraDisplay as ICogCameraDisplay; IPatternFinder pattern; if (patternResult.Status != eFoundStatus.NotFound && patternResult.PatternIndex != null) { pattern = GetPattern(patternResult.PatternIndex); } else { pattern = _patterns[patternInfo]; } if (PatternConstants.IsPatternBlock(patternInfo.PatternType)) { DrawPatternBlockResult(pattern, patternResult, cogCameraDisplay, isFixturePattern); } else { DrawPatternResult(pattern, patternResult, cogCameraDisplay, isFixturePattern); } } })); } private void DrawPatternResult( IPatternFinder pattern, PatternResult patternResult, ICogCameraDisplay cogCameraDisplay, bool isFixturePattern) { DrawFindROI(patternResult, cogCameraDisplay, isFixturePattern); pattern.Draw(patternResult, cogCameraDisplay, isFixturePattern); } private void DrawPatternBlockResult( IPatternFinder pattern, PatternResult patternResult, ICogCameraDisplay cogCameraDisplay, bool isFixturePattern) { foreach (var patternBlockResult in patternResult.Results) { PatternResult line1PatternResult = null; PatternResult line2PatternResult = null; if (patternBlockResult.GetType() == typeof(LineIntersectionResult)) { var intersectionResult = patternBlockResult as LineIntersectionResult; line1PatternResult = intersectionResult.Line1PatternResult; line2PatternResult = intersectionResult.Line2PatternResult; } else if (patternBlockResult.GetType() == typeof(CaliperResult)) { var caliperResult = patternBlockResult as CaliperResult; line1PatternResult = caliperResult.PatternResultFirst; line2PatternResult = caliperResult.PatternResultSecond; } DrawFindROI(line1PatternResult, cogCameraDisplay, isFixturePattern); DrawFindROI(line2PatternResult, cogCameraDisplay, isFixturePattern); pattern.Draw(patternResult, cogCameraDisplay, isFixturePattern); } } private void DrawFindROI( PatternResult patternResult, ICogCameraDisplay cogCameraDisplay, bool isFixturePattern) { var cogDisplay = cogCameraDisplay.GetDisplay() as CogDisplay; var color = CogColorConstants.Cyan; if (patternResult == null) { return; } if (patternResult.PatternType == ePatternType.Brightness && patternResult.Status == eFoundStatus.FoundOK) { color = ColorConverter.ConvertColor(eColor.Magenta); } else { color = GraphicColors.GetFindRoiColor(patternResult.Status, isFixturePattern); } cogCameraDisplay.AddPatternResultFindRoi(cogDisplay, color, patternResult.FindRoi); } /// /// 패턴 생성 /// /// 패턴 정보 /// 패턴 Finder 객체 public override IPatternFinder CreatePattern(PatternInfo patternInfo) { switch (patternInfo.PatternType) { case ePatternType.ImageModelFinder: return new ImageModelFinder(patternInfo); //case ePatternType.ShapeModelFinder: // return new ShapeModelFinder(patternInfo); //case ePatternType.PatternMatching: // return new PatternMatching(patternInfo); case ePatternType.LineFinder: return new LineFinder(patternInfo); case ePatternType.Caliper: return new Caliper(patternInfo); //case ePatternType.EdgeFinder: // return new EdgeFinder(patternInfo); case ePatternType.Blob: return new Blob(patternInfo); //case ePatternType.Code: // return new Code(patternInfo); //case ePatternType.Ocr: // return new OcrFinder(patternInfo); case ePatternType.Brightness: return new Brightness(patternInfo); case ePatternType.LineIntersection: return new LineIntersection(patternInfo); case ePatternType.LineWidth: return new LineWidth(patternInfo); case ePatternType.MachinePattern_A: case ePatternType.MachinePattern_B: case ePatternType.MachinePattern_C: return EquipAdapter.Instance.MachinePatternManager.GetPattern(patternInfo); } _logger.E($"No matching of PatternType : {patternInfo.PatternType}"); return null; } /// /// 패턴 경로로부터 패턴 정보 가져오기 /// /// 패턴 루트 경로 /// 패턴 정보 리스트 public override List GetPatternInfoListFromFiles(string curRecipePath) { var patternInfoList = new List(); var camRecipe = VisionRecipeManager.GetCamRecipe(_fovInfo); var patternCount = 0; if (VisionSettingManager.VisionSetting.UseCamPattern) { patternCount = PatternConstants.CAM_PATTERN_COUNT; } else { patternCount = PatternConstants.FOV_PATTERN_COUNT; } for (int patternId = 0; patternId < patternCount; patternId++) { string patternDirPath; if (VisionSettingManager.VisionSetting.UseCamPattern) { patternDirPath = Path.Combine( curRecipePath, PatternConstants.DIR_NAME_PATTERN, ((int)_camId).ToString(), patternId.ToString()); } else { patternDirPath = Path.Combine( curRecipePath, PatternConstants.DIR_NAME_PATTERN, ((int)_fovInfo.UnitId).ToString(), ((int)_fovInfo.SubSysId).ToString(), ((int)_fovInfo.FovId).ToString(), patternId.ToString()); } if (Directory.Exists(patternDirPath)) { var patternDirPathList = Directory.GetDirectories(patternDirPath, "??", SearchOption.TopDirectoryOnly); foreach (var subPatternDirPath in patternDirPathList) { if (Directory.Exists(subPatternDirPath)) { var patternInfoFilePath = Path.Combine(subPatternDirPath, PatternConstants.FILE_NAME_PATTERN_INFO); if (File.Exists(patternInfoFilePath)) { var patternInfo = LoadPatternInfoFromFile(patternInfoFilePath); patternInfo.MilSystemId = GetMilSystemId(camRecipe.CamId); patternInfo.PatternIndex = new PatternIndex( _fovInfo.UnitId, _fovInfo.SubSysId, _fovInfo.FovName, _fovInfo.FovId, patternId, Convert.ToInt32(Path.GetFileName(subPatternDirPath))); patternInfoList.Add(patternInfo); } } } } } return patternInfoList; } private PatternInfo LoadPatternInfoFromFile(string filePath) { return JsonConvert.DeserializeObject( File.ReadAllText(filePath), typeof(PatternInfo)) as PatternInfo; } /// /// MilSystemId 가져오기 (미사용) /// /// 카메라 ID /// MilSystemId public override int GetMilSystemId(eCamId camId) { //var camConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(camId.ToString()) as CamConfig; //return (int)CogEnvironment.Instance.GetSystem(camConfig.CamConnConfig.BoardSlotPos); return 0; // 임시 } private Dictionary SortDictionary(Dictionary dict) { return dict.OrderBy(item => item.Key).ToDictionary(x => x.Key, x => x.Value); } /// /// 찾을 패턴 개수 가져오기 /// /// 패턴 정보 /// 찾을 패턴 개수 public override int GetFindNumber(PatternInfo patternInfo) { if (patternInfo.PatternType == ePatternType.ImageModelFinder) { ImageModelFinder imageModelFinder = new ImageModelFinder(patternInfo); return (imageModelFinder.GetFindNumber()); } else { return 1; } } /// /// 트레인을 지원하는 패턴인지 체크 /// /// 패턴 정보 /// 트레인 지원 패턴 여부 public override bool IsTrainPattern(PatternInfo patternInfo) { var pattern = GetPattern(patternInfo); if (pattern is IPatternTrain) { return true; } else { return false; } } public override bool IsDeletable(PatternInfo patternInfo, int patternIndex) { if (patternInfo.PatternType == ePatternType.LineIntersection) { var runparam = GetRunParam(patternInfo) as LineIntersectionRunParam; if (runparam.PatternId1 == patternIndex || runparam.PatternId2 == patternIndex) { return false; } } else if (patternInfo.PatternType == ePatternType.LineWidth) { var runparam = GetRunParam(patternInfo) as LineWidthRunParam; if (runparam.PatternId1 == patternIndex || runparam.PatternId2 == patternIndex) { return false; } } return true; } } }