static Image::Header param (const Image::Header& header, size_t nvols) {
   Image::Header ret (header);
   ret.datatype() = DataType::Float32;
   if (nvols) ret.dim(3) = nvols;
   else ret.set_ndim (3);
   return ret;
 }
Exemple #2
0
      Dynamic::~Dynamic()
      {

        INFO ("Dynamic seeeding required " + str (total_samples) + " samples to draw " + str (total_seeds) + " seeds");

#ifdef DYNAMIC_SEED_DEBUGGING
        const double final_mu = mu();

        // Output seeding probabilites at end of execution
        Image::Header H;
        H.info() = info();
        H.datatype() = DataType::Float32;
        Image::Buffer<float> prob_mean_data ("seed_prob_mean.mif", H), prob_sum_data ("seed_prob_sum.mif", H);
        Image::Buffer<float>::voxel_type prob_mean (prob_mean_data), prob_sum (prob_sum_data);
        VoxelAccessor v (accessor);
        Image::Loop loop;
        for (loop.start (v, prob_mean, prob_sum); loop.ok(); loop.next (v, prob_mean, prob_sum)) {
          if (v.value()) {

            float sum = 0.0;
            size_t count = 0;
            for (Fixel_map<Fixel_TD_seed>::ConstIterator i = begin (v); i; ++i) {
              sum += i().get_seed_prob (final_mu);
              ++count;
            }
            prob_mean.value() = sum / float(count);
            prob_sum .value() = sum;

          }
        }
#endif

      }
