579 lines
20 KiB
C#
579 lines
20 KiB
C#
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.Reflection.Metadata;
|
||
using System.Xml.Linq;
|
||
using DH.Commons.Base;
|
||
using DH.Commons.Enums;
|
||
using DH.Commons.Helper;
|
||
using DVPCameraType;
|
||
using OpenCvSharp;
|
||
using OpenCvSharp.Extensions;
|
||
using static System.Net.Mime.MediaTypeNames;
|
||
using static MvCamCtrl.NET.MyCamera;
|
||
using LogLevel = DH.Commons.Enums.EnumHelper.LogLevel;
|
||
|
||
|
||
namespace DH.Devices.Camera
|
||
{
|
||
|
||
public class Do3ThinkCamera : CameraBase, ILogger
|
||
{
|
||
|
||
private dvpCameraInfo stDevInfo = new dvpCameraInfo();
|
||
private dvpStatus nRet = dvpStatus.DVP_STATUS_OK;
|
||
private DVPCamera.dvpEventCallback pCallBackFunc;
|
||
private uint m_handle;
|
||
public bool Connected=false;
|
||
public int m_n_dev_count = 0;
|
||
private DVPCamera.dvpStreamCallback ImageCallback;
|
||
public dvpStreamFormat dvpStreamFormat = dvpStreamFormat.S_RGB24;
|
||
public int m_CamCount = 0;
|
||
public Double m_dfDisplayCount = 0;
|
||
|
||
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
||
public event Action<LogMsg> OnLog;
|
||
public ConcurrentDictionary<string, MatSet> _imageSetList = new ConcurrentDictionary<string, MatSet>();
|
||
|
||
|
||
public Do3ThinkCamera()
|
||
{
|
||
LoggerHelper.LogPath = "D://";
|
||
LoggerHelper.LogPrefix = CameraName;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public bool IsValidHandle(uint handle)
|
||
{
|
||
bool bValidHandle = false;
|
||
dvpStatus status = DVPCamera.dvpIsValid(handle, ref bValidHandle);
|
||
if (status == dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
return bValidHandle;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
public override bool CameraConnect()
|
||
{
|
||
try
|
||
{
|
||
pCallBackFunc = new DVPCamera.dvpEventCallback(cbExceptiondelegate);
|
||
nRet = DVPCamera.dvpOpenByUserId(CameraName,
|
||
dvpOpenMode.OPEN_NORMAL,
|
||
ref m_handle);
|
||
|
||
// ch:打开设备 | en:Open device
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception($"Create device failed:{nRet:x8}");
|
||
}
|
||
|
||
nRet = DVPCamera.dvpSetTargetFormat(m_handle, (dvpStreamFormat)dvpStreamFormat);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception($"Set image format failed:{nRet:x8}");
|
||
}
|
||
|
||
dvpCameraInfo camerainfo = new dvpCameraInfo();
|
||
nRet = DVPCamera.dvpGetCameraInfo(m_handle, ref camerainfo);
|
||
|
||
SerialNumber = camerainfo.SerialNumber;
|
||
//ch: 注册异常回调函数 | en:Register Exception Callback
|
||
nRet = DVPCamera.dvpRegisterEventCallback(m_handle, pCallBackFunc, dvpEvent.EVENT_DISCONNECTED, IntPtr.Zero);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"Register expection callback failed:{nRet}");
|
||
}
|
||
GC.KeepAlive(pCallBackFunc);
|
||
|
||
//// ch:设置采集连续模式 | en:Set Continues Aquisition Mode
|
||
if (IsContinueMode)
|
||
{
|
||
// ch:设置触发模式为off || en:set trigger mode as off
|
||
nRet = DVPCamera.dvpSetTriggerState(m_handle, false);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception("Set TriggerMode failed!");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// ch:设置触发模式为on || en:set trigger mode as on
|
||
nRet = DVPCamera.dvpSetTriggerState(m_handle, true);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception("Set TriggerMode failed!");
|
||
}
|
||
|
||
// 硬触发
|
||
if (IsHardwareTrigger)
|
||
{
|
||
// ch:触发源选择:1 - Line1; | en:Trigger source select:1 - Line1;
|
||
nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_LINE1);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception("Set Line1 Trigger failed!");
|
||
}
|
||
|
||
// ch:注册回调函数 | en:Register image callback
|
||
ImageCallback = new DVPCamera.dvpStreamCallback(ImageCallbackFunc);
|
||
nRet = DVPCamera.dvpRegisterStreamCallback(m_handle, ImageCallback, dvpStreamEvent.STREAM_EVENT_PROCESSED, IntPtr.Zero);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception("Register image callback failed!");
|
||
}
|
||
}
|
||
else // 软触发
|
||
{
|
||
nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_SOFTWARE);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception("Set Software Trigger failed!");
|
||
}
|
||
}
|
||
|
||
// ch:开启抓图 || en: start grab image
|
||
nRet = DVPCamera.dvpStart(m_handle);
|
||
if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
{
|
||
throw new Exception($"Start grabbing failed:{nRet:x8}");
|
||
}
|
||
//// 曝光
|
||
if (Exposure != 0)
|
||
{
|
||
SetExposure(Exposure);
|
||
}
|
||
//// 增益
|
||
if (Gain >= 0)
|
||
{
|
||
SetGain(Gain);
|
||
}
|
||
//全画幅
|
||
if (!IsAllPicEnabled)
|
||
SetPictureRoi((int)ROIX, (int)ROIY, (int)ROIW, (int)ROIH);
|
||
|
||
//// 设置 触发延迟
|
||
if (TriggerDelay > 0)
|
||
{
|
||
nRet = DVPCamera.dvpSetTriggerDelay(m_handle, TriggerDelay);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception("Set TriggerDelay failed!");
|
||
}
|
||
}
|
||
|
||
//// 信号消抖
|
||
if (LineDebouncerTime > 0)
|
||
{
|
||
nRet = DVPCamera.dvpSetTriggerJitterFilter(m_handle, LineDebouncerTime);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"LineDebouncerTime set failed:{nRet}");
|
||
}
|
||
}
|
||
|
||
//IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
|
||
//IIConfig.PropertyChanged += IIConfig_PropertyChanged;
|
||
Connected = true;
|
||
|
||
}
|
||
return true;
|
||
}
|
||
catch
|
||
{
|
||
Connected = false;
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 回调函数
|
||
/// </summary>
|
||
/// <param name="handle"></param>
|
||
/// <param name="_event"></param>
|
||
/// <param name="pContext"></param>
|
||
/// <param name="param"></param>
|
||
/// <param name="refVariant"></param>
|
||
/// <returns></returns>
|
||
public int cbExceptiondelegate(uint handle, dvpEvent _event, IntPtr pContext, int param, ref dvpVariant refVariant)
|
||
{
|
||
|
||
if (_event == dvpEvent.EVENT_DISCONNECTED)
|
||
{
|
||
|
||
}
|
||
|
||
|
||
return dvpStatus.DVP_STATUS_OK.ToInt();
|
||
}
|
||
|
||
private void IIConfig_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||
{
|
||
//if (e.PropertyName == "IsHardwareTrigger" && !IIConfig.IsContinueMode)
|
||
//{
|
||
// // ch:停止抓图 | en:Stop grab image
|
||
// nRet = DVPCamera.dvpStop(m_handle);
|
||
// if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
// {
|
||
// throw new Exception($"Stop grabbing failed{nRet:x8}");
|
||
// }
|
||
|
||
// // 硬触发
|
||
// if (IIConfig.IsHardwareTrigger)
|
||
// {
|
||
// // ch:触发源选择:1 - Line1; | en:Trigger source select:1 - Line1;
|
||
// nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_LINE1);
|
||
// if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
// {
|
||
// throw new Exception("Set Line1 Trigger failed!");
|
||
// }
|
||
|
||
// // ch:注册回调函数 | en:Register image callback
|
||
// ImageCallback = new DVPCamera.dvpStreamCallback(ImageCallbackFunc);
|
||
// nRet = DVPCamera.dvpRegisterStreamCallback(m_handle, ImageCallback, dvpStreamEvent.STREAM_EVENT_PROCESSED, IntPtr.Zero);
|
||
// if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
// {
|
||
// throw new Exception("Register image callback failed!");
|
||
// }
|
||
// }
|
||
// else // 软触发
|
||
// {
|
||
// nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_SOFTWARE);
|
||
// if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
// {
|
||
// throw new Exception("Set Software Trigger failed!");
|
||
// }
|
||
// }
|
||
|
||
// // ch:开启抓图 || en: start grab image
|
||
// nRet = DVPCamera.dvpStart(m_handle);
|
||
// if (dvpStatus.DVP_STATUS_OK != nRet)
|
||
// {
|
||
// throw new Exception($"Start grabbing failed:{nRet:x8}");
|
||
// }
|
||
// // 曝光
|
||
// if (IIConfig.DefaultExposure != 0)
|
||
// {
|
||
// SetExposure(IIConfig.DefaultExposure);
|
||
// }
|
||
// // 增益
|
||
// if (IIConfig.Gain >= 0)
|
||
// {
|
||
// SetGain(IIConfig.Gain);
|
||
// }
|
||
|
||
// // 设置 触发延迟
|
||
// if (IIConfig.TriggerDelay > 0)
|
||
// {
|
||
// nRet = DVPCamera.dvpSetTriggerDelay(m_handle, IIConfig.TriggerDelay);
|
||
// if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
// {
|
||
// throw new Exception("Set TriggerDelay failed!");
|
||
// }
|
||
// }
|
||
|
||
// // 信号消抖
|
||
// if (IIConfig.LineDebouncerTime > 0)
|
||
// {
|
||
// nRet = DVPCamera.dvpSetTriggerJitterFilter(m_handle, IIConfig.LineDebouncerTime);
|
||
// if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
// {
|
||
// throw new Exception($"LineDebouncerTime set failed:{nRet}");
|
||
// }
|
||
// }
|
||
//}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置曝光值
|
||
/// </summary>
|
||
/// <param name="exposure">曝光值</param>
|
||
/// <exception cref="Exception"></exception>
|
||
private void SetExposure(double exposure)
|
||
{
|
||
// 关闭自动曝光
|
||
nRet = DVPCamera.dvpSetAeOperation(m_handle, dvpAeOperation.AE_OP_OFF);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"Exposure set failed:{nRet}");
|
||
}
|
||
// 设置曝光值
|
||
nRet = DVPCamera.dvpSetExposure(m_handle, exposure);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"Exposure set failed:{nRet}");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 设置增益
|
||
/// </summary>
|
||
/// <param name="gain"></param>
|
||
/// <exception cref="Exception"></exception>
|
||
private void SetGain(float gain)
|
||
{
|
||
// 设置增益
|
||
nRet = DVPCamera.dvpSetAnalogGain(m_handle, gain);
|
||
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"Gain set failed:{nRet}");
|
||
}
|
||
}
|
||
private void SetPictureRoi(int x, int y, int W, int H)
|
||
{
|
||
dvpRegion dvpR = new dvpRegion();
|
||
|
||
dvpR.X = x;
|
||
dvpR.Y = y;
|
||
dvpR.W = W;
|
||
dvpR.H = H;
|
||
// 设置增益
|
||
nRet = DVPCamera.dvpSetRoi(m_handle, dvpR);
|
||
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"SetRoi set failed:{nRet}");
|
||
}
|
||
}
|
||
|
||
public int ImageCallbackFunc(uint handle, dvpStreamEvent _event, IntPtr pContext, ref dvpFrame refFrame, IntPtr pBuffer)
|
||
{
|
||
Mat cvImage = new Mat();
|
||
if (this.CameraName.Equals("Cam1"))
|
||
{
|
||
Console.WriteLine();
|
||
}
|
||
if (this.CameraName.Equals("Cam2"))
|
||
{
|
||
Console.WriteLine();
|
||
}
|
||
try
|
||
{
|
||
|
||
Interlocked.Increment(ref SnapshotCount);
|
||
|
||
|
||
int nWidth = refFrame.iWidth;
|
||
int nHeight = refFrame.iHeight;
|
||
|
||
// 根据图像格式创建Mat
|
||
switch (refFrame.format)
|
||
{
|
||
case dvpImageFormat.FORMAT_RGB24:
|
||
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pBuffer);
|
||
Cv2.CvtColor(cvImage, cvImage, ColorConversionCodes.RGB2BGR);
|
||
break;
|
||
|
||
case dvpImageFormat.FORMAT_BGR24:
|
||
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pBuffer);
|
||
break;
|
||
|
||
case dvpImageFormat.FORMAT_MONO:
|
||
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pBuffer);
|
||
break;
|
||
|
||
default:
|
||
cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pBuffer);
|
||
break;
|
||
}
|
||
Mat smat = cvImage.Clone();
|
||
var imageSet = new MatSet
|
||
{
|
||
|
||
_mat = smat,
|
||
|
||
};
|
||
InitialImageSet(imageSet);
|
||
|
||
var outImgSet = CopyImageSet(imageSet);
|
||
OnHImageOutput?.Invoke(DateTime.Now, this, outImgSet);
|
||
|
||
//存图
|
||
DisplayAndSaveOriginImage(imageSet.Id, SnapshotCount);
|
||
|
||
|
||
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
|
||
}
|
||
finally
|
||
{
|
||
cvImage?.Dispose();
|
||
}
|
||
return 0;
|
||
}
|
||
public void InitialImageSet(MatSet set)
|
||
{
|
||
//if (saveOption != null)
|
||
//{
|
||
// set.ImageSaveOption = saveOption.Copy();
|
||
//}
|
||
|
||
//set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage;
|
||
//set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage;
|
||
//set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
|
||
set.CameraId = this.CameraName;
|
||
|
||
set.ImageTime = DateTime.Now;
|
||
_imageSetList[set.Id] = set;
|
||
}
|
||
|
||
public virtual async void DisplayAndSaveOriginImage(string imgSetId, int _counter)
|
||
{
|
||
MatSet set = _imageSetList.Values.FirstOrDefault(u => u.Id == imgSetId);
|
||
|
||
if (set != null && set._mat != null)
|
||
{
|
||
await Task.Run(() =>
|
||
{
|
||
Bitmap? showImage = null;
|
||
|
||
try
|
||
{
|
||
showImage = set._mat.ToBitmap();
|
||
}
|
||
catch (Exception)
|
||
{
|
||
//释放 himage
|
||
ClearImageSet(set);
|
||
return;
|
||
}
|
||
|
||
// showImage.Save("D:/test333.bmp");
|
||
// Marshal.Copy(pbyteImageBuffer, 0, (IntPtr)lAddrImage, (int)dwBufferSize);
|
||
// Bitmap saveImage = showImage?.CopyBitmap();
|
||
// saveImage.Save("d://TEST444.BMP");
|
||
// OnShowImageUpdated?.Invoke(this, showImage, imgSetId);
|
||
if (IsSavePicEnabled && showImage != null)
|
||
{
|
||
string fullname = Path.Combine(ImageSaveDirectory, $"{CameraName}_{_counter:D7}_{set.Id}.{set._imageFormat.ToString().ToLower()}");
|
||
ImageSaveAsync(fullname, showImage);
|
||
}
|
||
|
||
//释放 himage
|
||
ClearImageSet(set);
|
||
});
|
||
}
|
||
}
|
||
static object _imageSetLock = new object();
|
||
public void ClearImageSet(MatSet set)
|
||
{
|
||
try
|
||
{
|
||
bool flag = false;
|
||
lock (_imageSetLock)
|
||
{
|
||
flag = _imageSetList.TryRemove(set.Id, out set);
|
||
if (flag)
|
||
{
|
||
set.Dispose();
|
||
}
|
||
//LogAsync(DateTime.Now, $"{Name}移除图片信息{(flag ? "成功" : "失败")},当前缓存数量:{_imageSetList.Count}", "");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogAsync(DateTime.Now, LogLevel.Exception, $"清理图片缓存异常,当前缓存数量{_imageSetList.Count},{ex.GetExceptionMessage()}");
|
||
}
|
||
}
|
||
public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
|
||
public virtual void ImageSaveAsync(string fullName, Bitmap map)
|
||
{
|
||
if (!IsSavePicEnabled)
|
||
{
|
||
map?.Dispose();
|
||
return;
|
||
}
|
||
|
||
ImageSaveSet imageSaveSet = new ImageSaveSet()
|
||
{
|
||
FullName = fullName,
|
||
SaveImage = map,
|
||
|
||
};
|
||
|
||
ImageSaveHelper.ImageSaveAsync(imageSaveSet);
|
||
}
|
||
public override bool CameraDisConnect()
|
||
{
|
||
try
|
||
{
|
||
|
||
// 1. 停止采集(如果正在运行)
|
||
dvpStreamState streamState = new dvpStreamState();
|
||
nRet = DVPCamera.dvpGetStreamState(m_handle, ref streamState);
|
||
if (streamState == dvpStreamState.STATE_STARTED)
|
||
{
|
||
// 先停止采集流
|
||
nRet = DVPCamera.dvpStop(m_handle);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"停止采集失败,错误码:0x{nRet:X8}");
|
||
}
|
||
}
|
||
|
||
// 2. 设置触发源为软件触发(此时设备已停止)
|
||
nRet = DVPCamera.dvpSetTriggerState(m_handle, false);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"设置软件触发失败,错误码:0x{nRet:X8}");
|
||
}
|
||
|
||
// 3. 注销事件回调
|
||
nRet = DVPCamera.dvpUnregisterEventCallback(m_handle, pCallBackFunc, dvpEvent.EVENT_DISCONNECTED, IntPtr.Zero);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"注销事件回调失败,错误码:0x{nRet:X8}");
|
||
}
|
||
|
||
// 4. 关闭设备
|
||
nRet = DVPCamera.dvpClose(m_handle);
|
||
if (nRet != dvpStatus.DVP_STATUS_OK)
|
||
{
|
||
throw new Exception($"关闭设备失败,错误码:0x{nRet:X8}");
|
||
}
|
||
|
||
m_handle = 0;
|
||
return true;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
public void LogAsync(LogMsg msg)
|
||
{
|
||
msg.MsgSource = CameraName;
|
||
msg.ThreadId = Thread.CurrentThread.ManagedThreadId;
|
||
|
||
//OnLog?.BeginInvoke(msg, null, null);
|
||
OnLog?.Invoke(msg);
|
||
|
||
//if (InitialConfig.IsEnableLog)
|
||
{
|
||
LoggerHelper.LogAsync(msg);
|
||
}
|
||
}
|
||
public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||
{
|
||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||
}
|
||
}
|
||
}
|