2026-01-26 14:51:28 +09:00

582 lines
24 KiB
C#

/*
* 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 {
/// <summary>
/// Cognex 패턴 에이전트
/// </summary>
public class CogPatternAgent : PatternAgentBase {
/// <summary>
/// 생성자
/// </summary>
/// <param name="subSysInfo">서브시스템 정보</param>
public CogPatternAgent(
FovInfo fovInfo) : base(fovInfo) {
LoadPatterns();
SetObservable();
}
private void SetObservable() {
var observable = VisionEventId.GetRecipeActivatedObservable();
observable.Subscribe(_ => LoadPatterns());
}
/// <summary>
/// 모든 패턴 Finder 객체 가져오기
/// </summary>
/// <returns>모든 패턴 Finder 객체</returns>
public override Dictionary<PatternInfo, IPatternFinder> GetPatterns() {
return _patterns;
}
#region Main Patterns
/// <summary>
/// 메인 패턴 정보 리스트 가져오기
/// </summary>
/// <param name="subSysInfo">서브시스템 정보</param>
/// <param name="fovId">FOV ID</param>
/// <returns>메인 패턴 정보 리스트</returns>
public override List<PatternInfo> GetMainPatterns(SubSysInfo subSysInfo, eFovId fovId) {
var fovIdxPrefix = PatternIndex.GetPrefix(subSysInfo.UnitId, subSysInfo.SubSysId, fovId);
return GetMainPatterns(fovIdxPrefix);
}
/// <summary>
/// 메인 패턴 정보 리스트 가져오기
/// </summary>
/// <param name="fovInfo">FOV 정보</param>
/// <returns>메인 패턴 정보 리스트</returns>
public override List<PatternInfo> GetMainPatterns(FovInfo fovInfo) {
var fovIdxPrefix = PatternIndex.GetPrefix(fovInfo.UnitId, fovInfo.SubSysId, fovInfo.FovId);
return GetMainPatterns(fovIdxPrefix);
}
#endregion
/// <summary>
/// 패턴 정보 가져오기
/// </summary>
/// <param name="fovInfo">FOV 정보</param>
/// <param name="patternId">패턴 ID</param>
/// <returns>패턴정보</returns>
public override PatternInfo GetPatternInfo(FovInfo fovInfo, int patternId) {
return GetPatternInfo(
new PatternIndex(fovInfo.UnitId, fovInfo.SubSysId, fovInfo.FovId, patternId));
}
/// <summary>
/// 패턴 루트 경로 가져오기
/// </summary>
/// <returns>패턴 루트 경로</returns>
public override string GetPatternInfoPath() {
if (VisionSettingManager.VisionSetting.UseCamPattern) {
return VisionEnv.VisionRootDataPath;
}
else {
return PatternConstants.GetCurrentRecipeFilePath();
}
}
/// <summary>
/// 패턴 가져오기
/// </summary>
/// <returns>패턴</returns>
public override int LoadPatterns() {
if (E1.OK != ClearPatterns(_patterns)) {
return E1.GENERIC;
}
if (E1.OK != LoadPatterns(_patterns)) {
return E1.GENERIC;
}
return E1.OK;
}
/// <summary>
/// 패턴 복사
/// </summary>
/// <param name="sourcePatternIndex">소스 패턴 인덱스</param>
/// <param name="dstPatternIndex">타겟 패턴 인덱스</param>
/// <returns>성공 유무</returns>
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);
}
/// <summary>
/// 패턴 Tool 가져오기
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <returns>패턴 Tool</returns>
public override object GetTool(PatternInfo patternInfo) {
if (GetPatterns().ContainsKey(patternInfo)) {
return GetPatterns()[patternInfo].GetTool();
}
return null;
}
#region Find for Sequence
/// <summary>
/// 패턴 찾기
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <param name="image">이미지</param>
/// <param name="cameraDisplay">카메라 디스플레이</param>
/// <param name="fixtureResult">픽스쳐 결과</param>
/// <returns>패턴 결과</returns>
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
/// <summary>
/// 패턴 찾기
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <param name="image">이미지</param>
/// <param name="findRoi">찾기 영역</param>
/// <returns>패턴 결과</returns>
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;
}
/// <summary>
/// 패턴 블록 찾기
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <param name="image">이미지</param>
/// <param name="findRoi">찾기 영역</param>
/// <returns>패턴 결과</returns>
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<PatternResult>();
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
/// <summary>
/// 패턴 결과 그리기
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <param name="patternResult">패턴 결과</param>
/// <param name="cameraDisplay">카메라 디스플레이</param>
/// <param name="isFixturePattern">픽스쳐 패턴 여부</param>
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);
}
/// <summary>
/// 패턴 생성
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <returns>패턴 Finder 객체</returns>
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;
}
/// <summary>
/// 패턴 경로로부터 패턴 정보 가져오기
/// </summary>
/// <param name="curRecipePath">패턴 루트 경로</param>
/// <returns>패턴 정보 리스트</returns>
public override List<PatternInfo> GetPatternInfoListFromFiles(string curRecipePath) {
var patternInfoList = new List<PatternInfo>();
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;
}
/// <summary>
/// MilSystemId 가져오기 (미사용)
/// </summary>
/// <param name="camId">카메라 ID</param>
/// <returns>MilSystemId</returns>
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<T, U> SortDictionary<T, U>(Dictionary<T, U> dict) {
return dict.OrderBy(item => item.Key).ToDictionary(x => x.Key, x => x.Value);
}
/// <summary>
/// 찾을 패턴 개수 가져오기
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <returns>찾을 패턴 개수</returns>
public override int GetFindNumber(PatternInfo patternInfo) {
if (patternInfo.PatternType == ePatternType.ImageModelFinder) {
ImageModelFinder imageModelFinder = new ImageModelFinder(patternInfo);
return (imageModelFinder.GetFindNumber());
}
else {
return 1;
}
}
/// <summary>
/// 트레인을 지원하는 패턴인지 체크
/// </summary>
/// <param name="patternInfo">패턴 정보</param>
/// <returns>트레인 지원 패턴 여부</returns>
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;
}
}
}