using Aurora; using Aurora.Api; using Aurora.Api.DataType; using MilCommon; using VisionCommon; using Hermes; using Matrox.MatroxImagingLibrary; 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 MilCamera { /// /// MIL 시뮬 카메라 디바이스 /// public class MilCameraMock : CameraBase { private List _DummyImgPaths = new List(); private List _DummyImgs = new List(); private IMilCameraDisplay _MilCameraDisplay; // Fov별로 가지는 MilCameraDisplay를 호출시마다 받아서 사용 private MilImgFlipAndRotationTool _MilImgFlipAndRotationTool; private MIL_ID _OriginalImage = MIL.M_NULL; // 원본 이미지 버퍼 private MIL_ID _FilteredImage = MIL.M_NULL; // Flip + Rotation 이미지 버퍼 private MIL_ID _FilteredLiveImage = MIL.M_NULL; // Flip + Rotation 라이브 이미지 버퍼 private MIL_ID _CroppedImage = MIL.M_NULL; // Flip + Rotation + Crop 이미지 버퍼 private MIL_ID _CroppedLiveImage = MIL.M_NULL; // Flip + Rotation + Crop 라이브 이미지 버퍼 private int _DummyImgCounter = 0; /// /// 생성자 /// /// 디바이스 ID public MilCameraMock(string deviceId) : base(deviceId) { LOG = new Logger(string.Format("MilCameraMock[{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); _MilImgFlipAndRotationTool = new MilImgFlipAndRotationTool(camId, CamConfig); var res = Init(); if (res == E1.OK) { CheckImageBufferRotationChanged(); } return res; } #region Init private int Init() { MilEnvironment.Instance.AllocSys(CamConfig.CamConnConfig.BoardType, CamConfig.CamConnConfig.BoardSlotPos); if (!MilEnvironment.Instance.HasValidLicense()) { LOG.FuncE("No MIL 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; } protected int AllocImages() { try { var results = new List(); //results.Add(AllocOriginalImage(ref _OriginalImage)); // 원본 이미지 불러오면서 버퍼가 자동 할당되므로 필요X results.Add(AllocFilteredImage(ref _FilteredImage)); results.Add(AllocFilteredImage(ref _FilteredLiveImage)); results.Add(AllocCroppedImage(ref _CroppedImage)); results.Add(AllocCroppedImage(ref _CroppedLiveImage)); results.AddRange(AllocProcImages()); foreach (int result in results) { if (result != E1.OK) { return E1.GENERIC; } } } catch (Exception e) { LOG.E(e.Message); 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; } #endregion protected override int DoDeactivate() { return Dispose(); } private int Dispose() { try { FreeImages(); return E1.OK; } catch (Exception e) { LOG.FuncE(e.Message); } return E1.GENERIC; } private void FreeImages() { try { MilEnvironment.FreeImage(_OriginalImage); MilEnvironment.FreeImage(_FilteredImage); MilEnvironment.FreeImage(_FilteredLiveImage); MilEnvironment.FreeImage(_CroppedImage); MilEnvironment.FreeImage(_CroppedLiveImage); MilEnvironment.FreeImage(_ParentImage); int bufSize = CamConfig.ChildImage.Enabled ? CamConfig.ChildImage.ChildBufRowCols.Count : CamConfig.HwTrigConfig.ProcBufSize; MilEnvironment.FreeProcImages(bufSize, _ProcImages); } 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 int GetExposure() => throw new NotImplementedException(); /// /// 카메라 최소 노출시간 읽기 /// /// 최소 노출시간 public override int GetMinExposure() => throw new NotImplementedException(); /// /// 카메라 최대 노출시간 읽기 /// /// 최대 노출시간 public override int GetMaxExposure() => throw new NotImplementedException(); /// /// 카메라 노출시간 쓰기 /// /// 노출시간[ms] /// 성공 유무 public override int SetExposure(int exposureTime_ms) { LOG.I($"Exposure Time Set : {exposureTime_ms} ms"); return E1.OK; } /// /// 이미지 반전 & 회전 Config 갱신 /// /// 이미지 반전 & 회전 Config /// 성공 유무 public override int ResetFlipAndRotation(FlipAndRotation flipAndRotation) { _MilImgFlipAndRotationTool?.ResetFlipAndRotation(flipAndRotation); return E1.OK; } private int AllocOriginalImage(ref MIL_ID image) { return MilEnvironment.Instance.AllocOriginalImage(CamConfig, ref image); } private int AllocFilteredImage(ref MIL_ID image) { return MilEnvironment.Instance.AllocFilteredImage(CamConfig, ref image); } private int AllocCroppedImage(ref MIL_ID image) { return MilEnvironment.Instance.AllocCroppedImage(CamConfig, ref image); } /// /// 이미지 버퍼 복제 /// /// 복제 버퍼 public override object CloneImageBuffer() { return MilEnvironment.CloneImage(_CroppedImage); } /// /// 디스플레이 가져오기 /// /// 디스플레이 public override ICameraDisplay GetDisplay() { return _MilCameraDisplay; } /// /// 디스플레이 지정하기 /// /// 디스플레이 public override void SetDisplay(ICameraDisplay cameraDisplay) { _MilCameraDisplay = cameraDisplay as IMilCameraDisplay; } /// /// 이미지 사이즈 가져오기 /// /// 이미지 사이즈 public override ImageSize GetImageSize() { return MilEnvironment.Instance.GetImageSize(CamConfig); } /// /// 버퍼로부터 이미지를 꺼내온다. 시뮬모드이므로 신규 그랩으로 처리 /// /// 디스플레이 /// 이미지 /// 성공 유무 public override int GetGrabImageFromBuffer(ICameraDisplay cameraDisplay, ref object image) { MilEnvironment.ClearImage(image); MilEnvironment.ClearImage(_OriginalImage); return GrabSync(cameraDisplay, ref image); } /// /// 동기식 그랩 /// /// 디스플레이 /// 그랩 이미지 /// 성공 유무 public override int GrabSync(ICameraDisplay cameraDisplay, ref object image) { SetDisplay(cameraDisplay as IMilCameraDisplay); MilEnvironment.ClearImage(image); MilEnvironment.ClearImage(_OriginalImage); if (_DummyImgPaths.Count > 0) { try { if (File.Exists(_DummyImgPaths[_DummyImgCounter])) { lock (LockThis) { MIL.MbufRestore(_DummyImgPaths[_DummyImgCounter], MilEnvironment.Instance.GetSystem( CamConfig.CamConnConfig.BoardType, CamConfig.CamConnConfig.BoardSlotPos), ref _OriginalImage); FlipAndRotateImage(); CropImage(); image = IsLiveOn() ? _CroppedLiveImage : _CroppedImage; AddImageIndex(_DummyImgCounter + 1, (MIL_ID)image); MIL.MbufFree(_OriginalImage); _OriginalImage = MIL.M_NULL; _DummyImgCounter++; if (_DummyImgCounter >= _DummyImgPaths.Count) { _DummyImgCounter = 0; } } SetFlyingImage(); SetDisplayImage(); return E1.OK; } } catch (Exception e) { LOG.E(e.Message); return E1.GENERIC; } } return E1.GENERIC; } #region For Hw Trigger private List AllocProcImages() { var results = new List(); if (!CamConfig.IsAlwaysSwTrigger()) { if (_ProcImages?.Length > 0) { MilEnvironment.FreeProcImages(_ProcImages.Length, _ProcImages); } if (CamConfig.ChildImage.Enabled) { results.Add(MilEnvironment.Instance.AllocParentImage(CamConfig, ref _ParentImage)); results.Add(MilEnvironment.Instance.AllocChildImages(CamConfig, _ParentImage, ref _ProcImages)); } else { _ProcImages = new object[CamConfig.HwTrigConfig.ProcBufSize]; results.Add(MilEnvironment.Instance.AllocProcImages(CamConfig, CamConfig.HwTrigConfig.ProcBufSize, ref _ProcImages)); } } return results; } #endregion #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 { SetDisplay(cameraDisplay); object childImage = CloneImageBuffer(); for (int i = 0; i < _ProcImages.Length; i++) { SetExposure((i + 1) * 5); GrabSync(_MilCameraDisplay, ref childImage); MilEnvironment.CopyImage((MIL_ID)childImage, (MIL_ID)_ProcImages[i]); } image = GetParentImage(); MilEnvironment.FreeImage(childImage); return E1.OK; } catch (Exception e) { LOG.FuncE(e.Message); } return E1.GENERIC; } #endregion private void AddImageIndex(int index, MIL_ID filteredImage) { if (filteredImage == MIL.M_NULL) { return; } var imageSize = MilEnvironment.GetImageSize(filteredImage); var imageCenter = MilEnvironment.GetImageCenter(filteredImage); // String - Image Index var fontSize = 60; var strPosX = imageCenter.X - fontSize; var strPosY = imageSize.Height - fontSize * (float)1.5; MIL.MgraFontScale(MIL.M_DEFAULT, 6, 6); MIL.MgraText(MIL.M_DEFAULT, filteredImage, strPosX, strPosY, index.ToString()); MIL.MgraFontScale(MIL.M_DEFAULT, 1, 1); } private void SetDisplayImage() { if (_MilCameraDisplay == null) { return; } if (IsLiveOn()) { if (_CroppedLiveImage != null) { _MilCameraDisplay.SetImage(_CroppedLiveImage); } } else { if (_CroppedImage != null) { _MilCameraDisplay.SetImage(_CroppedImage); } } } private void FlipAndRotateImage() { if (_OriginalImage == null) { LOG.FuncE("_OriginalImage is null."); return; } if (IsLiveOn()) { _MilImgFlipAndRotationTool.FlipAndRotation(_OriginalImage, ref _FilteredLiveImage); } else { _MilImgFlipAndRotationTool.FlipAndRotation(_OriginalImage, ref _FilteredImage); } } private void CropImage() { var cropRoi = GetCropRoi(); if (IsLiveOn()) { if (_FilteredLiveImage != null) { _CroppedLiveImage = MilEnvironment.CropImage(_FilteredLiveImage, cropRoi); } } else { if (_FilteredImage != null) { _CroppedImage = MilEnvironment.CropImage(_FilteredImage, cropRoi); } } } /// /// 라이브 시작 /// /// 디스플레이 public override void StartLive(ICameraDisplay cameraDisplay) { if (_CroppedLiveImage == MIL.M_NULL) { MessageBoxUtil.ShowMessageBoxError(string.Format(StrTokens.MSG_E_SomethingNotAllocated, "_CroppedLiveImage")); return; } 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(_MilCameraDisplay, ref tmpImage); Thread.Sleep(CamConfig.LiveDelay_Ms); } } catch (Exception e) { LOG.FuncE(e.Message); } } /// /// 디스플레이에서 이미지 꺼내오기 /// /// 디스플레이 /// 디스플레이 이미지 public override object GetImageFromDisplay(ICameraDisplay cameraDisplay) { var milCameraDisplay = cameraDisplay as IMilCameraDisplay; // 버퍼 그랩 이후, 디스플레이로부터 이미지를 꺼내오는 부분 // 이미지를 꺼내오기 전에 milCameraDisplay와 동일한 _MilCameraDisplay가 사전에 Set되어 있어야 함. if (milCameraDisplay.IsSetImage()) { return milCameraDisplay.GetImage(); } LOG.FuncE("Image of milCameraDisplay is null."); return MIL.M_NULL; } #region For Custumizing (장비 전용 API) public override int GetInitialExposure() { return 0; } #endregion } }