Exemple #1
0
        Worker::Thresholds::Thresholds (Tractography::Properties& properties) :
          max_length (std::numeric_limits<float>::infinity()),
          min_length (0.0f),
          max_weight (std::numeric_limits<float>::infinity()),
          min_weight (0.0f),
          step_size (get_step_size (properties))
        {
          if (properties.find ("max_dist") != properties.end()) {
            try {
              max_length = to<float>(properties["max_dist"]);
            } catch (...) { }
          }
          if (properties.find ("min_dist") != properties.end()) {
            try {
              min_length = to<float>(properties["min_dist"]);
            } catch (...) { }
          }

          if (std::isfinite (step_size)) {
            // User may set these values to a precise value, which may then fail due to floating-point
            //   calculation of streamline length
            // Therefore throw a bit of error margin in here
            float error_margin = 0.1;
            if (properties.find ("downsample_factor") != properties.end())
              error_margin = 0.5 / to<float>(properties["downsample_factor"]);
            max_length += error_margin * step_size;
            min_length -= error_margin * step_size;
          }

          if (properties.find ("max_weight") != properties.end())
            max_weight = to<float>(properties["max_weight"]);

          if (properties.find ("min_weight") != properties.end())
            min_weight = to<float>(properties["min_weight"]);
        }
        size_t determine_upsample_ratio (const Image::Info& info, const Tractography::Properties& properties, const float ratio)
        {
          if (info.ndim() < 3)
            throw Exception ("Cannot perform streamline mapping on image with less than three dimensions");

          Properties::const_iterator i = properties.find ("output_step_size");
          if (i == properties.end()) {
            i = properties.find ("step_size");
            if (i == properties.end())
              throw Exception ("Cannot perform streamline mapping: no step size information in track file header");
          }
          const float step_size = to<float> (i->second);

          return determine_upsample_ratio (info, step_size, ratio);
        }
Exemple #3
0
        Worker::Thresholds::Thresholds (Tractography::Properties& properties) :
          max_num_points (std::numeric_limits<size_t>::max()),
          min_num_points (0),
          max_weight (std::numeric_limits<float>::infinity()),
          min_weight (0.0)
        {

          std::string step_size_string;
          if (properties.find ("output_step_size") == properties.end())
            step_size_string = ((properties.find ("step_size") == properties.end()) ? "0.0" : properties["step_size"]);
          else
            step_size_string = properties["output_step_size"];

          float maxlength = 0.0, minlength = 0.0;
          if (properties.find ("max_dist") != properties.end()) {
            try {
              maxlength = to<float>(properties["max_dist"]);
            } catch (...) { }
          }
          if (properties.find ("min_dist") != properties.end()) {
            try {
              minlength = to<float>(properties["min_dist"]);
            } catch (...) { }
          }

          if (step_size_string == "variable" && (maxlength || minlength))
            throw Exception ("Cannot apply length threshold; step size is inconsistent between input track files");

          const float step_size = to<float>(step_size_string);

          if ((!step_size || !std::isfinite (step_size)) && (maxlength || minlength))
            throw Exception ("Cannot apply length threshold; step size information is incomplete");

          if (maxlength)
            max_num_points = Math::round (maxlength / step_size) + 1;
          if (minlength)
            min_num_points = std::max (2, round (minlength/step_size) + 1);

          if (properties.find ("max_weight") != properties.end())
            max_weight = to<float>(properties["max_weight"]);

          if (properties.find ("min_weight") != properties.end())
            min_weight = to<float>(properties["min_weight"]);

        }
