嘮叨
本文分三篇來介紹一個完整的CloudComapre插件的編寫教程,分別是插件框架篇、數(shù)據(jù)結(jié)構(gòu)篇、算法實現(xiàn)篇。
這是第二篇,數(shù)據(jù)結(jié)構(gòu)篇,你可以根據(jù)本文改成自己的插件,待卿臨幸。
qSAF源碼:Github . qSAF
前文概要
在上回中,我們已經(jīng)實現(xiàn)了插件的框架,現(xiàn)在要在doAction()中寫插件的具體實現(xiàn)。
插件需求
我們要做的是一個qSAF(Scan Angle Filter)插件,它可以過濾給定范圍內(nèi)點的掃描角度。
也就是用戶輸入兩個角度值,如20度、70度,
過濾輸出每個點的掃描角度在大于等于20度、小于等于70度的范圍的點云。
需求分析
要實現(xiàn)這個功能,我們需要有一個界面,可以讓用戶輸入兩個角度,然后獲取兩個角度值,接著遍歷每個點,獲取每個點的掃描角度,然后獲得角度在大于等于20度、小于等于70度范圍的點云,顯示輸出。
簡單地說,就是要:
- 輸入界面
- 遍歷角度
- 輸出點云
1. 輸入界面是QT基礎(chǔ);3. 輸出點云是CC套路;只有2. 遍歷角度有點糾結(jié)。
因此本文第二篇主要介紹2. 遍歷角度,即介紹點云中點的數(shù)據(jù)結(jié)構(gòu)。
注意:不同類型文件的數(shù)據(jù)結(jié)構(gòu)不同,本文以激光雷達文件(.las)來做介紹。
las文件的讀入
首先,我們從宇宙的起源開始說起……
額,還是從.las文件的讀入開始說起吧~
.las文件的讀入首先進過FileIOFilter這個類,判斷是雷達文件(.las)后,進入LASFilter類,并從它的loadFile()函數(shù)讀入。
先看下loadFile()函數(shù)聲明:
virtual CC_FILE_ERROR loadFile(QString filename, ccHObject& container, LoadParameters& parameters) override;
特別注意三個傳入?yún)?shù)!我就是忽視了這里才找了好久。。。
-
QString filename是點云文件名(包括路徑) -
ccHObject& container是一個實體(ccHObject),可以添加點云(ccPointCloud) -
LoadParameters& parameters是選擇讀入文件后提示要勾選雷達的哪些信息
然后看下loadFile()函數(shù)體
.las文件首先從io流讀入,再使用liblas這個外部庫存儲:
liblas::Reader reader(liblas::ReaderFactory().CreateWithStream(ifs));
這里說下liblas:
liblas是用于讀取和編寫非常常見的LAS LiDAR格式的C/C++庫,我們使用它來做對LAS的直接讀取。
官網(wǎng)如下:
然后把liblas讀入的文件進行各種處理和封裝,最終封裝成ccPointCloud
ccPointCloud* loadedCloud = 0;
int sfIndex = loadedCloud->addScalarField(field->sf);
...
loadedCloud->setName(chunkName);
...
loadedCloud->setMetaData(LAS_SCALE_X_META_DATA, QVariant(lasScale.x));
...
loadedCloud->addPoint(P);
...
然后通過:
container.addChild(loadedCloud);
添加到ccHObject中
所以:點云的信息,都是存儲在ccPointCloud中的!
而掃描角度存儲在ccPointCloud的標(biāo)量域中(ccScalarField)
ccPointCloud
前面已經(jīng)說了很多ccPointCloud了,它就是CloudCompare中存儲點云的類。
我們看看它的說明
//! A 3D cloud and its associated features (color, normals, scalar fields, etc.)
/** A point cloud can have multiple features:
- colors (RGB)
- normals (compressed)
- scalar fields
- an octree strucutre
- per-point visibility information (to hide/display subsets of points)
- other children objects (meshes, calibrated pictures, etc.)
**/
我要的掃描角度就在scalar fields
然而在ccPointCloud沒有直接的方法獲得眾多標(biāo)量域中的掃描角度
終于在它的父類ChunkedPointCloud中發(fā)現(xiàn)了
ChunkedPointCloud
ccPointCloud的父類ChunkedPointCloud中有如下兩個函數(shù):
# 通過標(biāo)量域名字獲得其在標(biāo)量域數(shù)組中的索引
int ChunkedPointCloud::getScalarFieldIndexByName(const char* name) const
# 通過索引獲得特定標(biāo)量域的指針
ScalarField* ChunkedPointCloud::getScalarField(int index) const
通過這兩個函數(shù)就可以獲得指向掃描角度的指針了,要想訪問掃描角度中每個點的值,需要使用ScalarField父類GenericChunkedArray的方法
GenericChunkedArray
# 通過每個點的索引訪問特定標(biāo)量域的每個的的值
inline const ElementType* getValue(unsigned index) const
LASOpenDlg
標(biāo)量域中掃描角度的名字可以在LASOpenDlg.h中找到
"Scan Angle Rank"
整理下思路
- 用
Scan Angle Rank,通過getScalarFieldIndexByName()獲得掃描角度在標(biāo)量域中的索引 - 用索引,通過
getScalarField()獲得掃描角度標(biāo)量域指針 - 用指針,通過
getValue()獲得每個點的值
這樣就獲取到了每個點的掃描角度值,然后:
- 比較掃描角度值與用戶輸入?yún)^(qū)間的大小,把合適的值存儲起來
- 把合適值封裝成點云實體
- 顯示在界面上
上面整理的思路在下篇實現(xiàn),現(xiàn)在我們已經(jīng)知道怎么獲取點云中掃描角度的值了,那其他信息呢?
點云其他信息的獲取
看下在QT的調(diào)試信息:

我們可以發(fā)現(xiàn),其實點云的信息都能在ccPointCloud中獲取,比如點容量、點數(shù)量、點坐標(biāo)、標(biāo)量域、顏色值等。
其中,標(biāo)量域vector中有9項信息,存儲的標(biāo)量域順序為:
- [0] Point Source ID
- [1] Scan Angle Rank
- [2] Flightline Edge
- [3] Scan Direction
- [4] Number of Returns
- [5] Return Number
- [6] Time
- [7] Intensity
- [8] Classification
至于如何獲取每種數(shù)據(jù),都有相應(yīng)的方法實現(xiàn),不是在ccPointCloud,就是在它的父類中,耐心點總能找到的~
下篇概要
下篇是算法實現(xiàn)篇,主要說了qSAF插件的具體實現(xiàn),包括上面說的:
- 輸入界面
- 遍歷角度
- 輸出點云
請戳這里:
我的博客:https://blog.huihut.com/
轉(zhuǎn)載請注明出處:http://blog.huihut.com/2017/04/27/CloudCompareSAFPlugin_2_DataStructure/