這裡主要針對PCL庫中outofcore查詢外網文獻以及模組的相關資料寫出以下內容,再次說明,文章出自“點雲PCL”,並且在部落格園發出,未經允許,請勿轉載轉載。

什麼是outofcore

outofcore,可以理解為使用記憶體對映的方法,來處理大規模點雲無法載入到記憶體的問題,並且這裡我暫且將其翻譯為“核外八叉樹”,因為根據PCL中的實現方法,就是以八叉樹的方法實現了記憶體對映的演算法。

在PCL中基於外存(out of core)的資料處理方法,藉助於八叉樹理論在完成大規模點雲的前提處理,並使用一種八叉樹領域的搜尋方法構建出散亂資料的拓撲結構。在視覺化與計算機圖形學領域,基於外核的演算法是涉及用來處理大資料量模型執行在有限記憶體中的方法,簡單來說,透過限制訪問到一個小的,處於快取記憶體中的模型的字塊實現的。

首先我們看一下PCL 的Outofcore的模組介紹,該模組介紹是就是透過記憶體對映的方法以及八叉樹的資料結構實現大規模點雲的儲存,資料位於某些輔助儲存介質上基於目錄的八叉樹層次結構中,並且PCL——outofcore提供了構造和遍歷outofcore八叉樹的框架,其他的輔助函式在後面將會具體講解。

PCL中的outofcore模組是由Urban Robotic整合起來,並且在PCL中實現了相關的例程,本文是在查閱了大量的相關資料的基礎上總結而成,其中難免會有一些理解錯誤,

該模組翻譯成中文可以翻譯為核外八叉樹,主要針對點雲的處理,同時也可以擴充套件成為網格或者體素的表示形式,outofcore支援空間索引資料儲存和快速的資料訪問,並且只有部分資料從硬碟載入到執行的記憶體中,以便能夠快速的視覺化。

所以該框架能夠滿足一下幾種條件:

(1)大資料,框架能夠處理大量的點雲或者大空間的資料

(2)支援非均勻資料,採集的點雲從分佈,密度以及精度上都是變化的,

(3)支援資料查詢,能夠有效的搜尋資料,查詢資料等操作

(4)資料更新,在大量資料集中能夠實現資料的新增和刪除等操作,比如濾波操作,

(5)能夠儲存資料質量,避免了簡化重取樣或者有失真壓縮。

Out-of-core octree(核外八叉樹)其實就是執行記憶體不足以載入大量的資料情況下,採用記憶體對映的方法,並且將資料儲存為八叉樹的形式儲存在硬碟上。

為了滿足資料查詢的要求,這裡採用了八叉樹儲存結構【以前的文章介紹過八叉樹】八叉樹是基於空間驅動的分割槽方法,如果資料分佈嚴重的不均勻,這種方法可能會有嚴重不平衡的缺點,在這種情況下提出了使用KDtree,需要較少的記憶體用於樹結構並且能夠快速的實現資料的訪問,但是一般pcl中的實現是主要使用了八叉樹只希望該模組能夠支援快速的資料更新,並且八叉樹是非常適合的實現核外實現的演算法,因為每個級別的分割槽都是相同的,因此不需要讀取額外的資訊。

一般來說這種方法很少有開源的方案供大家使用,其中PCL中就是一個較好的實現了核外八叉樹模組的演算法

,開源的模組中只關注核外的八叉樹實現以及視覺化的部分,並且樹的深度或者解析度完全由使用者自行定義。

以上是PCL1。7版本以上outofcore模組實現核外八叉樹的類,其中對cJSON的依賴關係作為pcl_outofcore的依賴項已經連結在一起,並且將函式已經封裝到兩個獨立的類OutofcoreOctreeNodeMetadata和OutofcoreOctreeMetadata

#FormatImgID_1##FormatImgID_2#

PCL中實現outofcore的檔案概括介紹

outofcore模組中實現核外八叉樹的四個主要的hpp檔案

1.octree。hpp

2。 octree2。hpp

3.octree ram container。hpp

4。 octree disk container。hpp

標頭檔案:

(a) octree base。h

(b) octree base node。h

(c) octree abstract node container。h∗

(d) metadata。h∗: 實現metadata的抽象類

(e) outofcore node data。h∗:實現核外節點層級的資料檔案的介面(tree。oct idx)

