源代码来自Halcon/IACallback (C#)。IA=Image Acquisition。
想调试Halcon的图像采集部分,就拿了3个AVT Stringray F-201B的相机来测试,发现回调函数部分不支持,所以程序没有完全调通。
整个程序按照这样逻辑来的:Show Available Device -> init device -> Start Acquire Thread-> Show available Callback Types -> Register Callback Type -> Grab Image Start -> Exit Program.
1)ShowAvailableDevice:
显示halcon所支持的图像采集设备的数量,并返回设备数量。如取得采集卡(准确的说应该是相机)的信息,使用
//HOperatorSet.InfoFramegrabber(cInterface, "device", out hv_Information, out hv_BoardList); HOperatorSet.InfoFramegrabber("GenICamTL", "info_boards", out hv_Information, out hv_BoardList);
源代码中cInterface="GigEVision",相机F-201B并不支持,后来我改为"GenICamTL"就可以了;语句
hv_BoardList.TupleSelect(i).S
取i=0,得到以下相机的信息(前面的"1)"是额外添加的):
1) | device:DEV_0xA4701130A5F3B | unique_name:DEV_0xA4701130A5F3B | interface:V imba1394Interface_0x0 | producer:C:\Program Files\Allied Vision\Vimba_2.1\Vimba1 394TL\Bin\Win64\Vimba1394TL.cti | vendor:AVT | model:Stingray F201B | tl_type:II DC | status:available
2)Init Device:
根据用户的选择打开对应的相机
HOperatorSet.OpenFramegrabber("GenICamTL", 1, 1, 0, 0, 0, 0, "default", -1, "default", -1, "false", "default", gDevices[deviceNumber - 1], -1, -1, out AcqHandle);
第一个参数name还是选择“GenICamTL”,否则还会出现异常。
3)Start Acquire Thread:
使用带参数的线程来异步采集图像
gWorkerThread = new Thread(new ParameterizedThreadStart(DoWork)); gWorkerThread.Start(AcqHandle); gThreadRunning = true;
输入的HTuple型的参数AcqHandle代表上面我们选择的相机,布尔型的变量gThreadRunning表示线程是否在运行,主体动作DoWork()完成图像的异步采集。
static void DoWork(object AcqHandle) { HOperatorSet.LockMutex(gAcqMutex); while (true) { HOperatorSet.WaitCondition(gAcqCondition, gAcqMutex); if (!gThreadRunning || gCountCallbacks > cMaxGrabImage) break; Console.WriteLine("Thread specific calculations"); try { HOperatorSet.GrabImageAsync(out gImage, (HTuple)AcqHandle, -1); } catch (HalconException ex) { Console.WriteLine(ex.GetErrorMessage()); } } HOperatorSet.UnlockMutex(gAcqMutex); Console.WriteLine("End acquisition thread\n"); }
由于是等待信号gAcqCondition,所以没有采集的动作。
4)Show Available Callback Types:
读取相机所支持的回调类型
HOperatorSet.GetFramegrabberParam(hAcqHandle, "available_callback_types", out Value);
输出值Value是个数组,通过以下语句打印结果:
Console.WriteLine(i + 1 + ") " + Value.TupleSelect(i).S);
得到F-20B相机所支持的所有回调(共181个,个人认为很多可以看做属性),如:
1) DeviceVendorName 2) DeviceModelName 3) DeviceFirmwareVersion 4) FirmwareVerMajor 5) FirmwareVerMinor 6) FirmwareVerBuild 7) DeviceMicrocontrollerVersion 8) DeviceSFNCVersionMajor 9) DeviceSFNCVersionMinor 10) DeviceSFNCVersionSubMinor 11) DeviceID 12) DeviceSerialNumber ... ... 180) [Stream]StreamAnnounceBufferMinimum 181) [Stream]DriverBuffersCount
5)Register Callback Type:
根据用户选择的Callback Type与程序中规定的callback(如transfer_end,event_queue_overflow,device_lost)对比,如果都不满足,就需要设置参数,包括EventSelector,EventNotification.
接下来判断是否要注册ExposureEnd,transfer_end并完成相应的注册。定义的delegate:
static HalconDotNet.HalconAPI.HFramegrabberCallback delegateCallback = MyCallbackFunction;
完成注册:
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(delegateCallback); ... ... HOperatorSet.SetFramegrabberCallback(AcqHandle, gCallbackTypes[callback_number - 1], ptr, myContext);
myContext是一个整型值(0,1,2)代表用户的选择。尝试强制改变myContext=1或2,使下面的MyCallbackFunction循环能够进去,结果没有如我所愿,程序显示:callback not supported.
我们再回到MyCallbackFunction的定义中:
public static int MyCallbackFunction(IntPtr handle, IntPtr user_context, IntPtr context) { int int_context = context.ToInt32(); if (int_context == (int)myCallbackTypes.EXPOSURE_END || int_context == (int)myCallbackTypes.TRANSFER_END) { HOperatorSet.LockMutex(gAcqMutex); HOperatorSet.SignalCondition(gAcqCondition); gCountCallbacks++; Console.WriteLine("Send signal to the worker thread"); HOperatorSet.UnlockMutex(gAcqMutex); } Console.WriteLine("User specific callback function executed"); return 0; }参数context就是用户的选择,对比选择,然后给采集线程发送信号gAcqCondition就可以开始采集了。
通过对比上一步得到的181个回调类型,发现没有一个与这几个相同,可能是硬件并不支持。
6)Grab Image Start:
为了避免冲突,此处的Grab与线程间的Grab都使用了Halcon中的互斥器Mutex(这不是Windows中的Mutex)
static HMutex gAcqMutex; ... ... gAcqMutex = new HMutex("", ""); ... ... HOperatorSet.LockMutex(gAcqMutex); ... ... HOperatorSet.UnlockMutex(gAcqMutex);
知道用户点击Enter结束采集。
7)Exit Program:
退出程序过程包括:取消注册Callback;给线程发送退出信号;等待线程结束;清除资源。
static void exitProgram(HTuple AcqHandle, bool init_device, bool reg_rallback, int callback_number) { HOperatorSet.LockMutex(gAcqMutex); if (reg_rallback) HOperatorSet.SetFramegrabberCallback(AcqHandle, gCallbackTypes[callback_number - 1], 0, 0); HOperatorSet.UnlockMutex(gAcqMutex); if (init_device) { gThreadRunning = false; HOperatorSet.SignalCondition(gAcqCondition); gWorkerThread.Join(); HOperatorSet.ClearMutex(gAcqMutex); HOperatorSet.ClearCondition(gAcqCondition); HOperatorSet.CloseFramegrabber(AcqHandle); } Environment.Exit(0); }