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; } } }