/* * Copyright (c) 2025 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora; using Aurora.Api; using Aurora.Api.DataType; using CogCommon; using VisionCommon; using Hermes; using Cognex.VisionPro; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Threading; using System.Threading.Tasks; using System.Windows; using VisionCommonUI; using VisionCommonUI.Resources; namespace CogCamera { /// /// Cognex 시뮬 카메라 디바이스 /// public class CogCameraMock : CameraBase { private List _DummyImgPaths = new List(); private List _DummyImgs = new List(); private ICogCameraDisplay _CogCameraDisplay; // Fov별로 가지는 CogCameraDisplay를 호출시마다 받아서 사용 private CogImgFlipAndRotationTool _CogImgFlipAndRotationTool; private ICogImage _OriginalImage = null; // 원본 이미지 버퍼 private ICogImage _FilteredImage = null; // Flip + Rotation 이미지 버퍼 private ICogImage _FilteredLiveImage = null; // Flip + Rotation 라이브 이미지 버퍼 private ICogImage _CroppedImage = null; // Flip + Rotation + Crop 이미지 버퍼 private ICogImage _CroppedLiveImage = null; // Flip + Rotation + Crop 라이브 이미지 버퍼 private int _DummyImgCounter = 0; /// /// 생성자 /// /// public CogCameraMock(string deviceId) : base(deviceId) { LOG = new Logger(string.Format("CogCameraMock[{0}]", deviceId)); Task.Run(() => { SetDummyImages(); }); } private void SetDummyImages() { try { var dummyImgDestPath = Path.Combine(System.Environment.CurrentDirectory, "_dummyImages", DeviceId); _DummyImgPaths.AddRange( Directory.EnumerateFiles(dummyImgDestPath, "*.bmp", SearchOption.TopDirectoryOnly) ); _DummyImgPaths.AddRange( Directory.EnumerateFiles(dummyImgDestPath, "*.png", SearchOption.TopDirectoryOnly) ); _DummyImgPaths.AddRange( Directory.EnumerateFiles(dummyImgDestPath, "*.jpg", SearchOption.TopDirectoryOnly) ); _DummyImgPaths.AddRange( Directory.EnumerateFiles(dummyImgDestPath, "*.jpeg", SearchOption.TopDirectoryOnly) ); foreach (var dummyImgPath in _DummyImgPaths) { LOG.FuncI("Current Img File : {0} ", dummyImgPath); _DummyImgs.Add((Bitmap)Image.FromFile(dummyImgPath)); } } catch (Exception e) { LOG.FuncE(e.Message); } } protected override int DoActivate(IDeviceConfig config) { CamConfig = config as CamConfig; eCamId camId = CamRecipe.GetCamIdFromDevId(DeviceId); _CogImgFlipAndRotationTool = new CogImgFlipAndRotationTool(camId, CamConfig); var res = Init(); if (res == E1.OK) { CheckImageBufferRotationChanged(); } return res; } #region Init private int Init() { if (!CogEnvironment.Instance.HasValidLicense()) { LOG.FuncE("No Cognex License."); return E1.GENERIC; } if (E1.OK != SetImageSize()) { MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_ImageSizeSettingError); return E1.GENERIC; } if (E1.OK != AllocImages()) { LOG.FuncE("AllocImage Error."); return E1.GENERIC; } return E1.OK; } private int SetImageSize() { try { if (_DummyImgs.Count > 0) { CamConfig.ImageSize.Width = _DummyImgs[0].Width; CamConfig.ImageSize.Height = _DummyImgs[0].Height; } else { CamConfig.ImageSize.Width = 2448; // Default SizeX CamConfig.ImageSize.Height = 2048; // Default SizeY } CamConfig.ImageSize.Channel = 1; CamConfig.ImageSize.BitDepth = 8; } catch (Exception e) { LOG.E(e.Message); return E1.GENERIC; } return E1.OK; } protected int AllocImages() { try { var results = new List(); results.Add(AllocOriginalImage(ref _OriginalImage)); results.Add(AllocFilteredImage(ref _FilteredImage)); results.Add(AllocFilteredImage(ref _FilteredLiveImage)); results.Add(AllocCroppedImage(ref _CroppedImage)); results.Add(AllocCroppedImage(ref _CroppedLiveImage)); foreach (int result in results) { if (result != E1.OK) { return E1.GENERIC; } } _CroppedImage = new CogImage8Grey(CamConfig.ImageSize.Width, CamConfig.ImageSize.Height); _FilteredImage = new CogImage8Grey(CamConfig.ImageSize.Width, CamConfig.ImageSize.Height); _FilteredLiveImage = new CogImage8Grey(CamConfig.ImageSize.Width, CamConfig.ImageSize.Height); } catch (Exception e) { LOG.E(e.Message); return E1.GENERIC; } return E1.OK; } private int AllocOriginalImage(ref ICogImage image) { return CogEnvironment.Instance.AllocOriginalImage(CamConfig, ref image); } private int AllocFilteredImage(ref ICogImage image) { if (CamConfig.ImageSize.Channel == 3) { return CogEnvironment.Instance.AllocColorImage(CamConfig, false, ref image); } else { return CogEnvironment.Instance.AllocGrayImage(CamConfig, false, ref image); } } private int AllocCroppedImage(ref ICogImage image) { if (CamConfig.ImageSize.Channel == 3) { return CogEnvironment.Instance.AllocColorImage(CamConfig, true, ref image); } else { return CogEnvironment.Instance.AllocGrayImage(CamConfig, true, ref image); } } #endregion protected override int DoDeactivate() { FreeImages(); CogEnvironment.Instance.Dispose(); return E1.OK; } private void FreeImages() { try { CogEnvironment.FreeImage(_FilteredImage); CogEnvironment.FreeImage(_FilteredLiveImage); } catch (Exception e) { LOG.E(e.Message); } } /// /// 카메라 연결 유무 /// /// 연결 유무 public override bool IsConnected() => IsActivated; /// /// 카메라 Gain 읽기 /// /// Gain 값 public override int GetGain() => throw new NotImplementedException(); /// /// 카메라 Gain 쓰기 /// /// Gain 값 /// 성공 유무 public override int SetGain(int gain) => throw new NotImplementedException(); /// /// 카메라 노출시간 읽기 /// /// 노출시간 public override double GetExposure() => throw new NotImplementedException(); /// /// 카메라 최소 노출시간 읽기 /// /// 최소 노출시간 public override double GetMinExposure() => throw new NotImplementedException(); /// /// 카메라 최대 노출시간 읽기 /// /// 최대 노출시간 public override double GetMaxExposure() => throw new NotImplementedException(); /// /// 카메라 노출시간 쓰기 /// /// 노출시간[ms] /// 성공 유무 public override int SetExposure(double exposureTime_ms) => throw new NotImplementedException(); /// /// 이미지 반전 & 회전 Config 갱신 /// /// 이미지 반전 & 회전 Config /// 성공 유무 public override int ResetFlipAndRotation(FlipAndRotation flipAndRotation) { _CogImgFlipAndRotationTool.ResetFlipAndRotation(flipAndRotation); return E1.OK; } /// /// 이미지 버퍼 복제 /// /// 복제 버퍼 public override object CloneImageBuffer() { return CogEnvironment.CloneImage(_CroppedImage); } /// /// 디스플레이 가져오기 /// /// 디스플레이 public override ICameraDisplay GetDisplay() { return _CogCameraDisplay; } /// /// 디스플레이 지정하기 /// /// 디스플레이 public override void SetDisplay(ICameraDisplay cameraDisplay) { _CogCameraDisplay = cameraDisplay as ICogCameraDisplay; } /// /// 이미지 사이즈 가져오기 /// /// 이미지 사이즈 public override ImageSize GetImageSize() { return CogEnvironment.Instance.GetImageSize(CamConfig); } /// /// 버퍼로부터 이미지를 꺼내온다. 시뮬모드이므로 신규 그랩으로 처리 /// /// 디스플레이 /// 이미지 /// 성공 유무 public override int GetGrabImageFromBuffer(ICameraDisplay cameraDisplay, ref object image) { return GrabSync(cameraDisplay, ref image); } /// /// 동기식 그랩 /// /// 디스플레이 /// 그랩 이미지 /// 성공 유무 public override int GrabSync(ICameraDisplay cameraDisplay, ref object image) { SetDisplay(cameraDisplay as ICogCameraDisplay); CogEnvironment.ClearImage(image); CogEnvironment.ClearImage(_OriginalImage); if (_DummyImgPaths.Count > 0) { try { if (File.Exists(_DummyImgPaths[_DummyImgCounter])) { lock (LockThis) { Bitmap bmpImg = GetDummyImage(); AddImageIndex(bmpImg, _DummyImgCounter + 1); _OriginalImage = new CogImage8Grey(bmpImg); FlipAndRotateImage(); CropImage(); image = IsLiveOn() ? _CroppedLiveImage : _CroppedImage; CogEnvironment.FreeImage(_OriginalImage); _OriginalImage = null; _DummyImgCounter++; if (_DummyImgCounter >= _DummyImgPaths.Count) { _DummyImgCounter = 0; } } SetDisplayImage(); return E1.OK; } } catch (Exception e) { LOG.E(e.Message); return E1.GENERIC; } } return E1.GENERIC; } private Bitmap GetDummyImage() { try { return (Bitmap)Image.FromFile(_DummyImgPaths[_DummyImgCounter]); } catch (Exception e) { LOG.FuncE(e.Message); } return null; } private void AddImageIndex(Bitmap bitmap, int index) { if (bitmap == null) { return; } using (var graphics = Graphics.FromImage(bitmap)) { var imageCenterX = bitmap.Width / 2; var drawStr = index.ToString(); // String - Image Index var fontSize = 60; var strPosX = imageCenterX - fontSize; var strPosY = bitmap.Height - fontSize * (float)1.5; var strBrush = new SolidBrush(Color.FromKnownColor(KnownColor.White)); var font = new Font("Consolas", fontSize, System.Drawing.FontStyle.Bold); // Rectangle - Black background var strSize = graphics.MeasureString(drawStr, font); var rect = new RectangleF( strPosX, strPosY, strSize.Width, strSize.Height); graphics.FillRectangle(Brushes.Black, rect); graphics.DrawString(drawStr, font, strBrush, strPosX, strPosY); } } #region For Flying /// /// 플라잉 시작 /// /// FOV 정보 /// 추가 파라미터 /// 성공 유무 public override int StartFlying(FovInfo fovInfo, object param = null) { if (IsFlyingRunning()) { LOG.FuncW("Flying Already Running..."); return E1.GENERIC; } LOG.I("Flying Start."); try { var camDisplay = CameraDisplayManager.GetDisplay(fovInfo); SetDisplay(camDisplay); _FlyingIdx = 0; _IsFlyingRunning = true; //StartMdigProcess(); } catch (Exception e) { LOG.FuncE(e.Message); return E1.GENERIC; } return E1.OK; } /// /// 플라잉 종료 /// /// 추가 파라미터 /// 성공 유무 public override int StopFlying(object param = null) { LOG.I("Flying Stopped."); try { _IsFlyingRunning = false; //StopMdigProcess(); } catch (Exception e) { LOG.FuncE(e.Message); return E1.GENERIC; } return E1.OK; } private void SetFlyingImage() { if (!CamConfig.TriggerMode.IsFlying) { return; } try { FlipAndRotateImage(); CropImage(); _FlyingIdx = (_FlyingIdx < _ProcImages.Length) ? _FlyingIdx : 0; //MilEnvironment.CopyImage(_CroppedImage, (MIL_ID)_ProcImages[_FlyingIdx++]); SetDisplayImage(); } catch (Exception e) { LOG.FuncE(e.Message); } } #endregion #region For Child Image /// /// Child 이미지들로 Parent(원장) 이미지가 정상적으로 만들어지는지 검증 /// /// 디스플레이 /// 원장(부모) 이미지 /// 성공 유무 public override int VerifyChildImage(ICameraDisplay cameraDisplay, ref object image) { try { return E1.OK; } catch (Exception e) { LOG.FuncE(e.Message); } return E1.GENERIC; } #endregion private void SetDisplayImage() { if (_CogCameraDisplay == null) { return; } if (IsLiveOn()) { if (_FilteredLiveImage != null) { _CogCameraDisplay.SetImage(_CroppedLiveImage); } } else { if (_FilteredImage != null) { _CogCameraDisplay.SetImage(_CroppedImage); } } } private void FlipAndRotateImage() { if (_OriginalImage == null) { LOG.FuncE("_OriginalImage is null."); return; } if (IsLiveOn()) { _CogImgFlipAndRotationTool.FlipAndRotation(_OriginalImage, ref _FilteredLiveImage); } else { _CogImgFlipAndRotationTool.FlipAndRotation(_OriginalImage, ref _FilteredImage); } } private void CropImage() { var cropRoi = GetCropRoi(); if (IsLiveOn()) { if (_FilteredLiveImage != null) { _CroppedLiveImage = CogEnvironment.CropImage(_FilteredLiveImage, cropRoi); } } else { if (_FilteredImage != null) { _CroppedImage = CogEnvironment.CropImage(_FilteredImage, cropRoi); } } } /// /// 라이브 시작 /// /// 디스플레이 public override void StartLive(ICameraDisplay cameraDisplay) { lock (_LiveLock) { // 이미 라이브가 실행중이면, 디스플레이만 변경한다. SetDisplay(cameraDisplay); if (!IsLiveOn()) { LiveOn(); Task.Run(() => { StartLive_Simul(); }); } } } /// /// 라이브 종료 /// public override void StopLive() { lock (_LiveLock) { if (IsLiveOn()) { LiveOff(); } } } private void StartLive_Simul() { try { object tmpImage = null; // 라이브때 리턴 이미지는 필요X while (IsLiveOn()) { GrabSync(_CogCameraDisplay, ref tmpImage); Thread.Sleep(CamConfig.LiveDelay_Ms); } } catch (Exception e) { LOG.FuncE(e.Message); } } /// /// 디스플레이에서 이미지 꺼내오기 /// /// 디스플레이 /// 디스플레이 이미지 public override object GetImageFromDisplay(ICameraDisplay cameraDisplay) { var cogCameraDisplay = cameraDisplay as ICogCameraDisplay; // 버퍼 그랩 이후, 디스플레이로부터 이미지를 꺼내오는 부분 // 이미지를 꺼내오기 전에 cogCameraDisplay와 동일한 _CogCameraDisplay가 사전에 Set되어 있어야 함. if (cogCameraDisplay.IsSetImage()) { return cogCameraDisplay.GetImage(); } LOG.FuncE("Image of cogCameraDisplay is null."); return null; } //public override MIL_ID GetGrabImageFromQueue(eGrabTrigSrcType grabTrigSrcType) { // // TO-DO // return MIL.M_NULL; //} } }