825 lines
35 KiB
C#
825 lines
35 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.Drawing;
|
|||
|
using System.Drawing.Imaging;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Reflection;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Text;
|
|||
|
using System.Threading;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using System.Timers;
|
|||
|
using System.Windows.Forms;
|
|||
|
using LeatherApp.Interface;
|
|||
|
//using MvCamCtrl.NET;
|
|||
|
using MvFGCtrlC.NET;
|
|||
|
using Newtonsoft.Json.Linq;
|
|||
|
using OpenCvSharp;
|
|||
|
using OpenCvSharp.Dnn;
|
|||
|
//using static ControllerDllCSharp.ClassLibControllerDll;
|
|||
|
namespace LeatherApp.Device
|
|||
|
{
|
|||
|
public class CamerCardDev : ABSCamerCardDev,IDisposable
|
|||
|
{
|
|||
|
[DllImport("user32.dll")]
|
|||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|||
|
private static extern bool IsWindow(IntPtr hWnd);
|
|||
|
|
|||
|
[DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory", SetLastError = false)]
|
|||
|
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
private int scanIndex = 0; //实际拍照从1开始命名,因先加的1
|
|||
|
private string bmpSavePath;
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 曝光 3.00-10000.00
|
|||
|
/// </summary>
|
|||
|
public float ExposureTime { get; private set; }
|
|||
|
/// <summary>
|
|||
|
/// 增益 0-23.981199
|
|||
|
/// </summary>
|
|||
|
public float Gain { get; private set; }
|
|||
|
/// <summary>
|
|||
|
/// 帧率 0-429496.718750
|
|||
|
/// </summary>
|
|||
|
public float ResultingFrameRate { get; private set; }
|
|||
|
/// <summary>
|
|||
|
/// 图片大小
|
|||
|
/// </summary>
|
|||
|
public System.Drawing.Size size { get; private set; }
|
|||
|
/// <summary>
|
|||
|
/// 是否连续模式
|
|||
|
/// </summary>
|
|||
|
public bool isContinuousMode { get; private set; }
|
|||
|
/// <summary>
|
|||
|
/// 是否打开设备成功
|
|||
|
/// </summary>
|
|||
|
public bool IsInit { get; private set; } = false;
|
|||
|
//public string ErrInfo { get; private set; }
|
|||
|
//private System.Timers.Timer timer = new System.Timers.Timer();
|
|||
|
private int _scannerCardIndex = 0;//采集卡索引
|
|||
|
private int _scannerIndex=0;//相机索引(一个采集卡上可插多个相机)
|
|||
|
|
|||
|
#region
|
|||
|
public enum SAVE_IAMGE_TYPE
|
|||
|
{
|
|||
|
Image_Undefined = 0, // ch:未定义的图像格式 | en:Undefined Image Type
|
|||
|
Image_Bmp = 1, // ch:BMP图像格式 | en:BMP Image Type
|
|||
|
Image_Jpeg = 2, // ch:JPEG图像格式 | en:Jpeg Image Type
|
|||
|
}
|
|||
|
|
|||
|
// ch:判断用户自定义像素格式 | en:Determine custom pixel format
|
|||
|
public const Int32 CUSTOMER_PIXEL_FORMAT = unchecked((Int32)0x80000000);
|
|||
|
|
|||
|
public const UInt32 TRIGGER_MODE_ON = 1; // ch:触发模式开 | en:Trigger mode on
|
|||
|
public const UInt32 TRIGGER_MODE_OFF = 0; // ch:触发模式关 | en:Trigger mode off
|
|||
|
|
|||
|
CSystem m_cSystem = new CSystem(); // ch:操作采集卡 | en:Interface operations
|
|||
|
CInterface m_cInterface = null; // ch:操作采集卡和设备 | en:Interface and device operation
|
|||
|
CDevice m_cDevice = null; // ch:操作设备和流 | en:Device and stream operation
|
|||
|
CStream m_cStream = null; // ch:操作流和缓存 | en:Stream and buffer operation
|
|||
|
|
|||
|
uint m_nInterfaceNum = 0; // ch:采集卡数量 | en:Interface number
|
|||
|
bool m_bIsIFOpen = false; // ch:采集卡是否打开 | en:Whether to open interface
|
|||
|
bool m_bIsDeviceOpen = false; // ch:设备是否打开 | en:Whether to open device
|
|||
|
bool m_bIsGrabbing = false; // ch:是否在抓图 | en:Whether to start grabbing
|
|||
|
uint m_nTriggerMode = TRIGGER_MODE_OFF; // ch:触发模式 | en:Trigger Mode
|
|||
|
|
|||
|
bool m_bThreadState = false; // ch:线程状态 | en:Thread state
|
|||
|
Thread m_hGrabThread = null; // ch:取流线程 | en:Grabbing thread
|
|||
|
|
|||
|
private static Object m_LockForSaveImage = new Object(); // ch:存图锁 | en:Lock for saving image
|
|||
|
IntPtr m_pDataBuf = IntPtr.Zero; // ch:数据缓存 | en:Data buffer
|
|||
|
uint m_nDataBufSize = 0; // ch:数据缓存大小 | en:Length of data buffer
|
|||
|
IntPtr m_pSaveImageBuf = IntPtr.Zero; // ch:图像缓存 | en:Image buffer
|
|||
|
uint m_nSaveImageBufSize = 0; // ch:图像缓存大小 | en:Length of image buffer
|
|||
|
MV_FG_INPUT_IMAGE_INFO m_stImageInfo = new MV_FG_INPUT_IMAGE_INFO(); // ch:图像信息 | en:Image info
|
|||
|
|
|||
|
delegate void ShowDisplayError(int nRet);
|
|||
|
|
|||
|
//显示图像控件句柄
|
|||
|
private PictureBox previewHwnd=null;
|
|||
|
#endregion
|
|||
|
|
|||
|
public CamerCardDev( )
|
|||
|
{
|
|||
|
}
|
|||
|
public override bool open(int cardIndex = 0,int scannerIndex = 0)
|
|||
|
{
|
|||
|
if (IsInit) return true;
|
|||
|
|
|||
|
//m_stIFInfoList = _m_stIFInfoList;
|
|||
|
_scannerCardIndex = cardIndex;
|
|||
|
_scannerIndex = scannerIndex;
|
|||
|
System.GC.Collect();
|
|||
|
try
|
|||
|
{
|
|||
|
int nRet = 0;
|
|||
|
bool bChanged = false;
|
|||
|
|
|||
|
// ch:枚举采集卡 | en:Enum interface
|
|||
|
nRet = m_cSystem.UpdateInterfaceList(
|
|||
|
CParamDefine.MV_FG_CAMERALINK_INTERFACE | CParamDefine.MV_FG_GEV_INTERFACE | CParamDefine.MV_FG_CXP_INTERFACE | CParamDefine.MV_FG_XoF_INTERFACE,
|
|||
|
ref bChanged);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Enum Interface failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return false;
|
|||
|
}
|
|||
|
m_nInterfaceNum = 0;
|
|||
|
|
|||
|
// ch:获取采集卡数量 | en:Get interface num
|
|||
|
nRet = m_cSystem.GetNumInterfaces(ref m_nInterfaceNum);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Get interface number failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (0 == m_nInterfaceNum)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "No interface found");
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (cardIndex + 1 > m_nInterfaceNum)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "cardIndex > interface.count!");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//打开采集卡
|
|||
|
// 如果已经打开,则先关闭采集卡
|
|||
|
if (null != m_cInterface)
|
|||
|
{
|
|||
|
m_cInterface.CloseInterface();
|
|||
|
m_cInterface = null;
|
|||
|
}
|
|||
|
// ch:打开采集卡,获得采集卡句柄 | en:Open interface, get handle
|
|||
|
nRet = m_cSystem.OpenInterface((uint)cardIndex, out m_cInterface);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Open Interface failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return false;
|
|||
|
}
|
|||
|
m_bIsIFOpen = true;
|
|||
|
|
|||
|
//====枚举设备
|
|||
|
uint nDeviceNum = 0;
|
|||
|
// ch:枚举采集卡上的相机 | en:Enum camera of interface
|
|||
|
nRet = m_cInterface.UpdateDeviceList(ref bChanged);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Update device list failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// ch:获取设备数量 | en:Get device number
|
|||
|
nRet = m_cInterface.GetNumDevices(ref nDeviceNum);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Get devices number failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (0 == nDeviceNum)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "No Device found");
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (scannerIndex + 1 > nDeviceNum)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "scannerIndex > Device.count!");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
//====打开设备
|
|||
|
// 如果已经打开,则先关闭通道
|
|||
|
if (null != m_cStream)
|
|||
|
{
|
|||
|
m_cStream.CloseStream();
|
|||
|
m_cStream = null;
|
|||
|
}
|
|||
|
// 如果已经打开,则先关闭设备
|
|||
|
if (null != m_cDevice)
|
|||
|
{
|
|||
|
m_cDevice.CloseDevice();
|
|||
|
m_cDevice = null;
|
|||
|
}
|
|||
|
// ch:打开设备,获得设备句柄 | en:Open device, get handle
|
|||
|
nRet = m_cInterface.OpenDevice((uint)scannerIndex, out m_cDevice);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Open device failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return false;
|
|||
|
}
|
|||
|
m_bIsDeviceOpen = true;
|
|||
|
|
|||
|
|
|||
|
//=====打开触发模式
|
|||
|
CParam cDeviceParam = new CParam(m_cInterface);
|
|||
|
// ch:打开触发模式 | en:Open Trigger Mode
|
|||
|
//nRet = cDeviceParam.SetEnumValue("TriggerMode", TRIGGER_MODE_ON);
|
|||
|
//if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
//{
|
|||
|
// WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Turn on trigger mode failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
// //关闭设备和采集卡
|
|||
|
// m_cDevice.CloseDevice();
|
|||
|
// m_bIsDeviceOpen = false;
|
|||
|
// m_cInterface.CloseInterface();
|
|||
|
// m_cInterface = null;
|
|||
|
// return false;
|
|||
|
//}
|
|||
|
m_nTriggerMode = TRIGGER_MODE_ON;
|
|||
|
cDeviceParam.SetEnumValue("TriggerSource", (uint)0);//CC1=0
|
|||
|
|
|||
|
// ch:注册回调函数 | en:Register image callback //本类不使用回调,使用线程主动循环读取
|
|||
|
//ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
|
|||
|
//nRet = device.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
|
|||
|
//if (MyCamera.MV_OK != nRet)
|
|||
|
//{
|
|||
|
// WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, $"Register image callback failed! ({nRet})");
|
|||
|
// return false;
|
|||
|
//}
|
|||
|
//开始采集
|
|||
|
//startGrab();
|
|||
|
//
|
|||
|
getParam();
|
|||
|
|
|||
|
IsInit = true;
|
|||
|
//timer.Elapsed += Timer_Elapsed;
|
|||
|
//timer.Interval = 100;
|
|||
|
//timer.Enabled = true;
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, ex.Message);
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
public override void close()
|
|||
|
{
|
|||
|
if (!IsInit) return;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
IsInit = false;
|
|||
|
|
|||
|
//=====关闭设备
|
|||
|
if (m_bThreadState)
|
|||
|
{
|
|||
|
m_bThreadState = false;
|
|||
|
m_hGrabThread.Join();
|
|||
|
}
|
|||
|
|
|||
|
int nRet = 0;
|
|||
|
if (m_bIsGrabbing)
|
|||
|
{
|
|||
|
// ch:停止取流 | en:Stop Acquisition
|
|||
|
nRet = m_cStream.StopAcquisition();
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low,"Stop acquistion failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
}
|
|||
|
m_bIsGrabbing = false;
|
|||
|
}
|
|||
|
|
|||
|
if (null != m_cStream)
|
|||
|
{
|
|||
|
// ch:关闭流通道 | en:Close stream channel
|
|||
|
nRet = m_cStream.CloseStream();
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low,"Close stream channel failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
}
|
|||
|
m_cStream = null;
|
|||
|
}
|
|||
|
|
|||
|
if (null != m_cDevice)
|
|||
|
{
|
|||
|
// ch:关闭设备 | en:Close device
|
|||
|
nRet = m_cDevice.CloseDevice();
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low,"Close device failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
}
|
|||
|
m_cDevice = null;
|
|||
|
}
|
|||
|
|
|||
|
m_bIsDeviceOpen = false;
|
|||
|
if (IntPtr.Zero != m_pDataBuf)
|
|||
|
{
|
|||
|
Marshal.FreeHGlobal(m_pDataBuf);
|
|||
|
m_pDataBuf = IntPtr.Zero;
|
|||
|
}
|
|||
|
m_nDataBufSize = 0;
|
|||
|
|
|||
|
if (IntPtr.Zero != m_pSaveImageBuf)
|
|||
|
{
|
|||
|
Marshal.FreeHGlobal(m_pSaveImageBuf);
|
|||
|
m_pSaveImageBuf = IntPtr.Zero;
|
|||
|
}
|
|||
|
m_nSaveImageBufSize = 0;
|
|||
|
|
|||
|
//======关闭采集卡
|
|||
|
if (null == m_cInterface)
|
|||
|
return;
|
|||
|
// ch:关闭采集卡 | en:Close interface
|
|||
|
nRet = m_cInterface.CloseInterface();
|
|||
|
//if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
//{
|
|||
|
// WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low,"Close interface failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
// return;
|
|||
|
//}
|
|||
|
m_cInterface = null;
|
|||
|
m_bIsIFOpen = false;
|
|||
|
}
|
|||
|
catch { }
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="hwnd">显示图像控件句柄</param>
|
|||
|
/// <returns></returns>
|
|||
|
public override bool start(PictureBox preview_Hwnd,string bmp_save_path)
|
|||
|
{
|
|||
|
if (!IsInit) return false;
|
|||
|
|
|||
|
this.previewHwnd= preview_Hwnd;
|
|||
|
this.bmpSavePath = bmp_save_path;
|
|||
|
//开始采集
|
|||
|
startGrab();
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// 停止采集
|
|||
|
/// </summary>
|
|||
|
public override void stop()
|
|||
|
{
|
|||
|
if (!IsInit) return;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
if (false == m_bIsDeviceOpen || false == m_bIsGrabbing)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// ch:标志位设为false | en:Set flag bit false
|
|||
|
m_bThreadState = false;
|
|||
|
m_hGrabThread.Join();
|
|||
|
|
|||
|
// ch:停止取流 | en:Stop Acquisition
|
|||
|
int nRet = m_cStream.StopAcquisition();
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
//WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low,"Stop acquistion failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return;
|
|||
|
}
|
|||
|
m_bIsGrabbing = false;
|
|||
|
|
|||
|
// ch:关闭流通道 | en:Close stream channel
|
|||
|
nRet = m_cStream.CloseStream();
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
//WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low,"Close stream channel failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
}
|
|||
|
m_cStream = null;
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// num 因拍了一张后回传的,当前已经是1了
|
|||
|
/// </summary>
|
|||
|
/// <param name="num"></param>
|
|||
|
public override void resetScanIndex()
|
|||
|
{
|
|||
|
scanIndex = 0;//
|
|||
|
}
|
|||
|
#region private
|
|||
|
//开始采集
|
|||
|
private void startGrab()
|
|||
|
{
|
|||
|
if (!m_bIsDeviceOpen)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Please open device first");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (m_bIsGrabbing)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// ch:获取流通道个数 | en:Get number of stream
|
|||
|
uint nStreamNum = 0;
|
|||
|
int nRet = m_cDevice.GetNumStreams(ref nStreamNum);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Get streams number failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return;
|
|||
|
}
|
|||
|
if (0 == nStreamNum)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "No valid stream channel");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// ch:打开流通道(目前只支持单个通道) | en:Open stream(Only a single stream is supported now)
|
|||
|
nRet = m_cDevice.OpenStream(0, out m_cStream);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Open stream failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// ch:设置SDK内部缓存数量 | en:Set internal buffer number
|
|||
|
const uint nBufNum = 5;
|
|||
|
nRet = m_cStream.SetBufferNum(nBufNum);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Set buffer number failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// ch:创建取流线程 | en:Create acquistion thread
|
|||
|
m_bThreadState = true;
|
|||
|
m_hGrabThread = new Thread(ReceiveThreadProcess);
|
|||
|
if (null == m_hGrabThread)
|
|||
|
{
|
|||
|
m_bThreadState = false;
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Create thread failed");
|
|||
|
return;
|
|||
|
}
|
|||
|
m_hGrabThread.Start();
|
|||
|
|
|||
|
// ch:开始取流 | en:Start Acquisition
|
|||
|
nRet = m_cStream.StartAcquisition();
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
m_bThreadState = false;
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Start acquistion failed, ErrorCode:" + nRet.ToString("X"));
|
|||
|
return;
|
|||
|
}
|
|||
|
m_bIsGrabbing = true;
|
|||
|
}
|
|||
|
public void setPreviewWin(PictureBox preview_Hwnd)
|
|||
|
{
|
|||
|
this.previewHwnd = preview_Hwnd;
|
|||
|
}
|
|||
|
public void ReceiveThreadProcess()
|
|||
|
{
|
|||
|
CImageProcess cImgProc = new CImageProcess(m_cStream);
|
|||
|
MV_FG_BUFFER_INFO stFrameInfo = new MV_FG_BUFFER_INFO(); // ch:图像信息 | en:Frame info
|
|||
|
MV_FG_INPUT_IMAGE_INFO stDisplayInfo = new MV_FG_INPUT_IMAGE_INFO(); // ch:显示的图像信息 | en:Display frame info
|
|||
|
const uint nTimeout = 1000;
|
|||
|
int nRet = 0;
|
|||
|
|
|||
|
while (m_bThreadState)
|
|||
|
{
|
|||
|
if (m_bIsGrabbing)
|
|||
|
{
|
|||
|
// ch:获取一帧图像缓存信息 | en:Get one frame buffer's info
|
|||
|
nRet = m_cStream.GetFrameBuffer(ref stFrameInfo, nTimeout);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS == nRet)
|
|||
|
{
|
|||
|
// 用于保存图片
|
|||
|
lock (m_LockForSaveImage)
|
|||
|
{
|
|||
|
if (IntPtr.Zero == m_pDataBuf || m_nDataBufSize < stFrameInfo.nFilledSize)
|
|||
|
{
|
|||
|
if (IntPtr.Zero != m_pDataBuf)
|
|||
|
{
|
|||
|
Marshal.FreeHGlobal(m_pDataBuf);
|
|||
|
m_pDataBuf = IntPtr.Zero;
|
|||
|
}
|
|||
|
|
|||
|
m_pDataBuf = Marshal.AllocHGlobal((Int32)stFrameInfo.nFilledSize);
|
|||
|
if (IntPtr.Zero == m_pDataBuf)
|
|||
|
{
|
|||
|
m_cStream.ReleaseFrameBuffer(stFrameInfo);
|
|||
|
break;
|
|||
|
}
|
|||
|
m_nDataBufSize = stFrameInfo.nFilledSize;
|
|||
|
}
|
|||
|
CopyMemory(m_pDataBuf, stFrameInfo.pBuffer, stFrameInfo.nFilledSize);
|
|||
|
|
|||
|
m_stImageInfo.nWidth = stFrameInfo.nWidth;
|
|||
|
m_stImageInfo.nHeight = stFrameInfo.nHeight;
|
|||
|
m_stImageInfo.enPixelType = stFrameInfo.enPixelType;
|
|||
|
m_stImageInfo.pImageBuf = m_pDataBuf;
|
|||
|
m_stImageInfo.nImageBufLen = stFrameInfo.nFilledSize;
|
|||
|
|
|||
|
//
|
|||
|
var imgbuff=SaveImage();
|
|||
|
if(imgbuff != null)
|
|||
|
{
|
|||
|
scanIndex++;
|
|||
|
//if (ScanEventPath != null)//Ge用的这个
|
|||
|
//{
|
|||
|
// string imagpath = $"{this.bmpSavePath}{scanIndex}_dev{_scannerCardIndex}.bmp";
|
|||
|
// File.WriteAllBytes(imagpath, imgbuff);
|
|||
|
// ScanEventPath?.Invoke(scanIndex, imagpath, _scannerCardIndex);
|
|||
|
//}
|
|||
|
//else
|
|||
|
{
|
|||
|
Mat mat = Mat.ImDecode(imgbuff);
|
|||
|
//string imagpath = $"{this.bmpSavePath}{scanIndex}_dev{_scannerCardIndex}.bmp";
|
|||
|
//File.WriteAllBytes(imagpath, imgbuff);
|
|||
|
ScanEvent?.Invoke(scanIndex, mat, _scannerCardIndex);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 自定义格式不支持显示
|
|||
|
if (RemoveCustomPixelFormats(stFrameInfo.enPixelType))
|
|||
|
{
|
|||
|
m_cStream.ReleaseFrameBuffer(stFrameInfo);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// 配置显示图像的参数
|
|||
|
//pictureBox1显示
|
|||
|
if (this.previewHwnd != null && IsWindow(this.previewHwnd.Handle))
|
|||
|
{
|
|||
|
stDisplayInfo.nWidth = stFrameInfo.nWidth;
|
|||
|
stDisplayInfo.nHeight = stFrameInfo.nHeight;
|
|||
|
stDisplayInfo.enPixelType = stFrameInfo.enPixelType;
|
|||
|
stDisplayInfo.pImageBuf = stFrameInfo.pBuffer;
|
|||
|
stDisplayInfo.nImageBufLen = stFrameInfo.nFilledSize;
|
|||
|
nRet = cImgProc.DisplayOneFrame(previewHwnd.Handle, ref stDisplayInfo);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
{
|
|||
|
m_cStream.ReleaseFrameBuffer(stFrameInfo);
|
|||
|
//this.Invoke(new ShowDisplayError(DisplayError), new object[] { nRet });
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
m_cStream.ReleaseFrameBuffer(stFrameInfo);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (TRIGGER_MODE_ON == m_nTriggerMode)
|
|||
|
{
|
|||
|
Thread.Sleep(5);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Thread.Sleep(5);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private byte[] SaveImage(SAVE_IAMGE_TYPE enSaveImageType= SAVE_IAMGE_TYPE.Image_Bmp)
|
|||
|
{
|
|||
|
int nRet = 0;
|
|||
|
|
|||
|
lock (m_LockForSaveImage)
|
|||
|
{
|
|||
|
if (IntPtr.Zero == m_pDataBuf)
|
|||
|
return null;// CErrorCode.MV_FG_ERR_NO_DATA;
|
|||
|
|
|||
|
if (RemoveCustomPixelFormats(m_stImageInfo.enPixelType))
|
|||
|
return null;//CErrorCode.MV_FG_ERR_INVALID_VALUE;
|
|||
|
|
|||
|
uint nMaxImageLen = m_stImageInfo.nWidth * m_stImageInfo.nHeight * 4 + 2048; // 确保存图空间足够,包括图像头
|
|||
|
if (IntPtr.Zero == m_pSaveImageBuf || m_nSaveImageBufSize < nMaxImageLen)
|
|||
|
{
|
|||
|
if (IntPtr.Zero != m_pSaveImageBuf)
|
|||
|
{
|
|||
|
Marshal.FreeHGlobal(m_pSaveImageBuf);
|
|||
|
m_pSaveImageBuf = IntPtr.Zero;
|
|||
|
}
|
|||
|
|
|||
|
m_pSaveImageBuf = Marshal.AllocHGlobal((Int32)nMaxImageLen);
|
|||
|
if (IntPtr.Zero == m_pSaveImageBuf)
|
|||
|
return null;//CErrorCode.MV_FG_ERR_OUT_OF_MEMORY;
|
|||
|
m_nSaveImageBufSize = nMaxImageLen;
|
|||
|
}
|
|||
|
|
|||
|
CImageProcess cImgSave = new CImageProcess(m_cStream);
|
|||
|
System.DateTime currentTime = new System.DateTime();
|
|||
|
currentTime = System.DateTime.Now;
|
|||
|
do
|
|||
|
{
|
|||
|
if (SAVE_IAMGE_TYPE.Image_Bmp == enSaveImageType)
|
|||
|
{
|
|||
|
MV_FG_SAVE_BITMAP_INFO stBmpInfo = new MV_FG_SAVE_BITMAP_INFO();
|
|||
|
|
|||
|
stBmpInfo.stInputImageInfo = m_stImageInfo;
|
|||
|
stBmpInfo.pBmpBuf = m_pSaveImageBuf;
|
|||
|
stBmpInfo.nBmpBufSize = m_nSaveImageBufSize;
|
|||
|
stBmpInfo.enCfaMethod = MV_FG_CFA_METHOD.MV_FG_CFA_METHOD_OPTIMAL;
|
|||
|
|
|||
|
// ch:保存BMP图像 | en:Save to BMP
|
|||
|
nRet = cImgSave.SaveBitmap(ref stBmpInfo);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
break;
|
|||
|
|
|||
|
// ch:将图像数据保存到本地文件 | en:Save image data to local file
|
|||
|
byte[] byteData = new byte[stBmpInfo.nBmpBufLen];
|
|||
|
Marshal.Copy(stBmpInfo.pBmpBuf, byteData, 0, (int)stBmpInfo.nBmpBufLen);
|
|||
|
|
|||
|
//保存文件
|
|||
|
//string strName = "Image_w" + stBmpInfo.stInputImageInfo.nWidth.ToString() +
|
|||
|
// "_h" + stBmpInfo.stInputImageInfo.nHeight.ToString() + "_" + currentTime.Minute.ToString() +
|
|||
|
// currentTime.Second.ToString() + currentTime.Millisecond.ToString() + ".bmp";
|
|||
|
//FileStream pFile = new FileStream(strName, FileMode.Create);
|
|||
|
//if (null == pFile)
|
|||
|
//{
|
|||
|
// nRet = CErrorCode.MV_FG_ERR_ERROR;
|
|||
|
// break;
|
|||
|
//}
|
|||
|
//pFile.Write(byteData, 0, byteData.Length);
|
|||
|
//pFile.Close();
|
|||
|
|
|||
|
return byteData;
|
|||
|
}
|
|||
|
else if (SAVE_IAMGE_TYPE.Image_Jpeg == enSaveImageType)
|
|||
|
{
|
|||
|
MV_FG_SAVE_JPEG_INFO stJpgInfo = new MV_FG_SAVE_JPEG_INFO();
|
|||
|
|
|||
|
stJpgInfo.stInputImageInfo = m_stImageInfo;
|
|||
|
stJpgInfo.pJpgBuf = m_pSaveImageBuf;
|
|||
|
stJpgInfo.nJpgBufSize = m_nSaveImageBufSize;
|
|||
|
stJpgInfo.nJpgQuality = 80; // JPG编码质量(0-100]
|
|||
|
stJpgInfo.enCfaMethod = MV_FG_CFA_METHOD.MV_FG_CFA_METHOD_OPTIMAL;
|
|||
|
|
|||
|
// ch:保存JPG图像 | en:Save to JPG
|
|||
|
nRet = cImgSave.SaveJpeg(ref stJpgInfo);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
break;
|
|||
|
|
|||
|
// ch:将图像数据保存到本地文件 | en:Save image data to local file
|
|||
|
byte[] byteData = new byte[stJpgInfo.nJpgBufLen];
|
|||
|
Marshal.Copy(stJpgInfo.pJpgBuf, byteData, 0, (int)stJpgInfo.nJpgBufLen);
|
|||
|
|
|||
|
//保存文件
|
|||
|
//string strName = "Image_w" + stJpgInfo.stInputImageInfo.nWidth.ToString() +
|
|||
|
// "_h" + stJpgInfo.stInputImageInfo.nHeight.ToString() + "_" + currentTime.Minute.ToString() +
|
|||
|
// currentTime.Second.ToString() + currentTime.Millisecond.ToString() + ".jpg";
|
|||
|
//FileStream pFile = new FileStream(strName, FileMode.Create);
|
|||
|
//if (null == pFile)
|
|||
|
//{
|
|||
|
// nRet = CErrorCode.MV_FG_ERR_ERROR;
|
|||
|
// break;
|
|||
|
//}
|
|||
|
//pFile.Write(byteData, 0, byteData.Length);
|
|||
|
//pFile.Close();
|
|||
|
return byteData;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
nRet = CErrorCode.MV_FG_ERR_INVALID_PARAMETER;
|
|||
|
break;
|
|||
|
}
|
|||
|
} while (false);
|
|||
|
}
|
|||
|
|
|||
|
return null;//
|
|||
|
}
|
|||
|
|
|||
|
// ch:去除自定义的像素格式 | en:Remove custom pixel formats
|
|||
|
private bool RemoveCustomPixelFormats(MV_FG_PIXEL_TYPE enPixelFormat)
|
|||
|
{
|
|||
|
Int32 nResult = ((int)enPixelFormat) & CUSTOMER_PIXEL_FORMAT;
|
|||
|
if (CUSTOMER_PIXEL_FORMAT == nResult)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
public override double[] getFeatureRangeValue(string featureName)
|
|||
|
{
|
|||
|
switch (featureName)
|
|||
|
{
|
|||
|
case "ExposureTime":
|
|||
|
return new double[2] { 0, 10000 };
|
|||
|
case "Gain":
|
|||
|
return new double[2] { 0.01, 255 };
|
|||
|
default: return new double[0] { };
|
|||
|
}
|
|||
|
}
|
|||
|
public override void getParam()
|
|||
|
{
|
|||
|
if (!IsInit) return;
|
|||
|
|
|||
|
CParam cDeviceParam = new CParam(m_cInterface);
|
|||
|
|
|||
|
MV_FG_FLOATVALUE stParam=new MV_FG_FLOATVALUE();
|
|||
|
int nRet = cDeviceParam.GetFloatValue("ExposureTime", ref stParam);
|
|||
|
if (nRet == CErrorCode.MV_FG_SUCCESS) ExposureTime = stParam.fCurValue;
|
|||
|
|
|||
|
nRet = cDeviceParam.GetFloatValue("Gain", ref stParam);
|
|||
|
if (nRet == CErrorCode.MV_FG_SUCCESS) Gain = stParam.fCurValue;
|
|||
|
|
|||
|
nRet = cDeviceParam.GetFloatValue("ResultingFrameRate", ref stParam);
|
|||
|
if (nRet == CErrorCode.MV_FG_SUCCESS) ResultingFrameRate = stParam.fCurValue;
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="exposureTime">曝光</param>
|
|||
|
/// <param name="gain">增益</param>
|
|||
|
/// <param name="resultingFrameRate">帧率</param>
|
|||
|
public override bool setParam(float exposureTime, float gain =-1, float resultingFrameRate =-1)
|
|||
|
{
|
|||
|
if (!IsInit) return false;
|
|||
|
|
|||
|
CParam cDeviceParam = new CParam(m_cInterface);
|
|||
|
//cDeviceParam.GetXmlFile()
|
|||
|
//cDeviceParam.GetNodeAccessMode
|
|||
|
//cDeviceParam.GetNodeInterfaceType
|
|||
|
bool change = false;
|
|||
|
int nRet;
|
|||
|
if (exposureTime != ExposureTime && exposureTime != -1)
|
|||
|
{
|
|||
|
//device.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
|
|||
|
//nRet = device.MV_CC_SetFloatValue_NET("ExposureTime", exposureTime);
|
|||
|
|
|||
|
nRet = cDeviceParam.SetEnumValue("ExposureAuto", (uint)0);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, "ExposureTime SetEnumValue(\"ExposureAuto\") res=" + nRet);
|
|||
|
nRet = cDeviceParam.SetFloatValue("ExposureTime", exposureTime);
|
|||
|
if (CErrorCode.MV_FG_SUCCESS != nRet)
|
|||
|
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, "ExposureTime SetFloatValue(\"ExposureTime\") res=" + nRet);
|
|||
|
change = true;
|
|||
|
}
|
|||
|
|
|||
|
if (gain != Gain && gain != -1)
|
|||
|
{
|
|||
|
//device.MV_CC_SetEnumValue_NET("GainAuto", 0);
|
|||
|
//nRet = device.MV_CC_SetFloatValue_NET("Gain", gain);
|
|||
|
cDeviceParam.SetEnumValue("GainAuto", (uint)0);
|
|||
|
cDeviceParam.SetFloatValue("Gain", gain);
|
|||
|
change = true;
|
|||
|
}
|
|||
|
|
|||
|
if (resultingFrameRate != ResultingFrameRate && resultingFrameRate != -1)
|
|||
|
{
|
|||
|
cDeviceParam.SetFloatValue("AcquisitionFrameRate", resultingFrameRate);
|
|||
|
change = true;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
if (change)
|
|||
|
getParam();
|
|||
|
return change;
|
|||
|
}
|
|||
|
|
|||
|
public void Dispose()
|
|||
|
{
|
|||
|
stop();
|
|||
|
close();
|
|||
|
}
|
|||
|
private byte[] bmp2bytes(Bitmap bmp)
|
|||
|
{
|
|||
|
MemoryStream ms = new MemoryStream();
|
|||
|
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
|
|||
|
byte[] bytes = ms.GetBuffer(); //byte[] bytes= ms.ToArray(); 这两句都可以,至于区别么,下面有解释
|
|||
|
ms.Close();
|
|||
|
bmp.Dispose();
|
|||
|
return bytes;
|
|||
|
}
|
|||
|
private Bitmap bytes2bmp(byte[] bytes)
|
|||
|
{
|
|||
|
MemoryStream ms1 = new MemoryStream(bytes);
|
|||
|
Bitmap bm = (Bitmap)Image.FromStream(ms1);
|
|||
|
ms1.Close();
|
|||
|
return bm;
|
|||
|
}
|
|||
|
public Bitmap read2Bmp(string path)
|
|||
|
{
|
|||
|
MemoryStream ms = new System.IO.MemoryStream(File.ReadAllBytes(path));
|
|||
|
Bitmap bmp = new Bitmap(ms);
|
|||
|
ms.Close();
|
|||
|
ms.Dispose();
|
|||
|
//FileStream fs = new FileStream(path, FileMode.Open);
|
|||
|
//byte[] bmpdata = new byte[fs.Length];
|
|||
|
//fs.Read(bmpdata, 0, bmpdata.Length);
|
|||
|
//Bitmap bmp = new Bitmap(fs);
|
|||
|
//fs.Close();
|
|||
|
|
|||
|
return bmp;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|