(f) outofcore base data。h∗:實現和外八叉樹高層級資料介面(tree。octree JSON file)

(g) OutofcoreDepthFirstIterator。h∗:核外八叉樹的深度優先迭代器,可以直接訪問外部節點的類

(h) OutofcoreIteratorBase。h∗: 基於pcl中octree模組中迭代器的抽象迭代器的類

(i) octree disk container。h: 磁碟容器的IO

(j) octree ram container。h: 核外八叉樹的核心資料結構(不再需要了)

(k) outofcore node data。h: 包含主節點資料結構以及用於插入和查詢的遞迴方法

(l) boost。h: 包含pcl outofcore中所需的所有boost標頭檔案

(m) cJSON。h: 為了與PCL構建系統相容,已進行了較小的修改

模板實現類的檔案:

(a)octree base。hpp

(b) octree base node。hpp

(c) octree disk container。hpp

(d) octree ram container。hpp

(e) OutofcoreDepthFirstIterator。hpp

(f) OutofcoreIteratorBase。hpp

原始檔

(a) cJSON。cpp

(b) outofcore node data。cpp

(c) outofcore base data。cpp

Outofcore節點的格式

在磁碟上每個內部節點和葉子節點最多可以包含兩個檔案,

*.oct_idx

以oct_idx為字尾的JSON資料檔案,格式為:

{

”version”:3 ,

”bb_min”:[xxx,yyy,zzz],

”bb_max”:[xxx,yyy,zzz],

”bin”:”pathtodata。pcd ”

}

可以使用OutofcoreOctreeNodeMetadata類直接訪問此JSON資料。 此類將介面抽象到磁碟上的JSON資料,因此從理論上講,該格式可以輕鬆更改為XML,YAML或其他所需格式。

*.pcd

pcd檔案包含與該節點關聯的所有點雲的標準格式(v7 +)PCD檔案。 該檔案同樣也適用於所有葉子節點,但僅適用於內部(“分支”)節點(如果已構建LOD)。 透過OutofcoreOctreeDiskContainer類可以訪問此檔案。

根節點包含了一個附件的檔案

*。octree 其中包含有關八叉樹結構的高階資訊。 格式為:

{

”name”:”test,

”version”:3,

”pointtype”:”urp”, #(needs to be changed ∗)

”lod”:3, #depth of the tree

”numpts”:[X0,X1,X2, 。。。 ,XD] , #total number of points at each LOD

”coordsystem”:”ECEF” #the tree is not affected by this value

}

如果想使用PCL 中的outofcore模組只需要新增

#include

#include

具體實現後面將會更加具體例程的解釋

PCL中outofcore模組實現了該演算法具有哪些特點

點雲的插入

(1)addPointCloud

(2)addPointCloud and genLOD

使用addPointCloud的方法可以公開的訪問並且將點雲插入到外部的八叉樹中,NaN無效點將會被忽略,所有點將以全密度插入到葉子節點中,可以透過迭代的呼叫addPointClooud的方法將多個點雲插入到外部的八叉樹中,並且建議使用結構PointCloud2來表示點雲

點雲查詢

點雲的查詢使用:queryBoundingBox

該函式是為了outofcore構建的八叉樹為點雲查詢提供的公共介面,該方法被過載,並且根據傳遞的引數,將返回位於指定深度的查詢邊界框內的所有點,或返回其並集將包含查詢邊界框內所有點的所有PCD檔案列表。

深度級別(LOD level of Depth):多解析度的核外八叉樹

構建LOD的方法: buildLOD, addPointCloud and genLOD

核外八叉樹的一個關鍵特性是所謂的“深度層次”簡稱LOD,按照習慣將八叉樹的根級成為0級,每一級都是i-1級別八倍取樣,(這裡我理解為金字塔結構)深度級別是透過隨機下采樣每個級別的點數來構建,此百分比可以透過OutOfcoreCreeBase類中的setSamplePercent的方法來設定,這一引數也是可以在建立點雲的多解析度表示的時候進行設定,可以達到快速的進行渲染的效果,渲染的過程中,可以基於某些查詢的方法,比如體素到視點的距離,訪問點雲所需要的解析度,當然也可以透過所在層級以及深度,邊界框進行訪問

