2

几个月前,我开始从事一个项目,开发一种算法来处理从线扫描相机设备获取的数据(例如,每 300us 一行 384 像素)。因为我是一名工程师而不是程序员,所以我开始使用 Python 来最小化学习曲线。在 SX 的帮助下,我成功地构建了一个 Python 应用程序(最终代码超过 2000 行),并成功地创建了一个图像处理算法来处理数据。我给客户留下了深刻的印象,他们希望将其提升到一个新的水平。现在,我需要它是实时的……这意味着 C++。我得到了 Koenig 和 Moo 的 Accelerated C++ 并开始阅读。所以,请对我放轻松。我喜欢学习编程,但我没有受过正规培训。我正在尽我所能!

我现在有一个 C++ 原型 GUI(使用 Qt),它包含通过 CameraLink 接口与相机通信所需的所有库。采集代码位于其自己的线程中并向 GUI 发出信号。所以,我的基础已经到位。我可以使用我当前的代码获取尽可能多的数据行,但我现在正试图弄清楚如何围绕它构建一个应用程序。甚至编写了一个与 Qt(MOCing 等)一起使用的自定义 makefile

无论如何,对于应用程序,我想要两种模式(这些是问题):

(1) “实时”视图...其中线扫描数据由 GUI 实时显示。我正在考虑使用循环缓冲区(例如,Boost::circular_buffer)来实时保存数据,并通过发出的信号将缓冲区的副本(memcpy?)简单地传递给 GUI。这站得住脚吗?我觉得缓冲区的副本是必要的,因为循环缓冲区将每 300us 左右更改一次,我不知道主事件循环能否跟上。同样,数据采集存在于自己的线程中。它必须比这更复杂吗?我是否必须在读取缓冲区时从缓冲区中弹出数据而不是使用循环缓冲区?我觉得循环缓冲区是要走的路,因为这正是我想要显示的那种图像。

(2) 数据处理模式...其中行扫描数据以块(即 384 x 384)像素的形式发出。以 300us (~3,333 Hz) 的扫描速率,即每 100ms 左右一个块或帧。在这 100 毫秒内,我需要对数据进行规范化、对象检测、阈值处理等。我计划在运行实时内核补丁的 Linux 机器上运行它。我觉得应该跟上。我需要在数据采集和数据处理线程之间进行通信……我需要套接字吗?

我在这里寻找有关如何开始使用这两个部分的建议。第二个更关键,但第一个将帮助我想象正在发生的事情。最终,我希望两种模式同时运行。我花了一周的大部分时间才走到这一步……但需要确保我的计划走在正确的道路上。

4

1 回答 1

2

至(1):

我感觉合理。从 GUI 代码和接收器代码访问相同的缓冲区时,您必须小心同步问题。一种可能的改进是稍微限制 GUI 更新的数量。屏幕刷新率通常为 50 或 60Hz,大多数 GUI 库都假设更新不会比这更频繁。

您还可以通过复制屏幕上实际显示的内容来减少复制的数据量。所以我建议可能稍微颠倒一下:GUI 获得一个更新计时器(看起来对您的目的来说足够好),它根据需要从循环缓冲区中提取新的显示内容。这样,您就可以减少许多不必要的(即不可见的)屏幕更新和缓冲区副本。

根据您的需要,您也可以只使用为问题的第 2 部分创建的块进行屏幕更新。

To (2):首先,当您使用多线程时,通常不需要套接字或类似的东西。

我建议您使用线程池之类的东西进行处理:当新块可用时,将它们复制到任务对象(您定义的具有处理代码并实现线程池理解的接口的类)并将其提供给线程池。

由于您使用的是 Qt,因此我将在这部分查看 QThreadPool 和 QRunnable。如果您需要以特定顺序完成处理块,事情会变得更有趣。基本上,您将拥有一个阻塞队列数据结构,您还将使用 QRunnable 对象提供该数据结构,然后另一个线程将它们从那里抓取并等待每个线程按照它们开始的顺序完成。

这里的通信将仅限于数据采集线程将输入切割成块并启动任务。如果您还需要从数据处理任务中控制数据采集线程,您可能需要一些不同的设计。

您也可能在不使用实时内核补丁的情况下侥幸逃脱。如果您用来访问线扫描相机的库缓冲了它的输入,那么如果您错过更新,您只会一个接一个地获得多行。同样,这取决于您需要多快做出反应,但是您正在对多行高的块进行图像处理,所以我希望您已经可以处理一些延迟。

ETA:我刚刚重新阅读了你的问题。所以你基本上每 100 毫秒只有 384x384 像素的块。我正要建议使用 Qt 信号,但您可能会遇到问题:Qt 信号在线程之间通信时在内部使用阻塞队列数据结构。不幸的是,它们的实现不允许您设置大小限制,因此如果您的 GUI 线程或处理线程不能足够快地处理它们(例如用户在 GUI 的模式对话框中),它们将被缓冲并耗尽内存。

相反,你可以使用这样的东西:

Acquisition thread ==> (Blocking Queue) ==> Processing thread

基本上,您的采集线程只会将块泵入队列。处理线程会循环从队列中抓取块并将它们发送到 GUI 进行显示,然后处理它们。或者如果您想要可视化,则反过来。

于 2013-09-21T19:36:34.500 回答