using Microsoft.Win32;
using System.ComponentModel;
using MVSDK_Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using TeamAAS.Camera.Images;
using TeamAAS.Camera.Models;
using static MVSDK_Net.IMVDefine;
using TeamAAS.Camera.Attributes;
using TeamAAS.Camera.Enums;
namespace TeamAAS.Camera.Cameras
{
///
/// 大华/华睿相机(MVSDK_Net SDK)
///
[Camera("iRayple", "大华相机")]
public class AHuaCamera : CameraBase
{
#region 字段
MVSDK_Net.MyCamera mvCameraAcq;
private bool IsHaveCamera = false;
private long m_picSize = 0;
IMVDefine.IMV_Frame frame = new IMVDefine.IMV_Frame();
IntPtr pTemp = IntPtr.Zero;
IntPtr pConvertDstBuffer = IntPtr.Zero;
int nConvertBufSize = 0;
private IMVDefine.IMV_PixelConvertParam stPixelConvertParam = new IMVDefine.IMV_PixelConvertParam();
private IMVDefine.IMV_EPixelType type = IMVDefine.IMV_EPixelType.gvspPixelMono8;
#endregion
[Browsable(false)]
public override string CameraBrand => "大华相机";
public AHuaCamera(Guid id, int index, string name, string serialNumber, string cameraIp, bool isFindByIp)
: base(id, index, name, serialNumber, cameraIp, isFindByIp)
{
mvCameraAcq = new MVSDK_Net.MyCamera();
var list = GetDevices();
foreach (var device in list)
{
if (device.CameraType == CameraType.GIGE)
{
if (IsFindByIp)
{
if (device.CameraIp == CameraIp)
{
IsHaveCamera = true;
ManufacturerName = device.ManufacturerName;
ModelName = device.Model;
SerialNumber = device.SerialNumber;
CameraType = device.CameraType;
int res = mvCameraAcq.IMV_CreateHandle(IMVDefine.IMV_ECreateHandleMode.modeByCameraKey, 0, serialNumber);
break;
}
}
else
{
if (device.SerialNumber == serialNumber)
{
IsHaveCamera = true;
ManufacturerName = device.ManufacturerName;
ModelName = device.Model;
SerialNumber = device.SerialNumber;
CameraType = device.CameraType;
CameraIp = device.CameraIp;
int res = mvCameraAcq.IMV_CreateHandle(IMVDefine.IMV_ECreateHandleMode.modeByCameraKey, 0, serialNumber);
break;
}
}
}
else
{
if (device.SerialNumber == serialNumber)
{
IsHaveCamera = true;
ManufacturerName = device.ManufacturerName;
ModelName = device.Model;
SerialNumber = device.SerialNumber;
CameraType = device.CameraType;
int res = mvCameraAcq.IMV_CreateHandle(IMVDefine.IMV_ECreateHandleMode.modeByCameraKey, 0, serialNumber);
break;
}
}
}
IsConnected = false;
}
#region 设备发现
public static CameraInfo[] GetDevices()
{
List cameras = new List();
if (!CheckSoftwareInstalled().isInstalled)
{
return cameras.ToArray();
}
IMVDefine.IMV_DeviceList deviceList = new IMVDefine.IMV_DeviceList();
IMVDefine.IMV_EInterfaceType interfaceTp = IMVDefine.IMV_EInterfaceType.interfaceTypeAll;
int res = MyCamera.IMV_EnumDevices(ref deviceList, (uint)interfaceTp);
if (res == IMVDefine.IMV_OK && deviceList.nDevNum > 0)
{
for (int i = 0; i < deviceList.nDevNum; i++)
{
IMVDefine.IMV_DeviceInfo deviceInfo =
(IMVDefine.IMV_DeviceInfo)
Marshal.PtrToStructure(
deviceList.pDevInfo + Marshal.SizeOf(typeof(IMVDefine.IMV_DeviceInfo)) * i,
typeof(IMVDefine.IMV_DeviceInfo));
if (deviceInfo.nCameraType == IMV_ECameraType.typeGigeCamera)
{
IMVDefine.IMV_GigEDeviceInfo gigEDeviceInfo =
(IMVDefine.IMV_GigEDeviceInfo)
ByteToStruct(deviceInfo.deviceSpecificInfo.gigeDeviceInfo,
typeof(IMVDefine.IMV_GigEDeviceInfo));
cameras.Add(new CameraInfo()
{
CameraNo = i + 1,
CameraName = deviceInfo.cameraName,
CameraBrand = "大华相机",
CameraType = CameraType.GIGE,
ManufacturerName = deviceInfo.manufactureInfo,
Model = deviceInfo.modelName,
SerialNumber = deviceInfo.serialNumber,
CameraIp = gigEDeviceInfo.ipAddress,
IsFindByIp = true,
});
}
else if (deviceInfo.nCameraType == IMV_ECameraType.typeU3vCamera)
{
cameras.Add(new CameraInfo()
{
CameraNo = i + 1,
CameraName = deviceInfo.cameraName,
CameraBrand = "大华相机",
CameraType = CameraType.USB,
ManufacturerName = deviceInfo.cameraName,
Model = deviceInfo.modelName,
SerialNumber = deviceInfo.serialNumber,
CameraIp = "",
});
}
else if (deviceInfo.nCameraType == IMV_ECameraType.typeCLCamera)
{
cameras.Add(new CameraInfo()
{
CameraNo = i + 1,
CameraName = deviceInfo.cameraName,
CameraBrand = "大华相机",
CameraType = CameraType.Link,
ManufacturerName = deviceInfo.cameraName,
Model = deviceInfo.modelName,
SerialNumber = deviceInfo.serialNumber,
CameraIp = "",
});
}
else
{
cameras.Add(new CameraInfo()
{
CameraNo = i + 1,
CameraName = deviceInfo.cameraName,
CameraBrand = "大华相机",
CameraType = CameraType.Unknown,
ManufacturerName = deviceInfo.cameraName,
Model = deviceInfo.modelName,
SerialNumber = deviceInfo.serialNumber,
CameraIp = "",
});
}
}
}
return cameras.ToArray();
}
public static (bool isInstalled, string version) CheckSoftwareInstalled()
{
string softwareName = "MV Viewer";
string softwareVersion = "2.5.1.1";
string[] registryPaths = new[]
{
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
};
foreach (var path in registryPaths)
{
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path))
{
if (key == null) continue;
foreach (string subKeyName in key.GetSubKeyNames())
{
using (RegistryKey subKey = key.OpenSubKey(subKeyName))
{
string displayName = subKey?.GetValue("DisplayName")?.ToString();
if (displayName != null && displayName.Contains(softwareName))
{
string version = subKey.GetValue("DisplayVersion")?.ToString();
var match = Regex.Match(version, @"^(\d+\.\d+\.\d+\.\d+)");
if (match.Success)
{
version = match.Groups[1].Value;
}
else
{
continue;
}
Version v1 = new Version(version);
Version v2 = new Version(softwareVersion);
if (v1 >= v2)
{
return (true, version);
}
else
{
return (false, version);
}
}
}
}
}
}
return (false, "");
}
#endregion
#region SDK 实现
public override bool OpenDevice()
{
using (WriteLockScope())
{
try
{
var list = GetDevices();
foreach (var device in list)
{
if (device.SerialNumber == SerialNumber)
{
IsHaveCamera = true;
ManufacturerName = device.ManufacturerName;
ModelName = device.Model;
SerialNumber = device.SerialNumber;
CameraType = device.CameraType;
int res = mvCameraAcq.IMV_CreateHandle(IMVDefine.IMV_ECreateHandleMode.modeByCameraKey, 0, SerialNumber);
break;
}
}
if (!IsHaveCamera)
{
return false;
}
int res1 = mvCameraAcq.IMV_Open();
if (res1 != IMVDefine.IMV_OK)
{
return IsConnected;
}
if (!IsConnected)
{
OnConnectChanged(true);
}
long width = 0;
long height = 0;
res1 = mvCameraAcq.IMV_GetIntFeatureValue("Width", ref width);
res1 = mvCameraAcq.IMV_GetIntFeatureValue("Height", ref height);
ImageWidth = (uint)width;
ImageHeight = (uint)height;
m_picSize = width * height;
// 按当前触发模式下发(默认连续采集 = TriggerMode Off,与历史硬编码一致)
ApplyTriggerToHardware(TriggerMode);
res1 = mvCameraAcq.IMV_StartGrabbingEx(3, IMV_EGrabStrategy.grabStrartegyLatestImage);
IsConnected = mvCameraAcq.IMV_IsOpen();
return IsConnected;
}
catch (Exception ex)
{
ErrorMessage = ex.Message;
IsConnected = false;
return false;
}
}
}
public override void CloseDevice()
{
using (WriteLockScope())
{
try
{
if (mvCameraAcq != null)
{
if (mvCameraAcq.IMV_IsOpen())
{
mvCameraAcq.IMV_StopGrabbing();
mvCameraAcq.IMV_Close();
}
mvCameraAcq.IMV_DestroyHandle();
}
}
catch { }
IsConnected = false;
OnConnectChanged(false);
}
}
#region 触发模式
/// 大华(iRayple/IMV)支持连续/软触发/硬触发(Line0)
public override IReadOnlyList SupportedTriggerModes => FullTriggerModes;
/// 历史行为:OpenDevice 硬编码 TriggerMode=Off,故默认连续采集
protected override CameraTriggerMode DefaultTriggerMode => CameraTriggerMode.连续采集;
protected override bool ApplyTriggerMode(CameraTriggerMode mode)
{
using (WriteLockScope())
return ApplyTriggerToHardware(mode);
}
///
/// 把触发模式下发到大华 IMV SDK(GenICam 字符串接口,返回 IMV_OK = 成功)。
/// 调用方需已持有写锁(OpenDevice/Grab 内部已在锁内;锁可重入)。
///
private bool ApplyTriggerToHardware(CameraTriggerMode mode)
{
if (mvCameraAcq == null || !mvCameraAcq.IMV_IsOpen()) return false;
mvCameraAcq.IMV_SetEnumFeatureSymbol("AcquisitionMode", "Continuous");
switch (mode)
{
case CameraTriggerMode.连续采集:
return mvCameraAcq.IMV_SetEnumFeatureSymbol("TriggerMode", "Off") == IMVDefine.IMV_OK;
case CameraTriggerMode.软触发:
mvCameraAcq.IMV_SetEnumFeatureSymbol("TriggerSource", "Software");
return mvCameraAcq.IMV_SetEnumFeatureSymbol("TriggerMode", "On") == IMVDefine.IMV_OK;
case CameraTriggerMode.硬触发上升沿:
case CameraTriggerMode.硬触发下降沿:
mvCameraAcq.IMV_SetEnumFeatureSymbol("TriggerSource", "Line0");
mvCameraAcq.IMV_SetEnumFeatureSymbol("TriggerActivation",
mode == CameraTriggerMode.硬触发上升沿 ? "Rising" : "Falling");
return mvCameraAcq.IMV_SetEnumFeatureSymbol("TriggerMode", "On") == IMVDefine.IMV_OK;
default: // 跟随相机:不下发,沿用相机自身配置
return true;
}
}
#endregion
public override GenImage Grab()
{
using (WriteLockScope())
{
var sw = Stopwatch.StartNew();
try
{
if (mvCameraAcq == null || !mvCameraAcq.IMV_IsOpen())
{
ErrorMessage = "相机未连接";
return null;
}
mvCameraAcq.IMV_ClearFrameBuffer();
// 仅软触发模式需主动发触发命令;连续采集自由出图,硬触发等外部信号
if (IsSoftwareTrigger)
mvCameraAcq.IMV_ExecuteCommandFeature("TriggerSoftware");
int res = mvCameraAcq.IMV_GetFrame(ref frame, 1000);
if (res == IMVDefine.IMV_OK)
{
try
{
// Mono图像处理
if (IsMonoPixelFormat(frame.frameInfo.pixelFormat))
{
type = IMVDefine.IMV_EPixelType.gvspPixelMono8;
if (frame.frameInfo.pixelFormat == IMVDefine.IMV_EPixelType.gvspPixelMono8)
{
pTemp = frame.pData;
}
else
{
if (pConvertDstBuffer == IntPtr.Zero || nConvertBufSize < (frame.frameInfo.width * frame.frameInfo.height))
{
if (pConvertDstBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pConvertDstBuffer);
pConvertDstBuffer = IntPtr.Zero;
}
pConvertDstBuffer = Marshal.AllocHGlobal((int)(frame.frameInfo.width * frame.frameInfo.height));
if (pConvertDstBuffer == IntPtr.Zero)
{
return null;
}
nConvertBufSize = (int)(frame.frameInfo.width * frame.frameInfo.height);
}
stPixelConvertParam.nWidth = frame.frameInfo.width;
stPixelConvertParam.nHeight = frame.frameInfo.height;
stPixelConvertParam.ePixelFormat = frame.frameInfo.pixelFormat;
stPixelConvertParam.pSrcData = frame.pData;
stPixelConvertParam.nSrcDataLen = frame.frameInfo.size;
stPixelConvertParam.nPaddingX = frame.frameInfo.paddingX;
stPixelConvertParam.nPaddingY = frame.frameInfo.paddingY;
stPixelConvertParam.eBayerDemosaic = IMVDefine.IMV_EBayerDemosaic.demosaicNearestNeighbor;
stPixelConvertParam.eDstPixelFormat = IMVDefine.IMV_EPixelType.gvspPixelMono8;
stPixelConvertParam.pDstBuf = pConvertDstBuffer;
stPixelConvertParam.nDstBufSize = frame.frameInfo.width * frame.frameInfo.height;
res = mvCameraAcq.IMV_PixelConvert(ref stPixelConvertParam);
if (res != IMVDefine.IMV_OK)
{
return null;
}
pTemp = pConvertDstBuffer;
}
}
// 彩色图像处理
else if (IsColorPixelFormat(frame.frameInfo.pixelFormat))
{
type = IMVDefine.IMV_EPixelType.gvspPixelRGB8;
if (frame.frameInfo.pixelFormat == IMVDefine.IMV_EPixelType.gvspPixelRGB8)
{
pTemp = frame.pData;
}
else
{
if (pConvertDstBuffer == IntPtr.Zero || nConvertBufSize < (frame.frameInfo.width * frame.frameInfo.height * 3))
{
if (pConvertDstBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pConvertDstBuffer);
pConvertDstBuffer = IntPtr.Zero;
}
pConvertDstBuffer = Marshal.AllocHGlobal((int)(frame.frameInfo.width * frame.frameInfo.height * 3));
if (pConvertDstBuffer == IntPtr.Zero)
{
return null;
}
nConvertBufSize = (int)(frame.frameInfo.width * frame.frameInfo.height * 3);
}
stPixelConvertParam.nWidth = frame.frameInfo.width;
stPixelConvertParam.nHeight = frame.frameInfo.height;
stPixelConvertParam.ePixelFormat = frame.frameInfo.pixelFormat;
stPixelConvertParam.pSrcData = frame.pData;
stPixelConvertParam.nSrcDataLen = frame.frameInfo.size;
stPixelConvertParam.nPaddingX = frame.frameInfo.paddingX;
stPixelConvertParam.nPaddingY = frame.frameInfo.paddingY;
stPixelConvertParam.eBayerDemosaic = IMVDefine.IMV_EBayerDemosaic.demosaicNearestNeighbor;
stPixelConvertParam.eDstPixelFormat = IMVDefine.IMV_EPixelType.gvspPixelRGB8;
stPixelConvertParam.pDstBuf = pConvertDstBuffer;
stPixelConvertParam.nDstBufSize = frame.frameInfo.width * frame.frameInfo.height * 3;
res = mvCameraAcq.IMV_PixelConvert(ref stPixelConvertParam);
if (res != IMVDefine.IMV_OK)
{
return null;
}
pTemp = pConvertDstBuffer;
}
}
else
{
return null;
}
Image = ConvertImage(frame.frameInfo.width, frame.frameInfo.height, pTemp, type);
if (Image != null)
{
ImageWidth = (uint)Image.Width;
ImageHeight = (uint)Image.Height;
ApplyGammaToImage(Image);
ErrorMessage = "";
TotalTime = sw.Elapsed;
return Image;
}
}
catch (Exception)
{
}
finally
{
mvCameraAcq.IMV_ReleaseFrame(ref frame);
}
}
else
{
ErrorMessage = res.ToString();
CloseDevice();
OpenDevice();
}
}
catch (Exception ex)
{
CloseDevice();
OpenDevice();
ErrorMessage = ex.Message;
}
return null;
}
}
public override bool SetExposureTime(float exposureTime)
{
using (WriteLockScope())
{
try
{
if (mvCameraAcq != null && mvCameraAcq.IMV_IsOpen())
{
long val = (long)exposureTime;
mvCameraAcq.IMV_SetIntFeatureValue("ExposureTime", val);
}
return true;
}
catch { return false; }
}
}
public override float GetExposureTime()
{
using (ReadLockScope())
{
try
{
if (mvCameraAcq != null && mvCameraAcq.IMV_IsOpen())
{
long val = 0;
mvCameraAcq.IMV_GetIntFeatureValue("ExposureTime", ref val);
return (float)val;
}
}
catch { }
return 0;
}
}
public override bool SetGain(float gain)
{
using (WriteLockScope())
{
try
{
if (mvCameraAcq != null && mvCameraAcq.IMV_IsOpen())
{
long val = (long)gain;
mvCameraAcq.IMV_SetIntFeatureValue("Gain", val);
}
return true;
}
catch { return false; }
}
}
public override float GetGain()
{
using (ReadLockScope())
{
try
{
if (mvCameraAcq != null && mvCameraAcq.IMV_IsOpen())
{
long val = 0;
mvCameraAcq.IMV_GetIntFeatureValue("Gain", ref val);
return (float)val;
}
}
catch { }
return 0;
}
}
public override bool SetGamma(float gamma)
{
using (WriteLockScope())
{
try
{
if (mvCameraAcq != null && mvCameraAcq.IMV_IsOpen())
{
long val = (long)gamma;
mvCameraAcq.IMV_SetIntFeatureValue("Gamma", val);
return true;
}
}
catch { }
UpdateGammaSnapshot(gamma);
return true;
}
}
public override float GetGamma()
{
using (ReadLockScope())
{
try
{
if (mvCameraAcq != null && mvCameraAcq.IMV_IsOpen())
{
long val = 0;
mvCameraAcq.IMV_GetIntFeatureValue("Gamma", ref val);
return (float)val;
}
}
catch { }
return Gamma;
}
}
#endregion
#region 辅助方法
private bool IsMonoPixelFormat(IMVDefine.IMV_EPixelType enType)
{
switch (enType)
{
case IMVDefine.IMV_EPixelType.gvspPixelMono8:
case IMVDefine.IMV_EPixelType.gvspPixelMono10:
case IMVDefine.IMV_EPixelType.gvspPixelMono10Packed:
case IMVDefine.IMV_EPixelType.gvspPixelMono12:
case IMVDefine.IMV_EPixelType.gvspPixelMono12Packed:
return true;
default:
return false;
}
}
private bool IsColorPixelFormat(IMVDefine.IMV_EPixelType enType)
{
switch (enType)
{
case IMVDefine.IMV_EPixelType.gvspPixelRGB8:
case IMVDefine.IMV_EPixelType.gvspPixelBGR8:
case IMVDefine.IMV_EPixelType.gvspPixelRGBA8:
case IMVDefine.IMV_EPixelType.gvspPixelBGRA8:
case IMVDefine.IMV_EPixelType.gvspPixelYUV422_8:
case IMVDefine.IMV_EPixelType.gvspPixelYUV422_8_UYVY:
case IMVDefine.IMV_EPixelType.gvspPixelBayGR8:
case IMVDefine.IMV_EPixelType.gvspPixelBayRG8:
case IMVDefine.IMV_EPixelType.gvspPixelBayGB8:
case IMVDefine.IMV_EPixelType.gvspPixelBayBG8:
case IMVDefine.IMV_EPixelType.gvspPixelBayGB10:
case IMVDefine.IMV_EPixelType.gvspPixelBayGB10Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayBG10:
case IMVDefine.IMV_EPixelType.gvspPixelBayBG10Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayRG10:
case IMVDefine.IMV_EPixelType.gvspPixelBayRG10Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayGR10:
case IMVDefine.IMV_EPixelType.gvspPixelBayGR10Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayGB12:
case IMVDefine.IMV_EPixelType.gvspPixelBayGB12Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayBG12:
case IMVDefine.IMV_EPixelType.gvspPixelBayBG12Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayRG12:
case IMVDefine.IMV_EPixelType.gvspPixelBayRG12Packed:
case IMVDefine.IMV_EPixelType.gvspPixelBayGR12:
case IMVDefine.IMV_EPixelType.gvspPixelBayGR12Packed:
return true;
default:
return false;
}
}
public GenImage ConvertImage(UInt32 nWidth, UInt32 nHeight, IntPtr pImageBuf, IMVDefine.IMV_EPixelType enPixelType)
{
try
{
if (enPixelType == IMVDefine.IMV_EPixelType.gvspPixelMono8)
{
return GenImage.FromIntPtr((int)nWidth, (int)nHeight, PixelType.Grey8, pImageBuf, (int)nWidth);
}
else if (enPixelType == IMVDefine.IMV_EPixelType.gvspPixelRGB8)
{
return GenImage.FromIntPtr((int)nWidth, (int)nHeight, PixelType.RGB24, pImageBuf, (int)nWidth * 3);
}
else if (enPixelType == IMVDefine.IMV_EPixelType.gvspPixelBGR8)
{
return GenImage.FromIntPtr((int)nWidth, (int)nHeight, PixelType.BGR24, pImageBuf, (int)nWidth * 3);
}
return null;
}
catch (System.Exception)
{
return null;
}
}
public static object ByteToStruct(Byte[] bytes, Type type)
{
int size = Marshal.SizeOf(type);
if (size > bytes.Length)
{
return null;
}
IntPtr structPtr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, structPtr, size);
object obj = Marshal.PtrToStructure(structPtr, type);
Marshal.FreeHGlobal(structPtr);
return obj;
}
#endregion
}
}