Exemple #3
0
void run ()
{
  Image::Buffer<float> dir_buf (argument[0]);
  Image::Buffer<float>::voxel_type dir_vox (dir_buf);

  Image::Header header (argument[0]);
  header.dim(3) = header.dim(3)/3;

  Image::Buffer<float> amp_buf (argument[1], header);
  Image::Buffer<float>::voxel_type amp_vox (amp_buf);

  Image::LoopInOrder loop (dir_vox, "converting directions to amplitudes...", 0, 3);

  for (loop.start (dir_vox, amp_vox); loop.ok(); loop.next (dir_vox, amp_vox)) {
    Math::Vector<float> dir (3);
    dir_vox[3] = 0;
    amp_vox[3] = 0;
    while (dir_vox[3] < dir_vox.dim(3)) {
      dir[0] = dir_vox.value(); ++dir_vox[3];
      dir[1] = dir_vox.value(); ++dir_vox[3];
      dir[2] = dir_vox.value(); ++dir_vox[3];

      float amplitude = 0.0;
      if (std::isfinite (dir[0]) && std::isfinite (dir[1]) && std::isfinite (dir[2]))
        amplitude = Math::norm (dir);

      amp_vox.value() = amplitude;
      ++amp_vox[3];
    }
  }
}
Exemple #4
0
void print_comments (const Image::Header& header)
{
  std::string buffer;
  for (std::vector<std::string>::const_iterator i = header.comments().begin(); i != header.comments().end(); ++i)
    buffer += *i + "\n";
  std::cout << buffer;
}
Exemple #5
0
void run () {

  Image::BufferPreload<bool> input_data (argument[0]);
  Image::BufferPreload<bool>::voxel_type input_voxel (input_data);

  const size_t filter_index = argument[1];

  Image::Filter::Base* filter = NULL;
  switch (filter_index) {
    case 0: filter = create_dilate_filter (input_voxel); break;
    case 1: filter = create_erode_filter  (input_voxel); break;
    case 2: filter = create_lcc_filter    (input_voxel); break;
    case 3: filter = create_median_filter (input_voxel); break;
    default: assert (0);
  }

  Image::Header header;
  header.info() = filter->info();
  Image::Stride::set_from_command_line (header);

  Image::Buffer<bool> output_data (argument[2], header);
  Image::Buffer<bool>::voxel_type output_voxel (output_data);

  filter->set_message (std::string("applying ") + std::string(argument[1]) + " filter to image " + std::string(argument[0]) + "... ");

  switch (filter_index) {
    case 0: (*dynamic_cast<Image::Filter::Dilate*>                    (filter)) (input_voxel, output_voxel); break;
    case 1: (*dynamic_cast<Image::Filter::Erode*>                     (filter)) (input_voxel, output_voxel); break;
    case 2: (*dynamic_cast<Image::Filter::LargestConnectedComponent*> (filter)) (input_voxel, output_voxel); break;
    case 3: (*dynamic_cast<Image::Filter::Median*>                    (filter)) (input_voxel, output_voxel); break;
  }

  delete filter;

}
Exemple #6
0
void print_properties (const Image::Header& header)
{
  std::string buffer;
  for (std::map<std::string, std::string>::const_iterator i = header.begin(); i != header.end(); ++i)
    buffer += i->first + ": " + i->second + "\n";
  std::cout << buffer;
}
Exemple #7
0
void print_vox (const Image::Header& header)
{
  std::string buffer;
  for (size_t i = 0; i < header.ndim(); ++i) {
    if (i) buffer += " ";
    buffer += str (header.vox (i));
  }
  std::cout << buffer << "\n";
}
Exemple #8
0
void print_strides (const Image::Header& header)
{
  std::string buffer;
  std::vector<ssize_t> strides (Image::Stride::get (header));
  Image::Stride::symbolise (strides);
  for (size_t i = 0; i < header.ndim(); ++i) {
    if (i) buffer += " ";
    buffer += header.stride (i) ? str (strides[i]) : "?";
  }
  std::cout << buffer << "\n";
}
Exemple #9
0
inline Point<> get_bounds (const Image::Header& header, Point<int> corner, int axis, const Point<>& ref, const Point<>& d1, const Point<>& d2) {
  const Math::Matrix<float>& T (header.transform());
  Point<> pos (T(0,3), T(1,3), T(2,3));
  for (size_t n = 0; n < 3; ++n) 
    if (corner[n]) 
      pos += header.dim(n) * header.vox(n) * Point<> (T(0,n), T(1,n), T(2,n));
  Point<> dir (T(0,axis), T(1,axis), T(2,axis));
  Point<> ret = get_bounds (pos, dir, ref, d1, d2);
  ret[2] /= -header.vox (axis) * header.dim (axis);
  return ret;
}
Exemple #10
0
void set_strides (Image::Header& header)
{
  Options opt = get_options ("stride");
  if (opt.size()) {
    std::vector<int> strides = opt[0][0];
    if (strides.size() > header.ndim())
      throw Exception ("too many axes supplied to -stride option");
    for (size_t n = 0; n < strides.size(); ++n)
      header.stride(n) = strides[n];
  }
}
Exemple #11
0
void run ()
{
  conv_t conversion = NONE;
  Options opt = get_options ("convert");
  if (opt.size()) {
    switch (int(opt[0][0])) {
      case 0: conversion = OLD; break;
      case 1: conversion = NEW; break;
      case 2:
#ifndef USE_NON_ORTHONORMAL_SH_BASIS
        conversion = NEW;
#else
        conversion = OLD;
#endif
        break;
      case 3: conversion = FORCE_OLDTONEW; break;
      case 4: conversion = FORCE_NEWTOOLD; break;
      default: assert (0); break;
    }
  }

  for (std::vector<ParsedArgument>::const_iterator i = argument.begin(); i != argument.end(); ++i) {

    const std::string path = *i;
    Image::Header H (path);
    if (H.ndim() != 4) {
      WARN ("Image \"" + H.name() + "\" is not 4D and therefore cannot be an SH image");
      continue;
    }
    const size_t lmax = Math::SH::LforN (H.dim(3));
    if (!lmax) {
      WARN ("Image \"" + H.name() + "\" does not contain enough volumes to be an SH image");
      continue;
    }
    if (Math::SH::NforL (lmax) != size_t(H.dim(3))) {
      WARN ("Image \"" + H.name() + "\" does not contain a number of volumes appropriate for an SH image");
      continue;
    }
    if (!H.datatype().is_floating_point()) {
      WARN ("Image \"" + H.name() + "\" does not use a floating-point data type and therefore cannot be an SH image");
      continue;
    }

    if (H.datatype().bytes() == 4)
      check_and_update<float>  (H, conversion);
    else
      check_and_update<double> (H, conversion);

  }

};
void run ()
{
  Image::Header header (argument[0]);

  header.datatype() = DataType::Float32;
  header.set_ndim (4);
  header.dim(3) = 3;
  Image::Stride::set (header, Image::Stride::contiguous_along_axis (3));

  Image::Buffer<float> warp_buffer (argument[1], header);

  Image::ThreadedLoop ("initialising warp image...", warp_buffer, 0, 3)
    .run (write_coordinates (warp_buffer), warp_buffer.voxel());
}
Exemple #13
0
    void save_bvecs_bvals (const Image::Header& header, const std::string& path)
    {

      std::string bvecs_path, bvals_path;
      if (path.size() >= 5 && path.substr (path.size() - 5, path.size()) == "bvecs") {
        bvecs_path = path;
        bvals_path = path.substr (0, path.size() - 5) + "bvals";
      } else if (path.size() >= 5 && path.substr (path.size() - 5, path.size()) == "bvals") {
        bvecs_path = path.substr (0, path.size() - 5) + "bvecs";
        bvals_path = path;
      } else {
        bvecs_path = path + "bvecs";
        bvals_path = path + "bvals";
      }

      const Math::Matrix<float>& grad (header.DW_scheme());
      Math::Matrix<float> G (grad.rows(), 3);

      // rotate vectors from scanner space to image space
      Math::Matrix<float> D (header.transform());
      Math::Permutation p (4);
      int signum;
      Math::LU::decomp (D, p, signum);
      Math::Matrix<float> image2scanner (4,4);
      Math::LU::inv (image2scanner, D, p);
      Math::Matrix<float> rotation = image2scanner.sub (0,3,0,3);
      Math::Matrix<float> grad_G = grad.sub (0, grad.rows(), 0, 3);
      Math::mult (G, float(0.0), float(1.0), CblasNoTrans, grad_G, CblasTrans, rotation);

      // deal with FSL requiring gradient directions to coincide with data strides
      // also transpose matrices in preparation for file output
      std::vector<size_t> order = Image::Stride::order (header, 0, 3);
      Math::Matrix<float> bvecs (3, grad.rows());
      Math::Matrix<float> bvals (1, grad.rows());
      for (size_t n = 0; n < G.rows(); ++n) {
        bvecs(0,n) = header.stride(order[0]) > 0 ? G(n,order[0]) : -G(n,order[0]);
        bvecs(1,n) = header.stride(order[1]) > 0 ? G(n,order[1]) : -G(n,order[1]);
        bvecs(2,n) = header.stride(order[2]) > 0 ? G(n,order[2]) : -G(n,order[2]);
        bvals(0,n) = grad(n,3);
      }

      bvecs.save (bvecs_path);
      bvals.save (bvals_path);

    }
        void oversample_header (Image::Header& header, const std::vector<float>& voxel_size)
        {
          INFO ("oversampling header...");

          Math::Matrix<float> transform (header.transform());
          for (size_t j = 0; j != 3; ++j) {
            for (size_t i = 0; i < 3; ++i)
              header.transform()(i,3) += 0.5 * (voxel_size[j] - header.vox(j)) * transform(i,j);
            header.dim(j) = std::ceil(header.dim(j) * header.vox(j) / voxel_size[j]);
            header.vox(j) = voxel_size[j];
          }
        }
