使用 LibRealSense 和 OpenCV 流传输 RGB 和深度数据

目录

简介 

本文将介绍如何使用 LibRealSenseOpenCV 流传输 RGB 和深度数据。 本文假定您已下载、安装 LibRealSense 和 OpenCV,并在 Ubuntu 中对其进行了相应的设置。 在本文中我将基于 Ubuntu 16.04 使用 Eclipse Neon IDE,尽管简单版本可能运行得更好。 只是它正好是创建该示例时所使用的 Eclipse 版本。

在本文中我做出如下假设,即读者:

  1. 熟悉 Eclipse IDE 的用途。 读者应了解如何打开 Eclipse 并创建新的空白 C++ 项目。
  2. 熟悉 C++ 的用途
  3. 知道如何使用 Linux。
  4. 了解 Github 并知道如何从 Github 资源库中下载项目。

本文结束后,大家将知道如何使用该代码库创建自己的 LibRealSense / OpenCV 应用。

规范 

LRS = LibRealSense。 这里我就不再赘述, 非常简单。 因此大家应该对 LRS 一目了然。

软件要求 

支持的摄像头 

  • 英特尔实感 R200

从理论上来说,实感摄像头(R200,F200,SR300)应适用于该代码示例,但仅 R200 通过测试

设置 Eclipse 项目 

如上所述,我假定读者知道如何打开 Eclipse 并创建全新的空白 C++ 项目。

我向大家展示用于创建项目时所使用的各种 C++ 头文件和链接器设置。

头文件内容 

下图所示为我所包含的头文件目录。 如果按照 LRS 安装步骤,应该将 LibRealSense 头文件放在合适的位置。 OpenCV 同样如此

头文件内容

库文件内容 

该图所示为运行时所需的库。 一个 LRS 库和三个 OpenCV 库。 同样我假设您对 LRS 和 OpenCV 进行了相应的设置。

库文件内容

main.cpp 源代码文件内容 

以下是示例应用的源代码。

/////////////////////////////////////////////////////////////////////////////

// License: Apache 2.0. See LICENSE file in root directory.

// Copyright(c) 2016 Intel Corporation. All Rights Reserved.

//

//

//

/////////////////////////////////////////////////////////////////////////////

// Authors
// * Rudy Cazabon
// * Rick Blacker
//
// Dependencies
// * LibRealSense
// * OpenCV
//
/////////////////////////////////////////////////////////////////////////////
// This code sample shows how you can use LibRealSense and OpenCV to display
// both an RGB stream as well as Depth stream into two separate OpenCV
// created windows.
//
/////////////////////////////////////////////////////////////////////////////

#include <librealsense/rs.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace rs;


// Window size and frame rate
int const INPUT_WIDTH      = 320;
int const INPUT_HEIGHT     = 240;
int const FRAMERATE        = 60;

// Named windows
char* const WINDOW_DEPTH = "Depth Image";
char* const WINDOW_RGB     = "RGB Image";


context      _rs_ctx;
device&      _rs_camera = *_rs_ctx.get_device( 0 );
intrinsics   _depth_intrin;
intrinsics  _color_intrin;
bool         _loop = true;


// Initialize the application state. Upon success will return the static app_state vars address

bool initialize_streaming( )
{
       bool success = false;
       if( _rs_ctx.get_device_count( ) > 0 )
       {
             _rs_camera.enable_stream( rs::stream::color, INPUT_WIDTH, INPUT_HEIGHT, rs::format::rgb8, FRAMERATE );
             _rs_camera.enable_stream( rs::stream::depth, INPUT_WIDTH, INPUT_HEIGHT, rs::format::z16, FRAMERATE );
             _rs_camera.start( );

             success = true;
       }
       return success;
}




/////////////////////////////////////////////////////////////////////////////
// If the left mouse button was clicked on either image, stop streaming and close windows.
/////////////////////////////////////////////////////////////////////////////
static void onMouse( int event, int x, int y, int, void* window_name )
{
       if( event == cv::EVENT_LBUTTONDOWN )
       {
             _loop = false;
       }
}


