Astra SDK  v2.1.3
Simple Depth Reader

Time Required: ~10 minutes

到目前为止您已经掌握了 Astra SDK 的一些基本概念,下一步我们利用 Astra SDK 的另外一个功能来从Astra读取深度数据。

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

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

准备工作

  1. 下载并解压最新的 Astra SDK,之前做过则忽略。
  2. 使用你喜欢的IDE,新建一个命令行程序工程并且新建一个叫“main.cpp”的源文件。
  3. 拷贝下面的代码到你的main.cpp文件:
#include <astra/astra.hpp>
// for std::printf
#include <cstdio>
int main(int argc, char** argv)
{
astra::StreamSet streamSet;
astra::StreamReader reader = streamSet.create_reader();
reader.stream<astra::DepthStream>().start();
// Your code will go here
return 0;
}
A Depth Stream
Definition: Depth.hpp:147
Stream Reader class
Definition: StreamReader.hpp:39
Stream Set Class
Definition: StreamSet.hpp:36
astra_status_t terminate()
Terminate the library, destroying all its streams.
Definition: astra_core.hpp:45
astra_status_t initialize()
Initializes the library.
Definition: astra_core.hpp:35
  • Line 7 - 初始化 Astra SDK
  • Line 9 - 构造一个 StreamSet
  • Line 10 - 创建一个 StreamReader
  • Line 12 - 启动一个深度流
  • Line 16 - 关闭 Astra SDK

侦听深度流

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

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

下面是 FrameListener 的使用示例...

  1. 我们需要定义一个listener 类来实现接口 FrameListener。这个类使我们能够访问从Astra摄像头输出的实际数据。 我们将通过 on_frame_ready 函数来得到这些帧。首先将下面的代码拷贝到你的 #includemain 函数之间:
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)
{
A Depth Frame
Definition: Depth.hpp:287
Frame class
Definition: Frame.hpp:32
Frame Listener class
Definition: FrameListener.hpp:31
const int height() const
get height
Definition: Image.hpp:444
const astra_frame_index_t frame_index() const
get frame index
Definition: Image.hpp:465
const int width() const
get width
Definition: Image.hpp:437
const bool is_valid() const
get is vaild
Definition: Image.hpp:430
const TDataType * data() const
get data pointer
Definition: Image.hpp:486
  • Line 10 - 构造函数,其变量表示程序退出之前总共要处理的帧数。
  • Line 14 - is_finished 用于判断是否我们已经处理了足够的帧数,该变量后面会用到。
  • Line 20 - 读取深度数据帧
  • Line 22 - 检查是否获取到有效的帧。
  • Line 24 - 打印深度帧信息到命令行窗口
  • Line 44 - 计算深度帧中心像素的索引
  • Line 47 - 获取中心像素的值
注意
本例中唯一必须的函数是 on_frame_ready 函数。其它函数都是为了配合而存在的。
  1. 定义好了 DepthFrameListener ,接下来我们在 main 函数中构造一个listener并将其添加到上一步创建的 StreamReader 里。
int main(int argc, char** argv)
{
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);
return 0;
}
void add_listener(FrameListener &listener)
add listener
Definition: StreamReader.hpp:87
void remove_listener(FrameListener &listener)
remove listener
Definition: StreamReader.hpp:101
  • Line 73 - 构造一个会循环100次的 DepthFrameListener
  • Line 75 - 将listener添加到reader
  • Line 79 - 将listener从reader移除

更新我们的listener

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

int main(int argc, char** argv)
{
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);
return 0;
}
  • Line 77-79 - The Astra SDK 更新循环。

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