Commit 8478bb2ba5fcf99a11db2458a79b9277dfdd3636

Authored by David Mayerich
2 parents fa8763a6 72175dcf

Merge branch 'master' of git.stim.ee.uh.edu:codebase/stimlib

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
... ...