Exemple #15
0
void run ()
{
  Image::Header input_header (argument[0]);
  Image::Buffer<bool> input_data (input_header);
  Image::Buffer<bool>::voxel_type input_voxel (input_data);

  Image::Filter::ConnectedComponents connected_filter(input_voxel);
  Image::Header header (input_data);
  header.info() = connected_filter.info();
  Image::Buffer<int> output_data (argument[1], header);
  Image::Buffer<int>::voxel_type output_vox (output_data);

  Options opt = get_options ("axes");
  std::vector<int> axes;
  if (opt.size()) {
    axes = opt[0][0];
    for (size_t d = 0; d < input_data.ndim(); d++)
      connected_filter.set_ignore_dim (d, true);
    for (size_t i = 0; i < axes.size(); i++) {
      if (axes[i] >= static_cast<int> (input_header.ndim()) || axes[i] < 0)
        throw Exception ("axis supplied to option -ignore is out of bounds");
      connected_filter.set_ignore_dim (axes[i], false);
    }
  }

  opt = get_options ("largest");
  if (opt.size())
    connected_filter.set_largest_only (true);

  opt = get_options ("connectivity");
  if (opt.size())
    connected_filter.set_26_connectivity(true);

  connected_filter.set_message ("computing connected components...");
  connected_filter (input_voxel, output_vox);
}
Exemple #16
0
 Segmented_FOD_receiver (const Image::Header& header, const DWI::Directions::Set& directions) :
   H (header),
   H_fixel (header),
   dirs (directions),
   lmax (0)
 {
   // aPSF does not have data for lmax > 10
   lmax = std::min (size_t(10), Math::SH::LforN (header.dim(3)));
   H.set_ndim (3);
   H.DW_scheme().clear();
   H_fixel.set_ndim (3);
   H_fixel.DW_scheme().clear();
   H_fixel.datatype() = DataType::UInt64;
   H_fixel.datatype().set_byte_order_native();
   H_fixel[Image::Sparse::name_key] = str(typeid(FixelMetric).name());
   H_fixel[Image::Sparse::size_key] = str(sizeof(FixelMetric));
 }
        void generate_header (Image::Header& header, const std::string& tck_file_path, const std::vector<float>& voxel_size)
        {

          Tractography::Properties properties;
          Tractography::Reader<float> file (tck_file_path, properties);

          Streamline<float> tck;
          size_t track_counter = 0;

          Point<float> min_values ( INFINITY,  INFINITY,  INFINITY);
          Point<float> max_values (-INFINITY, -INFINITY, -INFINITY);

          {
            ProgressBar progress ("creating new template image...", 0);
            while (file (tck) && track_counter++ < MAX_TRACKS_READ_FOR_HEADER) {
              for (std::vector<Point<float> >::const_iterator i = tck.begin(); i != tck.end(); ++i) {
                min_values[0] = std::min (min_values[0], (*i)[0]);
                max_values[0] = std::max (max_values[0], (*i)[0]);
                min_values[1] = std::min (min_values[1], (*i)[1]);
                max_values[1] = std::max (max_values[1], (*i)[1]);
                min_values[2] = std::min (min_values[2], (*i)[2]);
                max_values[2] = std::max (max_values[2], (*i)[2]);
              }
              ++progress;
            }
          }

          min_values -= Point<float> (3.0*voxel_size[0], 3.0*voxel_size[1], 3.0*voxel_size[2]);
          max_values += Point<float> (3.0*voxel_size[0], 3.0*voxel_size[1], 3.0*voxel_size[2]);

          header.name() = "tckmap image header";
          header.set_ndim (3);

          for (size_t i = 0; i != 3; ++i) {
            header.dim(i) = std::ceil((max_values[i] - min_values[i]) / voxel_size[i]);
            header.vox(i) = voxel_size[i];
            header.stride(i) = i+1;
            //header.set_units (i, Image::Axis::millimeters);
          }

          //header.set_description (0, Image::Axis::left_to_right);
          //header.set_description (1, Image::Axis::posterior_to_anterior);
          //header.set_description (2, Image::Axis::inferior_to_superior);

          Math::Matrix<float>& M (header.transform());
          M.allocate (4,4);
          M.identity();
          M(0,3) = min_values[0];
          M(1,3) = min_values[1];
          M(2,3) = min_values[2];
          file.close();
        }
