geboshi_V1/LeatherProject/LeatherApp/Device/CamerCardDev2.cs
2024-03-07 14:03:22 +08:00

562 lines
24 KiB
C#
Raw Permalink 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;
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 IKapBoardClassLibrary;
using LeatherApp.Interface;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
using OpenCvSharp.Dnn;
using ErrorCode = IKapBoardClassLibrary.ErrorCode;
namespace LeatherApp.Device
{
public class CamerCardDev2 : 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);
[DllImport("User32.dll")]
public extern static System.IntPtr GetDC(System.IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
//显示图像控件句柄
private PictureBox previewHwnd = null;
//
// 采集卡设备句柄。
public IntPtr m_hBoard = new IntPtr(-1);
// 当前帧索引。
public int m_nCurFrameIndex = 0;
// 图像缓冲区申请的帧数。
public int m_nTotalFrameCount = 1;
// 保存图像的文件名。
public string m_strFileName = "C:\\CSharpImage.bmp";
//
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 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;//相机索引(一个采集卡上可插多个相机)
public CamerCardDev2( )
{
}
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 ret = (int)ErrorCode.IK_RTN_OK;
uint nPCIeDevCount = 0;
StringBuilder resourceName;
uint resourceNameSize = 0;
IKapBoard.IKAPERRORINFO tIKei = new IKapBoard.IKAPERRORINFO();
// 获取连接的采集卡数量。
ret = IKapBoard.IKapGetBoardCount((int)BoardType.IKBoardPCIE, ref nPCIeDevCount);
CheckIKapBoard(ret);
// 当没有连接的采集卡时。
if (nPCIeDevCount == 0 || nPCIeDevCount< cardIndex+1)
{
WarningEvent?.Invoke(WarningEnum.High, "Get board count 0");
return false;
}
// 获取采集卡名称。
for (uint i = 0; i < nPCIeDevCount; i++)
{
resourceNameSize = 0;
resourceName = new StringBuilder(0);
IKapBoard.IKapGetBoardName((uint)BoardType.IKBoardPCIE, i, resourceName, ref resourceNameSize);
IKapBoard.IKapGetLastError(ref tIKei, true);
if (tIKei.uErrorCode == (uint)ErrorCode.IKStatus_BufferTooSmall)
{
resourceName = new StringBuilder((int)resourceNameSize);
IKapBoard.IKapGetBoardName((uint)BoardType.IKBoardPCIE, i, resourceName, ref resourceNameSize);
}
IKapBoard.IKapGetLastError(ref tIKei, true);
if (tIKei.uErrorCode != (uint)ErrorCode.IKStatus_Success)
{
WarningEvent?.Invoke(WarningEnum.High, "Get Device Name Fail. Error Code:"+tIKei.uErrorCode);
return false;
}
string sMesg = string.Concat("PCIE Device- ", i.ToString("d"), "\nName: ", resourceName);
}
// 打开采集卡。
//
// Open frame grabber.
m_hBoard = IKapBoard.IKapOpen((int)BoardType.IKBoardPCIE, 0);//采集卡索引0-n
if (m_hBoard.Equals(-1))
{
WarningEvent?.Invoke(WarningEnum.High, "Open device failure!");
return false;
}
// 导入配置文件。
string configFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\"+ Config.CarmerConfigFilePath;
if (!File.Exists(configFileName))
{
WarningEvent?.Invoke(WarningEnum.High, "Fail to get configuration, using default setting!");
return false;
}
ret = IKapBoard.IKapLoadConfigurationFromFile(m_hBoard, configFileName);
CheckIKapBoard(ret);
// 设置图像缓冲区帧数。
//
// Set frame count of buffer.
ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_COUNT, m_nTotalFrameCount);
CheckIKapBoard(ret);
// 设置超时时间。
//
// Set time out time.
int timeout = -1;
ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_TIME_OUT, timeout);
CheckIKapBoard(ret);
// 设置采集模式。
//
// Set grab mode.
int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK;//非阻塞StartGrab
ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode);
CheckIKapBoard(ret);
// 设置传输模式。
//
// Set transfer mode.
int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT;
ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode);
CheckIKapBoard(ret);
// 注册回调函数
//
// Register callback functions.
OnGrabStartProc = new IKapCallBackProc(OnGrabStartFunc);
ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStart, Marshal.GetFunctionPointerForDelegate(OnGrabStartProc), m_hBoard);
CheckIKapBoard(ret);
OnFrameReadyProc = new IKapCallBackProc(OnFrameReadyFunc);
ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameReady, Marshal.GetFunctionPointerForDelegate(OnFrameReadyProc), m_hBoard);
CheckIKapBoard(ret);
OnFrameLostProc = new IKapCallBackProc(OnFrameLostFunc);
ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameLost, Marshal.GetFunctionPointerForDelegate(OnFrameLostProc), m_hBoard);
CheckIKapBoard(ret);
OnTimeoutProc = new IKapCallBackProc(OnTimeoutFunc);
ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_TimeOut, Marshal.GetFunctionPointerForDelegate(OnTimeoutProc), m_hBoard);
CheckIKapBoard(ret);
OnGrabStopProc = new IKapCallBackProc(OnGrabStopFunc);
ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStop, Marshal.GetFunctionPointerForDelegate(OnGrabStopProc), m_hBoard);
CheckIKapBoard(ret);
// 设置行触发参数。
//SetLineTrigger();
//
getParam();
IsInit = true;
//timer.Elapsed += Timer_Elapsed;
//timer.Interval = 100;
//timer.Enabled = true;
return true;
}
catch (Exception ex)
{
WarningEvent?.Invoke(WarningEnum.High, ex.Message);
return false;
}
}
public override void close()
{
if (!IsInit) return;
try
{
IsInit = false;
// 清除回调函数。
UnRegisterCallback();
// 关闭设备。
CloseDevice();
}
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;
//开始采集
//第二个参数 nFrameCount 表示希望 IKapBoardClassLibrary 采集的帧数。
//如果 nFrameCount = 1IKapBoardClassLibrary 会从相机中采集一帧图像;
//如果 nFrameCount = N 且 N> 1则 IKapBoardClassLibrary 从相机中采集连续的 N 帧图 像;
//如果 nFrameCount = 0则 IKapBoardClassLibrary 开始连续采集图像。
var ret = IKapBoard.IKapStartGrab(m_hBoard, 0);
return ret == (int)ErrorCode.IK_RTN_OK;
}
/// <summary>
/// 停止采集
/// </summary>
public override void stop()
{
if (!IsInit) return;
try
{
// 停止图像采集。
var ret = IKapBoard.IKapStopGrab(m_hBoard);
CheckIKapBoard(ret);
}
catch
{
return;
}
}
/// <summary>
/// num 因拍了一张后回传的当前已经是1了
/// </summary>
/// <param name="num"></param>
public override void resetScanIndex()
{
scanIndex = 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;
bool change = false;
//CParam cDeviceParam = new CParam(m_cInterface);
//int nRet;
//if (exposureTime != ExposureTime && exposureTime != -1)
//{
// nRet = cDeviceParam.SetEnumValue("ExposureAuto", (uint)0);
// if (CErrorCode.MV_FG_SUCCESS != nRet)
// WarningEvent?.Invoke(WarningEnum.Low, "ExposureTime SetEnumValue(\"ExposureAuto\") res=" + nRet);
// nRet = cDeviceParam.SetFloatValue("ExposureTime", exposureTime);
// if (CErrorCode.MV_FG_SUCCESS != nRet)
// WarningEvent?.Invoke(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();
}
//---------------
/* @brief设置行触发参数。
*
* @briefSet line trigger parameters. */
void SetLineTrigger()
{
int ret = (int)ErrorCode.IK_RTN_OK;
// 设置CC1信号源。
//
// Set CC1 signal source.
ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_CC1_SOURCE, (int)CCSource.IKP_CC_SOURCE_VAL_INTEGRATION_SIGNAL1);
CheckIKapBoard(ret);
// 设置积分控制方法触发信号源。
//
// Set integration control method trigger source.
ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_INTEGRATION_TRIGGER_SOURCE, (int)IntegrationTriggerSource.IKP_INTEGRATION_TRIGGER_SOURCE_VAL_SHAFT_ENCODER1);
CheckIKapBoard(ret);
}
/* @brief清除回调函数。
*
* @briefUnregister callback functions. */
private void UnRegisterCallback()
{
int ret = (int)ErrorCode.IK_RTN_OK;
ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStart);
ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameReady);
ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameLost);
ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_TimeOut);
ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStop);
}
/* @brief关闭设备。
*
* @briefClose device. */
private void CloseDevice()
{
// 关闭采集卡设备。
//
// Close frame grabber device.
if (!m_hBoard.Equals(-1))
{
IKapBoard.IKapClose(m_hBoard);
m_hBoard = (IntPtr)(-1);
}
}
/* @brief判断 IKapBoard 函数是否成功调用。
* @param[in] ret函数返回值。
*
* @briefDetermine whether the IKapBoard function is called successfully.
* @param[in] retFunction return value. */
static void CheckIKapBoard(int ret)
{
if (ret != (int)ErrorCode.IK_RTN_OK)
{
string sErrMsg = "";
IKapBoard.IKAPERRORINFO tIKei = new IKapBoardClassLibrary.IKapBoard.IKAPERRORINFO();
// 获取错误码信息。
IKapBoard.IKapGetLastError(ref tIKei, true);
// 打印错误信息。
sErrMsg = string.Concat("Error",
sErrMsg,
"Board Type\t = 0x", tIKei.uBoardType.ToString("X4"), "\n",
"Board Index\t = 0x", tIKei.uBoardIndex.ToString("X4"), "\n",
"Error Code\t = 0x", tIKei.uErrorCode.ToString("X4"), "\n"
);
throw new Exception(sErrMsg);
}
}
#region Callback
delegate void IKapCallBackProc(IntPtr pParam);
/* @brief本函数被注册为一个回调函数。当图像采集开始时函数被调用。
*
* @briefThis function is registered as a callback function. When starting grabbing images, the function will be called. */
private IKapCallBackProc OnGrabStartProc;
/* @brief本函数被注册为一个回调函数。当采集丢帧时函数被调用。
*
* @briefThis function is registered as a callback function. When grabbing frame lost, the function will be called. */
private IKapCallBackProc OnFrameLostProc;
/* @brief本函数被注册为一个回调函数。当图像采集超时时函数被调用。
*
* @briefThis function is registered as a callback function. When grabbing images time out, the function will be called. */
private IKapCallBackProc OnTimeoutProc;
/* @brief本函数被注册为一个回调函数。当一帧图像采集完成时函数被调用。
*
* @briefThis function is registered as a callback function. When a frame of image grabbing ready, the function will be called. */
private IKapCallBackProc OnFrameReadyProc;
/* @brief本函数被注册为一个回调函数。当图像采集停止时函数被调用。
*
* @briefThis function is registered as a callback function. When stopping grabbing images, the function will be called. */
private IKapCallBackProc OnGrabStopProc;
#endregion
#region Callback
/* @brief本函数被注册为一个回调函数。当图像采集开始时函数被调用。
* @param[in] pParam输入参数。
*
* @briefThis function is registered as a callback function. When starting grabbing images, the function will be called.
* @param[in] pParamInput parameter. */
public void OnGrabStartFunc(IntPtr pParam)
{
Console.WriteLine("Start grabbing image");
}
/* @brief本函数被注册为一个回调函数。当采集丢帧时函数被调用。
* @param[in] pParam输入参数。
*
* @briefThis function is registered as a callback function. When grabbing frame lost, the function will be called.
* @param[in] pParamInput parameter. */
public void OnFrameLostFunc(IntPtr pParam)
{
Console.WriteLine("Image frame lost");
}
/* @brief本函数被注册为一个回调函数。当图像采集超时时函数被调用。
* @param[in] pParam输入参数。
*
* @briefThis function is registered as a callback function. When grabbing images time out, the function will be called.
* @param[in] pParamInput parameter. */
public void OnTimeoutFunc(IntPtr pParam)
{
Console.WriteLine("Grab image timeout");
}
/* @brief本函数被注册为一个回调函数。当一帧图像采集完成时函数被调用。
* @param[in] pParam输入参数。
*
* @briefThis function is registered as a callback function. When a frame of image grabbing ready, the function will be called.
* @param[in] pParamInput parameter. */
public void OnFrameReadyFunc(IntPtr pParam)
{
Console.WriteLine("Grab frame ready");
IntPtr hDev = (IntPtr)pParam;
IntPtr pUserBuffer = IntPtr.Zero;
int nFrameSize = 0;
int nFrameCount = 0;
IKapBoard.IKAPBUFFERSTATUS status = new IKapBoard.IKAPBUFFERSTATUS();
IKapBoard.IKapGetInfo(hDev, (uint)INFO_ID.IKP_FRAME_COUNT, ref nFrameCount);
IKapBoard.IKapGetBufferStatus(hDev, m_nCurFrameIndex, ref status);
// 当图像缓冲区满时。
//
// When the buffer is full.
if (status.uFull == 1)
{
// 获取一帧图像的大小。
//
// Get the size of a frame of image.
IKapBoard.IKapGetInfo(hDev, (uint)INFO_ID.IKP_FRAME_SIZE, ref nFrameSize);
// 获取缓冲区地址。
//
// Get the buffer address.
IKapBoard.IKapGetBufferAddress(hDev, m_nCurFrameIndex, ref pUserBuffer);
// === 保存图像。
//存文件
//IKapBoard.IKapSaveBuffer(hDev, m_nCurFrameIndex, m_strFileName, (int)ImageCompressionFalg.IKP_DEFAULT_COMPRESSION);
// 存到byte[]
byte[] imageBuff = new byte[nFrameSize]; // 创建字节数组
Marshal.Copy(pUserBuffer, imageBuff, 0, imageBuff.Length); // 将目标内存空间中的数据复制到结果字节数组
//存到地址
//IntPtr m_pDataBuf = Marshal.AllocHGlobal(nFrameSize); //分配空间
//CopyMemory(m_pDataBuf, pUserBuffer, (uint)nFrameSize);
//pictureBox1显示
if (this.previewHwnd != null && IsWindow(this.previewHwnd.Handle))
{
this.previewHwnd.Image = bytes2bmp(imageBuff);
}
}
m_nCurFrameIndex++;
m_nCurFrameIndex = m_nCurFrameIndex % m_nTotalFrameCount;
}
/* @brief本函数被注册为一个回调函数。当图像采集停止时函数被调用。
* @param[in] pParam输入参数。
*
* @briefThis function is registered as a callback function. When stopping grabbing images, the function will be called.
* @param[in] pParamInput parameter. */
public void OnGrabStopFunc(IntPtr pParam)
{
Console.WriteLine("Stop grabbing image");
}
#endregion
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;
}
}
}