buildLOD:buildLOD使用多解析度方法重新構建outofcore八叉樹的LOD。每個分支節點是其葉子的子取樣的並集。子取樣的百分比由setSamplePercent確定,預設為0。125^depth-maxdepth LOD演算法的細節請檢視【5】

程式碼實現以及註釋

實現從大規模點雲生成核外八叉樹的檔案系統的程式碼:

#include

#include

#include

#include //建議在使用outofcore點雲的形式使用該形式的點雲頭檔案

#include

#include

#include

#include

//新增outofcore的相關標頭檔案

#include

#include

typedef pcl::PointXYZ PointT;

using namespace pcl;

using namespace pcl::outofcore;

using pcl::console::parse_argument;

using pcl::console::parse_file_extension_argument;

using pcl::console::find_switch;

using pcl::console::print_error;

using pcl::console::print_warn;

using pcl::console::print_info;

#include

typedef OutofcoreOctreeBase<> octree_disk;

const int OCTREE_DEPTH (0);

const int OCTREE_RESOLUTION (1);

/*

實現讀取點雲檔案

*/

PCLPointCloud2::Ptr getCloudFromFile (boost::filesystem::path pcd_path)

{

PCLPointCloud2::Ptr cloud(new PCLPointCloud2);

if (io::loadPCDFile (pcd_path。string (), *cloud) == -1)

{

PCL_ERROR (“Couldn‘t read file\n”);

}

print_info (“(%d)\n”, (cloud->width * cloud->height));

return cloud;

}

int outofcoreProcess (std::vector pcd_paths, boost::filesystem::path root_dir,

int depth, double resolution, int build_octree_with, bool gen_lod, bool overwrite, bool multiresolution)

{

// Bounding box min/max pts

PointT min_pt, max_pt;

// Iterate over all pcd files resizing min/max

for (size_t i = 0; i < pcd_paths。size (); i++)

{

// Get cloud

PCLPointCloud2::Ptr cloud = getCloudFromFile (pcd_paths[i]);

PointCloud::Ptr cloudXYZ (new PointCloud);

fromPCLPointCloud2 (*cloud, *cloudXYZ);

PointT tmp_min_pt, tmp_max_pt;

if (i == 0)

{

getMinMax3D (*cloudXYZ, min_pt, max_pt); //獲取點雲資料在XYZ軸上的最大最小值

}

else

{

getMinMax3D (*cloudXYZ, tmp_min_pt, tmp_max_pt);

// Resize new min

if (tmp_min_pt。x < min_pt。x)

min_pt。x = tmp_min_pt。x;

if (tmp_min_pt。y < min_pt。y)

min_pt。y = tmp_min_pt。y;

if (tmp_min_pt。z < min_pt。z)

min_pt。z = tmp_min_pt。z;

// Resize new max

if (tmp_max_pt。x > max_pt。x)

max_pt。x = tmp_max_pt。x;

if (tmp_max_pt。y > max_pt。y)

max_pt。y = tmp_max_pt。y;

if (tmp_max_pt。z > max_pt。z)

max_pt。z = tmp_max_pt。z;

}

}

std::cout << “Bounds: ” << min_pt << “ - ” << max_pt << std::endl;

// The bounding box of the root node of the out-of-core octree must be specified

const Eigen::Vector3d bounding_box_min (min_pt。x, min_pt。y, min_pt。z);

const Eigen::Vector3d bounding_box_max (max_pt。x, max_pt。y, max_pt。z);

//specify the directory and the root node’s meta data file with a

//“。oct_idx” extension (currently it must be this extension)

boost::filesystem::path octree_path_on_disk (root_dir / “tree。oct_idx”);

print_info (“Writing: %s\n”, octree_path_on_disk。c_str ());

//make sure there isn‘t an octree there already

if (boost::filesystem::exists (octree_path_on_disk))

{

if (overwrite)

{

boost::filesystem::remove_all (root_dir);

}

else

{

PCL_ERROR (“There’s already an octree in the default location。 Check the tree directory\n”);

return (-1);

}

}

octree_disk *outofcore_octree;

//create the out-of-core data structure (typedef‘d above)

if (build_octree_with == OCTREE_DEPTH)

{

outofcore_octree = new octree_disk (depth, bounding_box_min, bounding_box_max, octree_path_on_disk, “ECEF”);

}

else

{

outofcore_octree = new octree_disk (bounding_box_min, bounding_box_max, resolution, octree_path_on_disk, “ECEF”);

}

uint64_t total_pts = 0;

// Iterate over all pcd files adding points to the octree

for (size_t i = 0; i < pcd_paths。size (); i++)

{

PCLPointCloud2::Ptr cloud = getCloudFromFile (pcd_paths[i]);

boost::uint64_t pts = 0;

if (gen_lod && !multiresolution)

{

print_info (“ Generating LODs\n”);

pts = outofcore_octree->addPointCloud_and_genLOD (cloud);

}

else

{

pts = outofcore_octree->addPointCloud (cloud, false);

}

print_info (“Successfully added %lu points\n”, pts);

print_info (“%lu Points were dropped (probably NaN)\n”, cloud->width*cloud->height - pts);

// assert ( pts == cloud->width * cloud->height );

total_pts += pts;

}

print_info (“Added a total of %lu from %d clouds\n”,total_pts, pcd_paths。size ());

double x, y;

outofcore_octree->getBinDimension (x, y);

print_info (“ Depth: %i\n”, outofcore_octree->getDepth ());

print_info (“ Resolution: [%f, %f]\n”, x, y)

if(multiresolution)

{

print_info (“Generating LOD。。。\n”);

outofcore_octree->setSamplePercent (0。25);

outofcore_octree->buildLOD ();

}

//free outofcore data structure; the destructor forces buffer flush to disk

delete outofcore_octree;

return 0;

}

