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;
///
/// 曝光 3.00-10000.00
///
public float ExposureTime { get; private set; }
///
/// 增益 0-23.981199
///
public float Gain { get; private set; }
///
/// 帧率 0-429496.718750
///
public float ResultingFrameRate { get; private set; }
///
/// 图片大小
///
public System.Drawing.Size size { get; private set; }
///
/// 是否打开设备成功
///
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 { }
}
///
///
///
/// 显示图像控件句柄
///
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 = 1,IKapBoardClassLibrary 会从相机中采集一帧图像;
//如果 nFrameCount = N 且 N> 1,则 IKapBoardClassLibrary 从相机中采集连续的 N 帧图 像;
//如果 nFrameCount = 0,则 IKapBoardClassLibrary 开始连续采集图像。
var ret = IKapBoard.IKapStartGrab(m_hBoard, 0);
return ret == (int)ErrorCode.IK_RTN_OK;
}
///
/// 停止采集
///
public override void stop()
{
if (!IsInit) return;
try
{
// 停止图像采集。
var ret = IKapBoard.IKapStopGrab(m_hBoard);
CheckIKapBoard(ret);
}
catch
{
return;
}
}
///
/// num 因拍了一张后回传的,当前已经是1了
///
///
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;
}
///
///
///
/// 曝光
/// 增益
/// 帧率
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:设置行触发参数。
*
* @brief:Set 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:清除回调函数。
*
* @brief:Unregister 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:关闭设备。
*
* @brief:Close 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:函数返回值。
*
* @brief:Determine whether the IKapBoard function is called successfully.
* @param[in] ret:Function 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:本函数被注册为一个回调函数。当图像采集开始时,函数被调用。
*
* @brief:This function is registered as a callback function. When starting grabbing images, the function will be called. */
private IKapCallBackProc OnGrabStartProc;
/* @brief:本函数被注册为一个回调函数。当采集丢帧时,函数被调用。
*
* @brief:This function is registered as a callback function. When grabbing frame lost, the function will be called. */
private IKapCallBackProc OnFrameLostProc;
/* @brief:本函数被注册为一个回调函数。当图像采集超时时,函数被调用。
*
* @brief:This function is registered as a callback function. When grabbing images time out, the function will be called. */
private IKapCallBackProc OnTimeoutProc;
/* @brief:本函数被注册为一个回调函数。当一帧图像采集完成时,函数被调用。
*
* @brief:This function is registered as a callback function. When a frame of image grabbing ready, the function will be called. */
private IKapCallBackProc OnFrameReadyProc;
/* @brief:本函数被注册为一个回调函数。当图像采集停止时,函数被调用。
*
* @brief:This 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:输入参数。
*
* @brief:This function is registered as a callback function. When starting grabbing images, the function will be called.
* @param[in] pParam:Input parameter. */
public void OnGrabStartFunc(IntPtr pParam)
{
Console.WriteLine("Start grabbing image");
}
/* @brief:本函数被注册为一个回调函数。当采集丢帧时,函数被调用。
* @param[in] pParam:输入参数。
*
* @brief:This function is registered as a callback function. When grabbing frame lost, the function will be called.
* @param[in] pParam:Input parameter. */
public void OnFrameLostFunc(IntPtr pParam)
{
Console.WriteLine("Image frame lost");
}
/* @brief:本函数被注册为一个回调函数。当图像采集超时时,函数被调用。
* @param[in] pParam:输入参数。
*
* @brief:This function is registered as a callback function. When grabbing images time out, the function will be called.
* @param[in] pParam:Input parameter. */
public void OnTimeoutFunc(IntPtr pParam)
{
Console.WriteLine("Grab image timeout");
}
/* @brief:本函数被注册为一个回调函数。当一帧图像采集完成时,函数被调用。
* @param[in] pParam:输入参数。
*
* @brief:This function is registered as a callback function. When a frame of image grabbing ready, the function will be called.
* @param[in] pParam:Input 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:输入参数。
*
* @brief:This function is registered as a callback function. When stopping grabbing images, the function will be called.
* @param[in] pParam:Input 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;
}
}
}