File: testing_diff_tck.cpp

package info (click to toggle)
mrtrix3 3.0.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 15,300 kB
  • sloc: cpp: 130,470; python: 9,603; sh: 597; makefile: 62; xml: 47
file content (134 lines) | stat: -rw-r--r-- 4,616 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* Copyright (c) 2008-2025 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include <limits>

#include "command.h"
#include "types.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"
#include "dwi/tractography/streamline.h"

#define DEFAULT_HAUSDORFF 1e-5
#define DEFAULT_MAXFAIL 0

using namespace MR;
using namespace App;

void usage ()
{
  AUTHOR = "J-Donald Tournier (jdtournier@gmail.com)";

  SYNOPSIS = "Compare two track files for differences, within specified tolerance";

  DESCRIPTION
  + "This uses the symmetric Hausdorff distance to compare streamline pairs. For each "
    "streamline in the first input, the distance to the corresponding streamline in the "
    "second file is used and compared to the tolerance."

  + "If probabilistic streamlines tractography is to be tested, provide a larger file "
    "as the reference second input (streamlines from first file are matched to the second "
    "file, but not the other way around), and use the -unordered option."

  + "If the streamlines are not guaranteed to be provided in the same order between the "
    "two files, using the -unordered option will result in, for every streamline in the "
    "first input file, comparison against every streamline in the second file, with the "
    "distance to the nearest streamline in the second file compared against the threshold.";

  ARGUMENTS
  + Argument ("tck1", "the file from which all tracks will be checked.").type_tracks_in ()
  + Argument ("tck2", "the reference track file").type_tracks_in ();

  OPTIONS
  + Option ("distance", "maximum permissible Hausdorff distance in mm (default: " + str(DEFAULT_HAUSDORFF) + "mm)")
    + Argument ("value").type_float (0.0)

  + Option ("maxfail", "the maximum number of streamlines permitted to exceed the "
                       "Hausdorff distance before the unit test will fail (default: " + str(DEFAULT_MAXFAIL) + ")")

  + Option ("unordered", "compare the streamlines in an unordered fashion; "
            " i.e. compare every streamline in the first file to all streamlines in the second file");
}


inline bool within_haussdorf (const DWI::Tractography::Streamline<>& tck1, const DWI::Tractography::Streamline<>& tck2, float tol)
{
  tol *= tol;
  for (const auto& a : tck1) {
    float distance = std::numeric_limits<float>::max();
    for (const auto& b : tck2)
      distance = std::min (distance, (a - b).squaredNorm());
    if (distance > tol)
      return false;
  }
  return true;
}

inline bool within_haussdorf (const DWI::Tractography::Streamline<>& tck, const vector<DWI::Tractography::Streamline<>>& list, float tol)
{
  for (auto& tck2 : list) {
    if (within_haussdorf (tck, tck2, tol))
      return true;
  }
  return false;
}



void run ()
{
  const size_t maxfail = get_option_value ("maxfail", DEFAULT_MAXFAIL);
  const float tol = get_option_value ("distance", DEFAULT_HAUSDORFF);

  size_t mismatch_count = 0;

  DWI::Tractography::Properties properties1, properties2;
  DWI::Tractography::Reader<> reader1 (argument[0], properties1);
  DWI::Tractography::Reader<> reader2 (argument[1], properties2);

  if (get_options ("unordered").size()) {

    vector<DWI::Tractography::Streamline<>> ref_list;
    DWI::Tractography::Streamline<> tck;

    while (reader2 (tck))
      ref_list.push_back (tck);

    while (reader1 (tck))
      if (!within_haussdorf (tck, ref_list, tol))
        ++mismatch_count;

  } else {

    DWI::Tractography::Streamline<> tck1, tck2;

    while (reader1 (tck1)) {
      if (!reader2 (tck2))
        throw Exception ("More streamlines in first file than second file");
      if (!within_haussdorf (tck1, tck2, tol))
        ++mismatch_count;
    }

    if (reader2 (tck2))
      throw Exception ("More streamlines in second file than first file");

  }

  if (mismatch_count > maxfail)
    throw Exception (str(mismatch_count) + " mismatched streamlines - test FAILED");

  CONSOLE (str(mismatch_count) + " mismatched streamlines - data checked OK");
}