求3D點集中最近點的一個空間二叉樹實現
[email protected] 2010.09.12
(2011-03-04 修改節點內存泄漏,漏了一句m_nodePool.push_back(m_cur); )
tag:求3D點集中最近點,空間二叉樹,點集最小包圍球
摘要:
這幾天爲了解決一個顏色空間匹配搜索速度太慢的問題(求3D點集中最近點),寫了一個基於3D空間二叉樹分割的算法的實現,
速度提高了幾十倍;
正文:
A: 問題簡單描述
已知3D點集U(較多),求出U中與給定點p最近的點;可能會非常多次
的給定不同的p點,而點集U不變;
B: 一些基礎代碼和最簡單的一個實現和其簡要優化
定義3D點:
尋找最近點的算法簡單實現:
該算法遍歷點集U(points[]),找尋點集中距離test_point最近的點,返回其座標,算法複雜度爲O(N);
簡單優化:
前面的程序計算點之間的距離來比較大小,涉及到開方運算,比較慢;而比較的時候,改成比較距離的平方效果也一樣,
函數返回距離的時候,在把最終結果開方就好了;代碼如下:
這個代碼的速度是前面實現的3倍多;
當然該算法還可以繼續優化的;但因爲算法複雜度太高,進一步優化的意義不大;
下面給出一個平均複雜度O(log(N))的算法
C: 基於3D空間二叉樹分割的算法的實現
對點集U進行預處理,生成一棵3D空間二叉樹:
將點集U的最長軸按中值劃分成2個新的點集;計算新形成的2個點集的最小包圍球;
如果新劃分出的點集的點個數比較多,可以進一步劃分,一直到不用劃分;
(劃分方法可以是該軸的中值、均值或平分個數的值等,程序裏選擇用中值劃分;
包圍體也可以爲其它3D幾何包圍體,比如正6面體等,程序裏選擇球型包圍體,算法實現更簡單快速些)
利用二叉樹尋找離給定點最近的點:
程序用深度優先順序遍歷二叉樹,遇到有2分支的時候優先處理距離近的分支;
快速排除一個點集的算法原理: 假設搜尋過程中,當前已經得到的離p點最近的點的距離爲minD,
現在尋找到了點集u(包圍球半徑ur,球心座標up); 如果 (p到up的距離 - ur) > minD ,那麼該點集u和
其子點集都可以立即排除掉了;而且該判斷表達式還可以改進爲 p到up的距離的平方>(minD+ur)的平方
計算起來就更加快速了;
(如果想用廣度優先算法遍歷二叉樹,可以維持一個隊列,儲存當前沒有被排除的點集,然後展開這些點集,快速排除不可能的點集,直到沒有點集分
支可以展開;這種遍歷方式可以利用的快速排除一個點集的算法原理爲: 假設搜尋過程中,當前已經得
到的離p點最近的點集距離爲minD,該點集包圍球半徑爲ur,現在尋找到了點集v(包圍球半徑vr,球心坐
標vp); 如果 (p到vp的距離 - mr) > (minD+ur),那麼該點集v和其子點集就可以立即排除掉;該判斷表
達式也可以改進爲 p到vp的距離的平方 > (minR+ur+mr)的平方 ! )
代碼實現:
D:完整測試代碼
E:速度對比
使用的編譯器爲vc2008;測試使用的CPU爲i7 920;
--------------------------------------------
3D點集數量: 64
遍歷算法0: 每秒處理1134824個點
遍歷算法1: 每秒處理3564980個點
空間2叉樹算法: 每秒處理4871770個點
--------------------------------------------
3D點集數量: 256
遍歷算法0: 每秒處理291841個點
遍歷算法1: 每秒處理1059374個點
空間2叉樹算法: 每秒處理3144091個點
--------------------------------------------
3D點集數量: 1000
遍歷算法0: 每秒處理76064個點
遍歷算法1: 每秒處理295625個點
空間2叉樹算法: 每秒處理2068754個點
--------------------------------------------
3D點集數量: 10000
遍歷算法0: 每秒處理7643個點
遍歷算法1: 每秒處理30166個點
空間2叉樹算法: 每秒處理1111412個點
--------------------------------------------
3D點集數量: 100000
遍歷算法0: 每秒處理772個點
遍歷算法1: 每秒處理2984個點
空間2叉樹算法: 每秒處理604217個點
--------------------------------------------
3D點集數量: 1000000
遍歷算法0: 每秒處理83個點
遍歷算法1: 每秒處理272個點
空間2叉樹算法: 每秒處理272924個點