Commit 4df9ec0e82ddb0bc0314f26e7077958a11062aa8
1 parent
3800c27f
compare networks and give netmets metric function added in network class
Showing
2 changed files
with
141 additions
and
24 deletions
Show diff stats
stim/biomodels/fiber.h
@@ -193,7 +193,6 @@ public: | @@ -193,7 +193,6 @@ public: | ||
193 | if(this == &rhs) return *this; //test for and handle self-assignment | 193 | if(this == &rhs) return *this; //test for and handle self-assignment |
194 | 194 | ||
195 | copy(rhs); | 195 | copy(rhs); |
196 | - | ||
197 | } | 196 | } |
198 | 197 | ||
199 | /// Calculate the length of the fiber and return it. | 198 | /// Calculate the length of the fiber and return it. |
@@ -331,7 +330,7 @@ public: | @@ -331,7 +330,7 @@ public: | ||
331 | /// @param q is the query point used to locate the nearest point on the fiber centerline | 330 | /// @param q is the query point used to locate the nearest point on the fiber centerline |
332 | unsigned int nearest_idx(stim::vec<T> q){ | 331 | unsigned int nearest_idx(stim::vec<T> q){ |
333 | 332 | ||
334 | - stim::vec<double> temp( (double) q[0], (double) q[1], (double) q[2]); | 333 | + stim::vec<double> temp((double) q[0], (double) q[1], (double) q[2]); |
335 | 334 | ||
336 | unsigned int idx = ann(temp); //determine the index of the nearest neighbor | 335 | unsigned int idx = ann(temp); //determine the index of the nearest neighbor |
337 | 336 | ||
@@ -449,6 +448,7 @@ public: | @@ -449,6 +448,7 @@ public: | ||
449 | return N; | 448 | return N; |
450 | } | 449 | } |
451 | 450 | ||
451 | + | ||
452 | /// Bracket operator returns the element at index i | 452 | /// Bracket operator returns the element at index i |
453 | 453 | ||
454 | /// @param i is the index of the element to be returned as a stim::vec | 454 | /// @param i is the index of the element to be returned as a stim::vec |
@@ -467,8 +467,8 @@ public: | @@ -467,8 +467,8 @@ public: | ||
467 | 467 | ||
468 | std::vector<T> v(3); //v-direction vector of the segment | 468 | std::vector<T> v(3); //v-direction vector of the segment |
469 | stim::vec<T> p(3); //- intermediate point to be added | 469 | stim::vec<T> p(3); //- intermediate point to be added |
470 | - std::vector<T> p1(3); // p1 - starting point of an segment on the fiber, | ||
471 | - std::vector<T> p2(3); // p2 - ending point, | 470 | + stim::vec<T> p1(3); // p1 - starting point of an segment on the fiber, |
471 | + stim::vec<T> p2(3); // p2 - ending point, | ||
472 | double sum=0; //distance summation | 472 | double sum=0; //distance summation |
473 | std::vector<stim::vec<T> > fiberPositions = centerline(); | 473 | std::vector<stim::vec<T> > fiberPositions = centerline(); |
474 | std::vector<stim::vec<T> > newPointList; // initialize list of new resampled points on the fiber | 474 | std::vector<stim::vec<T> > newPointList; // initialize list of new resampled points on the fiber |
@@ -476,14 +476,10 @@ public: | @@ -476,14 +476,10 @@ public: | ||
476 | unsigned int N = fiberPositions.size(); // number of points on the fiber | 476 | unsigned int N = fiberPositions.size(); // number of points on the fiber |
477 | for(unsigned int f=0; f< N-1; f++) | 477 | for(unsigned int f=0; f< N-1; f++) |
478 | { | 478 | { |
479 | - for(unsigned int d = 0; d < 3; d++) | ||
480 | - { | ||
481 | - p1[d] = fiberPositions[f][d]; // starting point of the segment on the centerline | ||
482 | - p2[d] = fiberPositions[f + 1][d]; // ending point of the segment on the centerline | ||
483 | - v[d] = p2[d] - p1[d]; //direction vector | ||
484 | - sum +=v[d] * v[d]; //length of segment-distance between starting and ending point | ||
485 | - } | ||
486 | - //newPointList.push_back(fiberPositions[f]); //always push the starting point | 479 | + |
480 | + p1 = fiberPositions[f]; p2 = fiberPositions[f + 1]; v = p2 - p1; | ||
481 | + for(unsigned int d = 0; d < 3; d++){ | ||
482 | + sum +=v[d] * v[d];} //length of segment-distance between starting and ending point | ||
487 | 483 | ||
488 | T lengthSegment = sqrt(sum); //find Length of the segment as distance between the starting and ending points of the segment | 484 | T lengthSegment = sqrt(sum); //find Length of the segment as distance between the starting and ending points of the segment |
489 | 485 |
stim/biomodels/network.h
1 | #ifndef STIM_NETWORK_H | 1 | #ifndef STIM_NETWORK_H |
2 | #define STIM_NETWORK_H | 2 | #define STIM_NETWORK_H |
3 | 3 | ||
4 | -#include <list> | ||
5 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | +#include <assert.h> | ||
6 | #include <sstream> | 6 | #include <sstream> |
7 | #include <fstream> | 7 | #include <fstream> |
8 | #include <algorithm> | 8 | #include <algorithm> |
@@ -33,8 +33,7 @@ class network{ | @@ -33,8 +33,7 @@ class network{ | ||
33 | public: | 33 | public: |
34 | unsigned v[2]; //unique id's designating the starting and ending | 34 | unsigned v[2]; //unique id's designating the starting and ending |
35 | // default constructor | 35 | // default constructor |
36 | - edge() : fiber<T>(){v[1] = -1; v[0] = -1;} | ||
37 | - | 36 | + edge() : fiber<T>(){v[1] = -1; v[0] = -1;} |
38 | /// Constructor - creates an edge from a list of points by calling the stim::fiber constructor | 37 | /// Constructor - creates an edge from a list of points by calling the stim::fiber constructor |
39 | 38 | ||
40 | ///@param p is an array of positions in space | 39 | ///@param p is an array of positions in space |
@@ -122,7 +121,7 @@ class network{ | @@ -122,7 +121,7 @@ class network{ | ||
122 | 121 | ||
123 | std::vector<unsigned> id2vert; //this list stores the OBJ vertex ID associated with each network vertex | 122 | std::vector<unsigned> id2vert; //this list stores the OBJ vertex ID associated with each network vertex |
124 | 123 | ||
125 | - unsigned i[2]; //temporary, IDs associated with the first and last points in an OBJ line | 124 | + unsigned i[2]; //temporary, IDs associated with the first and last points in an OBJ line |
126 | 125 | ||
127 | //for each line in the OBJ object | 126 | //for each line in the OBJ object |
128 | for(unsigned int l = 1; l <= O.numL(); l++){ | 127 | for(unsigned int l = 1; l <= O.numL(); l++){ |
@@ -145,10 +144,10 @@ class network{ | @@ -145,10 +144,10 @@ class network{ | ||
145 | it = find(id2vert.begin(), id2vert.end(), i[0]); //look for the first node | 144 | it = find(id2vert.begin(), id2vert.end(), i[0]); //look for the first node |
146 | it_idx = std::distance(id2vert.begin(), it); | 145 | it_idx = std::distance(id2vert.begin(), it); |
147 | if(it == id2vert.end()){ //if i[0] hasn't already been used | 146 | if(it == id2vert.end()){ //if i[0] hasn't already been used |
148 | - vertex new_vertex = new_edge[0]; //create a new vertex, assign it a position | ||
149 | - new_vertex.e[0].push_back(E.size()); //add the current edge as outgoing | ||
150 | - new_edge.v[0] = V.size(); //add the new vertex to the edge | ||
151 | - V.push_back(new_vertex); //add the new vertex to the vertex list | 147 | + vertex new_vertex = new_edge[0]; //create a new vertex, assign it a position |
148 | + new_vertex.e[0].push_back(E.size()); //add the current edge as outgoing | ||
149 | + new_edge.v[0] = V.size(); //add the new vertex to the edge | ||
150 | + V.push_back(new_vertex); //add the new vertex to the vertex list | ||
152 | id2vert.push_back(i[0]); //add the ID to the ID->vertex conversion list | 151 | id2vert.push_back(i[0]); //add the ID to the ID->vertex conversion list |
153 | } | 152 | } |
154 | else{ //if the vertex already exists | 153 | else{ //if the vertex already exists |
@@ -170,7 +169,7 @@ class network{ | @@ -170,7 +169,7 @@ class network{ | ||
170 | new_edge.v[1] = it_idx; | 169 | new_edge.v[1] = it_idx; |
171 | } | 170 | } |
172 | 171 | ||
173 | - E.push_back(new_edge); //push the edge to the list | 172 | + E.push_back(new_edge); //push the edge to the list |
174 | 173 | ||
175 | } | 174 | } |
176 | } | 175 | } |
@@ -197,14 +196,136 @@ class network{ | @@ -197,14 +196,136 @@ class network{ | ||
197 | stim::network<T> n; //create a new network that will be an exact copy, with resampled fibers | 196 | stim::network<T> n; //create a new network that will be an exact copy, with resampled fibers |
198 | n.V = V; //copy all vertices | 197 | n.V = V; //copy all vertices |
199 | 198 | ||
200 | - n.E.resize(E.size()); //allocate space for the edge list | 199 | + n.E.resize(edges()); //allocate space for the edge list |
201 | 200 | ||
202 | //copy all fibers, resampling them in the process | 201 | //copy all fibers, resampling them in the process |
203 | - for(unsigned e = 0; e < E.size(); e++){ //for each edge in the edge list | 202 | + for(unsigned e = 0; e < edges(); e++){ //for each edge in the edge list |
204 | n.E[e] = E[e].resample(spacing); //resample the edge and copy it to the new network | 203 | n.E[e] = E[e].resample(spacing); //resample the edge and copy it to the new network |
205 | } | 204 | } |
206 | 205 | ||
207 | - return n; //return the resampled network | 206 | + return n; //return the resampled network |
207 | + } | ||
208 | + | ||
209 | + | ||
210 | + // this function gives sum of lengths of all the fibers in the network | ||
211 | + float lengthOfNetwork(){ | ||
212 | + stim::fiber<T> FIBER; // initialize a fiber used in looping through all edges casting into fibers in the network | ||
213 | + float networkLength=0;float N=0; // initialize variables for finding total length of all the fibers | ||
214 | + // for each edge in the network | ||
215 | + for (unsigned int i=0; i < E.size(); i ++) | ||
216 | + { | ||
217 | + FIBER = get_fiber(i); // cast each edge to fiber | ||
218 | + N= FIBER.length(); // find length of the fiber | ||
219 | + networkLength = networkLength + N; // running sum of fiber lengths | ||
220 | + } | ||
221 | + return networkLength; | ||
222 | + } | ||
223 | + | ||
224 | + | ||
225 | + // list of all the points after resampling -- function used only on a resampled network | ||
226 | + std::vector<stim::vec<T> > points_afterResampling(){ | ||
227 | + std::vector<stim::vec<T> > pointsVector; // points in the resampled network | ||
228 | + stim::fiber<T> FIBER; // initialize a fiber used in looping through all edges casting into fibers in the network | ||
229 | + std::vector<stim::vec<T> > pointsFiber; // resampled points on each fiber of the network | ||
230 | + for(unsigned e = 0; e < E.size(); e++){ // for each edge in the edge list | ||
231 | + FIBER = get_fiber(e); // Cast edge to a fiber | ||
232 | + pointsFiber = FIBER.centerline(); // find points on the edge returns a stim vec | ||
233 | + for (unsigned v = 0; v < FIBER.n_pts(); v++){ // iterate one point at a time from the stim::vec | ||
234 | + pointsVector.push_back(pointsFiber[v]);} //add the points on centerline to the stim::vec points list | ||
235 | + } | ||
236 | + return pointsVector; | ||
237 | + } | ||
238 | + | ||
239 | + | ||
240 | + // total number of points on all fibers after resampling -- function used only on a resampled network | ||
241 | + unsigned int total_points(){ | ||
242 | + unsigned int n = points_afterResampling().size(); | ||
243 | + return n; | ||
244 | + } | ||
245 | + | ||
246 | + // gaussian function | ||
247 | + float gaussianFunction(float x, float std=25){ return exp(-x/(2*std*std));} // by default std = 25 | ||
248 | + | ||
249 | + // sum of values in a stim vector | ||
250 | + float sum(stim::vec<T> metricList){ | ||
251 | + float sumMetricList = 0; // Initialize variable to calculate sum | ||
252 | + for (unsigned int count=0; count<metricList.size(); count++) // for each element in the stim vector | ||
253 | + { sumMetricList += metricList[count];} // running sum of values | ||
254 | + return sumMetricList; | ||
255 | + } | ||
256 | + | ||
257 | + | ||
258 | + // distance between two points | ||
259 | + double dist(stim::vec<T> p0, stim::vec<T> p1){ | ||
260 | + double sum = 0; // initialize variables | ||
261 | + stim::vec<T> v = p1 - p0;; // direction vector | ||
262 | + for(unsigned int d = 0; d < 3; d++){ // for each dimension | ||
263 | + sum += v[d] * v[d];} // running sum of modulus of direction vector | ||
264 | + return sqrt(sum); | ||
265 | + } | ||
266 | + | ||
267 | + | ||
268 | + /// This function compares two networks and returns a metric | ||
269 | + float compare(stim::network<T> networkTruth, float sigma){ | ||
270 | + float metric = 0.0; // initialize metric to be returned after comparing the networks | ||
271 | + ANNkd_tree* kdt; // initialize a pointer to a kd tree | ||
272 | + double **c; // centerline (array of double pointers) - points on kdtree must be double | ||
273 | + unsigned int n_data = total_points(); // set the number of points | ||
274 | + c = (double**) malloc(sizeof(double*) * n_data); // allocate the array pointer | ||
275 | + for(unsigned int i = 0; i < n_data; i++) // allocate space for each point of 3 dimensions | ||
276 | + {c[i] = (double*) malloc(sizeof(double) * 3);} | ||
277 | + std::vector<stim::vec<T> > pointsVector = points_afterResampling(); //get vertices in the network after resampling | ||
278 | + for(unsigned int i = 0; i < n_data; i++) // loop through all the vertices after resampling | ||
279 | + { | ||
280 | + for(unsigned int d = 0; d < 3; d++){ // for each dimension | ||
281 | + c[i][d] = double(pointsVector[i][d]); // copy the coordinate and convert_to_double | ||
282 | + } | ||
283 | + } | ||
284 | + ANNpointArray pts = (ANNpointArray)c; // create an array of data points of type double | ||
285 | + kdt = new ANNkd_tree(pts, n_data, 3); // build a KD tree using the annpointarray | ||
286 | + double eps = 0; // error bound | ||
287 | + ANNdistArray dists1;dists1 = new ANNdist[1]; // near neighbor distances | ||
288 | + ANNdistArray dists2; dists2 = new ANNdist[1]; // near neighbor distances | ||
289 | + ANNidxArray nnIdx1; nnIdx1 = new ANNidx[1]; // near neighbor indices // allocate near neigh indices | ||
290 | + ANNidxArray nnIdx2; nnIdx2 = new ANNidx[1]; // near neighbor indices // allocate near neigh indices | ||
291 | + int N; // number of points on the fiber in the second network | ||
292 | + float totalNetworkLength = networkTruth.lengthOfNetwork(); | ||
293 | + stim::vec<float> fiberMetric(networkTruth.edges()); // allocate space for accumulating fiber metric as each fiber is evaluated | ||
294 | + stim::fiber<T> FIBER; // Initialize a fiber will be used in calculating the metric | ||
295 | + //for each fiber in the second network, find nearest distance in the kd tree | ||
296 | + for (unsigned int i=0; i < networkTruth.edges(); i ++) // loop through all the edges/fibers in the network | ||
297 | + { | ||
298 | + FIBER = networkTruth.get_fiber(i); // Get the fiber corresponding to the index i | ||
299 | + std::vector< stim::vec<T> > fiberPoints = FIBER.centerline(); // Get the points on the fiber | ||
300 | + N = FIBER.n_pts(); // number of points on the fiber | ||
301 | + stim::vec<float> segmentMetric(N-1); // allocate space for a vec array that stores metric for each segmen in the fiber | ||
302 | + // for each segment in the fiber | ||
303 | + for (unsigned j = 0; j < N - 1; j++) | ||
304 | + { | ||
305 | + stim::vec<T> p1 = fiberPoints[j];stim::vec<T> p2 = fiberPoints[j+1]; // starting and ending points on the segments | ||
306 | + ANNpoint queryPt1; queryPt1 = annAllocPt(3); // allocate memory for query points | ||
307 | + ANNpoint queryPt2; queryPt2 = annAllocPt(3); | ||
308 | + | ||
309 | + //for each dimension of the points connecting segment | ||
310 | + for (unsigned d = 0; d < 3; d++){ | ||
311 | + queryPt1[d] = double(fiberPoints[j][d]); // starting point on segment in network whose closest distance on KD tree should be found | ||
312 | + queryPt2[d] = double(fiberPoints[j + 1][d]); // ending point on segment in network whose closest distance on KD tree should be found | ||
313 | + } | ||
314 | + kdt->annkSearch( queryPt1, 1, nnIdx1, dists1, eps); // search the nearest point in KD tree to query point(point on network), find the distance | ||
315 | + kdt->annkSearch( queryPt2, 1, nnIdx2, dists2, eps); // search the nearest point in KD tree to query point(point on network), find the distance | ||
316 | + // find the gaussian of the distance and subtract it from 1 to calculate the error | ||
317 | + float error1 = 1.0f - gaussianFunction(float(dists1[0]), sigma);float error2 = 1.0f - gaussianFunction(float(dists2[0]), sigma); | ||
318 | + // average the error and scale it with distance between the points | ||
319 | + segmentMetric[j] = ((error1 + error2) / 2) * dist(p1, p2) ; | ||
320 | + /*segmentDists[j] = dist(p1, p2); */ | ||
321 | + } | ||
322 | + fiberMetric[i] = sum(segmentMetric); | ||
323 | + /*distsList[i] = sum(segmentDists);*/ | ||
324 | + } | ||
325 | + /*assert (sum(distsList)==totalNetworkLength);*/ | ||
326 | + metric = sum(fiberMetric)/totalNetworkLength; //normalize the scaled error of all the points with total length of the network | ||
327 | + assert (0<=metric <=1); //assert metroc os always less than or equal to one and greater than or equal to zero | ||
328 | + return metric; | ||
208 | } | 329 | } |
209 | }; //end stim::network class | 330 | }; //end stim::network class |
210 | }; //end stim namespace | 331 | }; //end stim namespace |