Commit 8478bb2ba5fcf99a11db2458a79b9277dfdd3636
Merge branch 'master' of git.stim.ee.uh.edu:codebase/stimlib
Showing
3 changed files
with
363 additions
and
6 deletions
Show diff stats
stim/biomodels/centerline.h
... | ... | @@ -3,6 +3,7 @@ |
3 | 3 | |
4 | 4 | #include <vector> |
5 | 5 | #include <stim/math/vec3.h> |
6 | +#include <stim/structures/kdtree.cuh> | |
6 | 7 | |
7 | 8 | namespace stim{ |
8 | 9 | |
... | ... | @@ -134,6 +135,362 @@ public: |
134 | 135 | return L.back(); |
135 | 136 | } |
136 | 137 | |
138 | + /// stitch two centerlines | |
139 | + ///@param c1, c2: two centerlines | |
140 | + ///@param sigma: sample rate | |
141 | + static std::vector< stim::centerline<T> > stitch(stim::centerline<T> c1, stim::centerline<T> c2 = stim::centerline<T>()) { | |
142 | + | |
143 | + std::vector< stim::centerline<T> > result; | |
144 | + stim::centerline<T> new_centerline; | |
145 | + stim::vec3<T> new_vertex; | |
146 | + | |
147 | + // if only one centerline, stitch itself! | |
148 | + if (c2.size() == 0) { | |
149 | + size_t num = c1.size(); | |
150 | + size_t id = 100000; // store the downsample start position | |
151 | + T threshold; | |
152 | + if (num < 4) { // if the number of vertex is less than 4, do nothing | |
153 | + result.push_back(c1); | |
154 | + return result; | |
155 | + } | |
156 | + else { | |
157 | + // test geometry start vertex | |
158 | + stim::vec3<T> v1 = c1[1] - c1[0]; // vector from c1[0] to c1[1] | |
159 | + for (size_t p = 2; p < num; p++) { // 90° standard??? | |
160 | + stim::vec3<T> v2 = c1[p] - c1[0]; | |
161 | + float cosine = v2.dot(v1); | |
162 | + if (cosine < 0) { | |
163 | + id = p; | |
164 | + threshold = v2.len(); | |
165 | + break; | |
166 | + } | |
167 | + } | |
168 | + if (id != 100000) { // find a downsample position on the centerline | |
169 | + T* c; | |
170 | + c = (T*)malloc(sizeof(T) * (num - id) * 3); | |
171 | + for (size_t p = id; p < num; p++) { | |
172 | + for (size_t d = 0; d < 3; d++) { | |
173 | + c[p * 3 + d] = c1[p][d]; | |
174 | + } | |
175 | + } | |
176 | + stim::kdtree<T, 3> kdt; | |
177 | + kdt.create(c, num - id, 5); // create tree | |
178 | + | |
179 | + T* query = (T*)malloc(sizeof(T) * 3); | |
180 | + for (size_t d = 0; d < 3; d++) | |
181 | + query[d] = c1[0][d]; | |
182 | + size_t index; | |
183 | + T dist; | |
184 | + | |
185 | + kdt.search(query, 1, &index, &dist); | |
186 | + | |
187 | + free(query); | |
188 | + free(c); | |
189 | + | |
190 | + if (dist > threshold) { | |
191 | + result.push_back(c1); | |
192 | + } | |
193 | + else { | |
194 | + // the loop part | |
195 | + new_vertex = c1[index]; | |
196 | + new_centerline.push_back(new_vertex); | |
197 | + for (size_t p = 0; p < index + 1; p++) { | |
198 | + new_vertex = c1[p]; | |
199 | + new_centerline.push_back(new_vertex); | |
200 | + } | |
201 | + result.push_back(new_centerline); | |
202 | + new_centerline.clear(); | |
203 | + | |
204 | + // the tail part | |
205 | + for (size_t p = index; p < num; p++) { | |
206 | + new_vertex = c1[p]; | |
207 | + new_centerline.push_back(new_vertex); | |
208 | + } | |
209 | + result.push_back(new_centerline); | |
210 | + } | |
211 | + } | |
212 | + else { // there is one potential problem that two positions have to be stitched | |
213 | + // test geometry end vertex | |
214 | + stim::vec3<T> v1 = c1[num - 2] - c1[num - 1]; | |
215 | + for (size_t p = num - 2; p > 0; p--) { // 90° standard | |
216 | + stim::vec3<T> v2 = c1[p - 1] - c1[num - 1]; | |
217 | + float cosine = v2.dot(v1); | |
218 | + if (cosine < 0) { | |
219 | + id = p; | |
220 | + threshold = v2.len(); | |
221 | + break; | |
222 | + } | |
223 | + } | |
224 | + if (id != 100000) { // find a downsample position | |
225 | + T* c; | |
226 | + c = (T*)malloc(sizeof(T) * (id + 1) * 3); | |
227 | + for (size_t p = 0; p < id + 1; p++) { | |
228 | + for (size_t d = 0; d < 3; d++) { | |
229 | + c[p * 3 + d] = c1[p][d]; | |
230 | + } | |
231 | + } | |
232 | + stim::kdtree<T, 3> kdt; | |
233 | + kdt.create(c, id + 1, 5); // create tree | |
234 | + | |
235 | + T* query = (T*)malloc(sizeof(T) * 1 * 3); | |
236 | + for (size_t d = 0; d < 3; d++) | |
237 | + query[d] = c1[num - 1][d]; | |
238 | + size_t index; | |
239 | + T dist; | |
240 | + | |
241 | + kdt.search(query, 1, &index, &dist); | |
242 | + | |
243 | + free(query); | |
244 | + free(c); | |
245 | + | |
246 | + if (dist > threshold) { | |
247 | + result.push_back(c1); | |
248 | + } | |
249 | + else { | |
250 | + // the tail part | |
251 | + for (size_t p = 0; p < index + 1; p++) { | |
252 | + new_vertex = c1[p]; | |
253 | + new_centerline.push_back(new_vertex); | |
254 | + } | |
255 | + result.push_back(new_centerline); | |
256 | + new_centerline.clear(); | |
257 | + | |
258 | + // the loop part | |
259 | + for (size_t p = index; p < num; p++) { | |
260 | + new_vertex = c1[p]; | |
261 | + new_centerline.push_back(new_vertex); | |
262 | + } | |
263 | + new_vertex = c1[index]; | |
264 | + new_centerline.push_back(new_vertex); | |
265 | + result.push_back(new_centerline); | |
266 | + } | |
267 | + } | |
268 | + else { // no stitch position | |
269 | + result.push_back(c1); | |
270 | + } | |
271 | + } | |
272 | + } | |
273 | + } | |
274 | + | |
275 | + | |
276 | + // two centerlines | |
277 | + else { | |
278 | + // find stitch position based on nearest neighbors | |
279 | + size_t num1 = c1.size(); | |
280 | + T* c = (T*)malloc(sizeof(T) * num1 * 3); // c1 as reference point | |
281 | + for (size_t p = 0; p < num1; p++) // centerline to array | |
282 | + for (size_t d = 0; d < 3; d++) // because right now my kdtree code is a relatively close code, it has its own structure | |
283 | + c[p * 3 + d] = c1[p][d]; // I will merge it into stimlib totally in the near future | |
284 | + | |
285 | + stim::kdtree<T, 3> kdt; // kdtree object | |
286 | + kdt.create(c, num1, 5); // create tree | |
287 | + | |
288 | + size_t num2 = c2.size(); | |
289 | + T* query = (T*)malloc(sizeof(T) * num2 * 3); // c2 as query point | |
290 | + for (size_t p = 0; p < num2; p++) { | |
291 | + for (size_t d = 0; d < 3; d++) { | |
292 | + query[p * 3 + d] = c2[p][d]; | |
293 | + } | |
294 | + } | |
295 | + std::vector<size_t> index(num2); | |
296 | + std::vector<T> dist(num2); | |
297 | + | |
298 | + kdt.search(query, num2, &index[0], &dist[0]); // find the nearest neighbors in c1 for c2 | |
299 | + | |
300 | + // clear up | |
301 | + free(query); | |
302 | + free(c); | |
303 | + | |
304 | + // find the average vertex distance of one centerline | |
305 | + T sigma1 = 0; | |
306 | + T sigma2 = 0; | |
307 | + for (size_t p = 0; p < num1 - 1; p++) | |
308 | + sigma1 += (c1[p] - c1[p + 1]).len(); | |
309 | + for (size_t p = 0; p < num2 - 1; p++) | |
310 | + sigma2 += (c2[p] - c2[p + 1]).len(); | |
311 | + sigma1 /= (num1 - 1); | |
312 | + sigma2 /= (num2 - 1); | |
313 | + float threshold = 4 * (sigma1 + sigma2) / 2; // better way to do this? | |
314 | + | |
315 | + T min_d = *std::min_element(dist.begin(), dist.end()); // find the minimum distance between c1 and c2 | |
316 | + | |
317 | + if (min_d > threshold) { // if the minimum distance is too large | |
318 | + result.push_back(c1); | |
319 | + result.push_back(c2); | |
320 | + | |
321 | +#ifdef DEBUG | |
322 | + std::cout << "The distance between these two centerlines is too large" << std::endl; | |
323 | +#endif | |
324 | + } | |
325 | + else { | |
326 | + auto smallest = std::min_element(dist.begin(), dist.end()); | |
327 | + auto i = std::distance(dist.begin(), smallest); // find the index of min-distance in distance list | |
328 | + | |
329 | + // stitch position in c1 and c2 | |
330 | + int id1 = index[i]; | |
331 | + int id2 = i; | |
332 | + | |
333 | + // actually there are two cases | |
334 | + // first one inacceptable | |
335 | + // second one acceptable | |
336 | + if (id1 != 0 && id1 != num1 - 1 && id2 != 0 && id2 != num2 - 1) { // only stitch one end vertex to another centerline | |
337 | + result.push_back(c1); | |
338 | + result.push_back(c2); | |
339 | + } | |
340 | + else { | |
341 | + if (id1 == 0 || id1 == num1 - 1) { // if the stitch vertex is the first or last vertex of c1 | |
342 | + // for c2, consider two cases(one degenerate case) | |
343 | + if (id2 == 0 || id2 == num2 - 1) { // case 1, if stitch position is also on the end of c2 | |
344 | + // we have to decide which centerline get a new vertex, based on direction | |
345 | + // for c1, computer the direction change angle | |
346 | + stim::vec3<T> v1, v2; | |
347 | + float alpha1, alpha2; // direction change angle | |
348 | + if (id1 == 0) | |
349 | + v1 = (c1[1] - c1[0]).norm(); | |
350 | + else | |
351 | + v1 = (c1[num1 - 2] - c1[num1 - 1]).norm(); | |
352 | + v2 = (c2[id2] - c1[id1]).norm(); | |
353 | + alpha1 = v1.dot(v2); | |
354 | + if (id2 == 0) | |
355 | + v1 = (c2[1] - c2[0]).norm(); | |
356 | + else | |
357 | + v1 = (c2[num2 - 2] - c2[num2 - 1]).norm(); | |
358 | + v2 = (c1[id1] - c2[id2]).norm(); | |
359 | + alpha2 = v1.dot(v2); | |
360 | + if (abs(alpha1) > abs(alpha2)) { // add the vertex to c1 in order to get smooth connection | |
361 | + // push back c1 | |
362 | + if (id1 == 0) { // keep geometry information | |
363 | + new_vertex = c2[id2]; | |
364 | + new_centerline.push_back(new_vertex); | |
365 | + for (size_t p = 0; p < num1; p++) { // stitch vertex on c2 -> geometry start vertex on c1 -> geometry end vertex on c1 | |
366 | + new_vertex = c1[p]; | |
367 | + new_centerline.push_back(new_vertex); | |
368 | + } | |
369 | + } | |
370 | + else { | |
371 | + for (size_t p = 0; p < num1; p++) { // stitch vertex on c2 -> geometry end vertex on c1 -> geometry start vertex on c1 | |
372 | + new_vertex = c1[p]; | |
373 | + new_centerline.push_back(new_vertex); | |
374 | + } | |
375 | + new_vertex = c2[id2]; | |
376 | + new_centerline.push_back(new_vertex); | |
377 | + } | |
378 | + result.push_back(new_centerline); | |
379 | + new_centerline.clear(); | |
380 | + | |
381 | + // push back c2 | |
382 | + for (size_t p = 0; p < num2; p++) { | |
383 | + new_vertex = c2[p]; | |
384 | + new_centerline.push_back(new_vertex); | |
385 | + } | |
386 | + result.push_back(new_centerline); | |
387 | + } | |
388 | + else { // add the vertex to c2 in order to get smooth connection | |
389 | + // push back c1 | |
390 | + for (size_t p = 0; p < num1; p++) { | |
391 | + new_vertex = c1[p]; | |
392 | + new_centerline.push_back(new_vertex); | |
393 | + } | |
394 | + result.push_back(new_centerline); | |
395 | + new_centerline.clear(); | |
396 | + | |
397 | + // push back c2 | |
398 | + if (id2 == 0) { // keep geometry information | |
399 | + new_vertex = c1[id1]; | |
400 | + new_centerline.push_back(new_vertex); | |
401 | + for (size_t p = 0; p < num2; p++) { // stitch vertex on c2 -> geometry start vertex on c1 -> geometry end vertex on c1 | |
402 | + new_vertex = c2[p]; | |
403 | + new_centerline.push_back(new_vertex); | |
404 | + } | |
405 | + } | |
406 | + else { | |
407 | + for (size_t p = 0; p < num2; p++) { // stitch vertex on c2 -> geometry end vertex on c1 -> geometry start vertex on c1 | |
408 | + new_vertex = c2[p]; | |
409 | + new_centerline.push_back(new_vertex); | |
410 | + } | |
411 | + new_vertex = c1[id1]; | |
412 | + new_centerline.push_back(new_vertex); | |
413 | + } | |
414 | + result.push_back(new_centerline); | |
415 | + } | |
416 | + } | |
417 | + else { // case 2, the stitch position is on c2 | |
418 | + // push back c1 | |
419 | + if (id1 == 0) { // keep geometry information | |
420 | + new_vertex = c2[id2]; | |
421 | + new_centerline.push_back(new_vertex); | |
422 | + for (size_t p = 0; p < num1; p++) { // stitch vertex on c2 -> geometry start vertex on c1 -> geometry end vertex on c1 | |
423 | + new_vertex = c1[p]; | |
424 | + new_centerline.push_back(new_vertex); | |
425 | + } | |
426 | + } | |
427 | + else { | |
428 | + for (size_t p = 0; p < num1; p++) { // geometry end vertex on c1 -> geometry start vertex on c1 -> stitch vertex on c2 | |
429 | + new_vertex = c1[p]; | |
430 | + new_centerline.push_back(new_vertex); | |
431 | + } | |
432 | + new_vertex = c2[id2]; | |
433 | + new_centerline.push_back(new_vertex); | |
434 | + } | |
435 | + result.push_back(new_centerline); | |
436 | + new_centerline.clear(); | |
437 | + | |
438 | + // push back c2 | |
439 | + for (size_t p = 0; p < id2 + 1; p++) { // first part | |
440 | + new_vertex = c2[p]; | |
441 | + new_centerline.push_back(new_vertex); | |
442 | + } | |
443 | + result.push_back(new_centerline); | |
444 | + new_centerline.clear(); | |
445 | + | |
446 | + for (size_t p = id2; p < num2; p++) { // second part | |
447 | + new_vertex = c2[p]; | |
448 | + new_centerline.push_back(new_vertex); | |
449 | + } | |
450 | + result.push_back(new_centerline); | |
451 | + } | |
452 | + } | |
453 | + else { // if the stitch vertex is the first or last vertex of c2 | |
454 | + // push back c2 | |
455 | + if (id2 == 0) { // keep geometry information | |
456 | + new_vertex = c1[id1]; | |
457 | + new_centerline.push_back(new_vertex); | |
458 | + for (size_t p = 0; p < num2; p++) { // stitch vertex on c1 -> geometry start vertex on c2 -> geometry end vertex on c2 | |
459 | + new_vertex = c2[p]; | |
460 | + new_centerline.push_back(new_vertex); | |
461 | + } | |
462 | + } | |
463 | + else { | |
464 | + for (size_t p = 0; p < num2; p++) { // geometry end vertex on c2 -> geometry start vertex on c2 -> stitch vertex on c1 | |
465 | + new_vertex = c2[p]; | |
466 | + new_centerline.push_back(new_vertex); | |
467 | + } | |
468 | + new_vertex = c1[id1]; | |
469 | + new_centerline.push_back(new_vertex); | |
470 | + result.push_back(new_centerline); | |
471 | + new_centerline.clear(); | |
472 | + | |
473 | + // push back c1 | |
474 | + for (size_t p = 0; p < id1 + 1; p++) { // first part | |
475 | + new_vertex = c1[p]; | |
476 | + new_centerline.push_back(new_vertex); | |
477 | + } | |
478 | + result.push_back(new_centerline); | |
479 | + new_centerline.clear(); | |
480 | + | |
481 | + for (size_t p = id1; p < num1; p++) { // second part | |
482 | + new_vertex = c1[p]; | |
483 | + new_centerline.push_back(new_vertex); | |
484 | + } | |
485 | + result.push_back(new_centerline); | |
486 | + } | |
487 | + } | |
488 | + } | |
489 | + } | |
490 | + } | |
491 | + return result; | |
492 | + } | |
493 | + | |
137 | 494 | /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned |
138 | 495 | std::vector< stim::centerline<T> > split(unsigned int idx){ |
139 | 496 | ... | ... |
stim/envi/bip.h
... | ... | @@ -419,10 +419,10 @@ public: |
419 | 419 | file.read((char*)in, in_bytes); //read an input spectrum |
420 | 420 | for (size_t b = 0; b < Bout; b++) { //for each band |
421 | 421 | wc = bandlist[b]; //set the desired wavelength |
422 | - band_bounds(wc, b0, b1); //get the surrounding bands | |
422 | + hsi<T>::band_bounds(wc, b0, b1); //get the surrounding bands | |
423 | 423 | w0 = w[b0]; //get the wavelength for the lower band |
424 | 424 | w1 = w[b1]; //get the wavelength for the higher band |
425 | - out[b] = lerp(wc, in[b0], w0, in[b1], w1); //interpolate the spectral values to get the desired output value | |
425 | + out[b] = hsi<T>::lerp(wc, in[b0], w0, in[b1], w1); //interpolate the spectral values to get the desired output value | |
426 | 426 | } |
427 | 427 | } |
428 | 428 | else | ... | ... |
stim/envi/hsi.h
... | ... | @@ -63,8 +63,8 @@ protected: |
63 | 63 | } |
64 | 64 | |
65 | 65 | /// Gets the two band indices surrounding a given wavelength |
66 | - void band_bounds(double wavelength, unsigned long long& low, unsigned long long& high){ | |
67 | - unsigned long long B = Z(); | |
66 | + void band_bounds(double wavelength, size_t& low, size_t& high){ | |
67 | + size_t B = Z(); | |
68 | 68 | for(high = 0; high < B; high++){ |
69 | 69 | if(w[high] > wavelength) break; |
70 | 70 | } |
... | ... | @@ -92,7 +92,7 @@ protected: |
92 | 92 | /// @param s is the spectrum in main memory of length Z() |
93 | 93 | /// @param wavelength is the wavelength value to interpolate out |
94 | 94 | T interp_spectrum(T* s, double wavelength){ |
95 | - unsigned long long low, high; //indices for the bands surrounding wavelength | |
95 | + size_t low, high; //indices for the bands surrounding wavelength | |
96 | 96 | band_bounds(wavelength, low, high); //get the surrounding band indices |
97 | 97 | |
98 | 98 | if(high == w.size()) return s[w.size()-1]; //if the high band is above the wavelength range, return the highest wavelength value |
... | ... | @@ -225,4 +225,4 @@ public: |
225 | 225 | |
226 | 226 | } //end namespace STIM |
227 | 227 | |
228 | -#endif | |
229 | 228 | \ No newline at end of file |
229 | +#endif | ... | ... |