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; }
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 }
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]; } } }
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; }
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; }
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; }
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"; }
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"; }
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; }
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]; } }
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()); }
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]; } }
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); }
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(); }
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]; } } }
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(); } }
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)); }
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"); } }
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"); } }
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; }
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; }
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(); } } }