4.2 Simple Depth Reader

Time Required: ~10 minutes

完成了Hello World指引想学习更多的知识?到目前为止您已经掌握了 Astra 的一些基本概念,下一步我们利用 Astra 的另外一个功能来从Astra读取深度数据。

看完这个指引,你将熟悉这些方面

  • FrameListener 类的目的
  • 如何定义 FrameListener
  • FrameListener 来处理深度流

准备工作

  1. 下载并解压最新的 Astra SDK,之前做过则忽略。
  2. 使用你喜欢的IDE,新建一个命令行程序工程并且新建一个叫“main.cpp”的源文件。
  3. 拷贝下面的代码到你的main.cpp文件:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <astra/astra.hpp>
// for std::printf
#include <cstdio>

int main(int argc, char** argv)
{
   astra::initialize();

   astra::StreamSet streamSet;
   astra::StreamReader reader = streamSet.create_reader();

   reader.stream<astra::DepthStream>().start();

   // Your code will go here

   astra::terminate();

   return 0;
}
  • Line 7 - 初始化 Astra
  • Line 9 - 构造一个 StreamSet
  • Line 10 - 创建一个 StreamReader
  • Line 12 - 启动一个深度流
  • Line 16 - 关闭 Astra

侦听深度流

在Hello World 教程,我们通过循环调用 StreamReaderget_latest_frame 函数处理了多个数据帧构成的流。这种调用方法非常适合Hello World这种简单应用。但是,如果我们想要访问多个数据流,想要处理多个 StreamSet,或者在每个 StreamSet 里有多个 StreamReader ,怎么办? 在这几种情况下,采用循环的方式会让问题变得非常复杂。

为了让这种问题变得简单, Astra 提供了一种事件机制。该机制定义并创建了 FrameListenerFrameListener 有个成员函数 on_frame_ready 会在特定类型的一帧新数据到来的时候自动被调用。所以,相比于使用 StreamReaderget_latest_frame 函数,侦听器(listener)自动并且及时地得到了最新的数据。

下面是 FrameListener 的使用示例…

  1. 我们需要定义一个listener 类来实现接口 FrameListener。这个类使我们能够访问从Astra摄像头输出的实际数据。 我们将通过 on_frame_ready 函数来得到这些帧。首先将下面的代码拷贝到你的 #includemain 函数之间:
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class DepthFrameListener : public astra::FrameListener
{
public:
   DepthFrameListener(int maxFramesToProcess)
       : maxFramesToProcess_(maxFramesToProcess)
   {}

   bool is_finished() const { return isFinished_; }

private:
   void on_frame_ready(astra::StreamReader& reader,
                       astra::Frame& frame) override
   {
       const astra::DepthFrame depthFrame = frame.get<astra::DepthFrame>();

       if (depthFrame.is_valid())
       {
           print_depth_frame(depthFrame);
           ++framesProcessed_;
       }

       isFinished_ = framesProcessed_ >= maxFramesToProcess_;
   }

   void print_depth_frame(const astra::DepthFrame& depthFrame) const
   {
       const int frameIndex = depthFrame.frame_index();
       const short middleValue = get_middle_value(depthFrame);

       std::printf("Depth frameIndex: %d value: %d \n", frameIndex, middleValue);
   }

   short get_middle_value(const astra::DepthFrame& depthFrame) const
   {
       const int width = depthFrame.width();
       const int height = depthFrame.height();

       const size_t middleIndex = ((width * (height / 2.f)) + (width / 2.f));

       const short* frameData = depthFrame.data();
       const short middleValue = frameData[middleIndex];

       return middleValue;
   }

   bool isFinished_{false};
   int framesProcessed_{0};
   int maxFramesToProcess_{0};
};

int main(int argc, char** argv)
{
  • Line 10 - 构造函数,其变量表示程序退出之前总共要处理的帧数。
  • Line 14 - is_finished 用于判断是否我们已经处理了足够的帧数,该变量后面会用到。
  • Line 20 - 读取深度数据帧
  • Line 22 - 检查是否获取到有效的帧。
  • Line 24 - 打印深度帧信息到命令行窗口
  • Line 44 - 计算深度帧中心像素的索引
  • Line 47 - 获取中心像素的值

注解

本例中唯一必须的函数是 on_frame_ready 函数。其它函数都是为了配合而存在的。

  1. 定义好了 DepthFrameListener ,接下来我们在 main 函数中构造一个listener并将其添加到上一步创建的 StreamReader 里。
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
int main(int argc, char** argv)
{
   astra::initialize();

   astra::StreamSet streamSet;
   astra::StreamReader reader = streamSet.create_reader();

   reader.stream<astra::DepthStream>().start();

   int maxFramesToProcess = 100;
   DepthFrameListener listener(maxFramesToProcess);

   reader.add_listener(listener);

   // More of your code will go here

   reader.remove_listener(listener);

   astra::terminate();

   return 0;
}
  • Line 73 - 构造一个会循环100次的 DepthFrameListener
  • Line 75 - 将listener添加到reader
  • Line 79 - 将listener从reader移除

更新我们的listener

我们已经将 Astra 和 StreamSet 运行起来了,而且我们还通过 StreamSetStreamReader 来侦听了数据帧。但我们不知道数据帧什么时候会从Astra里面输出,所以我们需要在一个循环里反复调用 astra_update 去持续更新这些listener。

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
int main(int argc, char** argv)
{
   astra::initialize();

   astra::StreamSet streamSet;
   astra::StreamReader reader = streamSet.create_reader();

   reader.stream<astra::DepthStream>().start();

   const int maxFramesToProcess = 100;
   DepthFrameListener listener(maxFramesToProcess);

   reader.add_listener(listener);

   do {
      astra_update();
   } while (!listener.is_finished());

   reader.remove_listener(listener);

   astra::terminate();

   return 0;
}
  • Line 77-79 - Astra 更新循环。

我们现在编译并运行工程。当你观察完命令行窗口打印的一些深度帧信息后,你会发现你已经掌握了 Astra 的事件机制使用方法。现在,让我们更进一步,发挥你的想象,用 Astra 去实现你的各种创意吧!