这两种方式是相机SDK(如MVS)提供的两种不同图像获取机制,其核心区别在于 "谁主动"。
核心区别对比
| 特性 | 回调取图 (Callback) | 轮询取图 (Polling) |
|---|---|---|
| 工作机制 | 事件驱动 。相机采集到一帧图像后,主动调用用户预先注册好的回调函数,将图像数据"推送"给应用程序。 | 查询驱动 。应用程序需要主动、不断地 调用取图函数(如 GetImageBuffer),向相机"索取"是否有新图像。 |
| 程序流程 | 异步、非阻塞。注册回调函数后,主线程可以继续处理其他任务,图像到达时自动处理。 | 同步、阻塞。通常在循环中调用取图函数,如果无新图像,函数会等待(可设置超时)或立即返回,程序流围绕这个循环进行。 |
| 控制权 | 在相机/底层SDK手中。图像就绪时立即触发回调,实时性高。 | 在应用程序手中。由应用程序决定何时去取图,灵活性高。 |
| 资源占用 | CPU占用相对平稳,仅在图像到来时触发处理。 | 如果循环频率很高,可能造成CPU空转,占用率偏高。 |
| 复杂度 | 编程模型稍复杂,需要理解异步回调、上下文管理、线程安全。 | 编程模型简单直观,顺序执行,易于理解和调试。 |
优缺点分析
回调取图 (Callback)
优点:
-
高实时性/低延迟:图像从相机缓冲区到用户处理程序的路径最短,几乎在图像就绪的瞬间就被通知,特别适合对时序要求严苛的应用。
-
高效率:避免了不必要的查询开销,CPU仅在有事可做时被唤醒,系统整体效率高。
-
适合连续流采集:是处理稳定、高速视频流的理想方式,能保持稳定的帧率。
缺点:
-
编程复杂 :需要在回调函数中处理图像,而回调函数通常运行在SDK内部的独立线程中。这带来了线程安全问题(例如,不能直接在回调中更新UI),需要谨慎处理数据共享和同步。
-
流程控制受限:程序执行流程被回调事件打断,对于需要严格顺序控制的复杂状态机,不如轮询直观。
-
调试困难:异步回调导致堆栈信息不连贯,问题定位比线性代码困难。
轮询取图 (Polling)
优点:
-
控制灵活、逻辑简单:所有代码都运行在用户主线程(或单一控制线程)中,程序流程是线性的,易于编写、阅读和调试。你可以完全决定何时取图、是否跳帧、如何与其他设备同步。
-
易于集成:很容易嵌入到现有的主循环、状态机或基于定时器的系统中。
-
资源可控:通过控制轮询频率和超时时间,可以精确控制其对CPU的占用。
缺点:
-
潜在的高延迟:如果轮询间隔过长,图像可能在缓冲区中等待了一段时间才被取出,造成延迟。即使轮询很快,也引入了微小的查询延迟。
-
可能浪费CPU:如果采用非常短的超时或无阻塞的频繁查询,会导致CPU空转,利用率高但做的有效工作少。
-
可能丢帧:在高帧率下,如果应用程序处理图像的速度跟不上相机产生的速度,而轮询又不够及时,缓冲区可能溢出,导致丢帧。
适用场景建议
| 取图模式 | 典型应用场景 |
|---|---|
| 回调取图 | 1. 高速、连续采集 :如高速流水线检测、体育分析、科学研究。 2. 对延迟极其敏感 :如机器人视觉伺服、闭环控制。 3. 需要稳定帧率的视频流应用。 |
| 轮询取图 | 1. 中低速或触发采集 :如按键触发拍照、与PLC信号同步的抓拍。 2. GUI应用程序 :主线程需要负责UI响应,在定时器或后台线程中使用轮询取图,更容易与UI线程安全交互。 3. 多设备协同 :需要根据其他设备(如机械臂、传感器)的状态来决定是否取图。 4. 初学者或快速原型开发:逻辑简单,易于上手和调试。 |
海康SDK中的实践要点
-
回调中的耗时操作 :绝对禁止在回调函数中进行复杂的图像处理或阻塞操作。这会导致SDK内部线程被阻塞,无法及时处理后续图像,极易引起丢帧甚至崩溃。正确的做法是将图像数据快速拷贝到另一个队列或缓冲区,由另一个工作线程进行处理。
-
缓冲区管理 :无论是回调还是轮询,取图后都需要及时将图像缓冲区返还给SDK (调用
ReleaseImageBuffer),否则会导致SDK的内部缓冲区耗尽,无法接收新图像。 -
组合使用:在某些复杂应用中,可以混合使用。例如,用回调确保最高的捕获响应速度,但将图像压入队列后,由主线程轮询这个队列进行处理和显示,以简化UI更新。
总结
-
追求极致性能、低延迟、高吞吐的流式应用,首选回调。 但必须处理好多线程问题。
-
追求开发简便、控制灵活、事件驱动的应用(如触发拍照),或需要与主线程紧密交互,首选轮询。
选择哪种方式,最终取决于你的具体应用需求、帧率、延迟容忍度以及开发团队对多线程编程的熟悉程度。在性能可接受的前提下,轮询因其简单可靠,往往是更稳妥的工业选择;而回调则为高性能应用打开了大门。
代码:
自定义线程函数,创建一个线程,这个线程不会影响UI界面,打开软件,UI界面就是一个线程。 --- UI不能用来做耗时事件。导致UI界面卡住。 --- 点不动(死机)
相机取流,是不是需要一直存在。就应该一直存在,线程死了,会导致取不到图。
开始取流之后,轮询缓冲区了对吧,取到图像 -- UI界面显示,图像处理,需要实现,检测能在这个线程里吗?
--- 缓冲区拿到图像就开始检测,卡住了,不在拿图显示,UI界面会因为不在取图,停止显示。
手动控制不在取拿图,不是退出线程,等待在此点击采集才开始采集。 --- 缓冲区时刻有图像。
他只是一个工具,对于工具来说,需要底层吗。 -- 做自己,怎么用。
双击控件界面会进入其函数功能实现区域。
为什么需要在主对话框中创建一个新的线程,是因为主对话框是UI线程,这个线程是耗时的,如果在UI线程执行,那会导致UI界面卡住。
进程是什么,打开一个软件就是进程。
SDK只是负责拿到图像,不负责任何的图像操作,保存图像,是图像处理。