【3D感測器】如何擷取Intel RealSense™串流影像到OpenCV

作者:許哲豪 Jack

上次已透過「【3D感測器】Intel RealSense™ SDK無痛安裝指引」一文幫大家說明如何安裝,這次就幫大家說明如何從RealSense SDK擷取彩色、深度及紅外線串流影像並導入OpenCV中,方便後續開發自己的人機介面及相關計算功能。

Intel RealSense串流影像導入OpenCV Mat示意圖 (OmniXRI整理繪製)

我想大部份的人想開發一個3D的人機介面可以自由平移、縮放及旋轉視角是有點(大誤!是非常)困難的,所以RealSense SDK提供使用者輕易切換2D(平面)及3D(立體、深度)顯示及操作的介面。這項功能是基於通用3D繪圖引擎OpenGL達成的,雖然很方便操作,但於習慣自己用Visual Studio、QT及其它GUI工具開發人機介面程式的人反而有點不太方便,尤其是重度OpenCV使用者無法透過常用的VideoCapture函式直接取得RealSense各攝影機的串流影像,更是造成一些小困擾。

目前官方SDK範例程式”C:\Program Files (x86)\Intel RealSense SDK 2.0\samples\im-show\rs-imshow.cpp”可以讀取彩像影像和著虛擬色後的深度影像並傳至OpenCV Mat中再透過imshow函式進行顯示,但無法讀取紅外線影像。經過一番查找後,終於找到如何設定,首先建構一組接收管道(pipeline),再設定欲接收的串流影像類型及細部配置參數(config),接著就可以啟動(start)串流影像接收管道,最後把接收到的影格(frame)轉換成OpenCV Mat格式,就可透過imshow顯示或作其它處理使用。

這裡要注意的是,由於RealSense D435可以提供不同格式的影像(8bit, 16bit),而OpenCV只能顯示8bit,所以如遇到要顯示或運算16bit影像時要記得利用像convertScaleAbs之類的函式將16bit轉回8bit,才能正常處理。另外如果想轉存這些串流影像,則使用OpenCV VideoCapture及 VideoWriter函式處理即可。完整的範例如下所示,相關說明已於程式上註解,就不多贅述。

#include  // 引入RealSense標頭檔
#include    // 引入OpenCV標頭檔

using namespace std; // 使用std標準函式命名空間
using namespace cv;  // 使用OpenCV函式命名空間

// 主程式入口
int main(int argc, char * argv[]) try
{
  // 建構一個RealSense抽象設備的管道以容納擷取到的影像
  rs2::pipeline pipe;

  // 創建自定義參數以配置管道
  rs2::config cfg;

  // 設定影像尺寸(寬w,高h)
  const int w = 640;
  const int h = 480;

  // 設定欲顯示的影像流(可依需求啟動不一定要全設)
  cfg.enable_stream(RS2_STREAM_COLOR, w, h, RS2_FORMAT_BGR8, 30); // BGR888格式彩色影像 30fps
  cfg.enable_stream(RS2_STREAM_DEPTH, w, h, RS2_FORMAT_Z16, 30); // 16 bit格式灰階深度影像 30fps
  cfg.enable_stream(RS2_STREAM_INFRARED, 1, w, h, RS2_FORMAT_Y8, 30); // 8 bit格式左紅外線影像 30fps
  cfg.enable_stream(RS2_STREAM_INFRARED, 2, w, h, RS2_FORMAT_Y8, 30); // 8 bit格式右紅外線影像 30fps

  // 根據設定值啟動指定串流影像
  pipe.start(cfg);

  // 宣告深度(灰階)影像著虛擬色彩對應表
  rs2::colorizer color_map;

  while (waitKey(1) < 0) // 若有按鍵則結束顯示串流影像
  {
    // 等待下一組影像	
    rs2::frameset frames = pipe.wait_for_frames();

    // 取得每一張影像(可依需求不一定要全取)
    rs2::frame color_frame = frames.get_color_frame(); // 彩色影像
    rs2::frame depth_frame = frames.get_depth_frame().apply_filter(color_map); // 著虛擬色彩之深度影像
    rs2::frame irL_frame = frames.get_infrared_frame(1); // 左紅外線灰階影像
    rs2::frame irR_frame = frames.get_infrared_frame(2); // 右紅外線灰階影像
		
    // 建立OpenCV Mat格式之影像(可依需求不一定要全建立)
    Mat color_image(Size(w, h), CV_8UC3, (void*)color_frame.get_data(), Mat::AUTO_STEP); // 彩色影像
    Mat depth_image(Size(w, h), CV_8UC3, (void*)depth_frame.get_data(), Mat::AUTO_STEP); // 著虛擬色彩之深度影像
    Mat irL_image(Size(w, h), CV_8UC1, (void*)irL_frame.get_data(), Mat::AUTO_STEP); // 左紅外線灰階影像
    Mat irR_image(Size(w, h), CV_8UC1, (void*)irR_frame.get_data(), Mat::AUTO_STEP); // 右紅外線灰階影像		

    // 以OpenCV函式顯示擷取到影像(可依需求不一定要全顯示)
    imshow("Color Image", color_image); // 彩色影像
    imshow("Depth Image", depth_image); // 著虛擬色彩之深度影像
    imshow("Left IR Image", irL_image); // 左紅外線灰階影像
    imshow("Right IR Image", irR_image); // 右紅外線灰階影像
  }

  return EXIT_SUCCESS;
}
catch (const rs2::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;
}

小結

Intel RealSense SDK提供了很方便的2D/3D操作介面,但如果想透過OpenCV存取其產生的彩色、深度及紅外線串流影像進而產生客製化介面或更複雜應用,相信本文一定可以幫到大家。

參考文獻

【3D感測器】Intel RealSense™ SDK無痛安裝指引

(本文轉載自歐尼克斯實境互動工作室原文連結;責任編輯:林亮潔)
許 哲豪

Author: 許 哲豪

工作經驗超過二十年,主要專長機電整合、電腦視覺、人機互動、人工智慧、專利分析及新創輔導。曾任機電整合工程師、機器視覺研發副理、技轉中心商業發展經理。目前擔任多家公司兼任技術顧問並積極推廣實境互動相關技術。 主持歐尼克斯實境互動工作室(OmniXRI): http://omnixri.blogspot.com

Share This Post On
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x