使用 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 在此基础上创建更加复杂的应用。

ВложениеРазмер
Файл main.cpp4.55 КБ
Для получения подробной информации о возможностях оптимизации компилятора обратитесь к нашему Уведомлению об оптимизации.
Возможность комментирования русскоязычного контента была отключена. Узнать подробнее.