void

printHelp (int, char **argv)

{

print_info (“This program is used to process pcd fiels into an outofcore data structure viewable by the”);

print_info (“pcl_outofcore_viewer\n\n”);

print_info (“%s 。pcd \n”, argv[0]);

print_info (“\n”);

print_info (“Options:\n”);

print_info (“\t -depth \t Octree depth\n”);

print_info (“\t -resolution \t Octree resolution\n”);

print_info (“\t -gen_lod \t Generate octree LODs\n”);

print_info (“\t -overwrite \t Overwrite existing octree\n”);

print_info (“\t -multiresolution \t Generate multiresolutoin LOD\n”);

print_info (“\t -h \t Display help\n”);

print_info (“\n”);

}

int main (int argc, char* argv[])

{

// Check for help (-h) flag

if (argc > 1)

{

if (find_switch (argc, argv, “-h”))

{

printHelp (argc, argv);

return (-1);

}

}

// If no arguments specified

if (argc - 1 < 1)

{

printHelp (argc, argv);

return (-1);

}

if (find_switch (argc, argv, “-debug”))

{

pcl::console::setVerbosityLevel ( pcl::console::L_DEBUG );

}

// Defaults

int depth = 4;

double resolution = 。1;

bool gen_lod = false;

bool multiresolution = false;

bool overwrite = false;

int build_octree_with = OCTREE_DEPTH;

// If both depth and resolution specified

if (find_switch (argc, argv, “-depth”) && find_switch (argc, argv, “-resolution”))

{

PCL_ERROR (“Both -depth and -resolution specified, please specify one (Mutually exclusive)\n”);

}

// Just resolution specified (Update how we build the tree)

else if (find_switch (argc, argv, “-resolution”))

{

build_octree_with = OCTREE_RESOLUTION;

}

// Parse options

parse_argument (argc, argv, “-depth”, depth);

parse_argument (argc, argv, “-resolution”, resolution);

gen_lod = find_switch (argc, argv, “-gen_lod”);

overwrite = find_switch (argc, argv, “-overwrite”);

if (gen_lod && find_switch (argc, argv, “-multiresolution”))

{

multiresolution = true;

}

// Parse non-option arguments for pcd files

std::vector file_arg_indices = parse_file_extension_argument (argc, argv, “。pcd”);

std::vector pcd_paths;

for (size_t i = 0; i < file_arg_indices。size (); i++)

{

boost::filesystem::path pcd_path (argv[file_arg_indices[i]]);

if (!boost::filesystem::exists (pcd_path))

{

PCL_WARN (“File %s doesn’t exist”, pcd_path。string ()。c_str ());

continue;

}

pcd_paths。push_back (pcd_path);

}

// Check if we should process any files

if (pcd_paths。size () < 1)

{

PCL_ERROR (“No 。pcd files specified\n”);

return -1;

}

// Get root directory

boost::filesystem::path root_dir (argv[argc - 1]);

// Check if a root directory was specified, use directory of pcd file

if (root_dir。extension () == “。pcd”)

root_dir = root_dir。parent_path () / (root_dir。stem()。string() + “_tree”)。c_str();

return outofcoreProcess (pcd_paths, root_dir, depth, resolution, build_octree_with, gen_lod, overwrite, multiresolution);

}

