875 lines
37 KiB
C#
875 lines
37 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Diagnostics;
|
||
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 IKapC.NET;
|
||
using LeatherApp.Device.CamerUtil;
|
||
using LeatherApp.Interface;
|
||
using Newtonsoft.Json.Linq;
|
||
using OpenCvSharp;
|
||
using OpenCvSharp.Dnn;
|
||
using ErrorCode = IKapBoardClassLibrary.ErrorCode;
|
||
|
||
namespace LeatherApp.Device
|
||
{
|
||
public class CamerCardDevIK : ABSCamerCardDev,IDisposable
|
||
{
|
||
[DllImport("user32.dll")]
|
||
[return: MarshalAs(UnmanagedType.Bool)]
|
||
private static extern bool IsWindow(IntPtr hWnd);
|
||
|
||
[DllImport("kernel32.dll")]
|
||
public static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
|
||
// 相机句柄
|
||
//private IKDeviceCL m_pDev = new IKDeviceCL();
|
||
public IntPtr m_pDev = new IntPtr(-1);
|
||
// 采集卡句柄
|
||
public IntPtr m_pBoard = new IntPtr(-1);
|
||
// 用户缓冲区,用于图像数据转换
|
||
public IntPtr m_pUserBuffer = new IntPtr(-1);
|
||
// 是否正在采集
|
||
public volatile bool m_bGrabingImage = false;
|
||
// 是否已更新用户缓冲区
|
||
public volatile bool m_bUpdateImage = false;
|
||
// 相机类型,0为GV相机,1为CL相机,2为CXP相机
|
||
public int m_nType = -1;
|
||
// 图像宽度
|
||
public int m_nWidth = -1;
|
||
// 图像高度
|
||
public int m_nHeight = -1;
|
||
// 像素位数
|
||
public int m_nDepth = 8;
|
||
// 图像通道数
|
||
public int m_nChannels = 1;
|
||
// 相机索引
|
||
public int m_nDevIndex = -1;
|
||
// 采集卡索引
|
||
public int m_nBoardIndex = -1;
|
||
// 相机缓冲区个数
|
||
public int m_nFrameCount = 2;//只能1
|
||
// 当前帧索引
|
||
public int m_nCurFrameIndex = 0;
|
||
// 相机缓冲区大小
|
||
public int m_nBufferSize = 0;
|
||
// 用户缓冲区锁
|
||
public object m_mutexImage = new object();
|
||
|
||
|
||
//显示图像控件句柄
|
||
private PictureBox previewHwnd = null;
|
||
//
|
||
// 保存图像的文件名。
|
||
public string m_strFileName = "C:\\CSharpImage.bmp";
|
||
|
||
//
|
||
private int scanIndex = 0; //实际拍照从1开始命名,因先加的1
|
||
private string bmpSavePath;
|
||
|
||
private Thread readerThread;
|
||
private Queue<MyData> frameQueue =new Queue<MyData>();
|
||
/// <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;//相机索引(一个采集卡上可插多个相机)
|
||
private IKDeviceInfo devInfo;
|
||
BufferToImage hBuffer;
|
||
|
||
private class MyData
|
||
{
|
||
public MyData(int _index,Mat _mat)
|
||
{
|
||
index= _index;
|
||
mat = _mat;
|
||
}
|
||
public int index;
|
||
public Mat mat;
|
||
}
|
||
// 设备类型枚举
|
||
enum IKDeviceType
|
||
{
|
||
DEVICE_NIL = 0,
|
||
DEVICE_CML,
|
||
DEVICE_CXP,
|
||
DEVICE_USB,
|
||
DEVICE_GIGEVISION
|
||
}
|
||
// 设备信息结构体
|
||
struct IKDeviceInfo
|
||
{
|
||
public IKDeviceType nType;
|
||
public int nDevIndex;
|
||
public int nBoardIndex;
|
||
public string sDevName;
|
||
}
|
||
/// <summary>
|
||
/// 读取缓存队列线程
|
||
/// </summary>
|
||
private void readDataThread()
|
||
{
|
||
MyData mydate;
|
||
while (IsInit)
|
||
{
|
||
if (frameQueue.Count > 0) // 如果队列不为空则从队列中获取元素
|
||
{
|
||
lock (frameQueue)
|
||
{
|
||
mydate = frameQueue.Dequeue();
|
||
}
|
||
PhotoNumCacheEvent?.Invoke(frameQueue.Count);
|
||
WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, $"相机({_scannerCardIndex})从缓存队列提取一帧图像({mydate.index}),开始回调(队列剩余帧数:{frameQueue.Count})...", null, null);
|
||
ScanEvent?.Invoke(mydate.index, mydate.mat, _scannerCardIndex);
|
||
WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, $"相机({_scannerCardIndex})图像({mydate.index})回调完成.", null, null);
|
||
}
|
||
else
|
||
{
|
||
Thread.Sleep(10);
|
||
}
|
||
}
|
||
}
|
||
public CamerCardDevIK( )
|
||
{
|
||
m_nType = 1;
|
||
}
|
||
public override bool open(int nBoardIndex,int nDevIndex)
|
||
{
|
||
if (IsInit) return true;
|
||
_scannerCardIndex = nBoardIndex;
|
||
WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, "open ....",null,null);
|
||
try
|
||
{
|
||
closeDevice();
|
||
scanIndex = 0;
|
||
devInfo = new IKDeviceInfo();
|
||
readerThread = new Thread(readDataThread); // 创建读取线程
|
||
//
|
||
uint nDevCount = 2;
|
||
uint res = IKapCLib.ItkManGetDeviceCount(ref nDevCount);
|
||
if (res != (uint)ItkStatusErrorId.ITKSTATUS_OK)
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "ItkManGetDeviceCount failed");
|
||
return false;
|
||
}
|
||
|
||
IKapCLib.ITKDEV_INFO pDevInfo = new IKapCLib.ITKDEV_INFO();
|
||
IKapCLib.ITK_CL_DEV_INFO pClDevInfo = new IKapCLib.ITK_CL_DEV_INFO();
|
||
for (uint i = 0; i < nDevCount; ++i)
|
||
{
|
||
IKapCLib.ItkManGetDeviceInfo(i, ref pDevInfo);
|
||
if (pDevInfo.DeviceClass.CompareTo("CameraLink") == 0)
|
||
{
|
||
res = IKapCLib.ItkManGetCLDeviceInfo(i, ref pClDevInfo);
|
||
//if (res != (uint)ItkStatusErrorId.ITKSTATUS_OK)
|
||
// return;
|
||
if ((int)pClDevInfo.BoardIndex == nBoardIndex)
|
||
{
|
||
devInfo.nType = IKDeviceType.DEVICE_CML;
|
||
devInfo.nDevIndex = (int)i;
|
||
devInfo.nBoardIndex = (int)pClDevInfo.BoardIndex;
|
||
devInfo.sDevName = pDevInfo.FullName;
|
||
}
|
||
}
|
||
}
|
||
if(devInfo.nType != IKDeviceType.DEVICE_CML)
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "对应索引相机不存在 failed");
|
||
return false;
|
||
}
|
||
//
|
||
res = IKapCLib.ItkDevOpen((uint)devInfo.nDevIndex
|
||
, (int)(ItkDeviceAccessMode.ITKDEV_VAL_ACCESS_MODE_CONTROL)
|
||
, ref m_pDev);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Camera error:Open camera failed");
|
||
return false;
|
||
}
|
||
|
||
//打开采集卡
|
||
m_pBoard = IKapBoard.IKapOpen((uint)BoardType.IKBoardPCIE, (uint)devInfo.nBoardIndex);
|
||
if (m_pBoard == new IntPtr(-1))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "IKapOpen failed");
|
||
return false;
|
||
}
|
||
|
||
IsInit = true;
|
||
readerThread.Start();
|
||
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;
|
||
// 清除回调函数。
|
||
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;
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, "start ....");
|
||
// 导入配置文件。
|
||
string configFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\" + (_scannerCardIndex==0?Config.Carmer1ConfigFilePath: Config.Carmer2ConfigFilePath);
|
||
if (!File.Exists(configFileName))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Fail to get configuration, using default setting!");
|
||
return false;
|
||
}
|
||
var b=loadConfiguration(configFileName);
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, "开始采集 ..."+b.ToString());
|
||
|
||
this.previewHwnd= preview_Hwnd;
|
||
this.bmpSavePath = bmp_save_path;
|
||
//开始采集
|
||
//第二个参数 nFrameCount 表示希望 IKapBoardClassLibrary 采集的帧数。
|
||
//如果 nFrameCount = 1,IKapBoardClassLibrary 会从相机中采集一帧图像;
|
||
//如果 nFrameCount = N 且 N> 1,则 IKapBoardClassLibrary 从相机中采集连续的 N 帧图 像;
|
||
//如果 nFrameCount = 0,则 IKapBoardClassLibrary 开始连续采集图像。
|
||
|
||
int ret;
|
||
// 设置抓取模式,IKP_GRAB_NON_BLOCK为非阻塞模式
|
||
//int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK;
|
||
//ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode);
|
||
//if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
// return false;
|
||
|
||
//// 设置帧传输模式,IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT为同步保存模式
|
||
//int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT;
|
||
//ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode);
|
||
//if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
// return false;
|
||
|
||
//设置缓冲区格式
|
||
ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_COUNT, 1);//
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
// 设置帧超时时间
|
||
int timeout = -1;
|
||
ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_TIME_OUT, timeout);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
// 设置采集模式。
|
||
//
|
||
// Set grab mode.
|
||
int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK;
|
||
ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
// 设置传输模式。
|
||
int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT;
|
||
ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
// 注册回调函数
|
||
IntPtr hPtr = new IntPtr(-1);
|
||
OnGrabStartProc = new IKapCallBackProc(OnGrabStartFunc);
|
||
ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStart, Marshal.GetFunctionPointerForDelegate(OnGrabStartProc), hPtr);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
OnFrameReadyProc = new IKapCallBackProc(OnFrameReadyFunc);
|
||
ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameReady, Marshal.GetFunctionPointerForDelegate(OnFrameReadyProc), hPtr);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
OnFrameLostProc = new IKapCallBackProc(OnFrameLostFunc);
|
||
ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameLost, Marshal.GetFunctionPointerForDelegate(OnFrameLostProc), hPtr);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
OnTimeoutProc = new IKapCallBackProc(OnTimeoutFunc);
|
||
ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_TimeOut, Marshal.GetFunctionPointerForDelegate(OnTimeoutProc), hPtr);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
OnGrabStopProc = new IKapCallBackProc(OnGrabStopFunc);
|
||
ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStop, Marshal.GetFunctionPointerForDelegate(OnGrabStopProc), hPtr);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
m_bUpdateImage = false;
|
||
m_nCurFrameIndex = 0;
|
||
ret = IKapBoard.IKapStartGrab(m_pBoard, 0);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
|
||
//createBuffer
|
||
b = createBuffer();
|
||
if (!b)
|
||
return false;
|
||
|
||
getParam();
|
||
|
||
//
|
||
m_bGrabingImage = true;
|
||
return true;
|
||
}
|
||
/// <summary>
|
||
/// 停止采集
|
||
/// </summary>
|
||
public override void stop()
|
||
{
|
||
if (!IsInit) return;
|
||
|
||
try
|
||
{
|
||
// 停止图像采集。
|
||
var ret = IKapBoard.IKapStopGrab(m_pBoard);
|
||
clearBuffer();
|
||
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;
|
||
|
||
string result;
|
||
result = getFeatureValue("ExposureTime");
|
||
if (!string.IsNullOrEmpty(result))
|
||
ExposureTime = Convert.ToSingle(result);
|
||
|
||
result = getFeatureValue("Gain");
|
||
if (!string.IsNullOrEmpty(result))
|
||
Gain = Convert.ToSingle(result);
|
||
}
|
||
/// <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;
|
||
//WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, $"ExposureTime: {exposureTime},{ExposureTime}");
|
||
if (exposureTime != ExposureTime && exposureTime != -1)
|
||
{
|
||
if(setFeatureValue("ExposureTime", exposureTime.ToString()))
|
||
change = true;
|
||
}
|
||
//WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, $"Gain: {gain},{Gain}");
|
||
if (gain != Gain && gain != -1)
|
||
{
|
||
if (setFeatureValue("Gain", gain.ToString()))
|
||
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_pBoard, (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_pBoard, (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_pBoard, (uint)CallBackEvents.IKEvent_GrabStart);
|
||
ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameReady);
|
||
ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameLost);
|
||
ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_TimeOut);
|
||
ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStop);
|
||
}
|
||
|
||
/* @brief:关闭设备。
|
||
*
|
||
* @brief:Close device. */
|
||
private void CloseDevice()
|
||
{
|
||
// 关闭采集卡设备。
|
||
//
|
||
// Close frame grabber device.
|
||
if (!m_pBoard.Equals(-1))
|
||
{
|
||
IKapBoard.IKapClose(m_pBoard);
|
||
m_pBoard = (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)
|
||
{
|
||
WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, "图像开始采集...", null, null);
|
||
}
|
||
|
||
/* @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)
|
||
{
|
||
WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.High, $"相机({_scannerCardIndex})采集图像({scanIndex})丢帧(Image frame lost),急停告警,需结束重新开始!!!!", null, null);
|
||
}
|
||
|
||
/* @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)
|
||
{
|
||
WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.High, $"相机({_scannerCardIndex})采集图像({scanIndex})超时(Grab image timeout),请检查采集卡!", null, null);
|
||
}
|
||
|
||
/* @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)
|
||
{
|
||
try
|
||
{
|
||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||
stopwatch.Start();
|
||
int index = ++scanIndex;
|
||
WarningEvent?.BeginInvoke(DateTime.Now, WarningEnum.Normal, $"OnFrameReadyFunc 相机({_scannerCardIndex})一帧图像({index})采集完成,正在加入队列({frameQueue.Count})...", null, null);
|
||
|
||
IntPtr hPtr = new IntPtr(-1);
|
||
// 获取当前帧状态
|
||
var ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_CURRENT_BUFFER_INDEX, ref m_nCurFrameIndex);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return;
|
||
//IKapBoard.IKAPBUFFERSTATUS status = new IKapBoard.IKAPBUFFERSTATUS();
|
||
//IKapBoard.IKapGetBufferStatus(m_pBoard, m_nCurFrameIndex, ref status);
|
||
//var uFull = status.uFull;
|
||
//if (uFull == 1)//指明缓冲区是否为满
|
||
{
|
||
IKapBoard.IKapGetBufferAddress(m_pBoard, m_nCurFrameIndex, ref hPtr);
|
||
//Monitor.Enter(m_mutexImage);
|
||
lock (m_mutexImage)
|
||
{
|
||
CopyMemory(m_pUserBuffer, hPtr, m_nBufferSize);
|
||
m_bUpdateImage = true;
|
||
|
||
var bmp = hBuffer.toBmp(m_pUserBuffer);
|
||
Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
|
||
bmp.Dispose();
|
||
bmp = null;
|
||
//Monitor.Enter(frameQueue);
|
||
lock (frameQueue)
|
||
frameQueue.Enqueue(new MyData(index, mat));
|
||
PhotoNumCacheEvent?.BeginInvoke(frameQueue.Count, null, null);
|
||
}
|
||
}
|
||
//m_nCurFrameIndex++;
|
||
//m_nCurFrameIndex = m_nCurFrameIndex % m_nFrameCount;
|
||
stopwatch.Stop();
|
||
WarningEvent?.BeginInvoke(DateTime.Now, WarningEnum.Normal, $"OnFrameReadyFunc 相机({_scannerCardIndex})一帧图像({index})已加入队列({frameQueue.Count}).缓冲区索引={m_nCurFrameIndex};用时:{stopwatch.ElapsedMilliseconds}ms", null, null);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
WarningEvent?.BeginInvoke(DateTime.Now, WarningEnum.High, $"OnFrameReadyFunc 异常,急停告警,需结束重新开始!!!!{ex.Message}\r\n{ex.StackTrace}", null, null);
|
||
}
|
||
}
|
||
|
||
/* @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;
|
||
}
|
||
/*
|
||
* @brief:设置相机特征值
|
||
* @param [in] featureName:特征名[ExposureTime,Gain]
|
||
* @param [in] featureValue:特征值
|
||
* @return: 是否设置成功
|
||
*/
|
||
private bool setFeatureValue(string featureName, string featureValue)
|
||
{
|
||
IntPtr itkFeature = new IntPtr(-1);
|
||
uint nType = 0;
|
||
uint res = IKapCLib.ItkDevAllocFeature(m_pDev, featureName, ref itkFeature);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"setFeatureValue({featureName},{featureValue}) Camera error:Allocate feature failed");
|
||
return false;
|
||
}
|
||
res = IKapCLib.ItkFeatureGetType(itkFeature, ref nType);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"setFeatureValue({featureName},{featureValue}) Camera error:Get feature type failed");
|
||
return false;
|
||
}
|
||
switch (nType)
|
||
{
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT32:
|
||
res = IKapCLib.ItkFeatureSetInt32(itkFeature, Convert.ToInt32(featureValue));
|
||
break;
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT64:
|
||
res = IKapCLib.ItkFeatureSetInt64(itkFeature, Convert.ToInt64(featureValue));
|
||
break;
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_FLOAT:
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_DOUBLE:
|
||
res = IKapCLib.ItkFeatureSetDouble(itkFeature, Convert.ToDouble(featureValue));
|
||
break;
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_ENUM:
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_STRING:
|
||
res = IKapCLib.ItkFeatureFromString(itkFeature, featureValue);
|
||
break;
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_COMMAND:
|
||
res = IKapCLib.ItkFeatureExecuteCommand(itkFeature);
|
||
break;
|
||
}
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"setFeatureValue({featureName},{featureValue}) Camera error:Set feature failed:" + res);
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
private string getFeatureValue(string featureName)
|
||
{
|
||
IntPtr itkFeature = new IntPtr(-1);
|
||
uint nType = 0;
|
||
uint res = IKapCLib.ItkDevAllocFeature(m_pDev, featureName, ref itkFeature);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Allocate feature failed");
|
||
return "";
|
||
}
|
||
res = IKapCLib.ItkFeatureGetType(itkFeature, ref nType);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature type failed");
|
||
return "";
|
||
}
|
||
switch (nType)
|
||
{
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT32:
|
||
int result = 0;
|
||
res = IKapCLib.ItkFeatureGetInt32(itkFeature,ref result);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
|
||
return "";
|
||
}
|
||
return result.ToString();
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT64:
|
||
long resultL = 0;
|
||
res = IKapCLib.ItkFeatureGetInt64(itkFeature, ref resultL);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
|
||
return "";
|
||
}
|
||
return resultL.ToString();
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_FLOAT:
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_DOUBLE:
|
||
double resultD = 0;
|
||
res = IKapCLib.ItkFeatureGetDouble(itkFeature, ref resultD);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
|
||
return "";
|
||
}
|
||
return resultD.ToString();
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_ENUM:
|
||
case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_STRING:
|
||
string results = "";
|
||
res = IKapCLib.ItkFeatureFromString(itkFeature, results);
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
|
||
return "";
|
||
}
|
||
return results;
|
||
}
|
||
if (!Check(res))
|
||
{
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
|
||
return "";
|
||
}
|
||
return "";
|
||
}
|
||
public override double[] getFeatureRangeValue(string featureName)
|
||
{
|
||
switch (featureName)
|
||
{
|
||
case "ExposureTime":
|
||
//return new double[2] {3.2,63997};
|
||
return new double[2] { 10, 200 };
|
||
case "Gain":
|
||
return new double[2] { 0.01, 8.00 };
|
||
default: return new double[0] { };
|
||
}
|
||
}
|
||
/*
|
||
*@brief:检查错误码
|
||
*@param [in] err:错误码
|
||
*@return:是否错误
|
||
*/
|
||
private static bool Check(uint err)
|
||
{
|
||
if (err != (uint)ItkStatusErrorId.ITKSTATUS_OK)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine("Error code: {0}.\n", err.ToString("x8"));
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
//----
|
||
private bool isOpen()
|
||
{
|
||
return m_pDev != new IntPtr(-1) && m_pBoard != new IntPtr(-1);
|
||
}
|
||
|
||
private bool closeDevice()
|
||
{
|
||
frameQueue.Clear();
|
||
if (isOpen())
|
||
{
|
||
IKapBoard.IKapClose(m_pBoard);
|
||
IKapCLib.ItkDevClose(m_pDev);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
private bool loadConfiguration(string sFilePath)
|
||
{
|
||
int ret = IKapBoard.IKapLoadConfigurationFromFile(m_pBoard, sFilePath);
|
||
return ret == (int)ErrorCode.IK_RTN_OK;
|
||
}
|
||
|
||
private bool createBuffer()
|
||
{
|
||
int ret = (int)ErrorCode.IK_RTN_OK;
|
||
int nImageType = 0;
|
||
ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_IMAGE_WIDTH, ref m_nWidth);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_IMAGE_HEIGHT, ref m_nHeight);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_IMAGE_TYPE, ref nImageType);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_DATA_FORMAT, ref m_nDepth);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_SIZE, ref m_nBufferSize);
|
||
if (ret != (int)ErrorCode.IK_RTN_OK)
|
||
return false;
|
||
switch (nImageType)
|
||
{
|
||
case 0:
|
||
m_nChannels = 1;
|
||
break;
|
||
case 1:
|
||
case 3:
|
||
m_nChannels = 3;
|
||
break;
|
||
case 2:
|
||
case 4:
|
||
m_nChannels = 4;
|
||
break;
|
||
}
|
||
WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, $"图片类型:{nImageType},通道数:{m_nChannels},size:{m_nWidth}*{m_nHeight}");
|
||
m_pUserBuffer = Marshal.AllocHGlobal(m_nBufferSize);
|
||
|
||
//
|
||
hBuffer = new BufferToImage(m_nBufferSize , m_nDepth, m_nChannels , m_nWidth, m_nHeight);
|
||
|
||
return true;
|
||
}
|
||
|
||
private void clearBuffer()
|
||
{
|
||
if (m_pUserBuffer == new IntPtr(-1))
|
||
return;
|
||
Marshal.FreeHGlobal(m_pUserBuffer);
|
||
m_pUserBuffer = new IntPtr(-1);
|
||
}
|
||
}
|
||
}
|