点云下采样1
來源:https://zhuanlan.zhihu.com/p/353761080
本文介紹python點(diǎn)云數(shù)據(jù)處理中的點(diǎn)云下采樣算法和關(guān)鍵點(diǎn)算法以及在點(diǎn)云工具箱軟件中的實(shí)現(xiàn)。由于點(diǎn)云的海量和無序性,直接處理的方式在對(duì)鄰域進(jìn)行搜索時(shí)需要較高的計(jì)算成本。一個(gè)常用的解決方式就是對(duì)點(diǎn)云進(jìn)行下采樣,將對(duì)全部點(diǎn)云的操作轉(zhuǎn)換到下采樣所得到的點(diǎn)上,降低計(jì)算量。
一、均勻下采樣
均勻下采樣有多種不同的采樣方式,其中最遠(yuǎn)點(diǎn)采樣是較為簡(jiǎn)單的一種,首先需要選取一個(gè)種子點(diǎn),并設(shè)置一個(gè)內(nèi)點(diǎn)集合,每次從點(diǎn)云中不屬于內(nèi)點(diǎn)的集合找出一點(diǎn)距離內(nèi)點(diǎn)最遠(yuǎn)的點(diǎn),如下圖,這里的距離計(jì)算方式為該點(diǎn)至內(nèi)點(diǎn)所有點(diǎn)的最小距離。這種方式的下采樣點(diǎn)云分布均勻,但是算法復(fù)雜度較高效率低。
點(diǎn)云工具箱中該功能實(shí)現(xiàn)依賴于Open3d庫(kù),代碼如下:
import open3d as o3d # 讀取文件 pcd = o3d.io.read_point_cloud(path) # path為文件路徑 pcd_new = o3d.geometry.PointCloud.uniform_down_sample(pcd, value) # value值的設(shè)定為整數(shù),即value個(gè)點(diǎn)中選取一個(gè)點(diǎn)
二、體素下采樣
體素下采樣就是把三維空間體素化,然后在每個(gè)體素里采樣一個(gè)點(diǎn),通常可用中心點(diǎn)或最靠近中心的點(diǎn)作為采樣點(diǎn)。具體方法如下:
1. 創(chuàng)建體素:計(jì)算點(diǎn)云的包圍盒,然后把包圍盒離散成小體素。體素的長(zhǎng)寬高可以用戶設(shè)定,也可以通過設(shè)定包圍盒三個(gè)方向的格點(diǎn)數(shù)來求得。
2. 每個(gè)小體素包含了若干個(gè)點(diǎn),取中心點(diǎn)或離中心點(diǎn)最近的點(diǎn)為采樣點(diǎn)。
體素采樣的特點(diǎn):
效率非常高
采樣點(diǎn)分布比較均勻,但是均勻性沒有均勻采樣高
可以通過體素的尺寸控制點(diǎn)間距
不能精確控制采樣點(diǎn)個(gè)數(shù)
點(diǎn)云工具箱中該功能實(shí)現(xiàn)依賴于Open3d庫(kù),代碼如下:
pcd_new = o3d.geometry.PointCloud.voxel_down_sample(pcd, value) # value為體素的大小
三、曲率下采樣
曲率下采樣就是在點(diǎn)云曲率越大的地方,采樣點(diǎn)個(gè)數(shù)越多。一種簡(jiǎn)單有效的曲率下采樣實(shí)現(xiàn)方法如下:
1.通過該方法近似達(dá)到曲率的效果同時(shí)提高計(jì)算效率:計(jì)算每個(gè)點(diǎn)K鄰域,然后計(jì)算點(diǎn)到鄰域點(diǎn)的法線夾角值。曲率越大的地方,這個(gè)夾角值就越大。
2.設(shè)置一個(gè)角度閾值,比如5度。點(diǎn)的鄰域夾角值大于這個(gè)閾值的點(diǎn)被認(rèn)為是特征明顯的區(qū)域,其余的為不明顯區(qū)域。
3.均勻采樣特征明顯區(qū)域和不明顯區(qū)域,采樣數(shù)分別為S * (1 - U),S * U。S為目標(biāo)采樣數(shù),U為采樣均勻性。
該采樣方法的特點(diǎn):
幾何特征越明顯的區(qū)域,采樣點(diǎn)個(gè)數(shù)分布越多
計(jì)算效率高
采樣點(diǎn)局部分布是均勻的
穩(wěn)定性高:通過幾何特征區(qū)域的劃分,使得采樣結(jié)果抗噪性更強(qiáng)
點(diǎn)云工具箱中該功能實(shí)現(xiàn)代碼如下:
def vector_angle(x, y):
Lx = np.sqrt(x.dot(x))
Ly = (np.sum(y ** 2, axis=1)) ** (0.5)
cos_angle = np.sum(x * y, axis=1) / (Lx * Ly)
angle = np.arccos(cos_angle)
angle2 = angle * 360 / 2 / np.pi
return angle2
knn_num = 10 # 自定義參數(shù)值(鄰域點(diǎn)數(shù))
angle_thre = 30 # 自定義參數(shù)值(角度值)
N = 5 # 自定義參數(shù)值(每N個(gè)點(diǎn)采樣一次)
C = 10 # 自定義參數(shù)值(采樣均勻性>N)
pcd = o3d.io.read_point_cloud(path)
point = np.asarray(pcd.points)
point_size = point.shape[0]
tree = o3d.geometry.KDTreeFlann(pcd)
o3d.geometry.PointCloud.estimate_normals(
pcd, search_param=o3d.geometry.KDTreeSearchParamKNN(knn=knn_num))
normal = np.asarray(pcd.normals)
normal_angle = np.zeros((point_size))
for i in range(point_size):
[_, idx, dis] = tree.search_knn_vector_3d(point[i], knn_num + 1)
current_normal = normal[i]
knn_normal = normal[idx[1:]]
normal_angle[i] = np.mean(vector_angle(current_normal, knn_normal))
point_high = point[np.where(normal_angle >= angle_thre)]
point_low = point[np.where(normal_angle < angle_thre)]
pcd_high = o3d.geometry.PointCloud()
pcd_high.points = o3d.utility.Vector3dVector(point_high)
pcd_low = o3d.geometry.PointCloud()
pcd_low.points = o3d.utility.Vector3dVector(point_low)
pcd_high_down = o3d.geometry.PointCloud.uniform_down_sample(pcd_high, N)
pcd_low_down = o3d.geometry.PointCloud.uniform_down_sample(pcd_low, C)
pcd_finl = o3d.geometry.PointCloud()
pcd_finl.points = o3d.utility.Vector3dVector(np.concatenate((np.asarray(pcd_high_down.points),
np.asarray(pcd_low_down.points))))
四、曲面均勻采樣
曲面均勻采樣的算法實(shí)現(xiàn)依賴于Open3d庫(kù),從三角網(wǎng)格曲面數(shù)據(jù)均勻采樣得到點(diǎn)云。
點(diǎn)云工具箱中該功能實(shí)現(xiàn)依賴于Open3d庫(kù),代碼如下:
ply = o3d.io.read_triangle_mesh(path) pcd = ply.sample_points_uniformly(number_of_points = value) # number_of_points參數(shù)為采樣點(diǎn)數(shù)
五、泊松磁盤采樣
1. 泊松磁盤采樣(Poisson-Disk Sampling)性質(zhì)
一個(gè)理想的 Poisson 圓盤采樣點(diǎn)集需要滿足 3 個(gè)條件:
(1) 無偏差采樣性質(zhì) (采樣區(qū)域的每個(gè)沒有被覆蓋的點(diǎn)都有相同的概率接受一個(gè)新的采樣點(diǎn));
(2) 最小距離性質(zhì) (任意兩個(gè)采樣點(diǎn)之間的距離大于給定的采樣半徑);
(3) 最大化性質(zhì) (采樣區(qū)域被所有的采樣圓盤完全覆蓋).
滿足這 3 個(gè)條件的采樣方法稱為最大化 Poisson 圓盤采樣 (maximal Poisson-disk sampling, MPS).
2.Poisson-Disk Sampling偽代碼如下:
function WeightedSamplingElim(samples)
Build a K-Dtree for each samples
Assign weights wi to each sample si
Build a heap for si using weights wi
While number of samples > desired
sj <- pull the top sample from heap
For each sample si around sj
Remove wij from wi
Update the heap position of si
每個(gè)sample都會(huì)被分配一個(gè)對(duì)應(yīng)的權(quán)重,其權(quán)重的參數(shù)如下:
w[index] += weightFunction(point, p, d2, d_max)
其中point為每個(gè)泊松圓盤固定點(diǎn),p為point周圍的點(diǎn),d2為周圍點(diǎn)與point之間的距離
,d_max為設(shè)定Poisson radius距離。
點(diǎn)云工具箱中該功能實(shí)現(xiàn)依賴于Open3d庫(kù),代碼如下:
pcd = tri_mesh.sample_points_poisson_disk(number_of_points=value) # number_of_points參數(shù)為采樣點(diǎn)數(shù)
總結(jié)
- 上一篇: 【项目管理工具】SVN
- 下一篇: 关于产品项目复盘,我总结的四步法(附实例