WinForm之相机的单例模式
·
WinForm之相机的单例模式


一 定义海康相机类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HalconDotNet;
using MvCamCtrl.NET;
namespace WinForm之AOI外观检测.Camera
{
/// <summary>
/// 触发模式
/// </summary>
public enum TriggerMode
{
/// <summary>
/// 连续模式
/// </summary>
Continues,
/// <summary>
/// 触发模式
/// </summary>
Trigger
}
/// <summary>
/// 触发源
/// </summary>
public enum TriggerSource
{
/// <summary>
/// 外部触发
/// </summary>
Hardware,
/// <summary>
/// 软触发
/// </summary>
Software
}
public delegate void GrabHImage(HImage hImg);
public class HikCamera
{
// 抓取图像事件
public event GrabHImage grabHImage;
public HikCamera()
{
m_stDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
m_MyCamera = new MyCamera();
}
#region 共有属性
/// <summary>
/// 相机名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 相机序列号
/// </summary>
public string SerialNumber { get; set; }
/// <summary>
/// 相机是否已连接
/// </summary>
public bool IsConnect { get; private set; }
/// <summary>
/// 是否为触发模式
/// </summary>
public bool isTriggerMode { get; private set; }
/// <summary>
/// 是否开始采集
/// </summary>
public bool isGrabbing { get; private set; }
#endregion
#region 内部变量
// 设备列表
private MyCamera.MV_CC_DEVICE_INFO_LIST m_stDeviceList;
// 相机对象
private MyCamera m_MyCamera = null;
// 取像线程
Thread m_hReceiveThread = null;
// 帧信息
MyCamera.MV_FRAME_OUT_INFO_EX m_stFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
// 用于从驱动获取图像的缓存
IntPtr m_BufForDriver;
UInt32 m_nBufSizeForDriver = 0;
byte[] m_pDataForRed = null;
byte[] m_pDataForGreen = null;
byte[] m_pDataForBlue = null;
private Object BufForDriverLock = new Object();
private Object BufForImageLock = new Object(); // 读写图像时锁定
#endregion
public List<string> GetDeviceList()
{
List<string> deviceList = new List<string>();
EnumDevices();
for (int i = 0; i < m_stDeviceList.nDeviceNum; i++)
{
MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
if (device.nTLayerType == MyCamera.MV_USB_DEVICE)
{
MyCamera.MV_USB3_DEVICE_INFO usb3Info = (MyCamera.MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO));
deviceList.Add($"{usb3Info.chSerialNumber}");
}
else if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
{
MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
deviceList.Add($"{gigeInfo.chSerialNumber}");
}
}
return deviceList;
}
public bool OpenDevice()
{
// 枚举并搜索指定ID的相机是否存在
EnumDevices();
int camIdx = GetDeviceIndex(SerialNumber);
if (camIdx == -1)
{
MessageBox.Show("找不到该ID的相机!");
return false;
}
MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[camIdx],
typeof(MyCamera.MV_CC_DEVICE_INFO));
// 建立设备对象
if (null == m_MyCamera)
{
m_MyCamera = new MyCamera();
if (null == m_MyCamera)
{
MessageBox.Show("初始化相机对象失败");
return false;
}
}
// 创建设备
int nRet = m_MyCamera.MV_CC_CreateDevice_NET(ref device);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show($"创建设备失败,失败代码:{nRet}");
return false;
}
// 尝试打开设备
nRet = m_MyCamera.MV_CC_OpenDevice_NET();
if (MyCamera.MV_OK != nRet)
{
m_MyCamera.MV_CC_DestroyDevice_NET();
MessageBox.Show($"设备打开失败,失败代码:{nRet}");
return false;
}
// 探测网络最佳包大小(只对GigE相机有效)
if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
{
int nPacketSize = m_MyCamera.MV_CC_GetOptimalPacketSize_NET();
if (nPacketSize > 0)
{
nRet = m_MyCamera.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
if (nRet != MyCamera.MV_OK)
{
MessageBox.Show($"设置包大小失败,失败代码:{nRet}");
}
}
else
{
MessageBox.Show($"获取包大小失败,返回的包大小为:{nPacketSize}");
}
}
// 设置采集连续模式
m_MyCamera.MV_CC_SetEnumValue_NET("AcquisitionMode", (uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);
m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
// 注册异常回调
m_MyCamera.MV_CC_RegisterExceptionCallBack_NET(cbException, IntPtr.Zero);
IsConnect = true;
return true;
}
private void cbException(uint nMsgType, IntPtr pUser)
{
IsConnect = false;
if (nMsgType == MyCamera.MV_EXCEPTION_DEV_DISCONNECT)
{
// 先关闭设备
CloseDevice();
// 在尝试重新打开设备
if (OpenDevice())
{
MessageBox.Show("尝试重新连接设备失败!");
}
}
}
public void CloseDevice()
{
// 取流标志位清零
if (isGrabbing == true)
{
isGrabbing = false;
m_hReceiveThread.Join();
}
if (m_BufForDriver != IntPtr.Zero)
{
Marshal.Release(m_BufForDriver);
}
// 关闭设备
m_MyCamera.MV_CC_CloseDevice_NET();
m_MyCamera.MV_CC_DestroyDevice_NET();
IsConnect = false;
}
public bool StartGrab()
{
// 标志位置位true
isGrabbing = true;
m_hReceiveThread = new Thread(ReceiveThreadProcess);
m_hReceiveThread.Start();
// 取流之前先清除帧长度
m_stFrameInfo.nFrameLen = 0;
m_stFrameInfo.enPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8;
// 开始采集
int nRet = m_MyCamera.MV_CC_StartGrabbing_NET();
if (MyCamera.MV_OK != nRet)
{
isGrabbing = false;
m_hReceiveThread.Join();
MessageBox.Show($"连续采集失败,失败代码:{nRet}");
return false;
}
return true;
}
public bool StopGrab()
{
// 标志位设为false
isGrabbing = false;
m_hReceiveThread.Join();
// 停止采集
int nRet = m_MyCamera.MV_CC_StopGrabbing_NET();
if (nRet != MyCamera.MV_OK)
{
MessageBox.Show($"停止采集失败,失败代码:{nRet}");
return false;
}
return true;
}
public bool SetTriggerMode(TriggerMode triggerMode, TriggerSource triggerSource)
{
if (triggerMode == TriggerMode.Continues)
{
int nRet = m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
if (nRet == MyCamera.MV_OK)
isTriggerMode = false;
}
else if (triggerMode == TriggerMode.Trigger)
{
int nRet = m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
if (nRet == MyCamera.MV_OK)
isTriggerMode = true;
if (triggerSource == TriggerSource.Hardware)
{
// Line0触发
m_MyCamera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0);
// 采用上升沿触发
m_MyCamera.MV_CC_SetEnumValue_NET("TriggerActivation", 0);
// 线路防抖 250us
m_MyCamera.MV_CC_SetIntValue_NET("LineDebouncerTime", 250);
}
else if (triggerSource == TriggerSource.Software)
{
m_MyCamera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
}
else
{
MessageBox.Show("不支持的触发源");
return false;
}
}
else
{
MessageBox.Show("不支持的触发模式");
return false;
}
return true;
}
public bool SnapImage()
{
// 触发命令
int nRet = m_MyCamera.MV_CC_SetCommandValue_NET("TriggerSoftware");
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show($"单张采集触发失败,失败代码:{nRet}");
return false;
}
return true;
}
public void SetExposure(float exp)
{
// 关闭自动曝光
m_MyCamera.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
int nRet = m_MyCamera.MV_CC_SetFloatValue_NET("ExposureTime", exp);
if (nRet != MyCamera.MV_OK)
{
MessageBox.Show($"设置曝光失败,失败代码:{nRet}");
}
}
public float GetExposure()
{
// 曝光时间
MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
int nRet = m_MyCamera.MV_CC_GetFloatValue_NET("ExposureTime", ref stParam);
if (MyCamera.MV_OK == nRet)
{
return stParam.fCurValue;
}
return 0;
}
public void SetFrameRate(float fr)
{
int nRet = m_MyCamera.MV_CC_SetFloatValue_NET("AcquisitionFrameRate", fr);
if (nRet != MyCamera.MV_OK)
{
MessageBox.Show($"设置帧率失败,失败代码:{nRet}");
}
}
public float GetFrameRate()
{
// 帧率
MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
int nRet = m_MyCamera.MV_CC_GetFloatValue_NET("ResultingFrameRate", ref stParam);
if (MyCamera.MV_OK == nRet)
{
return stParam.fCurValue;
}
return 0;
}
public void SetGain(float gain)
{
m_MyCamera.MV_CC_SetEnumValue_NET("GainAuto", 0);
int nRet = m_MyCamera.MV_CC_SetFloatValue_NET("Gain", gain);
if (nRet != MyCamera.MV_OK)
{
MessageBox.Show($"设置增益失败,失败代码:{nRet}");
}
}
public float GetGain()
{
// 增益
MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
int nRet = m_MyCamera.MV_CC_GetFloatValue_NET("Gain", ref stParam);
if (MyCamera.MV_OK == nRet)
{
return stParam.fCurValue;
}
return 0;
}
public void SetGammaEnable(bool bEnable)
{
int nRet = m_MyCamera.MV_CC_SetBoolValue_NET("GammaEnable", bEnable);
if (nRet != MyCamera.MV_OK)
{
MessageBox.Show($"设置Gamma使能失败,失败代码:{nRet}");
}
}
public bool GetGammaEnable()
{
// 增益使能
bool bGamma = false;
int nRet = m_MyCamera.MV_CC_GetBoolValue_NET("GammaEnable", ref bGamma);
if (MyCamera.MV_OK == nRet)
{
return bGamma;
}
return false;
}
public void SetGammaValue(float gamma)
{
bool bEnable = false;
int nRet = m_MyCamera.MV_CC_GetBoolValue_NET("GammaEnable", ref bEnable);
if (bEnable)
{
nRet = m_MyCamera.MV_CC_SetFloatValue_NET("Gamma", gamma);
if (nRet != MyCamera.MV_OK)
{
//MessageBox.Show($"设置Gamma失败,失败代码:{nRet}");
}
}
}
public float GetGammaValue()
{
// Gamma值
bool bGamma = false;
int nRet = m_MyCamera.MV_CC_GetBoolValue_NET("GammaEnable", ref bGamma);
MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
if (MyCamera.MV_OK == nRet && bGamma)
{
m_MyCamera.MV_CC_GetFloatValue_NET("Gamma", ref stParam);
return stParam.fCurValue;
}
return 0;
}
public override string ToString()
{
return $"{Name}_{SerialNumber}";
}
#region 私有方法
// 取像线程
private void ReceiveThreadProcess()
{
MyCamera.MVCC_INTVALUE stParam = new MyCamera.MVCC_INTVALUE();
int nRet = m_MyCamera.MV_CC_GetIntValue_NET("PayloadSize", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show($"读取PayloadSize失败,失败代码:{nRet}");
return;
}
UInt32 nPayloadSize = stParam.nCurValue;
// 获取图像高
nRet = m_MyCamera.MV_CC_GetIntValue_NET("Height", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show($"获取图像高失败,失败代码:{nRet}");
return;
}
uint nHeight = stParam.nCurValue;
// 获取图像宽
nRet = m_MyCamera.MV_CC_GetIntValue_NET("Width", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show($"获取图像宽失败,失败代码:{nRet}");
return;
}
uint nWidth = stParam.nCurValue;
// 根据图像大小设置图像缓存
m_pDataForRed = new byte[nWidth * nHeight];
m_pDataForGreen = new byte[nWidth * nHeight];
m_pDataForBlue = new byte[nWidth * nHeight];
if (3 * nPayloadSize > m_nBufSizeForDriver)
{
if (m_BufForDriver != IntPtr.Zero)
{
Marshal.Release(m_BufForDriver);
}
m_nBufSizeForDriver = 3 * nPayloadSize;
m_BufForDriver = Marshal.AllocHGlobal((Int32)m_nBufSizeForDriver);
}
if (m_BufForDriver == IntPtr.Zero)
{
return;
}
IntPtr pImageBuffer = Marshal.AllocHGlobal((int)nPayloadSize * 3);
if (pImageBuffer == IntPtr.Zero)
{
MessageBox.Show($"申请图像缓存区失败!");
return;
}
MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
IntPtr RedPtr = IntPtr.Zero;
IntPtr GreenPtr = IntPtr.Zero;
IntPtr BluePtr = IntPtr.Zero;
IntPtr pTemp = IntPtr.Zero;
DateTime ProStartTime = DateTime.MinValue;
while (isGrabbing)
{
lock (BufForDriverLock)
{
nRet = m_MyCamera.MV_CC_GetOneFrameTimeout_NET(m_BufForDriver, m_nBufSizeForDriver, ref stFrameInfo, 1000);
if (nRet == MyCamera.MV_OK)
{
ProStartTime = DateTime.Now;
m_stFrameInfo = stFrameInfo;
}
}
HImage hImage = new HImage();
if (nRet == MyCamera.MV_OK)
{
// 彩色相机
if (IsColorData(stFrameInfo.enPixelType))
{
if (stFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
{
pTemp = m_BufForDriver;
}
else
{
nRet = ConvertToRGB(m_MyCamera, m_BufForDriver, stFrameInfo.nHeight, stFrameInfo.nWidth, stFrameInfo.enPixelType, pImageBuffer);
if (MyCamera.MV_OK != nRet)
{
return;
}
pTemp = pImageBuffer;
}
unsafe
{
byte* pBufForSaveImage = (byte*)pTemp;
UInt32 nSupWidth = (stFrameInfo.nWidth + (UInt32)3) & 0xfffffffc;//5120
for (int nRow = 0; nRow < stFrameInfo.nHeight; nRow++)
{
for (int col = 0; col < stFrameInfo.nWidth; col++)
{
m_pDataForRed[nRow * nSupWidth + col] = pBufForSaveImage[nRow * stFrameInfo.nWidth * 3 + (3 * col)];
m_pDataForGreen[nRow * nSupWidth + col] = pBufForSaveImage[nRow * stFrameInfo.nWidth * 3 + (3 * col + 1)];
m_pDataForBlue[nRow * nSupWidth + col] = pBufForSaveImage[nRow * stFrameInfo.nWidth * 3 + (3 * col + 2)];
}
}
}
RedPtr = Marshal.UnsafeAddrOfPinnedArrayElement(m_pDataForRed, 0);
GreenPtr = Marshal.UnsafeAddrOfPinnedArrayElement(m_pDataForGreen, 0);
BluePtr = Marshal.UnsafeAddrOfPinnedArrayElement(m_pDataForBlue, 0);
lock (BufForImageLock)
{
hImage.GenImage3Extern("byte", stFrameInfo.nWidth, stFrameInfo.nHeight, RedPtr, GreenPtr, BluePtr, IntPtr.Zero);
if (grabHImage != null)
grabHImage(hImage);
}
}
else if (IsMonoData(stFrameInfo.enPixelType)) // 黑白图像
{
if (stFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
{
pTemp = m_BufForDriver;
}
else
{
nRet = ConvertToMono8(m_MyCamera, m_BufForDriver, pImageBuffer, stFrameInfo.nHeight, stFrameInfo.nWidth, stFrameInfo.enPixelType);
if (MyCamera.MV_OK != nRet)
{
return;
}
pTemp = pImageBuffer;
}
// 通过事件传递图像数据
lock (BufForImageLock)
{
hImage.GenImage1("byte", stFrameInfo.nWidth, stFrameInfo.nHeight, pTemp);
grabHImage(hImage);
}
}
else
{
continue;
}
}
else
{
if (isTriggerMode)
{
Thread.Sleep(5);
}
}
}
}
// 枚举海康相机(GIGE,USB3)
public void EnumDevices()
{
// 枚举设备列表
m_stDeviceList.nDeviceNum = 0;
int nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_stDeviceList);
if (0 != nRet)
{
MessageBox.Show("枚举HIK相机设备失败!");
return;
}
}
// 获取相机对应的枚举索引
private int GetDeviceIndex(string CameraID)
{
for (int i = 0; i < m_stDeviceList.nDeviceNum; i++)
{
MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
{
MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
if (gigeInfo.chSerialNumber == CameraID)
return i;
}
else if (device.nTLayerType == MyCamera.MV_USB_DEVICE)
{
MyCamera.MV_USB3_DEVICE_INFO usb3Info = (MyCamera.MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(device.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO));
if (usb3Info.chSerialNumber == CameraID)
return i;
}
}
return -1;
}
// 判断是否为黑白图像
private Boolean IsMonoData(MyCamera.MvGvspPixelType enGvspPixelType)
{
switch (enGvspPixelType)
{
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
return true;
default:
return false;
}
}
// 判断是否为彩色图像
private Boolean IsColorData(MyCamera.MvGvspPixelType enGvspPixelType)
{
switch (enGvspPixelType)
{
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YCBCR411_8_CBYYCRYY:
return true;
default:
return false;
}
}
// 转换为RGB格式
private Int32 ConvertToRGB(object obj, IntPtr pSrc, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType, IntPtr pDst)
{
if (IntPtr.Zero == pSrc || IntPtr.Zero == pDst)
{
return MyCamera.MV_E_PARAMETER;
}
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
stPixelConvertParam.pSrcData = pSrc;//源数据
if (IntPtr.Zero == stPixelConvertParam.pSrcData)
{
return -1;
}
stPixelConvertParam.nWidth = nWidth;//图像宽度
stPixelConvertParam.nHeight = nHeight;//图像高度
stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.pDstBuffer = pDst;//转换后的数据
stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
stPixelConvertParam.nDstBufferSize = (uint)nWidth * nHeight * 3;
nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
if (MyCamera.MV_OK != nRet)
{
return -1;
}
return MyCamera.MV_OK;
}
// 转换为Mono8格式
private Int32 ConvertToMono8(object obj, IntPtr pInData, IntPtr pOutData, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType)
{
if (IntPtr.Zero == pInData || IntPtr.Zero == pOutData)
{
return MyCamera.MV_E_PARAMETER;
}
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
stPixelConvertParam.pSrcData = pInData;//源数据
if (IntPtr.Zero == stPixelConvertParam.pSrcData)
{
return -1;
}
stPixelConvertParam.nWidth = nWidth;//图像宽度
stPixelConvertParam.nHeight = nHeight;//图像高度
stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.pDstBuffer = pOutData;//转换后的数据
stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * 3);
nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
if (MyCamera.MV_OK != nRet)
{
return -1;
}
return nRet;
}
#endregion
}
}
二 相机单例模式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinForm之AOI外观检测.Camera
{
public class CameraService
{
//1. 私有静态变量(在第四步供外界使用),创建类的实例
//2. 私有构造函数,确保外部无法直接实例化(确保是单个实例)
//3. 确定供外界调用的代码资源
//4. 公开静态属性,供外界使用(把第一步类的实例,开放出去)
//5. 外界使用
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinForm之AOI外观检测.Camera
{
public class CameraService
{
//1. 私有静态变量(在第四步供外界使用),创建类的实例
//2. 私有构造函数,确保外部无法直接实例化(确保是单个实例)
//3. 确定供外界调用的代码资源
//4. 公开静态属性,供外界使用(把第一步类的实例,开放出去)
//5. 外界使用
//1. 私有静态变量(在第四步供外界使用),创建类的实例
private static CameraService intance = new CameraService();
//2. 私有构造函数,确保外部无法直接实例化(确保是单个实例)
private CameraService()
{
}
//4. 公开静态属性,供外界使用(把第一步类的实例,开放出去)
public static CameraService Instance
{
get { return intance; }
}
//3. 确定供外界调用的代码资源
#region 定义相机
public HikCamera Camera1 = null;
#endregion
#region 初始化相机连接
#endregion
#region 加载相机参数
#endregion
#region 设置相机参数
#endregion
#region 启动相机取像
#endregion
#region 关闭相机
#endregion
#region 相机软触发
#endregion
#region 图像回调方法
#endregion
}
}
三 设置相机配置页面

cbb_DeviceList
rbn_ContinuesMode
rbn_TriggerMode
rbn_SoftTrigger
rbn_HardTrigger
txt_Gain
txt_Exposure
txt_FrameRate
三 显示相机列表
CameraService
#region 定义相机
public HikCamera Camera1 = new HikCamera();
#endregion
#region 获取相机列表
public List<string> GetDeviceList()
{
return Camera1.GetDeviceList();
}
#endregion
界面-构造器里,显示所有相机
// 获取所有相机
List<string> cameraList = CameraService.Instance.GetDeviceList();
// 判定是否有设备
if(cameraList.Count>0)
{
// 默认显示第一个相机
cbb_DeviceList.Text = cameraList[0];
foreach (string item in cameraList)
{
cbb_DeviceList.Items.Add(item);
}
}

四 打开设备
#region 打开相机
public void OpenDevice(string CameraSeriesNum)
{
Camera1.SerialNumber = CameraSeriesNum;
Camera1.OpenDevice();
}
#endregion
/// <summary>
/// 打开设备
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Open_Click(object sender, EventArgs e)
{
//打开设备
CameraService.Instance.OpenDevice(cbb_DeviceList.Text.Trim());
}
五 关闭相机
#region 关闭相机
public void CloseDevice()
{
Camera1.CloseDevice();
}
#endregion
/// <summary>
/// 关闭设备
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Close_Click(object sender, EventArgs e)
{
CameraService.Instance.CloseDevice();
}
六 开始采集
把取图委托,放到打开相机函数中,更安全
#region 开始采集
public void StartGrab()
{
Camera1.grabHImage += CameraGrabHImage1;
Camera1.StartGrab();
}
#endregion
#region 图像回调方法
private void CameraGrabHImage1(HImage hImg)
{
// 获取主窗体
var mainForm = Application.OpenForms.OfType<MainForm>().FirstOrDefault();
// 使用扩展方法更新UI
mainForm.Invoke(new Action(() =>
{
HWindow_Final hWindow_Final2 = mainForm.Get_HWindow_Final2();
hWindow_Final2.HobjectToHimage(hImg);
}));
}
#endregion
/// <summary>
/// 开始采集
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_StartGrab_Click(object sender, EventArgs e)
{
CameraService.Instance.StartGrab();
}
七 停止采集
#region 停止采集
public void StopGrab()
{
Camera1.StopGrab();
}
#endregion
/// <summary>
/// 停止采集
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_StopGrab_Click(object sender, EventArgs e)
{
CameraService.Instance.StopGrab();
}
八 设置采集模式
#region 设置采集模式
public void SetTrigeModel(TriggerMode triggerMode,TriggerSource triggerSource)
{
Camera1.SetTriggerMode(triggerMode,triggerSource);
}
#endregion
/// <summary>
/// 设置采集模式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void rbn_ContinuesMode_CheckedChanged(object sender, EventArgs e)
{
if(rbn_ContinuesMode.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Continues,TriggerSource.Software);
}else if(rbn_TriggerMode.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Trigger, TriggerSource.Software);
}
}
/// <summary>
/// 设置采集模式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void rbn_TriggerMode_CheckedChanged(object sender, EventArgs e)
{
if (rbn_ContinuesMode.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Continues, TriggerSource.Software);
}
else if (rbn_TriggerMode.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Trigger, TriggerSource.Software);
}
}
九 设置软硬触发模式
/// <summary>
/// 设置触发模式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void rbn_SoftTrigger_CheckedChanged(object sender, EventArgs e)
{
if(rbn_SoftTrigger.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Trigger, TriggerSource.Software);
}
else if (rbn_HardTrigger.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Trigger, TriggerSource.Hardware);
}
}
/// <summary>
/// 设置触发模式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void rbn_HardTrigger_CheckedChanged(object sender, EventArgs e)
{
if (rbn_SoftTrigger.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Trigger, TriggerSource.Software);
}
else if (rbn_HardTrigger.Checked)
{
CameraService.Instance.SetTrigeModel(TriggerMode.Trigger, TriggerSource.Hardware);
}
}
软触发一次
#region 相机软触发
public void SnapImage()
{
Camera1.SnapImage();
}
#endregion
/// <summary>
/// 软触发一次
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_TriggerExec_Click(object sender, EventArgs e)
{
CameraService.Instance.SnapImage();
}
十 获取参数
定义相机参数类
public class CameraParamModel
{
/// <summary>
/// 相机序列号
/// </summary>
public string SerialNumber { get; set; }
/// <summary>
/// 曝光
/// </summary>
public float ExposureTime { get; set; }
/// <summary>
/// 增益
/// </summary>
public float Gain { get; set; }
}
#region 获取参数
public CameraParamModel GetCameraParams()
{
CameraParamModel cameraParam = new CameraParamModel();
cameraParam.ExposureTime = Camera1.GetExposure();
cameraParam.Gain = Camera1.GetGain();
return cameraParam;
}
#endregion
/// <summary>
/// 获取参数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_GetParam_Click(object sender, EventArgs e)
{
CameraParamModel cameraParam = CameraService.Instance.GetCameraParams();
txt_Exposure.Text = cameraParam.ExposureTime.ToString();
txt_Gain.Text = cameraParam.Gain.ToString();
}
十一 设置参数
#region 设置参数
public void SetCameraParams(CameraParamModel cameraParam)
{
Camera1.SetGain(cameraParam.Gain);
Camera1.SetExposure(cameraParam.ExposureTime);
}
#endregion
/// <summary>
/// 设置参数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_SetParam_Click(object sender, EventArgs e)
{
CameraParamModel cameraParam = new CameraParamModel();
cameraParam.Gain = (float)Convert.ToDouble(txt_Gain.Text.Trim());
cameraParam.ExposureTime = (float)Convert.ToDouble(txt_Exposure.Text.Trim());
CameraService.Instance.SetCameraParams(cameraParam);
}