/////////////////////////////////////////////////////////////////////////////
// Create the depth and RGB windows, set their mouse callbacks.
// Required if we want to create a window and have the ability to use it in
// different functions
/////////////////////////////////////////////////////////////////////////////
void setup_windows( )
{
       cv::namedWindow( WINDOW_DEPTH, 0 );
       cv::namedWindow( WINDOW_RGB, 0 );

       cv::setMouseCallback( WINDOW_DEPTH, onMouse, WINDOW_DEPTH );
       cv::setMouseCallback( WINDOW_RGB, onMouse, WINDOW_RGB );
}


/////////////////////////////////////////////////////////////////////////////
// Called every frame gets the data from streams and displays them using OpenCV.
/////////////////////////////////////////////////////////////////////////////
bool display_next_frame( )
{

       _depth_intrin       = _rs_camera.get_stream_intrinsics( rs::stream::depth );
       _color_intrin       = _rs_camera.get_stream_intrinsics( rs::stream::color );
	   

       // Create depth image
       cv::Mat depth16( _depth_intrin.height,
                                  _depth_intrin.width,
                                  CV_16U,
                                  (uchar *)_rs_camera.get_frame_data( rs::stream::depth ) );

       // Create color image
       cv::Mat rgb( _color_intrin.height,
                            _color_intrin.width,
                            CV_8UC3,
                            (uchar *)_rs_camera.get_frame_data( rs::stream::color ) );

       // < 800
       cv::Mat depth8u = depth16;
       depth8u.convertTo( depth8u, CV_8UC1, 255.0/1000 );

       imshow( WINDOW_DEPTH, depth8u );
       cvWaitKey( 1 );

       cv::cvtColor( rgb, rgb, cv::COLOR_BGR2RGB );
       imshow( WINDOW_RGB, rgb );
       cvWaitKey( 1 );

       return true;
}

/////////////////////////////////////////////////////////////////////////////
// Main function
/////////////////////////////////////////////////////////////////////////////
int main( ) try
{
       rs::log_to_console( rs::log_severity::warn );

       if( !initialize_streaming( ) )
       {
             std::cout << "Unable to locate a camera" << std::endl;
             rs::log_to_console( rs::log_severity::fatal );
             return EXIT_FAILURE;
       }

       setup_windows( );

       // Loop until someone left clicks on either of the images in either window.
       while( _loop )
       {
             if( _rs_camera.is_streaming( ) )
                    _rs_camera.wait_for_frames( );

             display_next_frame( );
       }


       _rs_camera.stop( );
       cv::destroyAllWindows( );
	   

       return EXIT_SUCCESS;

}
catch( const rs::error & e )
{
       std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n    " << e.what() << std::endl;
       return EXIT_FAILURE;
}
catch( const std::exception & e )
{
       std::cerr << e.what() << std::endl;
       return EXIT_FAILURE;
}

源代码解释 

概述 

结构非常简单。 它是一种源代码文件,包含我们运行该示例时所需的一切。 头文件包含在顶部。 因为它是示例应用,所以我们在设计防御型软件时无需太担心“最佳实践”。 是的,我们能够更好地检查错误,但这里我们旨在尽量简化该示例应用,以便更好地阅读和理解。

常量 

大家看,我们这里有许多关于宽度、高度和帧速率的常量值。 这些基本值用于指定我们希望流传输的图像大小、显示流数据的窗口大小,以及帧速率。 然后我们有两个字符串常量, 用于命名 OpenCV 窗口。

全局变量 

尽管我不是很喜欢全局变量,但在此类流传输应用中,我不介意违反一些规则。 而且,尽管此示例应用中的简单流传输不是资源密集型过程,但应用中的其他流程可能属于资源密集型。 因此,如果现在能够提升性能,之后将会提供诸多优势。

  • _ctx 用于返回设备(摄像头)。 请注意,我们此处正在进行硬编码,从而获取第一台设备。 检测设备的方法有许多,不过这超出了本文的叙述范围。
  • _rs_camera 表示我们开始流传输的实感设备(摄像头)。
  • _dept_intrin 表示包含当前深度帧信息的 LRS 内联对象。 本案例中我们最感兴趣的是图像大小。
  • _dept_intrin 表示包含当前色帧信息的 LRS 内联对象。 本案例中我们最感兴趣的是图像大小。
  • _loop 仅用于知道何时停止图像处理。 一开始设为真值,当用户在 OpenCV 窗口中点击图像时设为假值。