視覺化的程式碼如下(這些程式碼的編譯與實現建議在PCL1。7版本以上)

// C++

#include

#include

// PCL

#include

#include

#include

#include

#include

#include

#include

#include

#include

// PCL - visualziation

//#include

#include

#include

//#include “vtkVBOPolyDataMapper。h”

// PCL - outofcore

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace pcl;

using namespace pcl::outofcore;

using pcl::console::parse_argument;

using pcl::console::find_switch;

using pcl::console::print_error;

using pcl::console::print_warn;

using pcl::console::print_info;

//typedef PCLPointCloud2 PointT;

typedef PointXYZ PointT;

typedef OutofcoreOctreeBase, PointT> octree_disk;

typedef OutofcoreOctreeBaseNode, PointT> octree_disk_node;

//typedef octree_base , PointT> octree_disk;

typedef boost::shared_ptr OctreeDiskPtr;

//typedef octree_base_node , PointT> octree_disk_node;

typedef Eigen::aligned_allocator AlignedPointT;

// VTK

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

// Boost

#include

#include

#include

// Globals

vtkSmartPointer window;

class KeyboardCallback : public vtkCommand

{

public:

vtkTypeMacro(KeyboardCallback, vtkCommand)

static KeyboardCallback *

New ()

{

return new KeyboardCallback;

}

void

Execute (vtkObject *caller, unsigned long vtkNotUsed(eventId), void* vtkNotUsed(callData))

{

vtkRenderWindowInteractor *interactor = vtkRenderWindowInteractor::SafeDownCast (caller);

vtkRenderer *renderer = interactor->FindPokedRenderer (interactor->GetEventPosition ()[0],

interactor->GetEventPosition ()[1]);

std::string key (interactor->GetKeySym ());

bool shift_down = interactor->GetShiftKey();

cout << “Key Pressed: ” << key << endl;

Scene *scene = Scene::instance ();

OutofcoreCloud *cloud = static_cast (scene->getObjectByName (“my_octree”));

if (key == “Up” || key == “Down”)

{

if (key == “Up” && cloud)

{

if (shift_down)

{

cloud->increaseLodPixelThreshold();

}

else

{

cloud->setDisplayDepth (cloud->getDisplayDepth () + 1);

}

}

else if (key == “Down” && cloud)

{

if (shift_down)

{

cloud->decreaseLodPixelThreshold();

}

else

{

cloud->setDisplayDepth (cloud->getDisplayDepth () - 1);

}

}

}

if (key == “o”)

{

cloud->setDisplayVoxels(1-static_cast (cloud->getDisplayVoxels()));

}

if (key == “Escape”)

{

Eigen::Vector3d min (cloud->getBoundingBoxMin ());

Eigen::Vector3d max (cloud->getBoundingBoxMax ());

renderer->ResetCamera (min。x (), max。x (), min。y (), max。y (), min。z (), max。z ());

}

}

};

void

renderTimerCallback(vtkObject* caller, unsigned long int vtkNotUsed(eventId), void* vtkNotUsed(clientData), void* vtkNotUsed(callData))

{

vtkRenderWindowInteractor *interactor = vtkRenderWindowInteractor::SafeDownCast (caller);

interactor->Render ();

}

void

renderStartCallback(vtkObject* vtkNotUsed(caller), unsigned long int vtkNotUsed(eventId), void* vtkNotUsed(clientData), void* vtkNotUsed(callData))

{

//std::cout << “Start。。。”;

}

void

renderEndCallback(vtkObject* vtkNotUsed(caller), unsigned long int vtkNotUsed(eventId), void* vtkNotUsed(clientData), void* vtkNotUsed(callData))

{

//std::cout << “End” << std::endl;

}

int

outofcoreViewer (boost::filesystem::path tree_root, int depth, bool display_octree=true, unsigned int gpu_cache_size=512)

