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,6 +3,7 @@ | ||
3 | 3 | ||
4 | #include <vector> | 4 | #include <vector> |
5 | #include <stim/math/vec3.h> | 5 | #include <stim/math/vec3.h> |
6 | +#include <stim/structures/kdtree.cuh> | ||
6 | 7 | ||
7 | namespace stim{ | 8 | namespace stim{ |
8 | 9 | ||
@@ -134,6 +135,362 @@ public: | @@ -134,6 +135,362 @@ public: | ||
134 | return L.back(); | 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 | /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned | 494 | /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned |
138 | std::vector< stim::centerline<T> > split(unsigned int idx){ | 495 | std::vector< stim::centerline<T> > split(unsigned int idx){ |
139 | 496 |
stim/envi/bip.h
@@ -419,10 +419,10 @@ public: | @@ -419,10 +419,10 @@ public: | ||
419 | file.read((char*)in, in_bytes); //read an input spectrum | 419 | file.read((char*)in, in_bytes); //read an input spectrum |
420 | for (size_t b = 0; b < Bout; b++) { //for each band | 420 | for (size_t b = 0; b < Bout; b++) { //for each band |
421 | wc = bandlist[b]; //set the desired wavelength | 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 | w0 = w[b0]; //get the wavelength for the lower band | 423 | w0 = w[b0]; //get the wavelength for the lower band |
424 | w1 = w[b1]; //get the wavelength for the higher band | 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 | else | 428 | else |
stim/envi/hsi.h
@@ -63,8 +63,8 @@ protected: | @@ -63,8 +63,8 @@ protected: | ||
63 | } | 63 | } |
64 | 64 | ||
65 | /// Gets the two band indices surrounding a given wavelength | 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 | for(high = 0; high < B; high++){ | 68 | for(high = 0; high < B; high++){ |
69 | if(w[high] > wavelength) break; | 69 | if(w[high] > wavelength) break; |
70 | } | 70 | } |
@@ -92,7 +92,7 @@ protected: | @@ -92,7 +92,7 @@ protected: | ||
92 | /// @param s is the spectrum in main memory of length Z() | 92 | /// @param s is the spectrum in main memory of length Z() |
93 | /// @param wavelength is the wavelength value to interpolate out | 93 | /// @param wavelength is the wavelength value to interpolate out |
94 | T interp_spectrum(T* s, double wavelength){ | 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 | band_bounds(wavelength, low, high); //get the surrounding band indices | 96 | band_bounds(wavelength, low, high); //get the surrounding band indices |
97 | 97 | ||
98 | if(high == w.size()) return s[w.size()-1]; //if the high band is above the wavelength range, return the highest wavelength value | 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,4 +225,4 @@ public: | ||
225 | 225 | ||
226 | } //end namespace STIM | 226 | } //end namespace STIM |
227 | 227 | ||
228 | -#endif | ||
229 | \ No newline at end of file | 228 | \ No newline at end of file |
229 | +#endif |