Beispiel #1
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];
    }
  }
}
Beispiel #2
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];
    }
  }

}
Beispiel #3
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");
  }

}
Beispiel #4
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;

}
Beispiel #5
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;

}