{

cout << boost::filesystem::absolute (tree_root) << endl;

// Create top level scene

Scene *scene = Scene::instance ();

// Clouds

OutofcoreCloud *cloud = new OutofcoreCloud (“my_octree”, tree_root);

cloud->setDisplayDepth (depth);

cloud->setDisplayVoxels (display_octree);

OutofcoreCloud::cloud_data_cache。setCapacity(gpu_cache_size*1024);

scene->addObject (cloud);

// OutofcoreCloud *cloud2 = new OutofcoreCloud (“my_octree2”, tree_root);

// cloud2->setDisplayDepth (depth);

// cloud2->setDisplayVoxels (display_octree);

// scene->addObject (cloud2);

// Add Scene Renderables

Grid *grid = new Grid (“origin_grid”);

Axes *axes = new Axes (“origin_axes”);

scene->addObject (grid);

scene->addObject (axes);

// Create smart pointer with arguments

// Grid *grid_raw = new Grid(“origin_grid”);

// vtkSmartPointer grid;

// grid。Take(grid_raw);

// Create window and interactor

vtkSmartPointer interactor = vtkSmartPointer::New ();

window = vtkSmartPointer::New ();

window->SetSize (1000, 500);

interactor->SetRenderWindow (window);

interactor->Initialize ();

interactor->CreateRepeatingTimer (100);

// Viewports

Viewport octree_viewport (window, 0。0, 0。0, 0。5, 1。0);

Viewport persp_viewport (window, 0。5, 0。0, 1。0, 1。0);

// Cameras

Camera *persp_camera = new Camera (“persp”, persp_viewport。getRenderer ()->GetActiveCamera ());

Camera *octree_camera = new Camera (“octree”, octree_viewport。getRenderer ()->GetActiveCamera ());

scene->addCamera (persp_camera);

scene->addCamera (octree_camera);

octree_camera->setDisplay(true);

// Set viewport cameras

persp_viewport。setCamera (persp_camera);

octree_viewport。setCamera (octree_camera);

// Render once

window->Render ();

// Frame cameras

Eigen::Vector3d min (cloud->getBoundingBoxMin ());

Eigen::Vector3d max (cloud->getBoundingBoxMax ());

octree_viewport。getRenderer ()->ResetCamera (min。x (), max。x (), min。y (), max。y (), min。z (), max。z ());

persp_viewport。getRenderer ()->ResetCamera (min。x (), max。x (), min。y (), max。y (), min。z (), max。z ());

cloud->setRenderCamera(octree_camera);

// Interactor

// ————————————————————————————————————-

vtkSmartPointer style = vtkSmartPointer::New ();

style->SetAutoAdjustCameraClippingRange(false);

interactor->SetInteractorStyle (style);

// Callbacks

// ————————————————————————————————————-

vtkSmartPointer render_start_callback = vtkSmartPointer::New();

render_start_callback->SetCallback(renderStartCallback);

window->AddObserver(vtkCommand::StartEvent, render_start_callback);

vtkSmartPointer render_end_callback = vtkSmartPointer::New();

render_end_callback->SetCallback(renderEndCallback);

window->AddObserver(vtkCommand::EndEvent, render_end_callback);

vtkSmartPointer keyboard_callback = vtkSmartPointer::New ();

interactor->AddObserver (vtkCommand::KeyPressEvent, keyboard_callback);

interactor->CreateRepeatingTimer(1000);

vtkSmartPointer render_timer_callback = vtkSmartPointer::New();

render_timer_callback->SetCallback(renderTimerCallback);

interactor->AddObserver(vtkCommand::TimerEvent, render_timer_callback);

interactor->Start ();

return 0;

}

void

print_help (int, char **argv)

{

print_info (“This program is used to visualize outofcore data structure”);

print_info (“%s \n”, argv[0]);

print_info (“\n”);

print_info (“Options:\n”);

print_info (“\t -depth \t Octree depth\n”);

print_info (“\t -display_octree \t Toggles octree display\n”);

// print_info (“\t -mem_cache_size \t Size of pointcloud memory cache in MB (Defaults to 1024MB)\n”);

print_info (“\t -gpu_cache_size \t Size of pointcloud gpu cache in MB (512MB)\n”);

print_info (“\t -lod_threshold \t Bounding box screen projection threshold (10000)\n”);

print_info (“\t -v \t Print more verbosity\n”);

print_info (“\t -h \t Display help\n”);

print_info (“\n”);

exit (1);

}

