DHDHSoftware/DH.Devices.Camera/Do3ThinkCamera.cs
2025-04-16 08:47:59 +08:00

578 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 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;
}
return true;
}
catch
{
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));
}
}
}