源代码来自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);
}