Exemple #4
0
void run () {

  Tractography::Properties properties;
  Tractography::Reader<float> file (argument[0], properties);

  const size_t num_tracks = properties["count"].empty() ? 0 : to<size_t> (properties["count"]);

  float step_size = 0.0;
  if (properties.find ("output_step_size") != properties.end())
    step_size = to<float> (properties["output_step_size"]);
  else
    step_size = to<float> (properties["step_size"]);

  std::vector<float> voxel_size;
  Options opt = get_options("vox");
  if (opt.size())
    voxel_size = opt[0][0];

  if (voxel_size.size() == 1)
    voxel_size.assign (3, voxel_size.front());
  else if (!voxel_size.empty() && voxel_size.size() != 3)
    throw Exception ("voxel size must either be a single isotropic value, or a list of 3 comma-separated voxel dimensions");

  if (!voxel_size.empty())
    INFO ("creating image with voxel dimensions [ " + str(voxel_size[0]) + " " + str(voxel_size[1]) + " " + str(voxel_size[2]) + " ]");

  Image::Header header;
  opt = get_options ("template");
  if (opt.size()) {
    Image::Header template_header (opt[0][0]);
    header = template_header;
    header.comments().clear();
    if (!voxel_size.empty())
      oversample_header (header, voxel_size);
  }
  else {
    if (voxel_size.empty())
      throw Exception ("please specify either a template image or the desired voxel size");
    generate_header (header, argument[0], voxel_size);
  }

  header.set_ndim (3);

  opt = get_options ("contrast");
  contrast_t contrast = opt.size() ? contrast_t(int(opt[0][0])) : TDI;

  opt = get_options ("stat_vox");
  vox_stat_t stat_vox = opt.size() ? vox_stat_t(int(opt[0][0])) : V_SUM;

  opt = get_options ("stat_tck");
  tck_stat_t stat_tck = opt.size() ? tck_stat_t(int(opt[0][0])) : T_MEAN;

  float gaussian_fwhm_tck = 0.0, gaussian_denominator_tck = 0.0;
  opt = get_options ("fwhm_tck");
  if (opt.size()) {
    if (stat_tck != GAUSSIAN) {
      INFO ("Overriding per-track statistic to Gaussian as a full-width half-maximum has been provided.");
      stat_tck = GAUSSIAN;
    }
    gaussian_fwhm_tck = opt[0][0];
    const float gaussian_theta_tck = gaussian_fwhm_tck / (2.0 * sqrt (2.0 * log (2.0)));
    gaussian_denominator_tck = 2.0 * gaussian_theta_tck * gaussian_theta_tck;
  } else if (stat_tck == GAUSSIAN) {
    throw Exception ("If using Gaussian per-streamline statistic, need to provide a full-width half-maximum for the Gaussian kernel using the -fwhm option");
  }

  opt = get_options ("colour");
  const bool colour = opt.size();

  opt = get_options ("map_zero");
  const bool map_zero = opt.size();

  if (colour) {
    header.set_ndim (4);
    header.dim(3) = 3;
    //header.set_description (3, "directionally-encoded colour");
    Image::Stride::set (header, Image::Stride::contiguous_along_axis (3, header));
  }

  // Deal with erroneous statistics & provide appropriate messages
  switch (contrast) {

    case TDI:
      if (stat_vox != V_SUM && stat_vox != V_MEAN) {
        INFO ("Cannot use voxel statistic other than 'sum' or 'mean' for TDI generation - ignoring");
        stat_vox = V_SUM;
      }
      if (stat_tck != T_MEAN)
        INFO ("Cannot use track statistic other than default for TDI generation - ignoring");
      stat_tck = T_MEAN;
      break;

    case PRECISE_TDI:
      if (stat_vox != V_SUM) {
        INFO ("Cannot use voxel statistic other than 'sum' for precise TDI generation - ignoring");
        stat_vox = V_SUM;
      }
      if (stat_tck != T_MEAN)
        INFO ("Cannot use track statistic other than default for precise TDI generation - ignoring");
      stat_tck = T_MEAN;
      break;

    case ENDPOINT:
      if (stat_vox != V_SUM && stat_vox != V_MEAN) {
        INFO ("Cannot use voxel statistic other than 'sum' or 'mean' for endpoint map generation - ignoring");
        stat_vox = V_SUM;
      }
      if (stat_tck != T_MEAN)
        INFO ("Cannot use track statistic other than default for endpoint map generation - ignoring");
      stat_tck = T_MEAN;
      break;

    case LENGTH:
      if (stat_tck != T_MEAN)
        INFO ("Cannot use track statistic other than default for length-weighted TDI generation - ignoring");
      stat_tck = T_MEAN;
      break;

    case INVLENGTH:
      if (stat_tck != T_MEAN)
        INFO ("Cannot use track statistic other than default for inverse-length-weighted TDI generation - ignoring");
      stat_tck = T_MEAN;
      break;

    case SCALAR_MAP:
    case SCALAR_MAP_COUNT:
      break;

    case FOD_AMP:
      if (stat_tck == ENDS_MIN || stat_tck == ENDS_MEAN || stat_tck == ENDS_MAX || stat_tck == ENDS_PROD)
        throw Exception ("Can't use endpoint-based track-wise statistics with FOD_AMP contrast");
      break;

    case CURVATURE:
      break;

    default:
      throw Exception ("Undefined contrast mechanism");

  }


  opt = get_options ("datatype");
  bool manual_datatype = false;

  if (colour) {
    header.datatype() = DataType::Float32;
    manual_datatype = true;
  }

  if (opt.size()) {
    if (colour) {
      INFO ("Can't manually set datatype for directionally-encoded colour processing - overriding to Float32");
    } else {
      header.datatype() = DataType::parse (opt[0][0]);
      manual_datatype = true;
    }
  }

  if (get_options ("tck_weights_in").size() || (manual_datatype && header.datatype().is_integer())) {
    if ((manual_datatype && header.datatype().is_integer()))
      INFO ("Can't use an integer type if streamline weights are provided; overriding to Float32");
    header.datatype() = DataType::Float32;
    manual_datatype = true;
  }

  header.datatype().set_byte_order_native();

  for (Tractography::Properties::iterator i = properties.begin(); i != properties.end(); ++i)
    header.comments().push_back (i->first + ": " + i->second);
  for (std::multimap<std::string,std::string>::const_iterator i = properties.roi.begin(); i != properties.roi.end(); ++i)
    header.comments().push_back ("ROI: " + i->first + " " + i->second);
  for (std::vector<std::string>::iterator i = properties.comments.begin(); i != properties.comments.end(); ++i)
    header.comments().push_back ("comment: " + *i);

  size_t upsample_ratio = 1;
  opt = get_options ("upsample");
  if (opt.size()) {
    upsample_ratio = opt[0][0];
    INFO ("track upsampling ratio manually set to " + str(upsample_ratio));
  }
  else if (step_size && std::isfinite (step_size)) {
    // If accurately calculating the length through each voxel traversed, need a higher upsampling ratio
    //   (1/10th of the voxel size was found to give a good quantification of chordal length)
    // For all other applications, making the upsampled step size about 1/3rd of a voxel seems sufficient
    const float voxel_step_ratio = (contrast == PRECISE_TDI) ? 0.1 : 0.333;
    upsample_ratio = Math::ceil<size_t> (step_size / (minvalue (header.vox(0), header.vox(1), header.vox(2)) * voxel_step_ratio));
    INFO ("track upsampling ratio automatically set to " + str(upsample_ratio));
  }
  else {
    if (contrast != PRECISE_TDI)
      WARN ("track upsampling off; track step size information in header is absent or malformed");
  }

  const bool dump = get_options ("dump").size();
  if (dump && Path::has_suffix (argument[1], "mih"))
    throw Exception ("Option -dump only works when outputting to .mih image format");

  std::string msg = str("Generating ") + (colour ? "colour " : "") + "image with ";
  switch (contrast) {
    case TDI:              msg += "density";                    break;
    case PRECISE_TDI:      msg += "density (precise)";          break;
    case ENDPOINT:         msg += "endpoint density";           break;
    case LENGTH:           msg += "length";                     break;
    case INVLENGTH:        msg += "inverse length";             break;
    case SCALAR_MAP:       msg += "scalar map";                 break;
    case SCALAR_MAP_COUNT: msg += "scalar-map-thresholded tdi"; break;
    case FOD_AMP:          msg += "FOD amplitude";              break;
    case CURVATURE:        msg += "curvature";                  break;
    default:               msg += "ERROR";                      break;
  }
  msg += " contrast";
  if (contrast == SCALAR_MAP || contrast == SCALAR_MAP_COUNT || contrast == FOD_AMP || contrast == CURVATURE)
    msg += ", ";
  else
    msg += " and ";
  switch (stat_vox) {
    case V_SUM:  msg += "summed";  break;
    case V_MIN:  msg += "minimum"; break;
    case V_MEAN: msg += "mean";    break;
    case V_MAX:  msg += "maximum"; break;
    default:     msg += "ERROR";   break;
  }
  msg += " per-voxel statistic";
  if (contrast == SCALAR_MAP || contrast == SCALAR_MAP_COUNT || contrast == FOD_AMP || contrast == CURVATURE) {
    msg += " and ";
    switch (stat_tck) {
      case T_SUM:          msg += "summed";  break;
      case T_MIN:          msg += "minimum"; break;
      case T_MEAN:         msg += "mean";    break;
      case T_MAX:          msg += "maximum"; break;
      case T_MEDIAN:       msg += "median";  break;
      case T_MEAN_NONZERO: msg += "mean (nonzero)"; break;
      case GAUSSIAN:       msg += "gaussian (FWHM " + str (gaussian_fwhm_tck) + "mm)"; break;
      case ENDS_MIN:       msg += "endpoints (minimum)"; break;
      case ENDS_MEAN:      msg += "endpoints (mean)"; break;
      case ENDS_MAX:       msg += "endpoints (maximum)"; break;
      case ENDS_PROD:      msg += "endpoints (product)"; break;
      default:             msg += "ERROR";   break;
    }
    msg += " per-track statistic";
  }
  INFO (msg);

  switch (contrast) {
    case TDI:              header.comments().push_back ("track density image"); break;
    case PRECISE_TDI:      header.comments().push_back ("track density image (precise calculation)"); break;
    case ENDPOINT:         header.comments().push_back ("track endpoint density image"); break;
    case LENGTH:           header.comments().push_back ("track density image (weighted by track length)"); break;
    case INVLENGTH:        header.comments().push_back ("track density image (weighted by inverse track length)"); break;
    case SCALAR_MAP:       header.comments().push_back ("track-weighted image (using scalar image)"); break;
    case SCALAR_MAP_COUNT: header.comments().push_back ("track density image (using scalar image thresholding)"); break;
    case FOD_AMP:          header.comments().push_back ("track-weighted image (using FOD amplitude)"); break;
    case CURVATURE:        header.comments().push_back ("track-weighted image (using track curvature)"); break;
  }

  TrackLoader loader (file, num_tracks);

  // Use a branching IF instead of a switch statement to permit scope
  if (contrast == TDI || contrast == ENDPOINT || contrast == LENGTH || contrast == INVLENGTH || (contrast == CURVATURE && stat_tck != GAUSSIAN)) {

    if (!manual_datatype) {
      header.datatype() = (contrast == TDI || contrast == ENDPOINT) ? DataType::UInt32 : DataType::Float32;
      header.datatype().set_byte_order_native();
    }

    if (colour) {
      TrackMapperTWI <SetVoxelDEC> mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck);
      MapWriterColour<SetVoxelDEC> writer (header, argument[1], dump, stat_vox);
      Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelDEC(), writer);
    } else {
      TrackMapperTWI    <SetVoxel>   mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck);
      Ptr< MapWriterBase<SetVoxel> > writer (make_writer<SetVoxel> (header, argument[1], dump, stat_vox));
      Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxel(), *writer);
    }

  } else if (contrast == PRECISE_TDI) {

    if (!manual_datatype) {
      header.datatype() = DataType::Float32;
      header.datatype().set_byte_order_native();
    }

    if (colour) {
      TrackMapperTWI <SetVoxelDir> mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck);
      MapWriterColour<SetVoxelDir> writer (header, argument[1], dump, stat_vox);
      Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelDir(), writer);
    } else {
      TrackMapperTWI <       SetVoxelDir> mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck);
      MapWriter      <float, SetVoxelDir> writer (header, argument[1], dump, stat_vox);
      Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelDir(), writer);
    }

  } else if (contrast == CURVATURE && stat_tck == GAUSSIAN) {

    if (!manual_datatype) {
      header.datatype() = DataType::Float32;
      header.datatype().set_byte_order_native();
    }

    if (colour) {
      TrackMapperTWI <SetVoxelDECFactor> mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck, gaussian_denominator_tck);
      MapWriterColour<SetVoxelDECFactor> writer (header, argument[1], dump, stat_vox);
      Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelDECFactor(), writer);
    } else {
      TrackMapperTWI    <SetVoxelFactor>   mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck, gaussian_denominator_tck);
      Ptr< MapWriterBase<SetVoxelFactor> > writer (make_writer<SetVoxelFactor> (header, argument[1], dump, stat_vox));
      Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelFactor(), *writer);
    }

  } else if (contrast == SCALAR_MAP || contrast == SCALAR_MAP_COUNT || contrast == FOD_AMP) {

    opt = get_options ("image");
    if (!opt.size()) {
      if (contrast == SCALAR_MAP || contrast == SCALAR_MAP_COUNT)
        throw Exception ("If using 'scalar_map' or 'scalar_map_count' contrast, must provide the relevant scalar image using -image option");
      else
        throw Exception ("If using 'fod_amp' contrast, must provide the relevant spherical harmonic image using -image option");
    }

    Image::BufferPreload<float> input_image (opt[0][0]);
    if ((contrast == SCALAR_MAP || contrast == SCALAR_MAP_COUNT)) {
      if (!(input_image.ndim() == 3 || (input_image.ndim() == 4 && input_image.dim(3) == 1)))
        throw Exception ("Use of 'scalar_map' contrast option requires a 3-dimensional image; your image is " + str(input_image.ndim()) + "D");
    }

    if (contrast == FOD_AMP && input_image.ndim() != 4)
      throw Exception ("Use of 'fod_amp' contrast option requires a 4-dimensional image; your image is " + str(input_image.ndim()) + "D");

    if (!manual_datatype && (input_image.datatype() != DataType::Bit))
      header.datatype() = input_image.datatype();

    if (colour) {

      if (stat_tck == GAUSSIAN) {
        TrackMapperTWIImage <SetVoxelDECFactor> mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck, gaussian_denominator_tck, input_image);
        MapWriterColour     <SetVoxelDECFactor> writer (header, argument[1], dump, stat_vox);
        Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelDECFactor(), writer);
      } else {
        TrackMapperTWIImage <SetVoxelDEC> mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck, 0.0, input_image);
        MapWriterColour     <SetVoxelDEC> writer (header, argument[1], dump, stat_vox);
        Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelDEC(), writer);
      }

    } else {

      if (stat_tck == GAUSSIAN) {
        TrackMapperTWIImage <SetVoxelFactor>   mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck, gaussian_denominator_tck, input_image);
        Ptr< MapWriterBase  <SetVoxelFactor> > writer (make_writer<SetVoxelFactor> (header, argument[1], dump, stat_vox));
        Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxelFactor(), *writer);
      } else {
        TrackMapperTWIImage <SetVoxel>   mapper (header, upsample_ratio, map_zero, step_size, contrast, stat_tck, 0.0, input_image);
        Ptr< MapWriterBase  <SetVoxel> > writer (make_writer<SetVoxel> (header, argument[1], dump, stat_vox));
        Thread::run_queue (loader, Tractography::Streamline<float>(), Thread::multi (mapper), SetVoxel(), *writer);
      }

    }

  } else {
    throw Exception ("Undefined contrast mechanism for output image");
  }

}
Exemple #5
0
void run ()
{

  const bool weights_provided = get_options ("tck_weights_in").size();

  float step_size = NaN;
  size_t count = 0, header_count = 0;
  float min_length = std::numeric_limits<float>::infinity();
  float max_length = 0.0f;
  double sum_lengths = 0.0, sum_weights = 0.0;
  std::vector<double> histogram;
  std::vector<LW> all_lengths;
  all_lengths.reserve (header_count);

  {
    Tractography::Properties properties;
    Tractography::Reader<float> reader (argument[0], properties);

    if (properties.find ("count") != properties.end())
      header_count = to<size_t> (properties["count"]);

    if (properties.find ("output_step_size") != properties.end())
      step_size = to<float> (properties["output_step_size"]);
    else
      step_size = to<float> (properties["step_size"]);
    if (!std::isfinite (step_size) || !step_size) {
      WARN ("Streamline step size undefined in header");
      if (get_options ("histogram").size())
        WARN ("Histogram will be henerated using a 1mm interval");
    }

    std::unique_ptr<File::OFStream> dump;
    auto opt = get_options ("dump");
    if (opt.size())
      dump.reset (new File::OFStream (std::string(opt[0][0]), std::ios_base::out | std::ios_base::trunc));

    ProgressBar progress ("Reading track file", header_count);
    Streamline<> tck;
    while (reader (tck)) {
      ++count;
      const float length = std::isfinite (step_size) ? tck.calc_length (step_size) : tck.calc_length();
      if (std::isfinite (length)) {
        min_length = std::min (min_length, length);
        max_length = std::max (max_length, length);
        sum_lengths += tck.weight * length;
        sum_weights += tck.weight;
        all_lengths.push_back (LW (length, tck.weight));
        const size_t index = std::isfinite (step_size) ? std::round (length / step_size) : std::round (length);
        while (histogram.size() <= index)
          histogram.push_back (0.0);
        histogram[index] += tck.weight;
      }
      if (dump)
        (*dump) << length << "\n";
      ++progress;
    }
  }

  if (histogram.front())
    WARN ("read " + str(histogram.front()) + " zero-length tracks");
  if (count != header_count)
    WARN ("expected " + str(header_count) + " tracks according to header; read " + str(count));

  const float mean_length = sum_lengths / sum_weights;

  float median_length = 0.0f;
  if (weights_provided) {
    // Perform a weighted median calculation
    std::sort (all_lengths.begin(), all_lengths.end());
    size_t median_index = 0;
    double sum = sum_weights - all_lengths[0].get_weight();
    while (sum > 0.5 * sum_weights) { sum -= all_lengths[++median_index].get_weight(); }
    median_length = all_lengths[median_index].get_length();
  } else {
    median_length = Math::median (all_lengths).get_length();
  }

  double stdev = 0.0;
  for (std::vector<LW>::const_iterator i = all_lengths.begin(); i != all_lengths.end(); ++i)
    stdev += i->get_weight() * Math::pow2 (i->get_length() - mean_length);
  stdev = std::sqrt (stdev / (((count - 1) / float(count)) * sum_weights));

  const size_t width = 12;

  std::cout << " " << std::setw(width) << std::right << "mean"
            << " " << std::setw(width) << std::right << "median"
            << " " << std::setw(width) << std::right << "std. dev."
            << " " << std::setw(width) << std::right << "min"
            << " " << std::setw(width) << std::right << "max"
            << " " << std::setw(width) << std::right << "count\n";

  std::cout << " " << std::setw(width) << std::right << (mean_length)
            << " " << std::setw(width) << std::right << (median_length)
            << " " << std::setw(width) << std::right << (stdev)
            << " " << std::setw(width) << std::right << (min_length)
            << " " << std::setw(width) << std::right << (max_length)
            << " " << std::setw(width) << std::right << (count) << "\n";

  auto opt = get_options ("histogram");
  if (opt.size()) {
    File::OFStream out (opt[0][0], std::ios_base::out | std::ios_base::trunc);
    if (!std::isfinite (step_size))
      step_size = 1.0f;
    if (weights_provided) {
      out << "Length,Sum_weights\n";
      for (size_t i = 0; i != histogram.size(); ++i)
        out << str(i * step_size) << "," << str(histogram[i]) << "\n";
    } else {
      out << "Length,Count\n";
      for (size_t i = 0; i != histogram.size(); ++i)
        out << str(i * step_size) << "," << str<size_t>(histogram[i]) << "\n";
    }
    out << "\n";
  }

}
void run ()
{

  const std::string path = argument[0];

  Tractography::Properties properties;
  Tractography::Reader<float> reader (path, properties);

  size_t init_count = 0;
  if (properties.find ("count") == properties.end()) {
    INFO ("\"count\" field not set in file " + path);
  } else {
    init_count = to<size_t>(properties["count"]);
    INFO ("Value of \"count\" in file " + path + " is " + str(init_count));
  }

  // Read the actual number of streamlines in the file
  Tractography::Streamline<float> tck;
  size_t count = 0;
  {
    ProgressBar progress ("evaluating actual streamline data count...");
    while (reader (tck)) {
      ++count;
      ++progress;
    }
  }
  reader.close();
  INFO ("Actual number of streamlines read is " + str(count));

  // Find the appropriate file offset in the header
  KeyValue kv (argument[0], "mrtrix tracks");
  std::string data_file;
  int64_t count_offset = 0;
  int64_t current_offset = 0;
  while (kv.next()) {
    std::string key = lowercase (kv.key());
    if (key == "count")
      count_offset = current_offset;
    current_offset = kv.tellg();
  }
  kv.close();

  if (!count_offset)
    throw Exception ("could not find location of \"count\" field in file \"" + path + "\"");
  DEBUG ("File offset for \"count\" field is " + str(count_offset));

  // Overwrite this data
  // Used C-style file access here as ofstream would either wipe the file contents, or
  //   append the data instead of inserting it
  FILE* fp;
  fp = fopen (path.c_str(), "r+");
  if (!fp)
    throw Exception ("could not open tracks file \"" + path + "\" for repair");
  if (fseek (fp, count_offset, SEEK_SET)) {
    fclose (fp);
    throw Exception ("unable to seek to the appropriate position in the file");
  }
  const std::string string = "count: " + str(count) + "\ntotal_count: " + str(count) + "\nEND\n";
  const int rvalue = fputs (string.c_str(), fp);
  fclose (fp);
  if (rvalue == EOF) {
    WARN ("\"count\" field may not have been properly updated");
  } else {
    INFO ("\"count\" field updated successfully");
  }

}
Exemple #7
0
void run ()
{

  const size_t num_inputs = argument.size() - 1;
  const std::string output_path = argument[num_inputs];

  // Make sure configuration is sensible
  if (get_options("tck_weights_in").size() && num_inputs > 1)
    throw Exception ("Cannot use per-streamline weighting with multiple input files");

  // Get the consensus streamline properties from among the multiple input files
  Tractography::Properties properties;
  size_t count = 0;
  vector<std::string> input_file_list;

  for (size_t file_index = 0; file_index != num_inputs; ++file_index) {

    input_file_list.push_back (argument[file_index]);

    Properties p;
    Reader<float> reader (argument[file_index], p);

    for (vector<std::string>::const_iterator i = p.comments.begin(); i != p.comments.end(); ++i) {
      bool present = false;
      for (vector<std::string>::const_iterator j = properties.comments.begin(); !present && j != properties.comments.end(); ++j)
        present = (*i == *j);
      if (!present)
        properties.comments.push_back (*i);
    }

    // ROI paths are ignored - otherwise tckedit will try to find the ROIs used
    //   during streamlines generation!

    size_t this_count = 0, this_total_count = 0;

    for (Properties::const_iterator i = p.begin(); i != p.end(); ++i) {
      if (i->first == "count") {
        this_count = to<float>(i->second);
      } else if (i->first == "total_count") {
        this_total_count += to<float>(i->second);
      } else {
        Properties::iterator existing = properties.find (i->first);
        if (existing == properties.end())
          properties.insert (*i);
        else if (i->second != existing->second)
          existing->second = "variable";
      }
    }

    count += this_count;

  }

  DEBUG ("estimated number of input tracks: " + str(count));

  load_rois (properties);

  // Some properties from tracking may be overwritten by this editing process
  // Due to the potential use of masking, we have no choice but to clear the
  //   properties class of any fields that would otherwise propagate through
  //   and be applied as part of this editing
  erase_if_present (properties, "min_dist");
  erase_if_present (properties, "max_dist");
  erase_if_present (properties, "min_weight");
  erase_if_present (properties, "max_weight");
  Editing::load_properties (properties);

  // Parameters that the worker threads need to be aware of, but do not appear in Properties
  const bool inverse   = get_options ("inverse").size();
  const bool ends_only = get_options ("ends_only").size();

  // Parameters that the output thread needs to be aware of
  const size_t number = get_option_value ("number", size_t(0));
  const size_t skip   = get_option_value ("skip",   size_t(0));

  Loader loader (input_file_list);
  Worker worker (properties, inverse, ends_only);
  // This needs to be run AFTER creation of the Worker class
  // (worker needs to be able to set max & min number of points based on step size in input file,
  //  receiver needs "output_step_size" field to have been updated before file creation)
  Receiver receiver (output_path, properties, number, skip);

  Thread::run_queue (
      loader, 
      Thread::batch (Streamline<>()),
      Thread::multi (worker), 
      Thread::batch (Streamline<>()),
      receiver);

}
Exemple #8
0
void erase_if_present (Tractography::Properties& p, const std::string s)
{
  auto i = p.find (s);
  if (i != p.end())
    p.erase (i);
}
void load_properties (Tractography::Properties& properties)
{

  // ROIOption
  Options opt = get_options ("include");
  for (size_t i = 0; i < opt.size(); ++i)
    properties.include.add (ROI (opt[i][0]));

  opt = get_options ("exclude");
  for (size_t i = 0; i < opt.size(); ++i)
    properties.exclude.add (ROI (opt[i][0]));

  opt = get_options ("mask");
  for (size_t i = 0; i < opt.size(); ++i)
    properties.mask.add (ROI (opt[i][0]));


  // LengthOption
  opt = get_options ("maxlength");
  if (opt.size()) {
    if (properties.find ("max_dist") == properties.end()) {
      properties["max_dist"] = str(opt[0][0]);
    } else {
      try {
        const float maxlength = std::min (float(opt[0][0]), to<float>(properties["max_dist"]));
        properties["max_dist"] = str(maxlength);
      } catch (...) {
        properties["max_dist"] = str(opt[0][0]);
      }
    }
  }
  opt = get_options ("minlength");
  if (opt.size()) {
    if (properties.find ("min_dist") == properties.end()) {
      properties["min_dist"] = str(opt[0][0]);
    } else {
      try {
        const float minlength = std::max (float(opt[0][0]), to<float>(properties["min_dist"]));
        properties["min_dist"] = str(minlength);
      } catch (...) {
        properties["min_dist"] = str(opt[0][0]);
      }
    }
  }


  // ResampleOption
  // The relevant entry in Properties is updated at a later stage


  // TruncateOption
  // These have no influence on Properties


  // WeightsOption
  // Only the thresholds have an influence on Properties
  opt = get_options ("maxweight");
  if (opt.size())
    properties["max_weight"] = std::string(opt[0][0]);
  opt = get_options ("minweight");
  if (opt.size())
    properties["min_weight"] = std::string(opt[0][0]);

}
value_type AFDConnectivity::get (const std::string& path)
{

  Tractography::Properties properties;
  Tractography::Reader<value_type> reader (path, properties);
  const size_t track_count = (properties.find ("count") == properties.end() ? 0 : to<size_t>(properties["count"]));
  DWI::Tractography::Mapping::TrackLoader loader (reader, track_count, "summing apparent fibre density within track");

  // If WBFT is provided, this is the sum of (volume/length) across streamlines
  // Otherwise, it's a sum of lengths of all streamlines (for later scaling by mean streamline length)
  double sum_contributions = 0.0;

  size_t count = 0;

  Tractography::Streamline<value_type> tck;
  while (loader (tck)) {
    ++count;

    SetDixel dixels;
    mapper (tck, dixels);
    double this_length = 0.0, this_volume = 0.0;

    for (SetDixel::const_iterator i = dixels.begin(); i != dixels.end(); ++i) {
      this_length += i->get_length();

      // If wbft has not been provided (i.e. FODs have not been pre-segmented), need to
      //   check to see if any data have been provided for this voxel; and if not yet,
      //   run the segmenter
      if (!have_wbft) {

        VoxelAccessor v (accessor());
        assign_pos_of (*i, 0, 3).to (v);
        if (!v.value()) {

          assign_pos_of (*i, 0, 3).to (v_fod);
          DWI::FMLS::SH_coefs fod_data;
          DWI::FMLS::FOD_lobes fod_lobes;

          fod_data.vox[0] = v_fod.index (0); fod_data.vox[1] = v_fod.index (1); fod_data.vox[2] = v_fod.index (2);
          fod_data.resize (v_fod.size (3));
          for (auto i = Loop(3) (v_fod); i; ++i)
            fod_data[v_fod.index (3)] = v_fod.value();

          (*fmls) (fod_data, fod_lobes);
          (*this) (fod_lobes);

        }
      }

      const size_t fixel_index = dixel2fixel (*i);
      Fixel& fixel = fixels[fixel_index];
      fixel.add_to_selection (i->get_length());
      if (have_wbft)
        this_volume += fixel.get_selected_volume (i->get_length());

    }

    if (have_wbft)
      sum_contributions += (this_volume / this_length);
    else
      sum_contributions += this_length;

  }

  if (!have_wbft) {

    // Streamlines define a fixel mask; go through and get all the fibre volumes
    double sum_volumes = 0.0;

    if (all_fixels) {

      // All fixels contribute to the result
      for (std::vector<Fixel>::const_iterator i = fixels.begin(); i != fixels.end(); ++i) {
        if (i->is_selected())
          sum_volumes += i->get_FOD();
      }

    } else {

      // Only allow one fixel per voxel to contribute to the result
      VoxelAccessor v (accessor());
      for (auto l = Loop(v) (v); l; ++l) {
        if (v.value()) {
          value_type voxel_afd = 0.0, max_td = 0.0;
          for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i) {
            if (i().get_selected_length() > max_td) {
              max_td = i().get_selected_length();
              voxel_afd = i().get_FOD();
            }
          }
          sum_volumes += voxel_afd;
        }
      }

    }

    // sum_contributions currently stores sum of streamline lengths;
    //   turn into a mean length, then combine with volume to get a connectivity value
    const double mean_length = sum_contributions / double(count);
    sum_contributions = sum_volumes / mean_length;

  }

  return sum_contributions;

}