1樓:_鈊_煩_薏亂
marching cubes演算法(醫學影象三維繪製中的面繪製)2007-08-16 00:50建議要看的資料
[1] lorensen w e, cline h e .marching cubes: a high-resoulution 3d suface construction algorithm [j], computer graphics,1987, 21(4):
163~169
[2]整合化醫學影像演算法平臺理論與實踐田捷,趙明昌,何暉光 清華大學出版社2023年10月
marching cubes演算法工作原理
marching cubes演算法是三維資料場等值面生成的經典演算法,是體素單元內等值面抽取技術的代表。
等值面是空間中所有具有某個相同值的點的集合。它可以表示為, ,c是常數。則稱f(f)為體資料f中的等值面。
在mc演算法中,假定原始資料是離散的三維空間規則資料場。用於醫療診斷的斷層掃描(ct)及核磁共振成像(mri) 等產生的影象均屬於這一型別。mc演算法的基本思想是逐個處理資料場中的體素,分類出與等值面相交的體素,採用插值計算出等值面與體素稜邊的交點。
根據體素中每一頂點與等值面的相對位置,將等值面與立方體邊的交點按一定方式連線生成等值面,作為等值面在該立方體內的一個逼近表示。在計算出關於體資料場內等值面的有關引數後山常用的圖形軟體包或硬體提供的面繪製功能繪製出等值面。
圖2.1 離散的三維空間規則資料場中的一個體素
2.1.1 mc演算法的主要步驟
1. 確定包含等值面的體素
離散的三維空間規則資料場中的一個體素可以用圖2.1表示。8個資料點分別位於該體素的8個角點上。
mc演算法的基本假設是:沿著體素的邊其資料場呈區域性連續線性變化,根據這個假設,可認為,如果兩個相鄰取樣點一個為正點,一個為負點,則它們連成的邊上一定存在且僅有一個等值點 (設等值面值為c)。如果得到了體素各條邊上的等值點,就可以以這些點為頂點,用一系列的三角形擬合出該體素中的等值面。
因此確定立方體體素中等值面的分佈是該演算法的基礎。
首先對體素的8個頂點進行分類,以判斷其頂點是位於等值面之外,還是位於等值面之內。再根據8個頂點的狀態,確定等值面的剖分模式。頂點分類規則為:
1. 如體素頂點的資料值大於或等於等值面的值,則定義該頂點位於等值面之外, 記為正點,即「1「
2. 如體素頂點的資料值小於等值面的值,則定義該頂點位於等值面之內,記為負點, 即「0"
由於每個體素共有8個頂點,且每個頂點有正負兩種狀態,所以等值面可能以 =256種方式與一個體素相交。通過列舉出這256種情況,就能建立一張**,利用它可以查出任意體素中的等值面的三角面片表示。如果考慮互補對稱性,將等值面的值和8個角點的函式值的大小關係顛倒過來,即將體素的頂點標記置反(0變為1, 1變為0),這樣做不會影響該體素的8個角點和等值面之間的拓撲結構,可將256種方式簡化成128種。
其次,再利用旋轉對稱性,可將這128種構型進一步簡化成15種。圖3.2給出了這15種基本構型[131其中黑點標記為「1」的角點。
圖2.2 分佈狀態表
圖2.3 體素角點分佈不同情況
基於上面的分析,mc演算法中用一個位元組的空間構造了一個體素狀態表,如圖2.2所示,該狀態表中的每一位可表示出該體元中的一個角點的0或1的狀態。根據這一狀態表,就可知道當前體素屬於圖2.
3中哪一種情況,以及等值面將與哪一條邊相交。
2.求等值面與體元邊界的交點
在確定體素內三角剖分模式後,就要計算三角片頂點位置。當三維離散資料場的密度較高時,即當體素很小時,可以假定函式值沿體素邊界呈線性變化,這就是mc演算法的基本假設。因此,根據這一基本假設,可以直接用線性插值計算等值面與體素邊的交點。
對於當前被處理體素的某一條邊,如果其兩頂點 , 的標記值不同,那麼等值面一定與此邊相交,且僅有一個交點。交點為 其中p代表等值點座標, , 代表兩個端點的座標, , 代表兩個端點的灰度值,v代表域值。求出等值面與體素稜邊的交點以後,就可以將這些交點連線成三角形或多邊形,形成等值面的一部分。
3.等值面的法向量計算
為了利用圖形硬體顯示等值面圖象,必須給出形成等值面的各三角面片的法向分量,選擇適當的區域性面光照模型進行光照計算,以生成真實感圖形。
對於等值面上的每一點,其沿面的切線方向的梯度分量應該是零,因此,該點的梯度向量的方向也就代表了等值面在該點的法向量,當梯度值非零。所幸的是等值面往往是由兩種具有不同密度的物質的分解面,因此其上的每點的梯度向量均不為零,即
mc演算法採用中心差分方法求取樣點p〔m ,n, k ) 處的梯度向量,公式如下:
gx=〔g(i+1,j,k)-g(i-1,j,k)〕/2dx
gy=〔g(i,j+1,k)-g(i,j-1,k)〕/2dy
gz=〔g(i,j,k+1)-g(i,j,k-1)〕/2dz
其中d(i,j ,k)是切片k在畫素(i,j)的密度, , , 是立方體邊的長度。對g進行歸一化,得到(gx/|g|,gy/|g|,gz/|g|)作為(i,j,k)上的單位法向量。然後,對體素八個頂點上法向量進行線性插值就可得到位於體素稜邊上的三角片的各個頂點上的法向量。
設計算得到的某個三角片的三個頂點上的單位法向量分別為( , 和 ),這個三角片的幾何重心為 ,則該三角片的法向量起始於 ,終止於 。代入gourand光照模型公式,就可計算出小三角片表面的光強(灰度)。將其投影在某個特定的二維平面上進行顯示,從而顯示出物體富有光感的整個表面形態。
其中我們在記憶體中保留四個切片來計算立方體中所有頂點梯度。
2.1.2 mc演算法流程
1、將三維離散規則資料場分層讀入記憶體;
2、掃描兩層資料,逐個構造體素,每個體素中的8個角點取自相鄰的兩層;
3、將體素每個角點的函式值與給定的等值面值c做比較,根據比較結果,構造
該體素的狀態表;
4、根據狀態表,得出將與等值面有交點的邊界體素;
5、通過線性插值方法計算出體素稜邊與等值面的交點;
6、利用中心差分方法,求出體素各角點處的法向量,再通過線性插值方法,求出三角面片各頂點處的法向;
7,根據各三角面片上各頂點的座標及法向量繪製等值面影象。
mc**
marchingcubes(float lowthreshold,float highthreshold,float xspace,float yspace,float zspace)
psliced =new short [imagesize];
//因為等值面是每相鄰兩層切片為單位進行提取的,所以在處理後兩層切片時難免生成前兩層切片已經生成的頂點,這時候就用下面的陣列記錄哪些邊上的頂點已經生成了,如果遇到已經生成的頂點就不再重複計算而是直接使用記錄的索引,否則就生成新的頂點。
long *bottomxedge=new long[imagesize];
long *bottomyedge=new long[imagesize];
long *topxedge=new long[imagesize];
long *topyedge=new long[imagesize];
long *zedge=new long[imagesize];
tempslice=new short [imagesize];
if(bottomxedge==null||bottomyedge==null||
topxedge==null||topyedge==null||
zedge==null||tempslice==null)
//初始化資料
memset(bottomxedge,-1,sizeof(long)*imagesize);
memset(bottomyedge,-1,sizeof(long)*imagesize);
memset(topxedge,-1,sizeof(long)*imagesize);
memset(topyedge,-1,sizeof(long)*imagesize);
memset(zedge,-1,sizeof(long)*imagesize);
memset(tempslice,0,sizeof(short)*imagesize);
//計算某一層頂點和三角時所需要的一些變數
//一些迴圈變數
int i,j,k,w,r;
//cube型別
unsigned char cubetype(0);
//計演算法向量
float dx[8],dy[8],dz[8],squaroot;
//記錄某個cube生成
float vertpoint[12][6];
int cellverts[12]; //what use
int triindex[5][3]; //每個cube最多生成5條邊
//用於記錄已生成頂點索引的臨時變數
int offset;
//當前cube8個頂點的灰度值
short cubegrid[8];
long *edgegroup;
//得到資料
psliced=m_volumedata;
psliceb=tempslice;
pslicea=tempslice;
int tt,tt1;
//掃描4層切片的順序
/* -----------------------d |
-----------------------b |
-----------------------c |
-----------------------a |
v*///marching cubes 演算法開始實行 ?第一次迴圈時,只讀入一個切片?
for(i=0;i<=(slicenumber);i++)
else
for(j=0;jlowthreshold)&&(cubegrid[w]lowthreshold)
else if(s2<=lowthreshold) }
else if(s2lowthreshold)
else if(s1<=lowthreshold) }
//計算兩端點實際座標
x1=(k+g_coordvertex[index1][0])*xspace;
y1=(j+g_coordvertex[index1][1])*yspace;
z1=(i+g_coordvertex[index1][2])*zspace;
x2=(k+g_coordvertex[index2][0])*xspace;
y2=(j+g_coordvertex[index2][1])*yspace;
z2=(i+g_coordvertex[index2][2])*zspace;
//計算兩端點的法向量
nx1=dx[index1]/xspace;
ny1=dy[index1]/yspace;
nz1=dz[index1]/zspace;
nx2=dx[index2]/xspace;
ny2=dy[index2]/yspace;
nz2=dz[index2]/zspace;
float factor=((float)(s-s1))/((float)(s2-s1));
//插值計算交點座標
vertpoint[vertpos][0]=factor*(x2-x1)+x1;
vertpoint[vertpos][1]=factor*(y2-y1)+y1;
vertpoint[vertpos][2]=factor*(z2-z1)+z1;
//計演算法向量
vertpoint[vertpos][3]=factor*(nx1-nx2)-nx1;
vertpoint[vertpos][4]=factor*(ny1-ny2)-ny1;
vertpoint[vertpos][5]=factor*(nz1-nz2)-nz1;
//法向量歸一化
+vertpoint[vertpos][5]*vertpoint[vertpos][5]);
if(squaroot<=0)squaroot=1.0;
vertpoint[vertpos][3]/=squaroot;
vertpoint[vertpos][4]/=squaroot;
vertpoint[vertpos][5]/=squaroot;
//更新包圍盒資料
if(min[0]>vertpoint[vertpos][0])
if(min[1]>vertpoint[vertpos][1])
if(min[2]>vertpoint[vertpos][2])
if(max[0]m_fnumber;i++)
glend();
以上**只用於理解,未測試
什麼是愛情,什麼是友情什麼是愛情,什麼是友情,什麼是親情。
愛是包容而不是放縱 愛是關懷而不是寵愛 愛是相互交融而不是單相思 愛是百味而不全是甜蜜.真正的愛情並不一定是他人眼中的完美匹配 而是相愛的人彼此心靈的相互契合 是為了讓對方生活得更好而默默奉獻 這份愛不僅溫潤著他們自己,也同樣溫潤著那些世俗的心真正的愛情,是在能愛的時候,懂得珍惜 真正的愛情,是在無...
什麼是醜?什麼是美什麼是美什麼是醜
美與醜是審美文化的積澱,無所謂美,無所謂醜,人們推崇的就是美,相反就是醜。賈平凹說 醜到極處,便是美到極處 他說的是一塊石頭,挺有哲理,是不錯的。但對於一個人,就不適用了,人的美醜並沒有截然的界限。對普通的人來講,外表或許有美醜,但絕大部分的人外表都一般,並沒有很醜或者很美。對美醜,每個人的看法也很...
什麼是理性,什麼是真理,什麼是自由,什麼是信仰
首先,聖經是沒變化過的,現在的聖 經的版本和幾十年前出土的一千多年前的聖經完全一致的,這點你可以百多的到。第二,進化論是很符合理性的,希特勒的那本書 我的奮鬥 裡面的思想完全就是這種弱肉強食的思想,他認為猶太人是劣等名族,他在推進世界的進步,他在改善人類的基因,因為他是高貴的日耳曼民族,猶太人是對人...