int

main (int argc, char* argv[])

{

// Check for help (-h) flag

if (argc > 1)

{

if (find_switch (argc, argv, “-h”))

{

print_help (argc, argv);

return (-1);

}

}

// If no arguments specified

if (argc - 1 < 1)

{

print_help (argc, argv);

return (-1);

}

if (find_switch (argc, argv, “-v”))

console::setVerbosityLevel (console::L_DEBUG);

// Defaults

int depth = 4;

// unsigned int mem_cache_size = 1024;

unsigned int gpu_cache_size = 512;

unsigned int lod_threshold = 10000;

bool display_octree = find_switch (argc, argv, “-display_octree”);

// Parse options

parse_argument (argc, argv, “-depth”, depth);

// parse_argument (argc, argv, “-mem_cache_size”, mem_cache_size);

parse_argument (argc, argv, “-gpu_cache_size”, gpu_cache_size);

parse_argument (argc, argv, “-lod_threshold”, lod_threshold);

// Parse non-option arguments

boost::filesystem::path tree_root (argv[argc - 1]);

// Check if a root directory was specified, use directory of pcd file

if (boost::filesystem::is_directory (tree_root))

{

boost::filesystem::directory_iterator diterend;

for (boost::filesystem::directory_iterator diter (tree_root); diter != diterend; ++diter)

{

const boost::filesystem::path& file = *diter;

if (!boost::filesystem::is_directory (file))

{

if (boost::filesystem::extension (file) == octree_disk_node::node_index_extension)

{

tree_root = file;

}

}

}

}

return outofcoreViewer (tree_root, depth, display_octree, gpu_cache_size);

}

根據上面的處理的程式碼的實現提示:

使用深度引數化的方法

pcl_outofcore_process −depth 4 −gen_lod data01。pcd data02。pcd myoutofcoretree

要建立葉節點體素大小不超過50 cm的多解析度outofcore八叉樹,使用如下:

pcl _outofcoreprocess −resolution 0。 50 −genlod data01。pcd data02。pcd myotheroutofcoretree

在PCL中使用OutCore演算法可以使用自帶的工具裡的可執行檔案 構造過程可以透過深度或解析度引數化。如果指定了解析度(即最大葉尺寸),則自動計算深度。如果設定的樹太深:LOD的構建可能需要很長時間

pcl_outofcore_viewer 使用不同的深度視覺化的結果

這裡使用了不同的解析度的形式視覺化,對於大規模的點雲,根據不同的視角來顯示點雲,對於視覺化的部分我們載入進來,對於不需要的部分,我們可以不用載入進來。這也是為什麼能夠提高視覺化的效率。

下面這是使用了真實的PCD點雲資料,來做實驗例程。該PCD檔案是一個大規模的街景點雲,該點雲有200MB

PCL中outofcore模組---基於核外八叉樹的大規模點雲的顯示

該點雲直接視覺化的結果,我們可以看到點雲的數量以及載入的時間

PCL中outofcore模組---基於核外八叉樹的大規模點雲的顯示

我們分別使用了生成了不同的深度和不同解析度的核外八叉樹檔案

#FormatImgID_7##FormatImgID_8#

使用我們outofcore_viewer視覺化的結果

PCL中outofcore模組---基於核外八叉樹的大規模點雲的顯示

該演算法針對更大的點雲採用上述的方法生成核外八叉樹的形式,也可以很好實現點雲的視覺化

References

[1] PCL Urban Robotics Code Sprint Blog。

http://www。

pointclouds。org/blog/ur

cs

[2] Point Cloud Library Documentation: Module outofcore。

https://

docs。pointclouds。org/tr

unk/

group__outofcore。html。

[3] Urban Robotics。

http://www。

urbanrobotics。net

[4] Adam Stambler。 osgpcl: OpenSceneGraph Point Cloud Library Cloud Viewer。

https://

github。com/

adasta/osgpcl, 2012。

[5] Claus Scheiblauer and Michael Wimmer。 Out-of-core selection and editing of huge point clouds。 Computers & Graphics, 35(2):342–351, April 2011。

這裡的文章均為“點雲PCL”博主原創,未經允許,請勿轉載,謝謝大家的理解與合作

請關注公眾號,加入微信或者QQ交流群

PCL中outofcore模組---基於核外八叉樹的大規模點雲的顯示