4.2 Simple Depth Reader¶
Time Required: ~10 minutes
完成了Hello World指引想学习更多的知识?到目前为止您已经掌握了 Astra 的一些基本概念,下一步我们利用 Astra 的另外一个功能来从Astra读取深度数据。
看完这个指引,你将熟悉这些方面
FrameListener
类的目的如何定义
FrameListener
用
FrameListener
来处理深度流
准备工作¶
下载并解压最新的 Astra SDK,之前做过则忽略。
使用你喜欢的IDE,新建一个命令行程序工程并且新建一个叫“main.cpp”的源文件。
拷贝下面的代码到你的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 教程,我们通过循环调用 StreamReader
的 get_latest_frame
函数处理了多个数据帧构成的流。这种调用方法非常适合Hello World这种简单应用。但是,如果我们想要访问多个数据流,想要处理多个 StreamSet
,或者在每个 StreamSet
里有多个 StreamReader
,怎么办? 在这几种情况下,采用循环的方式会让问题变得非常复杂。
为了让这种问题变得简单, Astra 提供了一种事件机制。该机制定义并创建了 FrameListener
。 FrameListener
有个成员函数 on_frame_ready
会在特定类型的一帧新数据到来的时候自动被调用。所以,相比于使用 StreamReader
的 get_latest_frame
函数,侦听器(listener)自动并且及时地得到了最新的数据。
下面是 FrameListener
的使用示例...
我们需要定义一个listener 类来实现接口
FrameListener
。这个类使我们能够访问从Astra摄像头输出的实际数据。 我们将通过on_frame_ready
函数来得到这些帧。首先将下面的代码拷贝到你的#include
和main
函数之间:
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
函数。其它函数都是为了配合而存在的。
定义好了
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
运行起来了,而且我们还通过 StreamSet
的 StreamReader
来侦听了数据帧。但我们不知道数据帧什么时候会从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 去实现你的各种创意吧!