/// <summary> /// 主連結成分(体積最大の連結成分)の構造抽出 /// </summary> public void ExtractMainDendrite() { // SSDT //処理対象のクラスタ (体積が最大のもの) List <Point3DExd> scluster = clusters_e[0]; //距離変換 // Point3DExd initial = scluster[0]; //距離変換開始点 初めは適当に選択 // BFSを2回行うことで、最も距離の離れた2点間の距離を得る uint maxdistance = SSDTLoopEco(scluster); // 木構造生成 main_dendrite = new Dendrite((int)maxdistance + 1, param.resolutionXY, param.resolutionZ); foreach (var tmp in scluster) { if (!tmp.flag) { //同一距離値クラスタ var cld = new List <Point3Di>(); //距離値でクラスタリング RecursiveDistanceClusteringEco(tmp, cld); main_dendrite.AddNode((int)tmp.Distance, cld); } } //木構造生成 main_dendrite.CreateNodeTree(); }
private void SetSwcHeader(Dendrite d) { d.SwcHeader.SetVersionDate(); d.SwcHeader.SetSource(param.ipath); d.SwcHeader.SetScale(param.resolutionXY, param.resolutionXY, param.resolutionZ); d.SwcHeader.SetRootSetting(false); d.SwcHeader.SetInterpolation(param.interporation); if (param.interporation) { d.SwcHeader.SetInterpolation(true); d.SwcHeader.SetDistanceThreshold(param.distanceThreshold); d.SwcHeader.SetVolumeThreshold(param.volumeThreshold); } if (param.shavingLevel > 0) { d.SwcHeader.SetClipping(param.shavingLevel); } if (param.smoothingLevel > 0) { d.SwcHeader.SetSmoothing(param.smoothingLevel); } }
private void Write(string fname, Dendrite dendrite) { sbmain = new StringBuilder(); tmp = new StringBuilder(); tmpsb = new StringBuilder(); // VTKフォーマットの仕様書はこちら http://www.vtk.org/VTK/img/file-formats.pdf // このあたりの情報良さそう http://www.cacr.caltech.edu/~slombey/asci/vtk/vtk_formats.simple.html sbmain.AppendLine("# vtk DataFile Version 2.0"); // おまじない sbmain.AppendLine("Colored Dendrite"); // タイトル sbmain.AppendLine("ASCII"); // テキストで記述する (VTKはバイナリでも記述できる) sbmain.AppendLine("DATASET POLYDATA"); // lineで記述したい // 点データの記述 sbmain.AppendLine("POINTS " + dendrite.GetDendriteNodeNum().ToString() + " float"); OutputVTKPointsRec(dendrite.root, null); // 線データの記述 nlines = 0; // 線の本数 nlpoint = 0; // 1本の線を構成する点の個数 ndata = 0; // 書き込むデータの個数 flag = false; // 書き込みの途中であるか? OutputVTKLinesRec(dendrite.root, null); sbmain.AppendLine("LINES " + nlines.ToString() + " " + ndata.ToString()); sbmain.Append(tmpsb.ToString()); sbmain.AppendLine("POINT_DATA " + dendrite.GetDendriteNodeNum().ToString()); sbmain.AppendLine("SCALARS distance float 1"); sbmain.AppendLine("LOOKUP_TABLE default"); OutputVTKDistanceRec(dendrite.root, null); sbmain.AppendLine("SCALARS radius float 1"); sbmain.AppendLine("LOOKUP_TABLE radius"); OutputVTKRadiusRec(dendrite.root, null); sbmain.AppendLine("SCALARS functionaldistance float 1"); sbmain.AppendLine("LOOKUP_TABLE functionaldistance"); OutputVTKFDistanceRec(dendrite.root, null); sbmain.AppendLine("SCALARS degree int 1"); sbmain.AppendLine("LOOKUP_TABLE degree"); OutputVTKDegreeRec(dendrite.root, null); using (StreamWriter sw = new StreamWriter(Path.ChangeExtension(fname, ".vtk"))) { sw.Write(sbmain.ToString()); } }
public void SaveAsPajekFormat(String fname, Dendrite dend) { using (StreamWriter sw = new StreamWriter(System.IO.Path.ChangeExtension(fname, ".net"))) { sw.WriteLine("*Vertices {0}", dend.branch + dend.edge); int count = 1; PajekVerticesRD(sw, dend, dend.root, null, ref count); count = 1; sw.WriteLine("*Edges"); PajekEdgesRD(sw, dend.root, null, null); } }
/// <summary> /// DendriteインスタンスをSWCファイルに出力 /// </summary> /// <param name="filename">出力ファイル名</param> public void SaveToSWC(string filename, Dendrite dend) { // 拡張子をつける filename = Path.ChangeExtension(filename, ".swc"); using (var writer = new StreamWriter(filename)) { foreach (var line in dend.SwcHeader.PublishHeader()) { writer.WriteLine(line); } SaveToSWCRec(dend.root, null, writer); } }
public void SaveAsCytoscapeFreeFormat(String fname, Dendrite dend) { string nameEdges = Path.GetFileNameWithoutExtension(fname) + "_edge.txt"; string nameNodes = Path.GetFileNameWithoutExtension(fname) + "_node.txt"; using (StreamWriter swe = new StreamWriter(nameEdges)) using (StreamWriter swn = new StreamWriter(nameNodes)) { int count = 1; CytNodes(swn, dend, dend.root, null, ref count); count = 1; CytEdges(swe, dend, dend.root, null, null); } }
void CytNodes(StreamWriter sw, Dendrite dend, DendriteNode node, DendriteNode parent, ref int count) { if (node.NodeType != DendriteNodeType.CONNECT) { node.Id = count; sw.WriteLine("{0} {1} {2} {3} {4} {5}", count++, node.RealDistance, node.ElectricalDistance, (node.gx - dend.XMin) / (dend.XMax - dend.XMin), (node.gy - dend.YMin) / (dend.YMax - dend.YMin), (node.gz - dend.ZMin) / (dend.ZMax - dend.ZMin)); } foreach (DendriteNode next in node.ConnectedNodes) { if (next != parent) { CytNodes(sw, dend, next, node, ref count); } } }
// 参考情報: SWCファイルのフォーマット // 1. ノードID (1オリジン) // 2. NodeType (0:undefined, 1:soma, 2:axon, 3:dendrite, 4:apical dendrite, 5:fork point(ブランチ), 6:end point(エッジ), 7:custom) // 3,4,5. x座標,y座標,z座標 // 6. 半径 // 7. 親ノード (1オリジン, ルートノードの親ノードは-1) // http://research.mssm.edu/cnic/swc.html private IEnumerable <Dendrite> ParseSWC(IEnumerable <string> fileContents) { // nodeId -> DendriteNode var nodelist = new Dictionary <int, DendriteNode>(); var parser = new SwcParser(fileContents); foreach (var swcNode in parser.GetSwcNode()) { DendriteNode node = new DendriteNode(swcNode); nodelist.Add(node.Id, node); } // 1つのSWCファイルにルートノードは1つとは限らないので配列にしてある List <Dendrite> dendrites = new List <Dendrite>(); foreach (var node in nodelist.Values) { int parentNodeId = node.Distance; // nodeがルートノードだったとき if (parentNodeId == -1) { Dendrite dend = new Dendrite(/* maxdist = */ 0, /* rx = */ 1.0, /* rz = */ 1.0); dend.root = node; dendrites.Add(dend); } else { // nodeとその親ノードを連結する var parentNode = nodelist[parentNodeId]; parentNode.ConnectedNodes.Add(node); node.ConnectedNodes.Add(parentNode); } } // 1つのSWCファイルにルートノードは1つとは限らないので // それぞれについてツリー構造を生成 foreach (Dendrite dend in dendrites) { dend.Create(); dend.SwcHeader.InitBySwcComments(parser.Comments); } return(dendrites); }
// 参考情報: SWCファイルのフォーマット // 1. ノードID (1オリジン) // 2. NodeType (0:undefined, 1:soma, 2:axon, 3:dendrite, 4:apical dendrite, 5:fork point(ブランチ), 6:end point(エッジ), 7:custom) // 3,4,5. x座標,y座標,z座標 // 6. 半径 // 7. 親ノード (1オリジン, ルートノードの親ノードは-1) // http://research.mssm.edu/cnic/swc.html private IEnumerable<Dendrite> ParseSWC(IEnumerable<string> fileContents) { // nodeId -> DendriteNode var nodelist = new Dictionary<int, DendriteNode>(); var parser = new SwcParser(fileContents); foreach (var swcNode in parser.GetSwcNode()) { DendriteNode node = new DendriteNode(swcNode); nodelist.Add(node.Id, node); } // 1つのSWCファイルにルートノードは1つとは限らないので配列にしてある List<Dendrite> dendrites = new List<Dendrite>(); foreach (var node in nodelist.Values) { int parentNodeId = node.Distance; // nodeがルートノードだったとき if (parentNodeId == -1) { Dendrite dend = new Dendrite(/* maxdist = */ 0, /* rx = */ 1.0, /* rz = */ 1.0); dend.root = node; dendrites.Add(dend); } else { // nodeとその親ノードを連結する var parentNode = nodelist[parentNodeId]; parentNode.ConnectedNodes.Add(node); node.ConnectedNodes.Add(parentNode); } } // 1つのSWCファイルにルートノードは1つとは限らないので // それぞれについてツリー構造を生成 foreach (Dendrite dend in dendrites) { dend.Create(); dend.SwcHeader.InitBySwcComments(parser.Comments); } return dendrites; }
void PajekVerticesRD(StreamWriter sw, Dendrite dend, DendriteNode node, DendriteNode parent, ref int count) { if (node.NodeType != DendriteNodeType.CONNECT) { node.Id = count; sw.WriteLine("{0} \"{1}\" {2} {3} {4} ", count++, node.RealDistance, (node.gx - dend.XMin) / (dend.XMax - dend.XMin), (node.gy - dend.YMin) / (dend.YMax - dend.YMin), (node.gz - dend.ZMin) / (dend.ZMax - dend.ZMin)); //sw.WriteLine("{0} {1}", count++, node.RealDistance); } foreach (DendriteNode next in node.ConnectedNodes) { if (next != parent) { PajekVerticesRD(sw, dend, next, node, ref count); } } }
private void OutputSubDendrite() { DendriteIO io = new DendriteIO(); string rawFilename = Path.GetFileNameWithoutExtension(param.ofname); string dirname = Path.Combine(Path.GetDirectoryName(param.ofname), rawFilename + "-sub"); if (Directory.Exists(dirname)) { Directory.Delete(dirname, true); } Directory.CreateDirectory(dirname); // 出力するファイル名の末尾の桁数 // ファイル名は0オリジンにするので .Count - 1 にしている int digit = (NotMergedSubDendritesIdx.Count - 1).ToString().Length; // 出力するファイル名の末尾のID int sub_dendrite_id = 0; // 独立して存在している(他のノードに併合されていない)側枝ノードを、体積降順で並べ替える var orderByVolume = NotMergedSubDendritesIdx.OrderByDescending(x => sub_dendrites_volume[x]); foreach (int sub_index in orderByVolume) { Dendrite sdendrite = sub_dendrites[sub_index]; IList <DendriteNode> edge = sdendrite.GetEdgeNodes(); sdendrite.ChangeRootNode(edge[0]); string filename = CreateFileNameForSubDendriteIO(dirname, digit, sub_dendrite_id); string path = Path.Combine(dirname, filename); io.SaveToSWC(path, sdendrite); sub_dendrite_id++; if (param.outputVTK) { string vtkFilename = Path.ChangeExtension(filename, "vtk"); string vtkPath = Path.Combine(dirname, vtkFilename); VtkWriter.SaveToVTKLegacy(vtkPath, sdendrite); } } }
/// <summary> /// 副連結成分(体積最大の連結成分以外のやつ)の構造抽出 /// </summary> public void ExtractSubDendrites() { sub_dendrites = new List <Dendrite>(); sub_dendrites_volume = new List <int>(); for (uint i = 1; i < clusters_e.Count; i++) { IList <Point3DExd> scluster = clusters_e[i]; //処理対象クラスタ int volume = scluster.Count; //体積がしきい値を下回ったら戻る (ヒント: clusters_eは体積降順でソートされている) if (volume < param.volumeThreshold) { return; } uint subdistance = SSDTLoopEco(scluster); Dendrite subDendrite = new Dendrite((int)subdistance + 1, param.resolutionXY, param.resolutionZ); foreach (var tmp in scluster) { if (!tmp.flag) { var cld = new List <Point3Di>();//距離値クラスタリング用の一時リスト //距離値でクラスタリング RecursiveDistanceClusteringEco(tmp, cld); subDendrite.AddNode((int)tmp.Distance, cld); } } subDendrite.CreateNodeTree(); //subリストに追加 sub_dendrites.Add(subDendrite); sub_dendrites_volume.Add(volume); } }
void CytEdges(StreamWriter sw, Dendrite dend, DendriteNode node, DendriteNode parent, DendriteNode pnode) { if (pnode != null && node.NodeType != DendriteNodeType.CONNECT) { sw.WriteLine("{0} {1} {2} {3}", pnode.Id, node.Id, (node.RealDistance - pnode.RealDistance), (node.ElectricalDistance - pnode.ElectricalDistance)); } foreach (DendriteNode next in node.ConnectedNodes) { if (next != parent) { if (node.NodeType == DendriteNodeType.CONNECT) { CytEdges(sw, dend, next, node, pnode); } else { CytEdges(sw, dend, next, node, node); } } } }
public void SaveEdgeList(string fname, Dendrite dend) { StringBuilder[] sbs = new StringBuilder[dend.MaxDegree]; count = new int[dend.MaxDegree]; Array.Clear(count, 0, count.Length); for (int i = 0; i < dend.MaxDegree; i++) { sbs[i] = new StringBuilder(); flag = false; Edge(dend.root, null, i + 1, sbs[i]); } using (StreamWriter sw = new StreamWriter(fname)) { sw.WriteLine("# total length"); sw.WriteLine(dend.TotalLength); sw.WriteLine("# total e length"); sw.WriteLine(dend.TotalElectricalLength); sw.WriteLine("# count"); foreach (int c in count) { sw.Write("{0},", c); } sw.WriteLine(); int i = 1; foreach (StringBuilder sb in sbs) { sw.WriteLine("#{0}", i); sw.WriteLine(sb.ToString()); i++; } } }
public static void SaveToVTKLegacy(string fname, Dendrite dendrite) { var writer = new VtkWriter(); writer.Write(fname, dendrite); }
void CytEdges(StreamWriter sw, Dendrite dend, DendriteNode node, DendriteNode parent, DendriteNode pnode) { if (pnode != null && node.NodeType != DendriteNodeType.CONNECT) sw.WriteLine("{0} {1} {2} {3}", pnode.Id, node.Id, (node.RealDistance - pnode.RealDistance), (node.ElectricalDistance - pnode.ElectricalDistance)); foreach (DendriteNode next in node.ConnectedNodes) { if (next != parent) { if (node.NodeType == DendriteNodeType.CONNECT) CytEdges(sw, dend, next, node, pnode); else CytEdges(sw, dend, next, node, node); } } }
public void SaveEdgeList(string fname, Dendrite dend) { StringBuilder[] sbs = new StringBuilder[dend.MaxDegree]; count = new int[dend.MaxDegree]; Array.Clear(count, 0, count.Length); for (int i = 0; i < dend.MaxDegree; i++) { sbs[i] = new StringBuilder(); flag = false; Edge(dend.root, null, i + 1, sbs[i]); } using (StreamWriter sw = new StreamWriter(fname)) { sw.WriteLine("# total length"); sw.WriteLine(dend.TotalLength); sw.WriteLine("# total e length"); sw.WriteLine(dend.TotalElectricalLength); sw.WriteLine("# count"); foreach (int c in count) sw.Write("{0},", c); sw.WriteLine(); int i = 1; foreach (StringBuilder sb in sbs) { sw.WriteLine("#{0}", i); sw.WriteLine(sb.ToString()); i++; } } }
public void SaveAsTLP(String fname, Dendrite dend) { using (StreamWriter sw = new StreamWriter(System.IO.Path.ChangeExtension(fname, ".tlp"))) { sw.WriteLine("(tlp \"2.0\""); sw.WriteLine(" (date \"{0}\")", DateTime.Now); sw.WriteLine(" (comments \"This file was generated by SIGEN.\")"); int count; count = 1; //ノード生成 sw.Write(" (nodes "); // for (int i = 1; i <= dend.idsum; i++) sw.Write("{0} ", i); TLPNodes(sw, dend.root, null, ref count); sw.WriteLine(")"); ///プロパティ追加 /// ///viewColor sw.WriteLine(" (property 0 color \"viewColor\""); sw.WriteLine(" (default \"(0,0,0,255)\" \"(0,0,0,0)\" )"); sw.WriteLine(" )"); ///ノード座標 sw.WriteLine(" (property 0 layout \"viewLayout\""); sw.WriteLine(" (default \"(0,0,0)\" \"()\" )"); TLPCoord(sw, dend.root, null); sw.WriteLine(" )"); ///ノード半径 sw.WriteLine(" (property 0 double \"nodeRadius\""); sw.WriteLine(" (default \"0\" \"0\" )"); TLPRadius(sw, dend.root, null); sw.WriteLine(" )"); ///ノード距離 sw.WriteLine(" (property 0 double \"nodeRealDistance\""); sw.WriteLine(" (default \"0\" \"0\" )"); TLPDistance(sw, dend.root, null); sw.WriteLine(" )"); ///ノード電気的距離 sw.WriteLine(" (property 0 double \"nodeElectricalDistance\""); sw.WriteLine(" (default \"0\" \"0\" )"); TLPElectricalDistance(sw, dend.root, null); sw.WriteLine(" )"); ///ノードタイプ sw.WriteLine(" (property 0 int \"nodeType\""); sw.WriteLine(" (default \"0\" \"0\" )"); TLPNodeType(sw, dend.root, null); sw.WriteLine(" )"); //sw.WriteLine(" (property 0 bool \"viewSelection\" \n (default \"true\" \"true\")\n )"); //ノードの接続情報 count = 1; TLPEdge(sw, dend.root, null, null, ref count); sw.WriteLine(")"); /////エッジプロパティ //sw.WriteLine(" (property 0 double \"edgeLength\""); //sw.WriteLine(" (default \"0\" \"0\" )"); //count = 1; //TLPEdgeLength(sw, dend.root, null,null,ref count); //sw.WriteLine(" )"); } }
public void RelateSwcNode(Dendrite swc) { // addNodeToList(main_dendrite.root, null); の直前で-1を設定したかったけど // unassigned local variableで怒られた(´・ω・`) int currentSubDendriteIndex = -1; var nodeListImg = new List <DendriteNode>(); var node2subindex = new Dictionary <DendriteNode, int>(); Action <DendriteNode, DendriteNode> addNodeToList = null; addNodeToList = (node, parent) => { nodeListImg.Add(node); node2subindex.Add(node, currentSubDendriteIndex); foreach (var next in node.ConnectedNodes) { if (next == parent) { continue; } addNodeToList(next, node); } }; addNodeToList(main_dendrite.root, null); for (int i = 0; i < sub_dendrites.Count; i++) { currentSubDendriteIndex = i; addNodeToList(sub_dendrites[i].root, null); } foreach (var node in nodeListImg) { node.isConnected = false; } var img2swc = new Dictionary <DendriteNode, DendriteNode>(); var que = new Queue <DendriteNode>(); var removeCandidate = new HashSet <int>(); Action <DendriteNode, DendriteNode> mapping = null; mapping = (node, parent) => { Debug.Assert(nodeListImg.Count > 0); var pair = nodeListImg.First(); foreach (var item in nodeListImg) { if (node.EuclideanDistanceTo(item) < node.EuclideanDistanceTo(pair)) { pair = item; } } pair.isConnected = true; img2swc[pair] = node; que.Enqueue(pair); Debug.Assert(node2subindex.ContainsKey(pair)); if (node2subindex[pair] != -1) { removeCandidate.Add(node2subindex[pair]); } foreach (var next in node.ConnectedNodes) { if (next == parent) { continue; } mapping(next, node); } }; mapping(swc.root, null); while (que.Count > 0) { var node = que.Dequeue(); foreach (var next in node.ConnectedNodes) { if (next.isConnected) { continue; } next.isConnected = true; var newNode = new DendriteNode(-1, next.gx, next.gy, next.gz, next.Radius, -1); Debug.Assert(img2swc.ContainsKey(node)); img2swc[node].AddConnectedNode(newNode); newNode.AddConnectedNode(img2swc[node]); que.Enqueue(next); img2swc[next] = newNode; } } swc.ChangeRootNode(swc.root); main_dendrite = swc; int offset = 0; foreach (var item in removeCandidate.ToList().OrderBy(x => x)) { sub_dendrites.RemoveAt(item + offset); sub_dendrites_volume.RemoveAt(item + offset); offset--; } }
public void ConnectSubDendritesToOtherSubDendrites() { var nodelist = new Dictionary <int, List <DendriteNode> >(); foreach (int index in NotMergedSubDendritesIdx) { List <DendriteNode> node = sub_dendrites[index].GetEdgeNodeAndBranchNodes(); nodelist.Add(index, node); } DendriteNode masterNode = null; DendriteNode slaveNode = null; var cache = new Dictionary <Tuple2, NodeIndexer>(); while (true) { // masterとslaveの距離をあらかじめ計算しておいて配列に保存し、ソートしておくことで // 高速に計算できるが、需要がないようなので後回しにする。 // 配列に保存するのは距離がdistanceThreashold以下のものだけにしないとメモリが足りないと思います。 // Masterがどこかのノードに吸収されるかもしれないので、 // UnionFind木で管理しておきましょう int masterIndex = 0; int slaveIndex = 0; double min = Double.MaxValue; foreach (int master in NotMergedSubDendritesIdx) { for (int master2 = 0; master2 < nodelist[master].Count; master2++) { var dictKey = new Tuple2(master, master2); if (cache.ContainsKey(dictKey) == false || nodelist[cache[dictKey].ClusterIdx].Count == 0) { foreach (int slave in NotMergedSubDendritesIdx) { if (master == slave) { continue; } for (int slave2 = 0; slave2 < nodelist[slave].Count; slave2++) { double tmpdist = nodelist[master][master2].EuclideanDistanceTo(nodelist[slave][slave2]); // キャッシュがなかった場合は新しく追加 if (cache.ContainsKey(dictKey) == false) { cache.Add(dictKey, new NodeIndexer(tmpdist, slave, slave2)); } // キャッシュしていたノードが他のノードに併合されたパターン else if (nodelist[cache[dictKey].ClusterIdx].Count == 0) { cache[dictKey] = new NodeIndexer(tmpdist, slave, slave2); } // 再探索時に、キャッシュしていたノードよりも近いノードを見つけた場合には、キャッシュしている値を変更する else if (cache[dictKey].Norm >= tmpdist) { cache[dictKey] = new NodeIndexer(tmpdist, slave, slave2); } if (min >= tmpdist) { min = tmpdist; masterNode = nodelist[slave][slave2]; slaveNode = nodelist[master][master2]; masterIndex = master; slaveIndex = slave; } } } } // キャッシュが存在した場合はそれを利用 else { NodeIndexer nodeIndex = cache[dictKey]; double tmpdist = nodeIndex.Norm; int slave = nodeIndex.ClusterIdx; int slave2 = nodeIndex.NodeIdx; if (min >= tmpdist) { min = tmpdist; masterNode = nodelist[slave][slave2]; slaveNode = nodelist[master][master2]; masterIndex = master; slaveIndex = slave; } } } } if (min <= param.distanceThreshold) { //連結ノードにお互いを追加 masterNode.AddConnectedNode(slaveNode); slaveNode.AddConnectedNode(masterNode); //連結したサブノードリストはメインノードリストに吸収 nodelist[masterIndex].AddRange(nodelist[slaveIndex]); //サブを消去 nodelist[slaveIndex].Clear(); // マージされた NotMergedSubDendritesIdx.Remove(slaveIndex); sub_dendrites_volume[masterIndex] += sub_dendrites_volume[slaveIndex]; sub_dendrites_volume[slaveIndex] = 0; } else { break; } } foreach (int index in NotMergedSubDendritesIdx) { if (nodelist[index].Count > 0) { Dendrite node = sub_dendrites[index]; var edge = node.GetEdgeNodes(); node.ChangeRootNode(edge.Last()); } } }