Exemple #18
0
void run ()
{

  Image::Buffer<node_t> nodes_data (argument[0]);
  Image::Buffer<node_t>::voxel_type nodes (nodes_data);

  Node_map node_map;
  load_lookup_table (node_map);

  Options opt = get_options ("config");
  if (opt.size()) {

    if (node_map.empty())
      throw Exception ("Cannot properly interpret connectome config file if no lookup table is provided");

    ConfigInvLookup config;
    load_config (opt[0][0], config);

    // Now that we know the configuration, can convert the lookup table to reflect the new indices
    // If no corresponding entry exists in the config file, then the node doesn't get coloured
    Node_map new_node_map;
    for (Node_map::iterator i = node_map.begin(); i != node_map.end(); ++i) {
      ConfigInvLookup::const_iterator existing = config.find (i->second.get_name());
      if (existing != config.end())
        new_node_map.insert (std::make_pair (existing->second, i->second));
    }

    if (new_node_map.empty())
      throw Exception ("Config file and parcellation lookup table do not appear to belong to one another");
    new_node_map.insert (std::make_pair (0, Node_info ("Unknown", Point<uint8_t> (0, 0, 0), 0)));
    node_map = new_node_map;

  }


  if (node_map.empty()) {

    INFO ("No lookup table provided; colouring nodes randomly");

    node_t max_index = 0;
    Image::LoopInOrder loop (nodes);
    for (loop.start (nodes); loop.ok(); loop.next (nodes)) {
      const node_t index = nodes.value();
      if (index > max_index)
        max_index = index;
    }

    node_map.insert (std::make_pair (0, Node_info ("None", 0, 0, 0, 0)));
    Math::RNG rng;

    for (node_t i = 1; i <= max_index; ++i) {
      Point<uint8_t> colour;
      do {
        colour[0] = rng.uniform_int (255);
        colour[1] = rng.uniform_int (255);
        colour[2] = rng.uniform_int (255);
      } while (int(colour[0]) + int(colour[1]) + int(colour[2]) < 100);
      node_map.insert (std::make_pair (i, Node_info (str(i), colour)));
    }

  }


  Image::Header H;
  H.info() = nodes_data.info();
  H.set_ndim (4);
  H.dim(3) = 3;
  H.datatype() = DataType::UInt8;
  H.comments().push_back ("Coloured parcellation image generated by label2colour");

  Image::Buffer<uint8_t> out_data (argument[1], H);
  Image::Buffer<uint8_t>::voxel_type out (out_data);

  Image::LoopInOrder loop (nodes, "Colourizing parcellated node image... ");
  for (loop.start (nodes, out); loop.ok(); loop.next (nodes, out)) {
    const node_t index = nodes.value();
    Node_map::const_iterator i = node_map.find (index);
    if (i == node_map.end()) {
      out[3] = 0; out.value() = 0;
      out[3] = 1; out.value() = 0;
      out[3] = 2; out.value() = 0;
    } else {
      const Point<uint8_t>& colour (i->second.get_colour());
      out[3] = 0; out.value() = colour[0];
      out[3] = 1; out.value() = colour[1];
      out[3] = 2; out.value() = colour[2];
    }
  }

}
Exemple #19
0
void run ()
{
  if (get_options ("norealign").size())
    Image::Header::do_not_realign_transform = true;

  const bool format     = get_options("format")        .size();
  const bool ndim       = get_options("ndim")          .size();
  const bool dimensions = get_options("dimensions")    .size();
  const bool vox        = get_options("vox")           .size();
  const bool dt_long    = get_options("datatype_long") .size();
  const bool dt_short   = get_options("datatype_short").size();
  const bool stride     = get_options("stride")        .size();
  const bool offset     = get_options("offset")        .size();
  const bool multiplier = get_options("multiplier")    .size();
  const bool comments   = get_options("comments")      .size();
  const bool properties = get_options("properties")    .size();
  const bool transform  = get_options("transform")     .size();
  const bool dwgrad     = get_options("dwgrad")        .size();

  Options opt = get_options ("export_grad_mrtrix");
  const std::string dw_out_mrtrix = opt.size() ? opt[0][0] : std::string();
  opt = get_options ("export_grad_fsl");
  std::string dw_out_fsl_bvecs, dw_out_fsl_bvals;
  if (opt.size()) {
    dw_out_fsl_bvecs = str(opt[0][0]);
    dw_out_fsl_bvals = str(opt[0][1]);
  }

  if ((dw_out_mrtrix.size() || dw_out_fsl_bvecs.size()) && (argument.size() > 1))
    throw Exception ("Can only export gradient table information to file if a single input image is provided");

  const bool print_full_header = (!(format || ndim || dimensions || vox || dt_long || dt_short || stride
                                  || offset || multiplier || comments || properties || transform || dwgrad)
                                  && dw_out_mrtrix.empty() && dw_out_fsl_bvecs.empty());


  for (size_t i = 0; i < argument.size(); ++i) {
    Image::Header header (argument[i]);

    if (format)     std::cout << header.format() << "\n";
    if (ndim)       std::cout << header.ndim() << "\n";
    if (dimensions) print_dimensions (header);
    if (vox)        print_vox (header);
    if (dt_long)    std::cout << (header.datatype().description() ? header.datatype().description() : "invalid") << "\n";
    if (dt_short)   std::cout << (header.datatype().specifier() ? header.datatype().specifier() : "invalid") << "\n";
    if (stride)     print_strides (header);
    if (offset)     std::cout << header.intensity_offset() << "\n";
    if (multiplier) std::cout << header.intensity_scale() << "\n";
    if (comments)   print_comments (header);
    if (properties) print_properties (header);
    if (transform)  std::cout << header.transform();
    if (dwgrad)     std::cout << header.DW_scheme();

    if (dw_out_mrtrix.size()) {
      if (!header.DW_scheme().is_set())
        throw Exception ("no gradient information found within image \"" + header.name() + "\"");
      header.DW_scheme().save (dw_out_mrtrix);
    }

    if (dw_out_fsl_bvecs.size()) {
      if (!header.DW_scheme().is_set())
        throw Exception ("no gradient information found within image \"" + header.name() + "\"");
      DWI::save_bvecs_bvals (header, dw_out_fsl_bvecs, dw_out_fsl_bvals);
    }

    if (print_full_header)
      std::cout << header.description();
  }

}
Exemple #20
0
void run ()
{
    Image::Buffer<value_type> SH_data (argument[0]);
    Math::SH::check (SH_data);

    Options opt = get_options ("mask");

    std::unique_ptr<Image::Buffer<bool> > mask_data;
    if (opt.size())
        mask_data.reset (new Image::Buffer<bool> (opt[0][0]));

    opt = get_options ("seeds");
    Math::Matrix<value_type> dirs;
    if (opt.size())
        dirs.load (opt[0][0]);
    else {
        dirs.allocate (60,2);
        dirs = Math::Matrix<value_type> (default_directions, 60, 2);
    }
    if (dirs.columns() != 2)
        throw Exception ("expecting 2 columns for search directions matrix");

    opt = get_options ("num");
    int npeaks = opt.size() ? opt[0][0] : 3;

    opt = get_options ("direction");
    std::vector<Direction> true_peaks;
    for (size_t n = 0; n < opt.size(); ++n) {
        Direction p (Math::pi*to<float> (opt[n][0]) /180.0, Math::pi*float (opt[n][1]) /180.0);
        true_peaks.push_back (p);
    }
    if (true_peaks.size())
        npeaks = true_peaks.size();

    opt = get_options ("threshold");
    value_type threshold = -INFINITY;
    if (opt.size())
        threshold = opt[0][0];

    Image::Header header (SH_data);
    header.datatype() = DataType::Float32;

    opt = get_options ("peaks");
    std::unique_ptr<Image::Buffer<value_type> > ipeaks_data;
    if (opt.size()) {
        if (true_peaks.size())
            throw Exception ("you can't specify both a peaks file and orientations to be estimated at the same time");
        if (opt.size())
            ipeaks_data.reset (new Image::Buffer<value_type> (opt[0][0]));

        Image::check_dimensions (header, *ipeaks_data, 0, 3);
        npeaks = ipeaks_data->dim (3) / 3;
    }
    header.dim(3) = 3 * npeaks;
    Image::Buffer<value_type> peaks_data (argument[1], header);

    DataLoader loader (SH_data, mask_data.get());
    Processor processor (peaks_data, dirs, Math::SH::LforN (SH_data.dim (3)),
                         npeaks, true_peaks, threshold, ipeaks_data.get());

    Thread::run_queue (loader, Item(), Thread::multi (processor));
}
Exemple #21
0
void check_and_update (Image::Header& H, const conv_t conversion)
{

  const size_t lmax = Math::SH::LforN (H.dim(3));

  // Flag which volumes are m==0 and which are not
  const ssize_t N = H.dim(3);
  BitSet mzero_terms (N, false);
  for (size_t l = 2; l <= lmax; l += 2)
    mzero_terms[Math::SH::index (l, 0)] = true;

  // Open in read-write mode if there's a chance of modification
  typename Image::Buffer<value_type> buffer (H, (conversion != NONE));
  typename Image::Buffer<value_type>::voxel_type v (buffer);

  // Need to mask out voxels where the DC term is zero
  Image::Info info_mask (H);
  info_mask.set_ndim (3);
  info_mask.datatype() = DataType::Bit;
  Image::BufferScratch<bool> mask (info_mask);
  Image::BufferScratch<bool>::voxel_type v_mask (mask);
  size_t voxel_count = 0;
  {
    Image::LoopInOrder loop (v, "Masking image based on DC term...", 0, 3);
    for (loop.start (v, v_mask); loop.ok(); loop.next (v, v_mask)) {
      const value_type value = v.value();
      if (value && std::isfinite (value)) {
        v_mask.value() = true;
        ++voxel_count;
      } else {
        v_mask.value() = false;
      }
    }
  }

  // Get sums independently for each l
 
  // Each order has a different power, and a different number of m!=0 volumes.
  // Therefore, calculate the mean-square intensity for the m==0 and m!=0
  // volumes independently, and report ratio for each harmonic order
  Ptr<ProgressBar> progress;
  if (App::log_level > 0 && App::log_level < 2)
    progress = new ProgressBar ("Evaluating SH basis of image \"" + H.name() + "\"...", N-1);

  std::vector<float> ratios;

  for (size_t l = 2; l <= lmax; l += 2) {

    double mzero_sum = 0.0, mnonzero_sum = 0.0;
    Image::LoopInOrder loop (v, 0, 3);
    for (v[3] = ssize_t (Math::SH::NforL(l-2)); v[3] != ssize_t (Math::SH::NforL(l)); ++v[3]) {
      double sum = 0.0;
      for (loop.start (v, v_mask); loop.ok(); loop.next (v, v_mask)) {
        if (v_mask.value())
          sum += Math::pow2 (value_type(v.value()));
      }
      if (mzero_terms[v[3]]) {
        mzero_sum += sum;
        DEBUG ("Volume " + str(v[3]) + ", m==0, sum " + str(sum));
      } else {
        mnonzero_sum += sum;
        DEBUG ("Volume " + str(v[3]) + ", m!=0, sum " + str(sum));
      }
      if (progress)
      ++*progress;
    }

    const double mnonzero_MSoS = mnonzero_sum / (2.0 * l);
    const float power_ratio = mnonzero_MSoS/mzero_sum;
    ratios.push_back (power_ratio);

    INFO ("SH order " + str(l) + ", ratio of m!=0 to m==0 power: " + str(power_ratio) +
        ", m==0 power: " + str (mzero_sum));

  }

  if (progress)
    progress = NULL;

  // First is ratio to be used for SH basis decision, second is gradient of regression
  std::pair<float, float> regression = std::make_pair (0.0f, 0.0f);
  size_t l_for_decision;
  float power_ratio;

  // The gradient will change depending on the current basis, so the threshold needs to also
  // The gradient is as a function of l, not of even orders
  float grad_threshold = 0.02;

  switch (lmax) {

    // Lmax == 2: only one order to use
    case 2:
      power_ratio = ratios.front();
      l_for_decision = 2;
      break;

    // Lmax = 4: Use l=4 order to determine SH basis, can't check gradient since l=2 is untrustworthy
    case 4:
      power_ratio = ratios.back();
      l_for_decision = 4;
      break;

    // Lmax = 6: Use l=4 order to determine SH basis, but checking the gradient is not reliable:
    //   artificially double the threshold so the power ratio at l=6 needs to be substantially
    //   different to l=4 to throw a warning
    case 6:
      regression = std::make_pair (ratios[1] - 2*(ratios[2]-ratios[1]), 0.5*(ratios[2]-ratios[1]));
      power_ratio = ratios[1];
      l_for_decision = 4;
      grad_threshold *= 2.0;
      break;

    // Lmax >= 8: Do a linear regression from l=4 to l=lmax, project back to l=0
    // (this is a more reliable quantification on poor data than l=4 alone)
    default:
      regression = get_regression (ratios);
      power_ratio = regression.first;
      l_for_decision = 0;
      break;

  }

  // If the gradient is in fact positive (i.e. power ration increases for larger l), use the
  //   regression to pull the power ratio from l=lmax
  if (regression.second > 0.0) {
    l_for_decision = lmax;
    power_ratio = regression.first + (lmax * regression.second);
  }

  DEBUG ("Power ratio for assessing SH basis is " + str(power_ratio) + " as " + (lmax < 8 ? "derived from" : "regressed to") + " l=" + str(l_for_decision));

  // Threshold to make decision on what basis the data are currently stored in
  value_type multiplier = 1.0;
  if ((power_ratio > (5.0/3.0)) && (power_ratio < (7.0/3.0))) {

    CONSOLE ("Image \"" + str(H.name()) + "\" appears to be in the old non-orthonormal basis");
    switch (conversion) {
      case NONE: break;
      case OLD: break;
      case NEW: multiplier = 1.0 / M_SQRT2; break;
      case FORCE_OLDTONEW: multiplier = 1.0 / M_SQRT2; break;
      case FORCE_NEWTOOLD: WARN ("Refusing to convert image \"" + H.name() + "\" from new to old basis, as data appear to already be in the old non-orthonormal basis"); return;
    }
    grad_threshold *= 2.0;

  } else if ((power_ratio > (2.0/3.0)) && (power_ratio < (4.0/3.0))) {

    CONSOLE ("Image \"" + str(H.name()) + "\" appears to be in the new orthonormal basis");
    switch (conversion) {
      case NONE: break;
      case OLD: multiplier = M_SQRT2; break;
      case NEW: break;
      case FORCE_OLDTONEW: WARN ("Refusing to convert image \"" + H.name() + "\" from old to new basis, as data appear to already be in the new orthonormal basis"); return;
      case FORCE_NEWTOOLD: multiplier = M_SQRT2; break;
    }

  } else {

    multiplier = 0.0;
    WARN ("Cannot make unambiguous decision on SH basis of image \"" + H.name()
        + "\" (power ratio " + (lmax < 8 ? "in" : "regressed to") + " " + str(l_for_decision) + " is " + str(power_ratio) + ")");

    if (conversion == FORCE_OLDTONEW) {
      WARN ("Forcing conversion of image \"" + H.name() + "\" from old to new SH basis on user request; however NO GUARANTEE IS PROVIDED on appropriateness of this conversion!");
      multiplier = 1.0 / M_SQRT2;
    } else if (conversion == FORCE_NEWTOOLD) {
      WARN ("Forcing conversion of image \"" + H.name() + "\" from new to old SH basis on user request; however NO GUARANTEE IS PROVIDED on appropriateness of this conversion!");
      multiplier = M_SQRT2;
    }

  }

  // Decide whether the user needs to be warned about a poor diffusion encoding scheme
  if (regression.second)
    DEBUG ("Gradient of regression is " + str(regression.second) + "; threshold is " + str(grad_threshold));
  if (Math::abs(regression.second) > grad_threshold) {
    WARN ("Image \"" + H.name() + "\" may have been derived from poor directional encoding, or have some other underlying data problem");
    WARN ("(m!=0 to m==0 power ratio changing by " + str(2.0*regression.second) + " per even order)");
  }

  // Adjust the image data in-place if necessary
  if (multiplier && (multiplier != 1.0)) {

    Image::LoopInOrder loop (v, 0, 3);
    ProgressBar progress ("Modifying SH basis of image \"" + H.name() + "\"...", N-1);
    for (v[3] = 1; v[3] != N; ++v[3]) {
      if (!mzero_terms[v[3]]) {
        for (loop.start (v); loop.ok(); loop.next (v))
          v.value() *= multiplier;
      }
      ++progress;
    }

  } else if (multiplier && (conversion != NONE)) {
    INFO ("Image \"" + H.name() + "\" already in desired basis; nothing to do");
  }

}
Exemple #22
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 #23
0
void run () {
  Point<> p[3];
  for (size_t arg = 0; arg < 3; ++arg) {
    std::vector<float> V = argument[arg]; 
    if (V.size() != 3) 
      throw Exception ("coordinates must contain 3 elements");
    p[arg][0] = V[0];
    p[arg][1] = V[1];
    p[arg][2] = V[2];
  }

  Image::Header header (argument[3]);
  float vox = Math::pow (header.vox(0)*header.vox(1)*header.vox(2), 1.0f/3.0f);
  Options opt = get_options ("vox");
  if (opt.size()) 
    vox = opt[0][0];


  Point<> d1 = p[1] - p[0];
  Point<> d2 = p[2] - p[0];
  d1.normalise();
  d2.normalise();

  d2 = d2 - d1 * d1.dot(d2);
  d2.normalise();

  Point<> d3 = d1.cross(d2);


  float min1 = std::numeric_limits<float>::infinity();
  float min2 = std::numeric_limits<float>::infinity();
  float max1 = -std::numeric_limits<float>::infinity();
  float max2 = -std::numeric_limits<float>::infinity();

  update_bounds (min1, min2, max1, max2, header, Point<int>(0,0,0), 0, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,0,0), 1, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,0,0), 2, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(1,0,0), 1, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(1,0,0), 2, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,1,0), 0, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,1,0), 2, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,0,1), 0, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,0,1), 1, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(1,1,0), 2, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(1,0,1), 1, p[0], d1, d2);
  update_bounds (min1, min2, max1, max2, header, Point<int>(0,1,1), 0, p[0], d1, d2);


  Point<> translation (p[0] + min1*d1 + min2*d2);

  header.transform()(0,0) = d1[0];
  header.transform()(1,0) = d1[1];
  header.transform()(2,0) = d1[2];

  header.transform()(0,1) = d2[0];
  header.transform()(1,1) = d2[1];
  header.transform()(2,1) = d2[2];

  header.transform()(0,2) = d3[0];
  header.transform()(1,2) = d3[1];
  header.transform()(2,2) = d3[2];

  header.transform()(0,3) = translation[0];
  header.transform()(1,3) = translation[1];
  header.transform()(2,3) = translation[2];

  header.set_ndim (3);
  header.dim (0) = (max1-min1) / vox;
  header.dim (1) = (max2-min2) / vox;
  header.dim (2) = 1;

  header.vox(0) = header.vox(1) = header.vox(2) = vox;

  header.datatype() = DataType::Bit;
  header.DW_scheme().clear();

  Image::Buffer<bool> roi_buffer (argument[4], header);
  Image::Buffer<bool>::voxel_type roi (roi_buffer);
  Image::LoopInOrder loop (roi);
  for (loop.start (roi); loop.ok(); loop.next (roi))
    roi.value() = true;

}
Exemple #24
0
void run () {

  Image::Header input_header (argument[0]);
  const size_t filter_index = argument[1];

  // Separate code path for FFT filter
  if (!filter_index) {

    // Gets preloaded by the FFT filter anyways, so just use a buffer
    // FIXME Had to use cdouble throughout; seems to fail at compile time even trying to
    //   convert between cfloat and cdouble...
    Image::Buffer<cdouble> input_data (input_header);
    Image::Buffer<cdouble>::voxel_type input_voxel (input_data);
    Image::Filter::FFT* filter = (dynamic_cast<Image::Filter::FFT*> (create_fft_filter (input_voxel)));

    Image::Header header;
    header.info() = filter->info();
    set_strides (header);

    filter->set_message (std::string("applying FFT filter to image " + std::string(argument[0]) + "..."));

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

      Image::BufferScratch<cdouble> temp_data (header, "complex FFT result");
      Image::BufferScratch<cdouble>::voxel_type temp_voxel (temp_data);
      (*filter) (input_voxel, temp_voxel);

      header.datatype() = DataType::Float32;
      Image::Buffer<float> output_data (argument[2], header);
      Image::Buffer<float>::voxel_type output_voxel (output_data);

      Image::LoopInOrder loop (output_voxel);
      for (loop.start (temp_voxel, output_voxel); loop.ok(); loop.next (temp_voxel, output_voxel))
        output_voxel.value() = std::abs (cdouble(temp_voxel.value()));

    } else {

      Image::Buffer<cdouble> output_data (argument[2], header);
      Image::Buffer<cdouble>::voxel_type output_voxel (output_data);
      (*filter) (input_voxel, output_voxel);

    }

    delete filter;
    return;

  }

  Image::BufferPreload<float> input_data (input_header);
  Image::BufferPreload<float>::voxel_type input_voxel (input_data);

  Image::Filter::Base* filter = NULL;
  switch (filter_index) {
    case 0: assert (0); break;
    case 1: filter = create_gradient_filter (input_voxel); break;
    case 2: filter = create_median_filter   (input_voxel); break;
    case 3: filter = create_smooth_filter   (input_voxel); break;
    default: assert (0);
  }

  Image::Header header;
  header.info() = filter->info();
  set_strides (header);

  Image::Buffer<float> output_data (argument[2], header);
  Image::Buffer<float>::voxel_type output_voxel (output_data);

  filter->set_message (std::string("applying ") + std::string(argument[1]) + " filter to image " + std::string(argument[0]) + "...");

  switch (filter_index) {
    case 0: assert (0); break;
    case 1: (*dynamic_cast<Image::Filter::Gradient*> (filter)) (input_voxel, output_voxel); break;
    case 2: (*dynamic_cast<Image::Filter::Median*>   (filter)) (input_voxel, output_voxel); break;
    case 3: (*dynamic_cast<Image::Filter::Smooth*>   (filter)) (input_voxel, output_voxel); break;
  }

  delete filter;

}
Exemple #25
0
 Base::Base (const Image::Header& header) : 
   name (header.name()), 
   datatype (header.datatype()),
   segsize (Image::voxel_count (header)),
   is_new (false),
   writable (false) { }
