三維體數據分割算法

三維體數據分割算法

    本文基於分裂合併分割算法,提出了兩種新的分割算法:基於八叉樹的分裂合併算法和基於自適應包圍盒的分裂合併算法。下面將對這兩種算法進行描述node

1 分裂合併法分析

    區域生長法的原理是根據種子像素點(體數據中爲體素點)向其周圍擴散,對區域周圍的每個像素/體素進行分析。區域生長法須要用額外的內存區域來保存待生長的像素/體素點,而且算法的時間複雜度較大。區域生長的過程當中,須要以像素/體素爲單位一圈一圈地向外擴張。對於體數據來講,區域生長法花費較多的運算時間。算法

    分裂合併的基本思想是:先將整幅圖像或體數據依據某種規則分裂出不少個形狀規則的子區域,子區域內的像素或體素特徵具備一致性,而後合併特徵類似的子區域,從而實現分割的目的[2]。體數據分裂後的各子區域是一個立方體的體素集合,集合內全部體素屬於同一區域組織。分裂的同時須要對子區域生成連通圖,即將體數據中分裂區域之間的鄰接關係以圖的形式表達出來。合併的工做與區域生長法類似,先選擇一個區域生長的種子點,肯定該種子點所在的正方體分裂區域;而後以該區域爲中心,對其全部相鄰的子區域進行判斷;若是相鄰區域與該區域是同一組織則進行合併。該算法實際是以立方體節點爲最小單位對種子點進行生長,所以其運算效率要優於區域生長法。在區域分裂時須要生成區域鄰接圖,經過鄰接圖表示各子區域間的相鄰關係。在區域合併時,須要經過鄰接圖來查找等待合併的子區域。優化

    分裂的子區域結構須要包含如下幾種數據:spa

(1)空間包圍盒。用來記錄子區域的大小和位置;指針

(2)內部數據特徵值。能夠記錄所包含體素的灰度特徵,分佈狀況等;code

(3)相鄰節點。每一個非邊界節點至少有6個相鄰節點(每一個立方體面一個)。在區域合併時須要判斷該節點的全部相鄰節點。blog

    分裂子區域結構爲以下代碼中的結構體BoxNode。該結構中保存着其數據區域、特徵值、與之相鄰的子區域。遞歸

struct BoxNode                  // 節點包圍盒結構體,每個節點表示一個分裂後的子區域隊列

{ip

    Point ptStart;                  // 節點的開始位置

    Point ptEnd;                  // 節點的結束位置

    WORD voxelValue;            // 體素值

    long nMergeRagion;          // 該節點的合併區域,未合併時值爲-1

    std::set<BoxNode*> setNeighbours;       // 相鄰節點指針集合

    void AddNeighbour(BoxNode* nodePtr)     // 添加相鄰節點

    {setNeighbours.insert(nodePtr); }

    void RemoveNeighbour(BoxNode* nodePtr)  // 移除相鄰節點

    {setNeighbours.erase(nodePtr);}

};

2 基於八叉樹的分裂算法

    對於二維圖像來講,能夠採用四叉樹的方式對其進行分裂:首先選取區域一致性準則(如像素灰度值),而後根據這一準則將圖像等分紅四個區域,並分別判斷這些區域是否知足一致性準則;若是不知足一致性,則繼續分裂[24]。本課題所研究的是對三維體數據的分割,所以對其分裂時將基於二維的四叉樹方法擴展爲針對三維的八叉樹。

    八叉樹是每一個非葉節點有且僅有8個子節點的一種樹形結構體,它是表現一個被立方體封裝的三維物體的理想結構[5]。對於有着物體密集的數據集合,八叉樹可以快速的進行數據管理、可視化裁剪、光線跟蹤等三維空間操做。八叉樹的根節點包含一個立方體,它封閉着所有體數據。每一個節點的子節點是8個相同大小的立方體,它們將父節點等分爲八份。如圖5-6所示。

 

a.初始節點            b.第一次分裂             c.第二次分裂