十二 设置在线模式
/// <summary>
/// 判断是否在线模式
/// </summary>
private void IsOnLine_ToggledChanged()
{
// 在线模式
if (IsOnLine.Toggled)
{
MessageBox.Show("在线");
}
else
{
MessageBox.Show("离线");
}
}

十三 在线模式下启动相机
#region 初始化相机连接
public bool InitCameras(string CameraSeriesNum)
{
Camera1 = new HikCamera();
Camera1.SerialNumber = CameraSeriesNum;
Camera1.grabHImage += CameraGrabHImage2;
return true;
}
#endregion
private void CameraGrabHImage2(HImage hImg)
{
// 获取主窗体
var mainForm = Application.OpenForms.OfType<Form1>().FirstOrDefault();
// 使用扩展方法更新UI
mainForm.Invoke(new Action(() =>
{
mainForm.hWindow_Final1.HobjectToHimage(hImg);
//HWindow_Final hWindow_Final = mainForm.GetWH();
//hWindow_Final
}));
}

#region 启动相机取像
public void StartCameras1()
{
Camera1.GetDeviceList();
if (Camera1 == null)
{
MessageBox.Show($"相机 {Camera1.Name}:{Camera1.SerialNumber} 未配置!");
return;
}
// 打开设备
if (!Camera1.OpenDevice())
{
MessageBox.Show($"打开相机 {Camera1.Name}:{Camera1.SerialNumber} 失败!");
return;
}
else
{
// 启动相机取像
Camera1.StartGrab();
// 设置为软触发
Camera1.SetTriggerMode(TriggerMode.Trigger, TriggerSource.Software);
//($"相机 {Camera1.Name}:{Camera1.SerialNumber} 已连接!");
}
}
#endregion
初始化相机
// 初始化相机
if (txt_CameraSeriesNum.Text.Trim().Length==0)
{
rtb_Log.AppendText("初始化相机失败! 无相机序列号 \n");
}
else
{
CameraService.Instance.InitCameras(txt_CameraSeriesNum.Text.Trim());
rtb_Log.AppendText($"初始化相机成功! 相机序列号:{txt_CameraSeriesNum.Text.Trim()} \n");
}
是否在线模式
/// <summary>
/// 判断是否在线模式
/// </summary>
private void IsOnLine_ToggledChanged()
{
// 在线模式
if (IsOnLine.Toggled)
{
CameraService.Instance.StartCameras1();
rtb_Log.AppendText("相机已打开 \n");
}
else
{
CameraService.Instance.CloseDevice();
rtb_Log.AppendText("相机已关闭 \n");
}
}
十四 通讯触发相机拍照
CameraService.Instance.SnapImage();



十五 启动通讯服务
// 启动通讯
if(CommunicateService.Instance.StartCommunicateService())
{
lb_Comm_Status.Text = "启动";
lb_Comm_Status.BackColor = Color.Green;
rtb_Log.AppendText($"通讯服务端已启动 IP :{txt_Ip.Text.Trim()} 端口:{txt_Port.Text.Trim()}");
}
更多推荐

所有评论(0)