void run() {
  Image::BufferPreload<float> data_in (argument[0], Image::Stride::contiguous_along_axis (3));
  auto voxel_in = data_in.voxel();

  Math::Matrix<value_type> grad (DWI::get_valid_DW_scheme<float> (data_in));

  // Want to support non-shell-like data if it's just a straight extraction
  //   of all dwis or all bzeros i.e. don't initialise the Shells class
  std::vector<size_t> volumes;
  bool bzero = get_options ("bzero").size();
  Options opt = get_options ("shell");
  if (opt.size()) {
    DWI::Shells shells (grad);
    shells.select_shells (false, false);
    for (size_t s = 0; s != shells.count(); ++s) {
      DEBUG ("Including data from shell b=" + str(shells[s].get_mean()) + " +- " + str(shells[s].get_stdev()));
      for (std::vector<size_t>::const_iterator v = shells[s].get_volumes().begin(); v != shells[s].get_volumes().end(); ++v)
        volumes.push_back (*v);
    }
    // Remove DW information from header if b=0 is the only 'shell' selected
    bzero = (shells.count() == 1 && shells[0].is_bzero());
  } else {
    const float bzero_threshold = File::Config::get_float ("BValueThreshold", 10.0);
    for (size_t row = 0; row != grad.rows(); ++row) {
      if ((bzero && (grad (row, 3) < bzero_threshold)) || (!bzero && (grad (row, 3) > bzero_threshold)))
        volumes.push_back (row);
    }
  }

  if (volumes.empty())
    throw Exception ("No " + str(bzero ? "b=0" : "dwi") + " volumes present");

  std::sort (volumes.begin(), volumes.end());

  Image::Header header (data_in);

  if (volumes.size() == 1)
    header.set_ndim (3);
  else
    header.dim (3) = volumes.size();

  Math::Matrix<value_type> new_grad (volumes.size(), grad.columns());
  for (size_t i = 0; i < volumes.size(); i++)
    new_grad.row (i) = grad.row (volumes[i]);
  header.DW_scheme() = new_grad;

  Image::Buffer<value_type> data_out (argument[1], header);
  auto voxel_out = data_out.voxel();

  Image::Loop outer ("extracting volumes...", 0, 3);

  if (voxel_out.ndim() == 4) {

    for (auto i = outer (voxel_out, voxel_in); i; ++i) {
      for (size_t i = 0; i < volumes.size(); i++) {
        voxel_in[3] = volumes[i];
        voxel_out[3] = i;
        voxel_out.value() = voxel_in.value();
      }
    }

  } else {

    const size_t volume = volumes[0];
    for (auto i = outer (voxel_out, voxel_in); i; ++i) {
      voxel_in[3] = volume;
      voxel_out.value() = voxel_in.value();
    }

  }


}