日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

种子点生长算法下——三维种子点生长

發(fā)布時(shí)間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 种子点生长算法下——三维种子点生长 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇文章“二維種子點(diǎn)生長研究”介紹了二維種子點(diǎn)生長,對于平面圖像,二維種子點(diǎn)生長其實(shí)很容易理解,其典型應(yīng)用是“油漆桶”。例如在一個(gè)具有多片聯(lián)通區(qū)域的二維圖上,我們能用油漆桶尋找所需要的單片聯(lián)通區(qū)域。

  至于三維種子點(diǎn)生長,其目的與二維種子點(diǎn)生長一樣,都是要找出圖像中的聯(lián)通區(qū)域。三維圖像由于其多了一維,所以三維的聯(lián)通區(qū)域就不太好用二維圖片來查看了。關(guān)于三位圖片的介紹可以參考第一篇“圖像數(shù)據(jù)的組織方式。不過借助一些三維可視化軟件,如ParaView,我們也可以觀察三維圖像的內(nèi)容。

  下面的圖片是顯示在ParaView下打開一張三維圖片Lobster.raw的結(jié)果,我們通過調(diào)節(jié)不同體素值的透明度,就能凸顯出三維圖像中所需要關(guān)心的內(nèi)容。

圖像預(yù)覽
像素透明度曲線

  從上圖看,由于三維圖像本身是個(gè)長方體,各個(gè)像素有自己的顏色,所以只能看到外表面的樣子。順便提一下,在三維圖像中,我們一般不使用“像素”這個(gè)詞,而是使用“體素”來形容組成圖像的這些單元。我們可以使用ParaView體繪制屬性中調(diào)節(jié)透明度的選項(xiàng),把一部分值較小的體素設(shè)為透明,就能看到這個(gè)三維圖像中,值較大的體素就像一個(gè)個(gè)小磚頭一樣堆成了一個(gè)龍蝦的形狀。也就是說,如果我們在這些體素中找一個(gè)種子點(diǎn),利用三維圖像種子點(diǎn)生長算法,就能找到所有組成這個(gè)龍蝦的體素。

  上一篇文章已經(jīng)介紹了二維種子點(diǎn)生長算法的相關(guān)知識,介紹了三種種子點(diǎn)生長算法—泛洪法、掃描線法和區(qū)段法,并在最后分析了他們的性能。本文的核心部分是三維種子點(diǎn)點(diǎn)生長的討論,也就是把上一篇文章的算法擴(kuò)展到三維,那么本文也按照相同的結(jié)構(gòu)來說明這三種算法是如何擴(kuò)展到三維的。

  • 泛洪法
  • 掃描線法
  • 區(qū)段法
  • 算法分析與實(shí)驗(yàn)
  • 一、泛洪法

      泛洪法的基本思想上篇文章詳細(xì)介紹過,在三維圖像中,需要擴(kuò)展的主要是鄰域的范圍。鄰域從二維擴(kuò)展到三維后,就不再是四鄰域和八鄰域而是六鄰域和二十六鄰域。示意圖如下:

      其中綠色的點(diǎn)表示為當(dāng)前點(diǎn)(藍(lán)色點(diǎn))的6鄰域,綠色+紅色的點(diǎn)為這個(gè)像素的26鄰域。

      對于三維點(diǎn)P,P的6鄰域可以表示為:

        S=Adj6(P)={P0(P.X-1,P.Y,P.Z),P1(P.X+1,P.Y,P.Z),P2(P.X,P.Y-1,P.Z),P3(P.X,P.Y+1P.Z),P4(P.X,P.Y,P.Z-1),P5(P.X,P.Y,P.Z+1)}。

      P的26鄰域可以表示為:

        S=Adj26(P)={P0(P.X-1,P.Y,P.Z),P1(P.X+1,P.Y,P.Z),P2(P.X,P.Y-1,P.Z),P3(P.X,P.Y+1,P.Z),

                P4(P.X-1,P.Y-1,P.Z),P5(P.X+1,P.Y+1,P.Z),P6(P.X+1,P.Y-1,P.Z),P7(P.X-1,P.Y+1,P.Z),

                P8(P.X-1,P.Y-1,P.Z-1),P9(P.X+1,P.Y+1,P.Z-1),P10(P.X+1,P.Y-1,P.Z-1),P11(P.X-1,P.Y+1,P.Z-1)

                P12(P.X,P.Y-1,P.Z-1),P13(P.X,P.Y+1,P.Z-1),P14(P.X+1,P.Y,P.Z-1),P15(P.X-1,P.Y,P.Z-1),

                P16(P.X,P.Y,P.Z-1),P17(P.X,P.Y,P.Z+1),P18(P.X+1,P.Y-1,P.Z+1),P19(P.X-1,P.Y+1,P.Z+1),

                P20(P.X-1,P.Y-1,P.Z+1),P21(P.X+1,P.Y+1,P.Z+1),P22(P.X,P.Y-1,P.Z+1),P23(P.X,P.Y+1,P.Z+1)

                P24(P.X-1,P.Y,P.Z+1),P25(P.X+1,P.Y,P.Z+1)}。

      那么實(shí)際上,三維泛洪法采用和二維泛洪法一樣的邏輯。

    FloodFill(seed,bitmap,includePredicate,process)set all postions of flagMap to falseset container Q to empty.push seed into Qset seed position in flagMap to trueprocess(seed)while Q is not emptypop a point P from Qforeach point T in Adj(P)if includePredicate(T) is trueset position of T in flagMap to truepush T into Qprocess(T)end

      注意在三維的情況下,相應(yīng)的點(diǎn)類、圖像類、位圖標(biāo)記表類等基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)都需要分別增加一維。相應(yīng)類的c#定義如下:

    public struct Int16Triple{public int X;public int Y;public int Z;public Int16Triple(int x, int y,int z){X = x;Y = y;Z = z;}}public class BitMap3d{public const byte WHITE = 255;public const byte BLACK = 0;public byte[] data;public int width;public int height;public int depth;public BitMap3d(int width, int height,int depth, byte v){this.width = width;this.height = height;this.depth = depth;data = new byte[width * height * depth];for (int i = 0; i < width * height*depth; i++)data[i] = v;}public BitMap3d(byte[] data, int width, int height,int depth){this.data = data;this.width = width;this.height = height;this.depth = depth;}public void SetPixel(int x, int y,int z,byte v){data[x + y * width+z*width*height] = v;}public byte GetPixel(int x, int y,int z){return data[x + y * width+z*width*height];}public void ReadRaw(string path){FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);fs.Read(data, 0, width*height*depth);fs.Close();}public void SaveRaw(string path){FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);fs.Write(data, 0, data.Length);fs.Close();}}public class FlagMap3d{public int width;public int height;public int depth;BitArray flags;public FlagMap3d(int width, int height,int depth){this.width = width;this.height = height;this.depth = depth;flags = new BitArray(width * height*depth, false);}public void SetFlagOn(int x, int y, int z,bool v){flags[x + y * width+z*width*height] = v;}public bool GetFlagOn(int x, int y,int z){return flags[x + y * width+z*width*height];} }

      相應(yīng)實(shí)現(xiàn)的c#代碼如下:

    class FloodFill3d{protected BitMap3d bmp;protected FlagMap3d flagsMap;protected Container<Int16Triple> container;protected int count = 0;public byte min;public byte max;protected bool IncludePredicate(Int16Triple p){byte v = bmp.GetPixel(p.X, p.Y, p.Z);return v > min && v < max;}protected void Process(Int16Triple p){count++;return;}protected virtual void ExcuteFloodFill(BitMap3d data, Int16Triple seed){this.bmp = data;data.ResetVisitCount();flagsMap = new FlagMap3d(data.width, data.height,data.depth);Int16Triple[] adjPoints6 = new Int16Triple[6];flagsMap.SetFlagOn(seed.X, seed.Y, seed.Z,true);container.Push(seed);Process(seed);while (!container.Empty()){Int16Triple p = container.Pop();InitAdj6(ref adjPoints6, ref p);for (int adjIndex = 0; adjIndex < 6; adjIndex++){Int16Triple t = adjPoints6[adjIndex];if (t.X < data.width && t.X >= 0 && t.Y < data.height && t.Y >= 0&&t.Z<data.depth&&t.Z>=0){if (!flagsMap.GetFlagOn(t.X, t.Y,t.Z) && IncludePredicate(t)){flagsMap.SetFlagOn(t.X, t.Y,t.Z, true);container.Push(t);Process(t);}}}}return;}protected void InitAdj6(ref Int16Triple[] adjPoints6, ref Int16Triple p){adjPoints6[0].X = p.X - 1;adjPoints6[0].Y = p.Y;adjPoints6[0].Z = p.Z;adjPoints6[1].X = p.X + 1;adjPoints6[1].Y = p.Y;adjPoints6[1].Z = p.Z;adjPoints6[2].X = p.X;adjPoints6[2].Y = p.Y - 1;adjPoints6[2].Z = p.Z;adjPoints6[3].X = p.X;adjPoints6[3].Y = p.Y + 1;adjPoints6[3].Z = p.Z;adjPoints6[4].X = p.X;adjPoints6[4].Y = p.Y;adjPoints6[4].Z = p.Z-1;adjPoints6[5].X = p.X;adjPoints6[5].Y = p.Y;adjPoints6[5].Z = p.Z+1;}}

    二、掃描線法

      二維的掃描線法,是從一個(gè)點(diǎn)彈出堆棧后,對其左右掃描出兩個(gè)端點(diǎn),然后再對端點(diǎn)范圍的兩側(cè)即Y-1和Y+1方向進(jìn)行CheckRange。算法拓展到三維,只需增加檢查Z-1和Z+1方向即可。也就是“兩側(cè)”變成了“四側(cè)”,即:

  • (xleft,p.Y-1,p.Z)~(xright,p.Y-1,p.Z)
  • (xleft,p.Y+1,p.Z)~(xright,p.Y+1,p.Z)
  • (xleft,p.Y,p.Z-1)~(xright,p.Y,p.Z-1)
  • (xleft,p.Y,p.Z+1)~(xright,p.Y,p.Z+1)
  •   掃描這四條線等價(jià)于6向泛洪法,假如掃描下面八條線,就相當(dāng)于26向泛洪法

  • (xleft-1,p.Y-1,p.Z)~(xright+1,p.Y-1,p.Z)
  • (xleft-1,p.Y+1,p.Z)~(xright+1,p.Y+1,p.Z)
  • (xleft-1,p.Y,p.Z-1)~(xright+1,p.Y,p.Z-1)
  • (xleft-1,p.Y,p.Z+1)~(xright+1,p.Y,p.Z+1)
  • (xleft-1,p.Y-1,p.Z-1)~(xright+1,p.Y-1,p.Z-1)
  • (xleft-1,p.Y+1,p.Z+1)~(xright+1,p.Y+1,p.Z+1)
  • (xleft-1,p.Y+1,p.Z-1)~(xright+1,p.Y+1,p.Z-1)
  • (xleft-1,p.Y-1,p.Z+1)~(xright+1,p.Y-1,p.Z+1)
  •   掃描線法拓展到三維,基本操作FindXleft,FindXright,CheckRange分別修改至相應(yīng)的三維即可。其作用沒有任何變化。

      下面是三維掃描線線的c#代碼:

    class ScanlineFill3d{protected int count = 0;protected Container<Int16Triple> container;//這個(gè)容器可以是Queue和Stack中任意一種,這里抽象成一個(gè)Containerprotected BitMap3d bmp;public FlagMap3d flagsMap;protected virtual void ExcuteScanlineFill(BitMap3d data, Int16Triple seed){this.bmp = data;data.ResetVisitCount();flagsMap = new FlagMap3d(data.width, data.height, data.depth);flagsMap.SetFlagOn(seed.X, seed.Y, seed.Z, true);container.Push(seed);Process(seed);while (!container.Empty()){Int16Triple p = container.Pop();int xleft = FindXLeft(p);int xright = FindXRight(p);if (p.Y - 1 >= 0)CheckRange(xleft, xright, p.Y - 1, p.Z);if (p.Y + 1 < data.height)CheckRange(xleft, xright, p.Y + 1, p.Z);if (p.Z - 1 >= 0)CheckRange(xleft, xright, p.Y, p.Z - 1);if (p.Z + 1 < data.depth)CheckRange(xleft, xright, p.Y, p.Z + 1);}}//該函數(shù)為掃描線法主體protected void CheckRange(int xleft, int xright, int y, int z){for (int i = xleft; i <= xright; ){if ((!flagsMap.GetFlagOn(i, y, z)) && IncludePredicate(i, y, z)){int rb = i + 1;while (rb <= xright && (!flagsMap.GetFlagOn(rb, y, z)) && IncludePredicate(rb, y, z)){rb++;}rb--;Int16Triple t = new Int16Triple(rb, y, z);flagsMap.SetFlagOn(rb, y, z, true);container.Push(t);Process(t);i = rb + 1;}else{i++;}}}//CheckRange操作protected int FindXLeft(Int16Triple p){int xleft = p.X - 1;while (true){if (xleft == -1 || flagsMap.GetFlagOn(xleft, p.Y, p.Z)){break;}else{byte value = bmp.GetPixel(xleft, p.Y, p.Z);if (IncludePredicate(xleft, p.Y, p.Z)){Int16Triple t = new Int16Triple(xleft, p.Y, p.Z);flagsMap.SetFlagOn(xleft, p.Y, p.Z, true);Process(t);xleft--;}else{break;}}}return xleft + 1;}//FindXLeft操作protected int FindXRight(Int16Triple p){int xright = p.X + 1;while (true){if (xright == bmp.width || flagsMap.GetFlagOn(xright, p.Y, p.Z)){break;}else{byte value = bmp.GetPixel(xright, p.Y, p.Z);if (IncludePredicate(xright, p.Y, p.Z)){Int16Triple t = new Int16Triple(xright, p.Y, p.Z);flagsMap.SetFlagOn(xright, p.Y, p.Z, true);Process(t);xright++;}else{break;}}}return xright - 1;}//FindXRight操作public byte min;public byte max;protected bool IncludePredicate(int x,int y,int z){byte v = bmp.GetPixel(x, y,z);return v > min && v < max;}protected void Process(Int16Triple p){count++;}}

    三、區(qū)段法

      區(qū)段法擴(kuò)展到三維也遵循和掃描線法一樣的原則,相應(yīng)的基本操作FindXleft,FindXright,CheckRange需要分別修改到三維的情況。同時(shí)在主函數(shù)邏輯中,監(jiān)測相應(yīng)的相鄰區(qū)段時(shí)要注意ParentDirection所指示的父區(qū)段的特殊性。

      下面是三維區(qū)段法的C#代碼:

    enum ParentDirections{Y0 = 1, Y2 = 2,Z0=3,Z2=4, Non = 5}enum ExtendTypes{LeftRequired = 1, RightRequired = 2, AllRez = 3, UnRez = 4}struct Span{public int XLeft;public int XRight;public int Y;public int Z;public ExtendTypes Extended;public ParentDirections ParentDirection;}class SpanFill3d{protected int count = 0;protected BitMap3d bmp;public FlagMap3d flagsMap;protected Container<Span> container;//以Span為單位的Queue或Stack容器protected virtual void ExcuteSpanFill(BitMap3d data, Int16Triple seed){this.bmp = data;data.ResetVisitCount();flagsMap = new FlagMap3d(data.width, data.height,data.depth);Process(seed);flagsMap.SetFlagOn(seed.X, seed.Y,seed.Z, true);Span seedspan = new Span();seedspan.XLeft = seed.X;seedspan.XRight = seed.X;seedspan.Y = seed.Y;seedspan.Z = seed.Z;seedspan.ParentDirection = ParentDirections.Non;seedspan.Extended = ExtendTypes.UnRez;container.Push(seedspan);while (!container.Empty()){Span span = container.Pop();#region AllRezif (span.Extended == ExtendTypes.AllRez){if (span.ParentDirection == ParentDirections.Y2){if (span.Y - 1 >= 0)//[spx-spy,y-1,z]CheckRange(span.XLeft, span.XRight, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Z - 1 >= 0)//[spx-spy,y,z-1]CheckRange(span.XLeft, span.XRight, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < data.depth)//[spx-spy,y,z+1]CheckRange(span.XLeft, span.XRight, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Y0){if (span.Y + 1 < bmp.height)//[spx-spy,y+1,z]CheckRange(span.XLeft, span.XRight, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 > 0)//[spx-spy,y,z-1]CheckRange(span.XLeft, span.XRight, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < data.depth)//[spx-spy,y,z+1]CheckRange(span.XLeft, span.XRight, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Z2){if (span.Y - 1 >= 0)//[spx-spy,y-1,z]CheckRange(span.XLeft, span.XRight, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)//[spx-spy,y+1,z]CheckRange(span.XLeft, span.XRight, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)//[spx-spy,y,z-1]CheckRange(span.XLeft, span.XRight, span.Y, span.Z - 1, ParentDirections.Z2);continue;}if (span.ParentDirection == ParentDirections.Z0){if (span.Y - 1 >= 0)CheckRange(span.XLeft, span.XRight, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(span.XLeft, span.XRight, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z + 1 < data.depth)CheckRange(span.XLeft, span.XRight, span.Y, span.Z + 1, ParentDirections.Z0);continue;}throw new Exception();}#endregion#region UnRezif (span.Extended == ExtendTypes.UnRez){int xl = FindXLeft(span.XLeft, span.Y,span.Z);int xr = FindXRight(span.XRight, span.Y,span.Z);if (span.ParentDirection == ParentDirections.Y2){if (span.Y - 1 >= 0)CheckRange(xl, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height){if (xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y + 1, span.Z, ParentDirections.Y0);if (span.XRight != xr)CheckRange(span.XRight, xr, span.Y + 1, span.Z, ParentDirections.Y0);}if (span.Z - 1 >= 0)CheckRange(xl, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(xl, xr, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Y0){if (span.Y + 1 < bmp.height)CheckRange(xl, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Y - 1 >= 0){if (xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y - 1, span.Z, ParentDirections.Y2);if (span.XRight != xr)CheckRange(span.XRight, xr, span.Y - 1, span.Z, ParentDirections.Y2);}if (span.Z - 1 >= 0)CheckRange(xl, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(xl, xr, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Z2){if (span.Y - 1 >= 0)CheckRange(xl, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(xl, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)CheckRange(xl, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth){if (xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y, span.Z+1, ParentDirections.Z0);if (span.XRight != xr)CheckRange(span.XRight, xr, span.Y, span.Z+1, ParentDirections.Z0);}continue;}if (span.ParentDirection == ParentDirections.Z0){if (span.Y - 1 >= 0)CheckRange(xl, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(xl, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0){if (xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y, span.Z -1, ParentDirections.Z2);if (span.XRight != xr)CheckRange(span.XRight, xr, span.Y, span.Z - 1, ParentDirections.Z2);}if (span.Z + 1 < bmp.depth)CheckRange(xl, xr, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Non){if (span.Y + 1 < bmp.height)CheckRange(xl, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Y - 1 >= 0)CheckRange(xl, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Z - 1 >= 0)CheckRange(xl, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(xl, xr, span.Y, span.Z + 1, ParentDirections.Z0);continue;}throw new Exception();}#endregion#region LeftRequiredif (span.Extended == ExtendTypes.LeftRequired){int xl = FindXLeft(span.XLeft, span.Y,span.Z);if (span.ParentDirection == ParentDirections.Y2){if (span.Y - 1 >= 0)CheckRange(xl, span.XRight, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height && xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)CheckRange(xl, span.XRight, span.Y , span.Z-1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(xl, span.XRight, span.Y , span.Z+1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Y0){if (span.Y - 1 >= 0 && xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(xl, span.XRight, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)CheckRange(xl, span.XRight, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(xl, span.XRight, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Z2){if (span.Y - 1 >= 0 )CheckRange(xl, span.XRight, span.Y - 1, span.Z, ParentDirections.Y2); if (span.Y + 1 < bmp.height)CheckRange(xl, span.XRight, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)CheckRange(xl, span.XRight, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth && xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Z0){if (span.Y - 1 >= 0)CheckRange(xl, span.XRight, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(xl, span.XRight, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0 && xl != span.XLeft)CheckRange(xl, span.XLeft, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth )CheckRange(xl, span.XRight, span.Y, span.Z + 1, ParentDirections.Z0);continue;}throw new Exception();}#endregion#region RightRequiredif (span.Extended == ExtendTypes.RightRequired){int xr = FindXRight(span.XRight, span.Y,span.Z);if (span.ParentDirection == ParentDirections.Y2){if (span.Y - 1 >= 0)CheckRange(span.XLeft, xr, span.Y - 1,span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height && span.XRight != xr)CheckRange(span.XRight, xr, span.Y + 1,span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)CheckRange(span.XLeft, xr, span.Y, span.Z-1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(span.XLeft, xr, span.Y, span.Z+1, ParentDirections.Z0); continue;}if (span.ParentDirection == ParentDirections.Y0){if (span.Y + 1 < bmp.height)CheckRange(span.XLeft, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Y - 1 >= 0 && span.XRight != xr)CheckRange(span.XRight, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Z - 1 >= 0)CheckRange(span.XLeft, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(span.XLeft, xr, span.Y, span.Z + 1, ParentDirections.Z0); continue;}if (span.ParentDirection == ParentDirections.Z2){if (span.Y - 1 >= 0)CheckRange(span.XLeft, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(span.XLeft, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0)CheckRange(span.XLeft, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth && span.XRight != xr)CheckRange(span.XRight, xr, span.Y, span.Z + 1, ParentDirections.Z0);continue;}if (span.ParentDirection == ParentDirections.Z0){if (span.Y - 1 >= 0)CheckRange(span.XLeft, xr, span.Y - 1, span.Z, ParentDirections.Y2);if (span.Y + 1 < bmp.height)CheckRange(span.XLeft, xr, span.Y + 1, span.Z, ParentDirections.Y0);if (span.Z - 1 >= 0 && span.XRight != xr)CheckRange(span.XRight, xr, span.Y, span.Z - 1, ParentDirections.Z2);if (span.Z + 1 < bmp.depth)CheckRange(span.XLeft, xr, span.Y, span.Z + 1, ParentDirections.Z0); continue;}throw new Exception();}#endregion}}protected void CheckRange(int xleft, int xright, int y, int z,ParentDirections ptype){for (int i = xleft; i <= xright; ){if ((!flagsMap.GetFlagOn(i, y,z)) && IncludePredicate(i, y,z)){int lb = i;int rb = i + 1;while (rb <= xright && (!flagsMap.GetFlagOn(rb, y,z)) && IncludePredicate(rb, y,z)){rb++;}rb--;Span span = new Span();span.XLeft = lb;span.XRight = rb;span.Y = y;span.Z = z;if (lb == xleft && rb == xright){span.Extended = ExtendTypes.UnRez;}else if (rb == xright){span.Extended = ExtendTypes.RightRequired;}else if (lb == xleft){span.Extended = ExtendTypes.LeftRequired;}else{span.Extended = ExtendTypes.AllRez;}span.ParentDirection = ptype;for (int j = lb; j <= rb; j++){flagsMap.SetFlagOn(j, y,z, true);Process(new Int16Triple(j, y,z));}container.Push(span);i = rb + 1;}else{i++;}}}//區(qū)段法的CheckRange 注意與掃描線的CheckRange的不同protected int FindXRight(int x, int y,int z){int xright = x + 1;while (true){if (xright == bmp.width || flagsMap.GetFlagOn(xright, y,z)){break;}else{if (IncludePredicate(xright, y,z)){Int16Triple t = new Int16Triple(xright, y,z);flagsMap.SetFlagOn(xright, y,z ,true);Process(t);xright++;}else{break;}}}return xright - 1;}protected int FindXLeft(int x, int y,int z){int xleft = x - 1;while (true){if (xleft == -1 || flagsMap.GetFlagOn(xleft, y, z)){break;}else{if (IncludePredicate(xleft, y,z)){Int16Triple t = new Int16Triple(xleft, y,z);flagsMap.SetFlagOn(xleft, y,z, true);Process(t);xleft--;}else{break;}}}return xleft + 1;}public byte min;public byte max;protected bool IncludePredicate(int x, int y, int z){byte v = bmp.GetPixel(x, y, z);return v > min && v < max;}protected void Process(Int16Triple p){count++;}}

    ?四、算法測試與實(shí)驗(yàn)

      算法測試采用來自http://www.volvis.org的5組體數(shù)據(jù),注意這里的閾值范圍是值一個(gè)體素值的范圍(min,max),在此范圍內(nèi)的體素才納入?yún)^(qū)域。也就是說本文的includePredicate不再是跟上一篇一樣是判斷像素灰度為255的納入?yún)^(qū)域,而是判斷是否在這個(gè)(min,max)的范圍內(nèi)。

    圖像預(yù)覽 數(shù)據(jù)名稱 參數(shù)說明

    Lobster

    • 大小:301×324×56
    • 文件:Lobster.raw
    • 種子點(diǎn):(124,?168,?27)
    • 閾值范圍:37~255
    • 描述:CT?scan?of?a?lobster?contained?in?a?block?of?resin.
    engine
    • 大小:256×256×128
    • 文件:Engine.raw
    • 種子點(diǎn):(149,?44,?43)
    • 閾值范圍:64~255
    • 描述:CT?scan?of?two?cylinders?of?an?engine?block.
    backpack
    • 大小:301×324×56
    • 文件:Backpack.raw
    • 種子點(diǎn):(53,?390,?160)
    • 閾值范圍:46~255
    • 描述:CT?scan?of?a?backpack?filled?with?items.
    phantom
    • 大小:512×512×442
    • 文件:Phantom.raw
    • 種子點(diǎn):(256,256,227)
    • 閾值范圍:42~255
    • 描述:CT?scan?of?a?Colon?phantom?with?several?different?objects?and?five?pedunculated?large polyps?in?the?central?object.
    cube

    ?

    • 大小:200×200×200
    • 文件:Cube.raw
    • 種子點(diǎn):(50,50,50)
    • 閾值范圍:0~255
    • 描述:全白色,用于測試全部充滿的極端情況

      測試結(jié)果如下:

    測試數(shù)據(jù) 泛洪法(棧式) 泛洪法(隊(duì)列式) 掃描線法(棧式) 掃描線法(隊(duì)列式) 區(qū)段法(棧式) 區(qū)段法(隊(duì)列式) 區(qū)域點(diǎn)數(shù)
    lobster 86ms 76ms 56ms 64ms 40ms 47ms 277367
    engine 329ms 345ms 216ms 254ms 137ms 183ms 1154807
    backpack 596ms 638ms 426ms 470ms 319ms 351ms 19115450
    phantom 13468ms 14118ms 6520ms 8279ms 3701ms 4066ms 39759257
    cube 2120ms 2259ms 1292ms 1404ms 691ms 692ms 800000

      對于其中的backpack數(shù)據(jù)的單元訪問比例統(tǒng)計(jì)如下:

    算法 GetPixel/總點(diǎn)數(shù) GetFlagOn/總點(diǎn)數(shù) SetFlagOn/總點(diǎn)數(shù) Push和Pop/總點(diǎn)數(shù) 總點(diǎn)數(shù) 時(shí)間花費(fèi)
    泛洪法(棧式) 1.945581 5.997103 1.0 1.0 1915450 596ms
    泛洪法(隊(duì)列式) 1.945581 5.997103 1.0 1.0 1915450 638ms
    掃描線法(棧式) 4.165088 5.337406 1.0 0.2668 1915450 426ms
    掃描線法(隊(duì)列式) 2.715424 5.774523 1.0 0.7589 1915450 470ms
    區(qū)段法(棧式) 1.911485 3.526728 1.0 0.2147 1915450 319ms
    區(qū)段法(隊(duì)列式) 1.931963 3.754333 1.0 0.3628 1915450 351ms

      通過測試可以看出,相比于二維種子點(diǎn)生長,由于多了一維,所以利用X軸數(shù)據(jù)連續(xù)特性所能達(dá)到增加效率的效果明顯減弱。既可以從時(shí)間結(jié)果上看,也可以從單元訪問比例上看,都能得到這一結(jié)論。不過從整體上看,效率上仍然能夠得出如下結(jié)論:棧式算法略塊于隊(duì)列式算法;區(qū)段法快于掃描線法,掃描線法快于泛洪法。

    總結(jié)

    以上是生活随笔為你收集整理的种子点生长算法下——三维种子点生长的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。