工业相机软触发取图时间测试
测试一下工业相机的软触发到拿到图像的时间
相机:万年不变的0.3MP
使用方法:QueryPerformanceCounter(ref long x);
测试选用海康相机自带回调Demo,曝光时间设置到最小(20us)
using System;
using System.Collections.Generic;
using MvCamCtrl.NET;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
namespace Grab_Callback
{
class Grab_Callback
{
public static long timeStart = 0, timeEnd = 0;//系统计数器
public static long freq;//计数频率
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public extern static short QueryPerformanceCounter(ref long x);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public extern static short QueryPerformanceFrequency(ref long x);
public static MyCamera.cbOutputExdelegate ImageCallback;
public static MyCamera device = new MyCamera();
static void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
{
QueryPerformanceCounter(ref timeEnd);//计时
Console.WriteLine("Get one frame: Width[" + Convert.ToString(pFrameInfo.nWidth) + "] , Height[" + Convert.ToString(pFrameInfo.nHeight)
+ "] , FrameNum[" + Convert.ToString(pFrameInfo.nFrameNum) + "]");
}
static void Main(string[] args)
{
int nRet = MyCamera.MV_OK;
do
{
// ch:枚举设备 | en:Enum device
MyCamera.MV_CC_DEVICE_INFO_LIST stDevList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref stDevList);
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Enum device failed:{0:x8}", nRet);
break;
}
Console.WriteLine("Enum device count : " + Convert.ToString(stDevList.nDeviceNum));
if (0 == stDevList.nDeviceNum)
{
break;
}
MyCamera.MV_CC_DEVICE_INFO stDevInfo; // 通用设备信息
// ch:打印设备信息 en:Print device info
for (Int32 i = 0; i < stDevList.nDeviceNum; i++)
{
stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
if (MyCamera.MV_GIGE_DEVICE == stDevInfo.nTLayerType)
{
MyCamera.MV_GIGE_DEVICE_INFO stGigEDeviceInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);
uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);
uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);
uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff);
Console.WriteLine("\n" + i.ToString() + ": [GigE] User Define Name : " + stGigEDeviceInfo.chUserDefinedName);
Console.WriteLine("device IP :" + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4);
}
else if (MyCamera.MV_USB_DEVICE == stDevInfo.nTLayerType)
{
MyCamera.MV_USB3_DEVICE_INFO stUsb3DeviceInfo = (MyCamera.MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO));
Console.WriteLine("\n" + i.ToString() + ": [U3V] User Define Name : " + stUsb3DeviceInfo.chUserDefinedName);
Console.WriteLine("\n Serial Number : " + stUsb3DeviceInfo.chSerialNumber);
Console.WriteLine("\n Device Number : " + stUsb3DeviceInfo.nDeviceNumber);
}
}
Int32 nDevIndex = 0;
Console.Write("\nPlease input index (0 -- {0:d}) : ", stDevList.nDeviceNum - 1);
try
{
nDevIndex = Convert.ToInt32(Console.ReadLine());
}
catch
{
Console.Write("Invalid Input!\n");
break;
}
if (nDevIndex > stDevList.nDeviceNum - 1 || nDevIndex < 0)
{
Console.Write("Input Error!\n");
break;
}
stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[nDevIndex], typeof(MyCamera.MV_CC_DEVICE_INFO));
// ch:创建设备 | en:Create device
nRet = device.MV_CC_CreateDevice_NET(ref stDevInfo);
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Create device failed:{0:x8}", nRet);
break;
}
// ch:打开设备 | en:Open device
nRet = device.MV_CC_OpenDevice_NET();
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Open device failed:{0:x8}", nRet);
break;
}
// ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
{
int nPacketSize = device.MV_CC_GetOptimalPacketSize_NET();
if (nPacketSize > 0)
{
nRet = device.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
if (nRet != MyCamera.MV_OK)
{
Console.WriteLine("Warning: Set Packet Size failed {0:x8}", nRet);
}
}
else
{
Console.WriteLine("Warning: Get Packet Size failed {0:x8}", nPacketSize);
}
}
// ch:设置触发模式为off || en:set trigger mode as off
nRet = device.MV_CC_SetEnumValue_NET("TriggerMode", 1);
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Set TriggerMode failed!");
break;
}
// ch:设置触发模式为off || en:set trigger mode as off
nRet = device.MV_CC_SetEnumValue_NET("TriggerSource", 7);
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Set TriggerSource failed!");
break;
}
// ch:注册回调函数 | en:Register image callback
ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
nRet = device.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Register image callback failed!");
break;
}
QueryPerformanceFrequency(ref freq);//获取计数频率
// ch:开启抓图 || en: start grab image
nRet = device.MV_CC_StartGrabbing_NET();
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Start grabbing failed:{0:x8}", nRet);
break;
}
QueryPerformanceCounter(ref timeStart);
nRet = device.MV_CC_SetCommandValue_NET("TriggerSoftware");
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Soft trigger failed:{0:x8}", nRet);
break;
}
Thread.Sleep(1000);
Console.WriteLine("cost: " + Convert.ToString((timeEnd - timeStart) / Convert.ToDouble(freq) * 1000) + "ms");
// ch:停止抓图 | en:Stop grabbing
nRet = device.MV_CC_StopGrabbing_NET();
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Stop grabbing failed{0:x8}", nRet);
break;
}
// ch:关闭设备 | en:Close device
nRet = device.MV_CC_CloseDevice_NET();
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Close device failed{0:x8}", nRet);
break;
}
// ch:销毁设备 | en:Destroy device
nRet = device.MV_CC_DestroyDevice_NET();
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Destroy device failed:{0:x8}", nRet);
break;
}
} while (false);
if (MyCamera.MV_OK != nRet)
{
// ch:销毁设备 | en:Destroy device
nRet = device.MV_CC_DestroyDevice_NET();
if (MyCamera.MV_OK != nRet)
{
Console.WriteLine("Destroy device failed:{0:x8}", nRet);
}
}
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
}
}
测试结果:
这个计时函数的精度还是蛮高的,但是软触发出图15ms的耗时以这款相机将近200的帧率来说,还是有些偏长的。
后来了解到,软触发在命令的发送过程中耗时比较长,而且也会受到网络波动影响,看来如果对速度要求高的话,还是得用硬触发。