IntelRealSense 深度相机 测量物体的实际长度 —— rs-measure 官网文档翻译
總覽
本教程顯示了使用深度數據測量真實世界距離的簡單方法。
## Note: 測量真實世界中物體的維度是深度相機的一個明顯的應用之一。此樣本不是適當的測量工具,而是展示關鍵概念。使用更好的算法可以顯著改善測量結果。在這個教程中你將會學到怎樣:
- 在空間上將顏色流與深度對齊(和在rs-align中深度到顏色的對齊相反)
- 利用后處理來處理缺失和噪聲的深度數據
- 在2D像素和3D空間中的點之間進行轉換
- 利用多核來并行化數據流
- 使用OpenGL在深度之上疊加顏色
預期輸出
這個例子允許用戶測量物理世界中的兩個點。
代碼總覽
深度處理流程
我們通過定義所有的處理塊來開始這個例子。我們將要使用
// Colorizer is used to visualize depth data // Colorizer 用于可視化深度數據 rs2::colorizer color_map; // Use black to white color map // 使用黑色到白色顏色映射 color_map.set_option(RS2_OPTION_COLOR_SCHEME, 2.f); // Decimation filter reduces the amount of data (while preserving best samples) // 抽取濾波器減小數據的數量(同時保持最佳樣本) rs2::decimation_filter dec; // If the demo is too slow, make sure you run in Release (-DCMAKE_BUILD_TYPE=Release) // but you can also increase the following parameter to decimate depth more (reducing quality) // 如果這個demo太慢,確保你在release中運行(-DCMAKE_BUILD_TYPE=Release) // 但是你可以同樣增加下面的參數來更多的減少深度(降低質量) dec.set_option(RS2_OPTION_FILTER_MAGNITUDE, 2); // Define transformations from and to Disparity domain // 定義從和到時差域的轉換 rs2::disparity_transform depth2disparity; rs2::disparity_transform disparity2depth(false); // Define spatial filter (edge-preserving) // 定于空間過濾器(保留邊) rs2::spatial_filter spat; // Enable hole-filling // Hole filling is an aggressive heuristic and it gets the depth wrong many times // However, this demo is not built to handle holes // (the shortest-path will always prefer to "cut" through the holes since they have zero 3D distance) // 開啟填孔 // 填孔是一個積極的啟發性策略,它多次錯誤地獲得深度 // 然而,這個demo不是用于處理填孔的 // (最短的路徑總是喜歡切穿這些孔,因為它們的3D距離為零。) spat.set_option(RS2_OPTION_HOLES_FILL, 5); // 5 = fill all the zero pixels 5 = 填充所有的零像素 // Define temporal filter // 定義時間過濾器 rs2::temporal_filter temp; // Spatially align all streams to depth viewport // We do this because: // a. Usually depth has wider FOV, and we only really need depth for this demo // b. We don't want to introduce new holes // 將所有流在空間上對齊到深度視口 // 我們這樣做是因為: // a. 通常深度有一個更廣的FOV,并且對于這個demo我們只需要深度 // b. 我們不想引入新的洞 rs2::align align_to(RS2_STREAM_DEPTH);下面,我們為深度+顏色流配置相機管道
// Declare RealSense pipeline, encapsulating the actual device and sensors // 定義RealSense管道,封裝真正的設備和傳感器 rs2::pipeline pipe;rs2::config cfg; cfg.enable_stream(RS2_STREAM_DEPTH); // Enable default depth //啟用默認深度 // For the color stream, set format to RGBA // To allow blending of the color frame on top of the depth frame // 對于顏色流,設置格式為RGBA // 允許在深度幀頂部混合顏色幀 cfg.enable_stream(RS2_STREAM_COLOR, RS2_FORMAT_RGBA8); auto profile = pipe.start(cfg);我們的目標是生成沒有任何孔的深度,因為這將會對我們的算法構成直接問題。
減少丟失像素的最好方法是讓硬件來處理。
D400相機具有我們可以利用的高密度預設。
給定一個幀集,我們將按順序應用所有的處理塊。
首先我們應用align處理塊來將顏色幀對其到深度視口:
然后,我們應用深度后處理流:
rs2::frame depth = data.get_depth_frame(); // Decimation will reduce the resultion of the depth image, // closing small holes and speeding-up the algorithm // 抽取將減少深度圖像的結果 // 關閉小孔,并且加速算法 depth = dec.process(depth); // To make sure far-away objects are filtered proportionally // we try to switch to disparity domain // 確保按照比例過濾遠處的物體 // 我們嘗試轉換到視差域 depth = depth2disparity.process(depth); // Apply spatial filtering // 應用空間過濾器 depth = spat.process(depth); // Apply temporal filtering // 應用時間過濾 depth = temp.process(depth); // If we are in disparity domain, switch back to depth // 如果我們在視差域,切回到深度 depth = disparity2depth.process(depth); // Send the post-processed depth for path-finding // 發送后處理深度用于路徑查找 pathfinding_queue.enqueue(depth); 所有基于立體的3D相機都具有噪聲與距離平方成正比的特性。為了抵消這一點,我們將幀轉換為視差域,使噪聲在距離上更均勻。這對我們的結構光相機沒有任何作用(因為他們沒有這個屬性)我們同樣應用標準顏色映射
// Apply color map for visualization of depth // 應用顏色映射來可視化深度 auto colorized = color_map(depth);將像素和3D中的點進行轉換
要將深度圖像中的像素轉換為3D點,我們調用rs2_deproject_pixel_to_point C函數(定義在rsutil.h中)
這個函數需要深度內在函數(depths intrinsics),2D像素和距離(米為單位)。這是我們怎樣得到深度內部函數(depth intrinsics)的:
可以使用depth_frame類的get_distance函數獲取以米為單位的距離。
過度調用get_distance會導致性能不佳,因為編譯器無法跨模塊邊界進行優化,因此,直接從depth_sensor讀取 DEPTH_UNITS選項并使用它將原始深度像素轉換為米可能是有益的:將所有內容放在一起會產生相當冗長的dist_3d函數:
float dist_3d(const rs2_intrinsics& intr, const rs2::depth_frame& frame, pixel u, pixel v) {float upixel[2]; // From pixel //從像素float upoint[3]; // From point (in 3D) //從點(3D中)float vpixel[2]; // To pixel //到像素float vpoint[3]; // To point (in 3D) //到點(3D中)// Copy pixels into the arrays (to match rsutil signatures)// 將像素拷貝到數組中(匹配rsutil簽名)upixel[0] = u.first;upixel[1] = u.second;vpixel[0] = v.first;vpixel[1] = v.second;// Query the frame for distance // Note: this can be optimized// It is not recommended to issue an API call for each pixel// (since the compiler can't inline these)// However, in this example it is not one of the bottlenecks// 查詢幀的距離// 注意:這個可以被優化// 不建議為每個像素發出API調用// (因為編譯器不能內聯這些)// 然而,在這里例子中它不是瓶頸之一auto udist = frame.get_distance(upixel[0], upixel[1]);auto vdist = frame.get_distance(vpixel[0], vpixel[1]);// Deproject from pixel to point in 3D// 將像素反映射到3D中的點rs2_deproject_pixel_to_point(upoint, &intr, upixel, udist);rs2_deproject_pixel_to_point(vpoint, &intr, vpixel, vdist);// Calculate euclidean distance between the two points// 計算空間中兩個點的歐幾里得距離return sqrt(pow(upoint[0] - vpoint[0], 2) +pow(upoint[1] - vpoint[1], 2) +pow(upoint[2] - vpoint[2], 2)); }在后臺線程上運行處理
在此示例中的后處理運算可能相對較慢。為了不阻塞主(UI)線程,我們將有一個專門的線程進行后處理。
視頻處理線程
這個線程將消耗來自相機完整幀集,并且會產生包含顏色和著色深度幀的幀集(用于在主線程上渲染):
while (alive) {// Fetch frames from the pipeline and send them for processing// 從管道中獲取幀,并且發送它們進行處理 rs2::frameset fs;if (pipe.poll_for_frames(&fs)) {// Apply post processing// ...// 應用后處理過程// ...// Send resulting frames for visualization in the main thread// 發送結果幀,用于在主線程中進行可視化。postprocessed_frames.enqueue(data);} }主線程
主線程是唯一允許用來渲染屏幕的。
它從postprocessed_frames中獲取,并且只是展示結果:
我們使用glBlendFunc使用顏色alpha通道在深度之上覆蓋對其的顏色(流必須是格式RGBA才能工作)。
這個例子演示了一個簡單而復雜的處理流程。每個線程都有一些不同的速率,它們都需要同步而不是相互堵塞。
這是使用線程安全的frame_queues作為同步原語和rs2::frame引用計數來實現的,用于跨線程的對象生命周期管理。
總結
以上是生活随笔為你收集整理的IntelRealSense 深度相机 测量物体的实际长度 —— rs-measure 官网文档翻译的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rust闪退修复工具_在Linux上,如
- 下一篇: Selenium 实战到吹牛系列:八