我想说明,此处我们并不是很需要 _dept_intrin 和 _color_intrin。 它们不是任何计算的积, 仅用于收集 display_next_frame( ) 函数的内联数据,从而在创建 OpenCV Mat 对象时支持轻松读取该数据。 它们具备全局性,因此无需每帧都创建这两个变量。

函数 

main(…)

顾名思义,它属于主函数。 我们不需要任何命令行参数,因此选择不包含任何参数。 首先展示如何使用 LRS 登录控制台。 此处我们要求 LRS 打印向控制台发出的所有告警。 接下来调用 initialize_app_state(),以初始化帮助程序结构 _app_state。 如果出现错误,将其打印出来并退出。 之后调用 setup_windows()。 此时一切均已设置,所以我们可以开始流传输了。 该操作在 while 循环中完成。 尽管 _loop 为真值,但我们还是要查看摄像头是否正在流传输,如果是,等待帧。 我们调用 get_next_frame 获取摄像头的下一帧,并将其填充在 global _app_state 变量中,然后显示它。

如果 _loop 设为假值,我们中止 while 循环、停止摄像头,并告诉 OpenCV 关闭所有窗口。 此时应用将会退出。

initialize_streaming(…)

我们在此对摄像头进行初步设置,以支持流传输。 我们将有两个数据流,一个为深度数据流,一个为色彩数据流。 图像大小将由常量指定。 还必须指定数据流格式和帧速率。 为将来能够实现扩展,最好在此处添加某种错误检查/处理。 不过为了保持简便,我们选择尽量避免花哨。 假定为愉快路径。

setup_windows(…)

此函数非常容易理解。 我们让 OpenCV 创建两个新命名的窗口。 在名字中使用字符串常量 WINDOW_DEPTH 和 WINDOW_RGB。 创建完成后,我们关联鼠标回调函数“onMouse”。

onMouse(…)

只要用户在窗体上点击,即可触发 onMouse, 具体来说就是显示图像的地方。 我们使用该函数,就可轻松停止应用。 只需检查该事件是否为左按钮点击,如果是,将 Boolean flag _loop 设为假值。 这样将促使代码退出主函数中的 while 循环。

display_next_frame(…)

此函数负责在 OpenCV 窗口中显示 LRS 数据。 我们首先获取摄像头的内联数据。 然后创建深度和 rgb OpenCV Mat 对象。 我们指定它们的维度、格式,然后将它们的缓冲区分配至摄像头流数据当前帧。 深度 Mat 对象获取摄像头深度数据,色彩 Mat 对象获取摄像头色彩流。

接下来创建新的 Mat 对象 depth8u。 它可帮助按照 OpenCVs imgshow() 函数(无法显示 16 位深度图像)的要求将范围扩展至 0-255。

转换深度图像后,我们可使用 OpenCV 函数 imgshow 显示该图像。 我们通过 WINDOW_DEPTH 常量告诉它该使用哪个命名窗口,并为其提供深度图像。cvWaitKey(1) 让 OpenCV 暂停一会以便进行其他处理过程,比如按下按键。 完成深度窗口后,现在我们移至 color/rgb 窗口。cvtColor 可将 Mat rgb 对象从 OpenCVs BGR 转换成 RGB 色彩空间。 该步骤完成后,我们可重新显示图像并调用等待键。

总结 

本文向大家展示了我们如何轻松地使用 LibRealSense 开源库流传输实感摄像头的数据,并通过 OpenCV 在窗口中展示该数据。 尽管该示例非常简单,但它非常实用,可帮助您开发基础应用,并使用 OpenCV 在此基础上创建更加复杂的应用。

AnexoTamanho
Arquivo main.cpp4.55 KB
Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.