上次已透過「【3D感測器】Intel RealSense™ SDK無痛安裝指引」[1] 一文幫大家說明如何安裝,這次就幫大家說明如何從RealSense SDK擷取彩色、深度及紅外線串流影像並導入OpenCV中,方便後續開發自己的人機介面及相關計算功能。
Fig.1 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存取其產生的彩色、深度及紅外線串流影像進而產生客製化介面或更複雜應用,相信本文一定可以幫到大家。
參考文獻:
[1] 【3D感測器】Intel RealSense™ SDK無痛安裝指引
https://omnixri.blogspot.com/2019/10/3dintel-realsense-sdk.html
請問realsense d系列可以在昏暗房間使用? 主要取深度影像
回覆刪除可以的,深度影像是靠紅外線取像,就算在完全沒有光線的環境都能正確產出深度影像。但注意被偵測物件不能是透明或絨毛類或會吸光材料,就是拿雷射筆打在表面看不出是光點而是一團霧狀的材質。
刪除