5- 6八叉樹模型

    Volume表示整個體數據區域,P表示區域特徵一致性測度的謂詞邏輯,從最高層開始,將Volume分裂成8個相同的正方體子區域Volumei,對於任一個區域Volumei若是P(Volumei)false就將繼續對Volumei進行8等分,直至P(Volumei)trueVolumei爲單個體素爲止。對於一個2n 2n 2n的體數據,最多能夠分解至n層,第n層數據區域爲單個體素。對於本文實驗所採用的醫學圖像來講,圖像分辨率爲512 512。在對XOY平面上進行分裂時最多能夠分解至第8層。假如斷層數目爲M,那麼處理時將軸方向上的斷層個數設爲2k,使得 2k<= M< 2(k+1)在八叉樹分裂的同時須要生成區域鄰接圖,即每次分裂後,新生成的8個節點是上下左右相鄰的,而後判斷每一個新生成節點與原相鄰節點是否相鄰。

5- 7基於八叉樹的分裂算法流程圖


基於八叉樹分裂算法的步驟以下所述:

a.生成一個包含整個體數據的節點,該節點的開始位置爲原點:

ptStart(0, 0, 0);結束位置爲體數據的最大值ptEnd(xmax, ymax, zmax)

b. 對步驟a生成的節點進行特徵一致性檢測,若是不一致則該節點須要進行分裂處理,跳到步驟c,不然,跳到結束分裂;

c.將節點進行八叉樹分裂處理,即由該節點分裂出八個新的子節點;

d.創建新生成的八個子節點的相鄰關係,並更新新節點與舊節點的相鄰關係;

e.對新生成的八個子節點分別作特徵一致性檢測,若是不一致,則對該節點進行步驟c的操做;

f.分裂完成。

    基於八叉樹分裂算法採用分治遞歸的策略,可以快速有效的對體數據進行分裂處理。因爲該算法將一個問題拆分紅8個子問題,因此能夠採用並行的多CPU運算對其進行優化。但基於八叉樹分裂算法會產生過分分裂的狀況,假如體數據中一個特徵一致性區域正好位於某個待分裂節點的中心位置,那麼使用八叉樹會將該區域分裂成八份。

3 基於自適應包圍盒的分裂算法

    爲了解決區域的過分分裂的問題,本文提出一種基於自適應包圍盒的分裂算法,能有效解決這一過分分裂問題。該算法的基本思想是一次性的遍歷體數據中每一個體素,找出全部具備特徵值一致性的立方體區域,而後生成這些立方體區域的鄰接圖。

 

5- 8基於自適應包圍盒的分裂算法流程圖

    自適應包圍盒的分裂算法的實現步驟以下所述:

a. 首先建立一個分裂區域子節點集合setNodes,和一個與體數據相同大小的數據區域NodeArrayNodeArray用於存放每一個體素所在子節點的地址;還須要將NodeArray的數據內容設置爲空;

b.依次遍歷體數據中的每個體素點Voxel(xi, yi,zi);當完成遍歷後,跳轉到步驟g。

c.判斷Voxel(xi,yi,zi)是否已經被擴展過;判斷方法是看其對應NodeArray(xi,yi,zi)中的值是否爲空;若是是擴展過的,則返回步驟b;

d.建立一個子區域節點Nodej,該節點的起始位置爲Voxel(xi,yi,zi)

e.分別對XYZ三個座標軸的正方向進行擴展,並判斷新擴展的體素與Voxel(xi,yi,zi)是否具備特徵一致性;當某一方向出現不一致的體素時,則中止該方向的擴展;

f.步驟e完成後會獲得節點Nodej的結束位置Voxel(xi+m, yi+n,zi+k);先將Nodej所包含的體素Voxel(xs,ys,zs)所對應NodeArray(xs,ys,zs)的值設置爲Nodej的地址,再將其添加到子節點集合setNodes中;

g.在遍歷完體數據中全部體素後,經過遍歷NodeArray中的數據生成子區域節點的相鄰關係。

自適應包圍盒的分裂算法可以只經過兩次遍歷體數據,就能夠對體數據進行分裂;而且分裂後的區域不會有像八叉樹那種過分分裂的狀況。

4 節點合併算法

    該階段與區域生長算法很類似:首先選擇一個種子點,得到該種子點所在的子區域Vmerge。根據區域鄰接圖,對任意與Vmerge相鄰的子區域Vi,若P(Vmerge U Vi)==true,則將其合併並將Vi的相鄰子區域設爲Vmerge相鄰的子區域。直至沒有知足合併條件的相鄰區域爲止。

