886 lines
30 KiB
C#
886 lines
30 KiB
C#
/*
|
|
* 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.Diagnostics;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Cognex.VisionPro.FGGigE;
|
|
using Cognex.VisionPro.Exceptions;
|
|
using VisionCommonUI;
|
|
using System.Windows;
|
|
using VisionCommonUI.Resources;
|
|
using System.Collections.Generic;
|
|
|
|
namespace CogCamera {
|
|
/// <summary>
|
|
/// Cognex 카메라 디바이스
|
|
/// </summary>
|
|
public class CogCamera : CameraBase {
|
|
private ICogFrameGrabber _CogFrameGrabber;
|
|
private ICogAcqFifo _CogAcqFifo;
|
|
|
|
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 ICogCameraDisplay _CogCameraDisplay; // Fov별로 가지는 CogCameraDisplay를 호출시마다 받아서 사용
|
|
private CogImgFlipAndRotationTool _CogImgFlipAndRotationTool;
|
|
|
|
/// <summary>
|
|
/// 생성자
|
|
/// </summary>
|
|
/// <param name="deviceId">디바이스 ID</param>
|
|
public CogCamera(string deviceId) : base(deviceId) {
|
|
var subject = string.Format("CogCamera[{0}]", deviceId);
|
|
LOG = new Logger(subject);
|
|
TactTimeChecker = new TactTimeChecker(subject);
|
|
}
|
|
|
|
protected override int DoActivate(IDeviceConfig config) {
|
|
if (IsActivated) {
|
|
LOG.FuncI("Already Activated!");
|
|
return E1.OK;
|
|
}
|
|
|
|
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()) {
|
|
MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_NoCogLicense);
|
|
return E1.GENERIC;
|
|
}
|
|
if (E1.OK != InitDigitizer()) {
|
|
MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_DigitizerInitError);
|
|
return E1.GENERIC;
|
|
}
|
|
if (E1.OK != SetImageSize()) {
|
|
MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_ImageSizeSettingError);
|
|
return E1.GENERIC;
|
|
}
|
|
if (E1.OK != AllocImages()) {
|
|
MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_ImageNotAllocated);
|
|
return E1.GENERIC;
|
|
}
|
|
if (E1.OK != SetTrigger()) {
|
|
MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_TriggerSettingError);
|
|
return E1.GENERIC;
|
|
}
|
|
if (E1.OK != SetExposureTimeFromConfig()) {
|
|
MessageBoxUtil.ShowMessageBoxError(StrTokens.MSG_E_ExposureTimeSettingError);
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
private int InitDigitizer() {
|
|
try {
|
|
string ipAddress = CamConfig.CamConnConfig.IpAddress;
|
|
|
|
if (ipAddress != string.Empty) {
|
|
// CamConfig에 저장된 IP주소와 매칭되는 카메라를 찾아서 연결
|
|
_CogFrameGrabber = CogGrabberManager.Instance.GetCogFrameGrabberFromIpAddress(ipAddress);
|
|
}
|
|
else {
|
|
// CamConfig에 IP주소를 저장하지 않고 동적으로 카메라 연결
|
|
_CogFrameGrabber = CogGrabberManager.Instance.GetCogFrameGrabberFromDeviceId(DeviceId);
|
|
}
|
|
|
|
if (_CogFrameGrabber == null) {
|
|
LOG.FuncE("GigE camera does not exists.");
|
|
return E2.NOT_FOUND;
|
|
}
|
|
|
|
LOG.FuncI($"DeviceId : {DeviceId}");
|
|
LOG.FuncI($"_CogFrameGrabber.Name : {_CogFrameGrabber.Name}");
|
|
LOG.FuncI($"_CogFrameGrabber.Index : {_CogFrameGrabber.Index}");
|
|
LOG.FuncI($"_CogFrameGrabber.AvailablePortsNum : {_CogFrameGrabber.GetNumCameraPorts("Generic GigEVision (Mono)")}");
|
|
|
|
_CogAcqFifo = _CogFrameGrabber.CreateAcqFifo("Generic GigEVision (Mono)", CogAcqFifoPixelFormatConstants.Format8Grey, 0, true);
|
|
_CogAcqFifo.Complete += new CogCompleteEventHandler(HookHandler);
|
|
_CogAcqFifo.OwnedExposureParams.Exposure = (CamConfig.ExposureTime_Ms > 0) ? CamConfig.ExposureTime_Ms : 50; // Default
|
|
|
|
return E1.OK;
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
private int SetImageSize() {
|
|
int startX = 0;
|
|
int startY = 0;
|
|
int width = 0;
|
|
int height = 0;
|
|
int band = 1;
|
|
int bitDepth = 8;
|
|
|
|
try {
|
|
_CogAcqFifo.OwnedROIParams.GetROIXYWidthHeight(out startX, out startY, out width, out height);
|
|
CogImagePixelFormatConstants pixelConstants = _CogAcqFifo.AcquiredPixelFormat();
|
|
|
|
CamConfig.ImageSize.Width = (int)width;
|
|
CamConfig.ImageSize.Height = (int)height;
|
|
|
|
if (pixelConstants == CogImagePixelFormatConstants.Grey8) {
|
|
CamConfig.ImageSize.Channel = 1;
|
|
CamConfig.ImageSize.BitDepth = 8;
|
|
}
|
|
else {
|
|
CamConfig.ImageSize.Channel = 3;
|
|
CamConfig.ImageSize.BitDepth = 24;
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
LOG.E(e.Message);
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
private int SetExposureTimeFromConfig() {
|
|
try {
|
|
SetExposure(CamConfig.ExposureTime_Ms);
|
|
}
|
|
catch (Exception e) {
|
|
LOG.E(e.Message);
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
protected int AllocImages() {
|
|
try {
|
|
var results = new List<int>();
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 버퍼 복제
|
|
/// </summary>
|
|
/// <returns>복제 버퍼</returns>
|
|
public override object CloneImageBuffer() {
|
|
return CogEnvironment.CloneImage(_CroppedImage);
|
|
}
|
|
|
|
private int SetTrigger() {
|
|
try {
|
|
_CogAcqFifo.OwnedTriggerParams.TriggerEnabled = true;
|
|
|
|
if (CamConfig.TriggerMode.IsSoftware) {
|
|
return SetSwTrigger();
|
|
}
|
|
else {
|
|
return SetHwTrigger();
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
return E1.GENERIC;
|
|
}
|
|
}
|
|
|
|
private int SetHwTrigger() {
|
|
try {
|
|
_CogAcqFifo.OwnedTriggerParams.TriggerModel = CogAcqTriggerModelConstants.Auto;
|
|
|
|
#region AcquisitionControl Set
|
|
var cogGigEAccess = _CogAcqFifo.FrameGrabber.OwnedGigEAccess;
|
|
var features = cogGigEAccess.GetAvailableFeatures("AcquisitionControl");
|
|
|
|
foreach (var feature in features) {
|
|
var cur_key = feature.ToString();
|
|
|
|
if (cur_key.Equals("TriggerMode")) {
|
|
if (cogGigEAccess.IsWriteable("TriggerMode")) {
|
|
cogGigEAccess.SetFeature("TriggerMode", "On");
|
|
LOG.FuncI($"TriggerMode On");
|
|
}
|
|
}
|
|
if (cur_key.Equals("TriggerSource")) {
|
|
if (cogGigEAccess.IsWriteable("TriggerSource")) {
|
|
cogGigEAccess.SetFeature("TriggerSource", CamConfig.TrigSrc.ToString());
|
|
LOG.FuncI($"TriggerSource {CamConfig.TrigSrc.ToString()}");
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region DigitalIOControl Set For Strobe
|
|
features = cogGigEAccess.GetAvailableFeatures("DigitalIOControl");
|
|
foreach (var feature in features) {
|
|
var cur_key = feature.ToString();
|
|
|
|
// 현장 상황에 맞도록 변경 필요
|
|
//if (cur_key.Equals("LineSelector")) {
|
|
// if (cogGigEAccess.IsWriteable("LineSelector")) {
|
|
// cogGigEAccess.SetFeature("LineSelector", "Line2");
|
|
// LOG.FuncI($"LineSelector Line2");
|
|
// }
|
|
//}
|
|
//if (cur_key.Equals("LineSource")) {
|
|
// if (cogGigEAccess.IsWriteable("LineSource")) {
|
|
// cogGigEAccess.SetFeature("LineSource", "ExposureActive");
|
|
// LOG.FuncI($"LineSource ExposureActive");
|
|
// }
|
|
//}
|
|
}
|
|
#endregion
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
private int SetSwTrigger() {
|
|
try {
|
|
_CogAcqFifo.OwnedTriggerParams.TriggerModel = CogAcqTriggerModelConstants.Manual;
|
|
|
|
#region AcquisitionControl Set
|
|
var cogGigEAccess = _CogAcqFifo.FrameGrabber.OwnedGigEAccess;
|
|
var features = cogGigEAccess.GetAvailableFeatures("AcquisitionControl");
|
|
|
|
foreach (var feature in features) {
|
|
var cur_key = feature.ToString();
|
|
|
|
if (cur_key.Equals("AcquisitionMode")) {
|
|
if (cogGigEAccess.IsWriteable("AcquisitionMode")) {
|
|
cogGigEAccess.SetFeature("AcquisitionMode", "Continuous");
|
|
LOG.FuncI($"AcquisitionMode Continuous");
|
|
}
|
|
}
|
|
if (cur_key.Equals("TriggerMode")) {
|
|
if (cogGigEAccess.IsWriteable("TriggerMode")) {
|
|
cogGigEAccess.SetFeature("TriggerMode", "Off");
|
|
LOG.FuncI($"TriggerMode Off");
|
|
}
|
|
}
|
|
if (cur_key.Equals("TriggerSource")) {
|
|
if (cogGigEAccess.IsWriteable("TriggerSource")) {
|
|
cogGigEAccess.SetFeature("TriggerSource", "Software");
|
|
LOG.FuncI($"TriggerSource {CamConfig.TrigSrc.ToString()}");
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
return E1.OK;
|
|
}
|
|
#endregion
|
|
|
|
protected override int DoDeactivate() {
|
|
if (!IsActivated) {
|
|
LOG.I("Already Deactivated!");
|
|
return E1.OK;
|
|
}
|
|
|
|
return Dispose();
|
|
}
|
|
|
|
#region Dispose
|
|
private int Dispose() {
|
|
try {
|
|
StopBufLive();
|
|
FreeImages();
|
|
|
|
_CogFrameGrabber?.Disconnect(true);
|
|
CogGrabberManager.Instance.Dispose();
|
|
CogEnvironment.Instance.Dispose();
|
|
|
|
return E1.OK;
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
private void StopBufLive() {
|
|
if (!IsActivated)
|
|
return;
|
|
|
|
try {
|
|
lock (LockThis) {
|
|
StopLive();
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
LOG.E(e.Message);
|
|
}
|
|
}
|
|
|
|
private void FreeImages() {
|
|
try {
|
|
CogEnvironment.FreeImage(_OriginalImage);
|
|
CogEnvironment.FreeImage(_FilteredImage);
|
|
CogEnvironment.FreeImage(_FilteredLiveImage);
|
|
}
|
|
catch (Exception e) {
|
|
LOG.E(e.Message);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 카메라 연결 유무
|
|
/// </summary>
|
|
/// <returns>연결 유무</returns>
|
|
public override bool IsConnected() {
|
|
bool cached = false;
|
|
var status = _CogFrameGrabber?.GetStatus(cached);
|
|
|
|
return status == CogFrameGrabberStatusConstants.Active;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 카메라 Gain 읽기
|
|
/// </summary>
|
|
/// <returns>Gain 값</returns>
|
|
public override int GetGain() => throw new NotSupportedException();
|
|
|
|
/// <summary>
|
|
/// 카메라 Gain 쓰기
|
|
/// </summary>
|
|
/// <param name="gain">Gain 값</param>
|
|
/// <returns>성공 유무</returns>
|
|
public override int SetGain(int gain) => throw new NotSupportedException();
|
|
|
|
/// <summary>
|
|
/// 카메라 노출시간 읽기
|
|
/// </summary>
|
|
/// <returns>노출시간</returns>
|
|
public override double GetExposure() {
|
|
if (!IsConnected()) {
|
|
return E2.NOT_READY;
|
|
}
|
|
|
|
return _CogAcqFifo.OwnedExposureParams.Exposure;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 카메라 최소 노출시간 읽기
|
|
/// </summary>
|
|
/// <returns>최소 노출시간</returns>
|
|
public override double GetMinExposure() {
|
|
if (!IsConnected()) {
|
|
return E2.NOT_READY;
|
|
}
|
|
|
|
return _CogAcqFifo.OwnedExposureParams.MinExposure;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 카메라 최대 노출시간 읽기
|
|
/// </summary>
|
|
/// <returns>최대 노출시간</returns>
|
|
public override double GetMaxExposure() => throw new NotSupportedException();
|
|
|
|
/// <summary>
|
|
/// 카메라 노출시간 쓰기
|
|
/// </summary>
|
|
/// <param name="exposureTime_ms">노출시간[ms]</param>
|
|
/// <returns>성공 유무</returns>
|
|
public override int SetExposure(double exposureTime_ms) {
|
|
if (!IsConnected()) {
|
|
return E2.NOT_READY;
|
|
}
|
|
|
|
_CogAcqFifo.OwnedExposureParams.Exposure = CamConfig.ExposureTime_Ms;
|
|
LOG.I($"Exposure Time Set : {exposureTime_ms} ms");
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 반전 & 회전 Config 갱신
|
|
/// </summary>
|
|
/// <param name="flipAndRotation">이미지 반전 & 회전 Config</param>
|
|
/// <returns>성공 유무</returns>
|
|
public override int ResetFlipAndRotation(FlipAndRotation flipAndRotation) {
|
|
_CogImgFlipAndRotationTool.ResetFlipAndRotation(flipAndRotation);
|
|
return E1.OK;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 디스플레이 가져오기
|
|
/// </summary>
|
|
/// <returns>디스플레이</returns>
|
|
public override ICameraDisplay GetDisplay() {
|
|
return _CogCameraDisplay;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 디스플레이 지정하기
|
|
/// </summary>
|
|
/// <param name="cameraDisplay">디스플레이</param>
|
|
public override void SetDisplay(ICameraDisplay cameraDisplay) {
|
|
_CogCameraDisplay = cameraDisplay as ICogCameraDisplay;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 사이즈 가져오기
|
|
/// </summary>
|
|
/// <returns>이미지 사이즈</returns>
|
|
public override ImageSize GetImageSize() {
|
|
return CogEnvironment.Instance.GetImageSize(CamConfig);
|
|
}
|
|
|
|
#region Grab
|
|
/// <summary>
|
|
/// 버퍼로부터 이미지를 꺼내온다.
|
|
/// </summary>
|
|
/// <param name="cameraDisplay">디스플레이</param>
|
|
/// <param name="image">이미지</param>
|
|
/// <returns>성공 유무</returns>
|
|
public override int GetGrabImageFromBuffer(ICameraDisplay cameraDisplay, ref object image) {
|
|
SetDisplay(cameraDisplay as ICogCameraDisplay);
|
|
return GetGrabImage(ref image, isExtTrig: true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 동기식 그랩
|
|
/// </summary>
|
|
/// <param name="cameraDisplay">디스플레이</param>
|
|
/// <param name="image">그랩 이미지</param>
|
|
/// <returns>성공 유무</returns>
|
|
public override int GrabSync(ICameraDisplay cameraDisplay, ref object image) {
|
|
SetDisplay(cameraDisplay as ICogCameraDisplay);
|
|
CogEnvironment.ClearImage(image);
|
|
CogEnvironment.ClearImage(_OriginalImage);
|
|
|
|
if (CamConfig.TriggerMode.IsSoftware) {
|
|
return GrabSync_SwTrig(ref image);
|
|
}
|
|
else {
|
|
return GrabSync_HwTrig(ref image);
|
|
}
|
|
}
|
|
|
|
private int GrabSync_HwTrig(ref object grabImage) {
|
|
for (int i = 1; i <= CamConfig.GrabRetry; i++) {
|
|
int res = GrabSync_HwTrig_Internal(ref grabImage);
|
|
if (res == E1.OK) {
|
|
return E1.OK;
|
|
}
|
|
LOG.I($"Grab Retry : {i}");
|
|
}
|
|
LOG.E("Grab Fail");
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
private int GrabSync_HwTrig_Internal(ref object grabImage) {
|
|
try {
|
|
SetHookCompleted(false);
|
|
|
|
TriggerOn();
|
|
Thread.Sleep(CamConfig.HwTrigConfig.OffDelay_Ms);
|
|
TriggerOff();
|
|
|
|
return GetGrabImage(ref grabImage, isExtTrig: false);
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
private int GrabSync_SwTrig(ref object image) {
|
|
//TactTimeChecker.Start(TactTimeType.Grab, "GrabSyncWithFiltering");
|
|
try {
|
|
SetHookCompleted(false);
|
|
|
|
lock (LockThis) {
|
|
int ticket = _CogAcqFifo.StartAcquire();
|
|
}
|
|
//LOG.FuncI($"Grab Ticket : {ticket}");
|
|
|
|
return GetGrabImage(ref image, isExtTrig: false);
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
|
|
//TactTimeChecker.Stop(TactTimeType.Grab, "GrabSyncWithFiltering");
|
|
return E1.GENERIC;
|
|
}
|
|
|
|
private int GetGrabImage(ref object image, bool isExtTrig) {
|
|
var stopWatch = Stopwatch.StartNew();
|
|
while (stopWatch.ElapsedMilliseconds < CamConfig.GrabTimeout_Ms) {
|
|
bool hookCompleted = isExtTrig ? IsHookCompletedByExtTrig() : IsHookCompleted();
|
|
if (hookCompleted) {
|
|
//LOG.W($"Grab Completed : {stopWatch.ElapsedMilliseconds} ms");
|
|
|
|
FlipAndRotateImage();
|
|
CropImage();
|
|
SetDisplayImage();
|
|
|
|
image = IsLiveOn() ? _CroppedLiveImage : _CroppedImage;
|
|
|
|
return E1.OK;
|
|
}
|
|
Thread.Sleep(10);
|
|
}
|
|
|
|
LOG.E($"HookHandler Time Out!! [{CamConfig.GrabTimeout_Ms} ms] ");
|
|
return E1.GENERIC;
|
|
}
|
|
#endregion
|
|
|
|
#region Live
|
|
/// <summary>
|
|
/// 라이브 시작
|
|
/// </summary>
|
|
/// <param name="cameraDisplay">디스플레이</param>
|
|
public override void StartLive(ICameraDisplay cameraDisplay) {
|
|
lock (_LiveLock) {
|
|
// 이미 라이브가 실행중이면, 디스플레이만 변경한다.
|
|
SetDisplay(cameraDisplay);
|
|
|
|
if (!IsLiveOn()) {
|
|
LiveOn();
|
|
if (CamConfig.TriggerMode.IsSoftware) {
|
|
Task.Run(() => { StartLive_SwTrig(); });
|
|
}
|
|
else {
|
|
Task.Run(() => { StartLive_HwTrig(); });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 라이브 종료
|
|
/// </summary>
|
|
public override void StopLive() {
|
|
lock (_LiveLock) {
|
|
if (IsLiveOn()) {
|
|
LiveOff();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void StartLive_HwTrig() {
|
|
try {
|
|
while (IsLiveOn()) {
|
|
SetHookCompleted(false);
|
|
|
|
TriggerOn();
|
|
Thread.Sleep(CamConfig.HwTrigConfig.OffDelay_Ms);
|
|
TriggerOff();
|
|
|
|
var stopWatch = Stopwatch.StartNew();
|
|
while (stopWatch.ElapsedMilliseconds < CamConfig.GrabTimeout_Ms) {
|
|
if (IsHookCompleted()) {
|
|
FlipAndRotateImage();
|
|
CropImage();
|
|
SetDisplayImage();
|
|
break;
|
|
}
|
|
Thread.Sleep(10);
|
|
}
|
|
//Thread.Sleep(CamConfig.LiveDelay);
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
}
|
|
|
|
private void StartLive_SwTrig() {
|
|
try {
|
|
object tmpImage = null; // 라이브때 리턴 이미지는 필요X
|
|
|
|
while (IsLiveOn()) {
|
|
GrabSync(_CogCameraDisplay, ref tmpImage);
|
|
Thread.Sleep(CamConfig.LiveDelay_Ms);
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
private void TriggerOn() {
|
|
try {
|
|
EquipAdapter.Instance.EquipTrigger.TriggerOn(CamConfig);
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
}
|
|
|
|
private void TriggerOff() {
|
|
try {
|
|
EquipAdapter.Instance.EquipTrigger.TriggerOff(CamConfig);
|
|
}
|
|
catch (Exception e) {
|
|
LOG.FuncE(e.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 디스플레이에서 이미지 꺼내오기
|
|
/// </summary>
|
|
/// <param name="cameraDisplay">디스플레이</param>
|
|
/// <returns>디스플레이 이미지</returns>
|
|
public override object GetImageFromDisplay(ICameraDisplay cameraDisplay) {
|
|
// 버퍼 그랩 이후, 디스플레이로부터 이미지를 꺼내오는 부분
|
|
// 이미지를 꺼내오기 전에 cameraDisplay와 동일한 _CogCameraDisplay가 사전에 Set되어 있어야 함.
|
|
var cogCameraDisplay = cameraDisplay as ICogCameraDisplay;
|
|
if (cogCameraDisplay.IsSetImage()) {
|
|
return cogCameraDisplay.GetImage();
|
|
}
|
|
|
|
LOG.FuncE("Image of cogCameraDisplay is null.");
|
|
return null;
|
|
}
|
|
|
|
//public override ICogImage GetGrabImageFromQueue(eGrabTrigSrcType grabTrigSrcType) {
|
|
// if (_CogImgQueManager.IsImgQueSet(grabTrigSrcType))
|
|
// return _CogImgQueManager.Dequeue();
|
|
// else
|
|
// return null;
|
|
//}
|
|
|
|
private void HookHandler(object sender, CogCompleteEventArgs e) {
|
|
try {
|
|
PrintHookLog();
|
|
|
|
var acqInfo = new CogAcqInfo();
|
|
_OriginalImage = ((ICogAcqFifo)sender).CompleteAcquireEx(acqInfo);
|
|
//var rawImage = ((ICogAcqFifo)sender).CompleteAcquireEx(acqInfo);
|
|
//CogEnvironment.CopyImage(rawImage, ref _OriginalImage); // 중복 Copy 제거
|
|
|
|
SetHookCompleted(true);
|
|
if (CamConfig.TriggerMode.IsExternal) {
|
|
SetHookCompletedByExtTrig(true);
|
|
}
|
|
}
|
|
catch (Exception ex) {
|
|
LOG.FuncE(ex.Message);
|
|
}
|
|
}
|
|
|
|
private void PrintHookLog() {
|
|
if (!IsLiveOn()) {
|
|
LOG.FuncV("[HW Trigger] HookHandler Called.");
|
|
}
|
|
}
|
|
|
|
#region For Flying
|
|
/// <summary>
|
|
/// 플라잉 시작
|
|
/// </summary>
|
|
/// <param name="fovInfo">FOV 정보</param>
|
|
/// <param name="param">추가 파라미터</param>
|
|
/// <returns>성공 유무</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 플라잉 종료
|
|
/// </summary>
|
|
/// <param name="param">추가 파라미터</param>
|
|
/// <returns>성공 유무</returns>
|
|
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
|
|
/// <summary>
|
|
/// Child 이미지들로 Parent(원장) 이미지가 정상적으로 만들어지는지 검증
|
|
/// </summary>
|
|
/// <param name="cameraDisplay">디스플레이</param>
|
|
/// <param name="image">원장(부모) 이미지</param>
|
|
/// <returns>성공 유무</returns>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class HookDataStruct {
|
|
public ICogImage HookDigitizer;
|
|
public ICogImage HookImage;
|
|
public int HookCnt;
|
|
}
|
|
}
|
|
} |