a.經過種子點的座標位置找到種子點所在的子區域節點;而後建立一個待合併的隊列,並將剛纔找到的子區域節點放到該隊列中;再將該子區域節點放到合併區域集合中;

b.從待合併隊列中取出一個子區域節點;若是待合併隊列爲空則表示合併完成,跳轉到步驟d;

c.依次對步驟b中取出的節點的相鄰節點作一致性檢測,若是檢測經過,則將該相鄰節點分別放到待合併隊列和合並區域集合中;

d.完成合並操做。

 

代碼實現:

  1 /****************************************************************
  2   File name   :  VolumeDataSplitMerge.CPP
  3   Author      :  葉峯
  4   Version     :  1.0a
  5   Create Date :  2011/12/01   
  6   Description :  
  7   Others      :  
  8 *****************************************************************/
  9 
 10 // --------------------------------------------------------------------------------------
 11 
 12 #include <Windows.h>
 13 #include <set>
 14 
 15 // --------------------------------------------------------------------------------------
 16 
 17 struct Point                    // 體數據中的體素點座標
 18 {
 19     long x;
 20     long y;
 21     long z;
 22     Point()
 23     {
 24         x = 0; y = 0; z = 0;
 25     }
 26     Point(long _x, long _y, long _z)
 27     {
 28         x = _x; y = _y; z = _z;
 29     }
 30 };
 31 
 32 struct BoxNode                  // 節點包圍盒結構體
 33 {
 34     Point ptStart;              // 節點的開始位置
 35     Point ptEnd;                // 節點的結束位置
 36     WORD voxelValue;            // 體素值
 37     bool isMergedTest;          // 用於判斷該節點是否被合併
 38     std::set<BoxNode*> setNeighbours;       // 相鄰節點指針集合
 39     void AddNeighbour(BoxNode* nodePtr)     // 添加相鄰節點
 40     {
 41         setNeighbours.insert(nodePtr);  
 42     }
 43     void RemoveNeighbour(BoxNode* nodePtr)  // 移除相鄰節點
 44     {
 45         setNeighbours.erase(nodePtr);
 46     }
 47 };
 48 
 49 // --------------------------------------------------------------------------------------
 50 
 51 WORD* g_pVolumeData;            // 體數據
 52 long g_dwX, g_dwY, g_dwZ;       // 體數據的大小
 53 WORD g_nThreshold;  
 54 std::set<BoxNode*> g_setSplitNodes; // 分裂出的全部區域節點的集合
 55 
 56 // --------------------------------------------------------------------------------------
 57 
 58 // 判斷一個體素座標點是否在一包圍盒節點中
 59 inline bool IsPointInBox(const Point& point, const BoxNode& box)
 60 {
 61     return (point.x >= box.ptStart.x && point.x <= box.ptEnd.x &&
 62             point.y >= box.ptStart.y && point.y <= box.ptEnd.y &&
 63             point.z >= box.ptStart.z && point.z <= box.ptEnd.z);
 64 }
 65 
 66 // 得到一個座標點的體素值
 67 inline WORD GetVoxelValue(const Point& point)
 68 {
 69     return g_pVolumeData[point.z*g_dwY*g_dwX + point.y*g_dwX + point.x];
 70 }
 71 inline WORD GetVoxelValue(long x, long y, long z)
 72 {
 73     return g_pVolumeData[z*g_dwY*g_dwX + y*g_dwX + x];
 74 }
 75 
 76 // 判斷兩個體素值是否類似
 77 inline bool IsSimilar(WORD value0, WORD value1)
 78 {
 79     if (value0 > value1)
 80         return (value0 - value1 <= g_nThreshold);
 81     else
 82         return (value1 - value0 <= g_nThreshold);
 83 }
 84 
 85 // 判斷兩個節點包圍盒是否相鄰
 86 inline bool IsNodeNeighbour(const BoxNode* nodePtr0, const BoxNode* nodePtr1)
 87 {
 88     if (nodePtr0->ptStart.x - 1 == nodePtr1->ptEnd.x)
 89     {
 90         if (nodePtr0->ptStart.y <= nodePtr1->ptEnd.y &&
 91             nodePtr0->ptEnd.y <= nodePtr1->ptStart.y &&
 92             nodePtr0->ptStart.z <= nodePtr1->ptEnd.z &&
 93             nodePtr0->ptEnd.z <= nodePtr1->ptStart.z)
 94         {
 95             return true;
 96         }
 97     }
 98     else if (nodePtr0->ptEnd.x + 1 == nodePtr1->ptStart.x)
 99     {
100         if (nodePtr0->ptStart.y <= nodePtr1->ptEnd.y &&
101             nodePtr0->ptEnd.y <= nodePtr1->ptStart.y &&
102             nodePtr0->ptStart.z <= nodePtr1->ptEnd.z &&
103             nodePtr0->ptEnd.z <= nodePtr1->ptStart.z)
104         {
105             return true;
106         }
107     }
108     else if (nodePtr0->ptStart.y - 1 == nodePtr1->ptEnd.y)
109     {
110         if (nodePtr0->ptStart.x <= nodePtr1->ptEnd.x &&
111             nodePtr0->ptEnd.x <= nodePtr1->ptStart.x &&
112             nodePtr0->ptStart.z <= nodePtr1->ptEnd.z &&
113             nodePtr0->ptEnd.z <= nodePtr1->ptStart.z)
114         {
115             return true;
116         }
117     }
118     else if (nodePtr0->ptEnd.y + 1 == nodePtr1->ptStart.y)
119     {
120         if (nodePtr0->ptStart.x <= nodePtr1->ptEnd.x &&
121             nodePtr0->ptEnd.x <= nodePtr1->ptStart.x &&
122             nodePtr0->ptStart.z <= nodePtr1->ptEnd.z &&
123             nodePtr0->ptEnd.z <= nodePtr1->ptStart.z)
124         {
125             return true;
126         }
127     }
128     else if (nodePtr0->ptStart.z - 1 == nodePtr1->ptEnd.z)
129     {
130         if (nodePtr0->ptStart.y <= nodePtr1->ptEnd.y &&
131             nodePtr0->ptEnd.y <= nodePtr1->ptStart.y &&
132             nodePtr0->ptStart.x <= nodePtr1->ptEnd.x &&
133             nodePtr0->ptEnd.x <= nodePtr1->ptStart.x)
134         {
135             return true;
136         }
137     }
138     else if (nodePtr0->ptEnd.z + 1 == nodePtr1->ptStart.z)
139     {
140         if (nodePtr0->ptStart.y <= nodePtr1->ptEnd.y &&
141             nodePtr0->ptEnd.y <= nodePtr1->ptStart.y &&
142             nodePtr0->ptStart.x <= nodePtr1->ptEnd.x &&
143             nodePtr0->ptEnd.x <= nodePtr1->ptStart.x)
144         {
145             return true;
146         }
147     }
148 
149     return false;
150 }
151 
152 // --------------------------------------------------------------------------------------
153 // 更新8叉樹節點的相鄰關係
154 void UpdateOctreeNodeNeighbour(BoxNode* oldNodePtr, BoxNode* newNodePtr)
155 {
156     BoxNode* nerghbourNodePtr;
157     std::set<BoxNode*>::iterator itor = oldNodePtr->setNeighbours.begin();
158     while (itor != oldNodePtr->setNeighbours.end())
159     {
160         nerghbourNodePtr = *itor;
161         nerghbourNodePtr->RemoveNeighbour(oldNodePtr);
162         if (IsNodeNeighbour(nerghbourNodePtr, newNodePtr))
163         {
164             nerghbourNodePtr->AddNeighbour(newNodePtr);
165             newNodePtr->AddNeighbour(nerghbourNodePtr);
166         }
167         itor++;
168     }
169 }
170 
171 // 使用8叉樹法分裂體數據
172 void OctreeSplitVolumeData(BoxNode* nodePtr)
173 {
174     if (nodePtr == NULL)        // 當nodePtr爲空指針時表示對整個體數據進行分裂
175     {
176         nodePtr = new BoxNode();
177         nodePtr->ptStart = Point(0, 0, 0);
178         nodePtr->ptEnd = Point(g_dwX - 1, g_dwY - 1, g_dwZ - 1);
179         nodePtr->voxelValue = GetVoxelValue(nodePtr->ptStart);
180         nodePtr->isMergedTest = false;
181     }
182 
183     bool shouldSplit = false;
184     // 判斷是否須要分裂該節點
185     WORD voxelValue;
186     for (long z = nodePtr->ptStart.z; z <= nodePtr->ptEnd.z; z++)
187     {
188         for (long y = nodePtr->ptStart.y; y <= nodePtr->ptEnd.y; y++)
189         {
190             for (long x = nodePtr->ptStart.x; x <= nodePtr->ptEnd.x; x++)
191             {
192                 voxelValue = GetVoxelValue(x, y, z);
193                 if (!IsSimilar(voxelValue, nodePtr->voxelValue))
194                 {
195                     shouldSplit = true;
196                     break;
197                 }
198             }
199             if (shouldSplit)
200                 break;
201         }
202         if (shouldSplit)
203             break;
204     }
205 
206     if (!shouldSplit)
207     {
208         return;
209     }
210 
211     Point ptSplit;          // 分裂點
212     ptSplit.x = (nodePtr->ptStart.x + nodePtr->ptEnd.x)/2;
213     ptSplit.y = (nodePtr->ptStart.y + nodePtr->ptEnd.y)/2;
214     ptSplit.z = (nodePtr->ptStart.z + nodePtr->ptEnd.z)/2;
215 
216     // 8分原節點
217     BoxNode* nodeSplitPtr[8];
218     for (long i = 0; i < 8; i++)
219     {
220         nodeSplitPtr[i] = new BoxNode();
221         nodeSplitPtr[i]->ptStart = nodePtr->ptStart;
222         nodeSplitPtr[i]->ptEnd = ptSplit;
223 
224         if (i & 1)      // X軸向變化
225         {
226             nodeSplitPtr[i]->ptStart.x = ptSplit.x + 1;
227             nodeSplitPtr[i]->ptEnd.x = nodePtr->ptEnd.x;
228             if (nodeSplitPtr[i]->ptStart.x > nodeSplitPtr[i]->ptEnd.x) // 非法的分裂點
229             {
230                 delete nodeSplitPtr[i];
231                 nodeSplitPtr[i] = NULL;
232                 continue;
233             }
234         }
235         if (i & 2)      // Y軸向變化
236         {
237             nodeSplitPtr[i]->ptStart.y = ptSplit.y + 1;
238             nodeSplitPtr[i]->ptEnd.y = nodePtr->ptEnd.y;
239             if (nodeSplitPtr[i]->ptStart.y > nodeSplitPtr[i]->ptEnd.y) // 非法的分裂點
240             {
241                 delete nodeSplitPtr[i];
242                 nodeSplitPtr[i] = NULL;
243                 continue;
244             }
245         }
246         if (i & 4)      // Z軸向變化
247         {
248             nodeSplitPtr[i]->ptStart.z = ptSplit.z + 1;
249             nodeSplitPtr[i]->ptEnd.z = nodePtr->ptEnd.z;
250             if (nodeSplitPtr[i]->ptStart.z > nodeSplitPtr[i]->ptEnd.z) // 非法的分裂點
251             {
252                 delete nodeSplitPtr[i];
253                 nodeSplitPtr[i] = NULL;
254                 continue;
255             }
256         }
257 
258         nodeSplitPtr[i]->voxelValue = nodePtr->voxelValue;
259         nodeSplitPtr[i]->isMergedTest = false;
260         UpdateOctreeNodeNeighbour(nodePtr, nodeSplitPtr[i]);
261     }
262 
263     for (long i = 0; i < 8; i++)
264     {
265         if (nodeSplitPtr[i])
266         {
267             for (long j = 0; j < 8; j++)
268             {
269                 if (i != j && nodeSplitPtr[j])
270                 {
271                     // 添加相鄰關係
272                     nodeSplitPtr[i]->AddNeighbour(nodeSplitPtr[j]);
273                 }
274             }
275             g_setSplitNodes.insert(nodeSplitPtr[i]);
276         }
277     }
278 
279     // 刪除舊的節點
280     delete nodePtr;
281     g_setSplitNodes.erase(nodePtr);
282 
283     // 遞歸處理分裂的節點
284     for (long i = 0; i < 8; i++)
285     {
286         if (nodeSplitPtr[i])
287         {
288             OctreeSplitVolumeData(nodeSplitPtr[i]);
289         }
290     }
291 }
292 
293 // --------------------------------------------------------------------------------------
294 void UpdateVoxelNodePtr(BoxNode* nodePtr, BoxNode** listVoxelNodePtr)
295 {
296     for (long z = nodePtr->ptStart.z; z <= nodePtr->ptEnd.z; z++)
297         for (long y = nodePtr->ptStart.y; y <= nodePtr->ptEnd.y; y++)
298             for (long x = nodePtr->ptStart.x; x <= nodePtr->ptEnd.x; x++)
299                 listVoxelNodePtr[z*g_dwY*g_dwX + y*g_dwX + x] = nodePtr;
300 }
301 
302 // 自適應包圍盒法分裂體數據
303 void AdaptableSplitVolumeData()
304 {
305     // 記錄每個體素點所在的節點包圍盒
306     BoxNode** listVoxelNodePtr = (BoxNode**)malloc(sizeof(BoxNode*)*g_dwX*g_dwY*g_dwZ);
307     memset(listVoxelNodePtr, 0, sizeof(BoxNode*)*g_dwX*g_dwY*g_dwZ);
308 
309     for (long z = 0; z < g_dwZ; z++)
310     {
311         for (long y = 0; y < g_dwY; y++)
312         {
313             for (long x = 0; x < g_dwX; x++)
314             {
315                 if (listVoxelNodePtr[z*g_dwY*g_dwX + y*g_dwX + x] != NULL)
316                 {
317                     continue;
318                 }
319 
320                 BoxNode* nodePtr = new BoxNode();
321                 nodePtr->ptStart = Point(x, y, z);
322                 nodePtr->ptEnd = nodePtr->ptStart;
323                 nodePtr->voxelValue = GetVoxelValue(nodePtr->ptStart);
324                 nodePtr->isMergedTest = false;
325 
326                 // 擴張該節點
327                 bool xExtend = true;
328                 bool yExtend = true;
329                 bool zExtend = true;
330                 long extend;
331                 WORD voxelValue;
332                 while (xExtend || yExtend || zExtend)
333                 {
334                     if (xExtend)        // X軸方向擴張
335                     {
336                         extend = nodePtr->ptEnd.x + 1;
337                         if (extend == g_dwX)
338                         {
339                             xExtend = false;
340                         }
341                         else
342                         {
343                             for (long _z = nodePtr->ptStart.z; _z <= nodePtr->ptEnd.z; _z++)
344                             {
345                                 for (long _y = nodePtr->ptStart.y; _y <= nodePtr->ptEnd.y; _y++)
346                                 {
347                                     voxelValue = GetVoxelValue(extend, _y, _z);
348                                     if (!IsSimilar(voxelValue, nodePtr->voxelValue))
349                                     {
350                                         xExtend = false;
351                                         break;
352                                     }
353                                 }
354                                 if (!xExtend)
355                                 {
356                                     break;
357                                 }
358                             }
359 
360                             if (xExtend)
361                             {
362                                 nodePtr->ptEnd.x++;
363                             }
364                         }
365                     }
366 
367                     if (yExtend)        // Y軸方向擴張
368                     {
369                         extend = nodePtr->ptEnd.y + 1;
370                         if (extend == g_dwY)
371                         {
372                             yExtend = false;
373                         }
374                         else
375                         {
376                             for (long _z = nodePtr->ptStart.z; _z <= nodePtr->ptEnd.z; _z++)
377                             {
378                                 for (long _x = nodePtr->ptStart.x; _x <= nodePtr->ptEnd.x; _x++)
379                                 {
380                                     voxelValue = GetVoxelValue(_x, extend, _z);
381                                     if (!IsSimilar(voxelValue, nodePtr->voxelValue))
382                                     {
383                                         yExtend = false;
384                                         break;
385                                     }
386                                 }
387                                 if (!yExtend)
388                                 {
389                                     break;
390                                 }
391                             }
392 
393                             if (yExtend)
394                             {
395                                 nodePtr->ptEnd.y++;
396                             }
397                         }
398                     }
399                 }
400 
401                 if (zExtend)        // Z軸方向擴張
402                 {
403                     extend = nodePtr->ptEnd.z + 1;
404                     if (extend == g_dwZ)
405                     {
406                         zExtend = false;
407                     }
408                     else
409                     {
410                         for (long _x = nodePtr->ptStart.x; _x <= nodePtr->ptEnd.x; _x++)
411                         {
412                             for (long _y = nodePtr->ptStart.y; _y <= nodePtr->ptEnd.y; _y++)
413                             {
414                                 voxelValue = GetVoxelValue(_x, _y, extend);
415                                 if (!IsSimilar(voxelValue, nodePtr->voxelValue))
416                                 {
417                                     zExtend = false;
418                                     break;
419                                 }
420                             }
421                             if (!zExtend)
422                             {
423                                 break;
424                             }
425                         }
426 
427                         if (zExtend)
428                         {
429                             nodePtr->ptEnd.z++;
430                         }
431                     }
432                 }
433 
434                 UpdateVoxelNodePtr(nodePtr, listVoxelNodePtr);
435                 g_setSplitNodes.insert(nodePtr);
436             }
437         }
438     }
439 
440     // 生成節點的相鄰關係
441     BoxNode* nodePtr;
442     BoxNode* nodeNext;
443     for (long z = 0; z < g_dwZ - 1; z++)
444     {
445         for (long y = 0; y < g_dwY - 1; y++)
446         {
447             for (long x = 0; x < g_dwX - 1; x++)
448             {
449                 nodePtr = listVoxelNodePtr[z*g_dwY*g_dwX + y*g_dwX + x];
450                 nodeNext = listVoxelNodePtr[z*g_dwY*g_dwX + y*g_dwX + x + 1];
451                 if (nodePtr != nodeNext)
452                 {
453                     nodePtr->AddNeighbour(nodeNext);
454                     nodeNext->AddNeighbour(nodePtr);
455                 }
456                 nodeNext = listVoxelNodePtr[z*g_dwY*g_dwX + (y + 1)*g_dwX + x];
457                 if (nodePtr != nodeNext)
458                 {
459                     nodePtr->AddNeighbour(nodeNext);
460                     nodeNext->AddNeighbour(nodePtr);
461                 }
462                 nodeNext = listVoxelNodePtr[(z + 1)*g_dwY*g_dwX + y*g_dwX + x];
463                 if (nodePtr != nodeNext)
464                 {
465                     nodePtr->AddNeighbour(nodeNext);
466                     nodeNext->AddNeighbour(nodePtr);
467                 }
468             }
469         }
470     }
471 
472     free(listVoxelNodePtr);
473 }
474 
475 // --------------------------------------------------------------------------------------
476 
477 // 合併體數據
478 void MergeSplitVolumeData(IN const Point& ptStart,          // 輸入起始點座標
479                           OUT std::set<BoxNode*>& setMerge  // 輸出合併的節點集合 
480                           )
481 {
482     setMerge.clear();
483 
484     // 由起始點座標查找起始節點
485     BoxNode* pStartNode = NULL;
486     std::set<BoxNode*>::iterator itor = g_setSplitNodes.begin();
487     while(itor != g_setSplitNodes.end())
488     {
489         if (IsPointInBox(ptStart, *(*itor)))
490         {
491             pStartNode = *itor;
492             break;
493         }
494         itor++;
495     }
496     if (!pStartNode)
497     {
498         return;
499     }
500 
501     std::set<BoxNode*> setExtending;        // 正在擴張中的節點集合
502     std::set<BoxNode*> setExtendNext;       // 下一步須要擴張的節點集合
503     setExtending.insert(pStartNode);
504 
505     WORD voxelValue = pStartNode->voxelValue;
506     BoxNode* pCurrentNode;
507 
508     while(setExtending.size() > 0)
509     {
510         setExtendNext.clear();
511         std::set<BoxNode*>::iterator itor = setExtending.begin();
512         while (itor != setExtending.end())
513         {
514             pCurrentNode = *itor;
515             pCurrentNode->isMergedTest = true;
516             if (IsSimilar(voxelValue, (*itor)->voxelValue))
517             {
518                 setMerge.insert(*itor);
519 
520                 std::set<BoxNode*>::iterator itor2 = pCurrentNode->setNeighbours.begin();
521                 while(itor2 != pCurrentNode->setNeighbours.end())
522                 {
523                     if (!(*itor2)->isMergedTest)
524                     {
525                         setExtendNext.insert((*itor2));
526                     }
527                 }
528             }
529             itor++;
530         }
531 
532         setExtending = setExtendNext;
533     }
534 }
相關文章
相關標籤/搜索