void validate(boost::any& v, const std::vector<std::string>& values, input_path*, int) { std::string path = boost::program_options::validators::get_single_string(values); #if defined(BOOST_WINDOWS_PATH) cygwin_conv_path_t flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE; #elif defined(BOOST_POSIX_PATH) cygwin_conv_path_t flags = CCP_WIN_A_TO_POSIX | CCP_RELATIVE; #else # error "Boost filesystem path type doesn't seem to be set." #endif ssize_t size = cygwin_conv_path(flags, path.c_str(), NULL, 0); if (size < 0) { throw boost::program_options::validation_error( boost::program_options::validation_error::invalid_option_value); } boost::scoped_array<char> result(new char[size]); if(cygwin_conv_path(flags, path.c_str(), result.get(), size)) { throw boost::program_options::validation_error( boost::program_options::validation_error::invalid_option_value); } v = input_path(result.get()); }
/* * Entry point */ int main(int argc, char** argv) { // Check if enough parameters were supplied if (argc < 3) { std::cout << "USAGE: " << argv[0] << " <input image> <output image>\n"; return -1; } // These are our file names std::string input_path(argv[1]); std::string output_path(argv[2]); // Read image into memory NICE::ImageFile source_file(input_path); NICE::Image image; source_file.reader(&image); // Calculate pseudocolors NICE::ColorImage pseudo_image(image.width(), image.height()); NICE::imageToPseudoColor(image, pseudo_image); // Write image to disk NICE::ImageFile dest_image(output_path); dest_image.writer(&pseudo_image); return 0; }
/* * Entry point */ int main(int argc, char** argv) { // Check if enough parameters were supplied if (argc < 3) { std::cout << "USAGE: " << argv[0] << " <input image> <output image>\n"; return -1; } // These are our file names std::string input_path(argv[1]); std::string output_path(argv[2]); // Read file header and display header information NICE::ImageFile source_file(input_path); // Read image into memory NICE::Image image; source_file.reader(&image); // Allocate memory for result image NICE::Image result(image.width(), image.height()); // Put together a simple convolution kernel for our motion blur effect NICE::Matrix kernel(10,10); kernel.set(0); kernel.addIdentity(0.1); // Filter the image NICE::Filter::filter(image, kernel, result); // Write image to disk NICE::ImageFile dest_image(output_path); dest_image.writer(&result); return 0; }
void validate(boost::any& v, const std::vector<std::string>& values, input_path*, int) { std::string path = boost::program_options::validators::get_single_string(values); v = input_path(path); }
//****************************************************************************** // Main //****************************************************************************** int main(int argc, char **argv) { args::ArgumentParser parser("Checks if images are different within a tolerance.\n" "Intended for use with library tests.\n" "http://github.com/spinicist/QUIT"); args::HelpFlag help(parser, "HELP", "Show this help message", {'h', "help"}); args::Flag verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"}); args::ValueFlag<std::string> input_path(parser, "INPUT", "Input file for difference", {"input"}); args::ValueFlag<std::string> baseline_path(parser, "BASELINE", "Baseline file for difference", {"baseline"}); args::ValueFlag<double> tolerance(parser, "TOLERANCE", "Tolerance (mean percent difference)", {"tolerance"}, 0); args::ValueFlag<double> noise(parser, "NOISE", "Added noise level, tolerance is relative to this", {"noise"}, 0); args::Flag absolute(parser, "ABSOLUTE", "Use absolute difference, not relative (avoids 0/0 problems)", {'a', "abs"}); QI::ParseArgs(parser, argc, argv, verbose); auto input = QI::ReadImage(QI::CheckValue(input_path), verbose); auto baseline = QI::ReadImage(QI::CheckValue(baseline_path), verbose); auto diff = itk::SubtractImageFilter<QI::VolumeF>::New(); diff->SetInput1(input); diff->SetInput2(baseline); auto sqr_norm = itk::SquareImageFilter<QI::VolumeF, QI::VolumeF>::New(); if (absolute) { sqr_norm->SetInput(diff->GetOutput()); } else { auto diff_norm = itk::DivideImageFilter<QI::VolumeF, QI::VolumeF, QI::VolumeF>::New(); diff_norm->SetInput1(diff->GetOutput()); diff_norm->SetInput2(baseline); diff_norm->Update(); sqr_norm->SetInput(diff_norm->GetOutput()); } auto stats = itk::StatisticsImageFilter<QI::VolumeF>::New(); stats->SetInput(sqr_norm->GetOutput()); stats->Update(); const double mean_sqr_diff = stats->GetMean(); const double root_mean_sqr_diff = sqrt(mean_sqr_diff); const double rel_diff = (noise.Get() > 0) ? root_mean_sqr_diff / noise.Get() : root_mean_sqr_diff; const bool passed = rel_diff <= tolerance.Get(); QI::Log(verbose, "Mean Square Diff: {}\nRelative noise: {}\nSquare-root mean square diff: {}\nRelative Diff: {}\nTolerance: {}\nResult: ", mean_sqr_diff ,noise.Get() , root_mean_sqr_diff , rel_diff , tolerance.Get() , (passed ? "Passed" : "Failed")); if (passed) { return EXIT_SUCCESS; } else { return EXIT_FAILURE; } }
int main(int argc, char *argv[]) { po::variables_map args = fly::parse_args(argc, argv); fly::Driver driver; driver.set_trace_lexing(args.count("trace-lexing") > 0); driver.set_trace_parsing(args.count("trace-parsing") > 0); int result = driver.parse(args["input-file"].as<fs::path>()); if (result == 1) { std::cerr << "Parsing failed." << std::endl; std::exit(1); } fly::PLContext context; fly::NBlock root_node = driver.get_root(); context.generate_code(root_node); if (args.count("asm-only")) { fs::path output_path; if (args.count("output-file")) { output_path = args["output-file"].as<fs::path>().native(); } else { // Instead of placing the output file in the same directory as the input file, we place it in the current directory. This is consistent with the behavior of `clang -S /path/to/myfile.c'. fs::path input_path(args["input-file"].as<fs::path>()); output_path = input_path.filename(); if (args.count("emit-llvm")) { output_path.replace_extension("ll"); } else { output_path.replace_extension("s"); } } if (args.count("emit-llvm")) { fly::print_ir(context, output_path); } else { fly::print_native_asm(context, output_path); } } else if (args.count("emit-llvm")) { std::cerr << "Option `--emit-llvm' may only be used with `--asm-only'." << std::endl; return 1; } else { const fs::path output_path = args.count("output-file") > 0 ? args["output-file"].as<fs::path>() : "a.out"; if (args.count("lib-path")) { fly::compile_executable(context, output_path, args["lib-path"].as<fly::LibrarySearchPaths>()); } else { fly::LibrarySearchPaths lib_search_paths; fly::compile_executable(context, output_path, lib_search_paths); } } return 0; }
void validate(boost::any& v, const std::vector<std::string>& values, input_path*, int) { std::string path = boost::program_options::validators::get_single_string(values); char result[MAX_PATH + 1]; #if defined(BOOST_WINDOWS_PATH) cygwin_conv_to_win32_path(path.c_str(), result); #elif defined(BOOST_POSIX_PATH) cygwin_conv_to_posix_path(path.c_str(), result); #else # error "Boost filesystem path type doesn't seem to be set." #endif v = input_path(result); }
// extends population size to lambda using mutations based on (lamda/mu) factor void es::create_pop(unsigned int gen) { try { boost::format gen_dir(eap::run_directory+"gen%04d"); boost::format input_path(eap::run_directory + "gen%04d/ind%09d"); boost::filesystem::create_directory(str(gen_dir % gen)); std::vector<individual_ptr> new_pop; if (gen != 0) { for (unsigned int i=0; i<m_mu; ++i) { new_pop.push_back(create_individual(str(input_path % gen % i) + "a%02d.nec", m_pop[i]->m_positions)); } } else if (gen == 0) { for (unsigned int i=0; i<m_mu; ++i) { new_pop.push_back(m_pop[i]); } } for (unsigned int i=0; i<m_mu; ++i) { unsigned int counter = 0; while (counter<m_mulambda_factor) { int id = m_mu + i*m_mulambda_factor + counter; std::vector<position_ptr> placements = mutate_pos_once(m_pop[i]->m_positions); new_pop.push_back(create_individual(str(input_path % gen % id) + "a%02d.nec", placements)); counter++; } } m_pop = new_pop; } catch (...) { throw; } }
int main (int argc, char *argv[]) { if (argc < 2) { std::cout << "Error: Not enough arguments.\nUsage: ./streetname_fixer INPUT.pbf" << std::endl; return 1; } char* input_file_path = argv[1]; boost::filesystem::path input_path(input_file_path); if (!boost::filesystem::exists(input_path)) { std::cout << "Error: Input file " << input_file_path << " does not exists." << std::endl; } boost::filesystem::path output_path = input_path.filename().replace_extension(".csv"); std::unique_ptr<EndpointWayMapT> endpoint_way_map; std::unique_ptr<ParsedWayVectorT> parsed_ways; std::unique_ptr<StringTableT> string_table; parseInput(input_file_path, endpoint_way_map, parsed_ways, string_table); auto name_getter = [](const ParsedWay& w) { return w.name_id; }; auto ref_getter = [](const ParsedWay& w) { return w.ref_id; }; // Yes, just using inheritence would be possible, but we don't want virtual functions. // the lambdas will get inline. MissingValueDetector<decltype(name_getter)> name_detector(*endpoint_way_map, *parsed_ways, name_getter); MissingValueDetector<decltype(ref_getter)> ref_detector(*endpoint_way_map, *parsed_ways, ref_getter); std::vector<ConsistencyError> name_errors = name_detector(); std::cout << "Number of name errors: " << name_errors.size() << std::endl; writeOutput(name_errors, *string_table, "name", output_path.string()); std::vector<ConsistencyError> ref_errors = ref_detector(); std::cout << "Number of refs errors: " << ref_errors.size() << std::endl; writeOutput(ref_errors, *string_table, "ref", output_path.string()); return 0; }
/** * Predicts values of the new data file. The output classification is saved * into the same file (as xml attributes). The predicted values are saved * into the file "in_data_file.predict" * in_data_file An XML filename file with input filenames * is_unit_length If yes then vectors will be L1-normalized * */ bool Classifier::predict(string input_file, TextExpanderParams* exp_params, bool is_unit_length) { if(_verbose) printf("Predicting...\n"); // Load texts TextToClassify* texts = load_texts(input_file); if(!texts){ printf("Error: cannot load text from XML file '%s'\n", input_file.c_str()); return false; } // Extract features from the text string vectors_file = input_file + ".csv"; list<bool> has_data = text2vector(texts, vectors_file, exp_params, is_unit_length); if(has_data.size() == 0){ printf("Error: cannot extract features from %s\n", input_file.c_str()); return false; } // Predict labels of the texts list<pred> labels = predict_fs(vectors_file.c_str(), _model); // Delete input file string input_file_copy(input_file); // Bug: string destroyed after remove wpath input_path(input_file); if(exists(input_path)) remove(input_path); text2xml(texts, has_data, labels, input_file_copy); //insert_labels(input_file, labels, has_data); // The old version -- instead of four lines above if(DELETE_TMP){ wpath vectors_path(vectors_file); if(exists(vectors_path)) remove(vectors_path); } // Delete texts delete_text(texts); return true; }
string compiler_command() { array<string> result; //compiler if(is_gcc()) result=gcc_arguments(); else if(is_clang()) result=clang_arguments(); else stop(); //common result.append(compiler_arguments()); //paths result.push(input_path()); result.push(space("-o",output_path())); return result.join(" "); }
int main(int argc, char **argv) { args::ArgumentParser parser( "Calculates T1/B1 maps from MP2/3-RAGE data\nhttp://github.com/spinicist/QUIT"); args::Positional<std::string> input_path(parser, "INPUT FILE", "Path to complex MP-RAGE data"); args::HelpFlag help(parser, "HELP", "Show this help message", {'h', "help"}); args::Flag verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"}); args::ValueFlag<int> threads(parser, "THREADS", "Use N threads (default=4, 0=hardware limit)", {'T', "threads"}, QI::GetDefaultThreads()); args::ValueFlag<std::string> outarg( parser, "OUTPREFIX", "Add a prefix to output filenames", {'o', "out"}); args::ValueFlag<std::string> json_file( parser, "FILE", "Read JSON input from file instead of stdin", {"file"}); args::ValueFlag<float> beta_arg( parser, "BETA", "Regularisation factor for robust contrast calculation " "(https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0099676)", {'b', "beta"}, 0.0); args::Flag t1(parser, "T1", "Calculate T1 map via spline look-up", {'t', "t1"}); QI::ParseArgs(parser, argc, argv, verbose, threads); auto inFile = QI::ReadImage<QI::SeriesXF>(QI::CheckPos(input_path), verbose); auto ti_1 = itk::ExtractImageFilter<QI::SeriesXF, QI::VolumeXF>::New(); auto ti_2 = itk::ExtractImageFilter<QI::SeriesXF, QI::VolumeXF>::New(); auto region = inFile->GetLargestPossibleRegion(); region.GetModifiableSize()[3] = 0; ti_1->SetExtractionRegion(region); ti_1->SetDirectionCollapseToSubmatrix(); ti_1->SetInput(inFile); region.GetModifiableIndex()[3] = 1; ti_2->SetExtractionRegion(region); ti_2->SetDirectionCollapseToSubmatrix(); ti_2->SetInput(inFile); QI::Log(verbose, "Generating MP2 contrasts"); using BinaryFilter = itk::BinaryGeneratorImageFilter<QI::VolumeXF, QI::VolumeXF, QI::VolumeF>; auto MP2Filter = BinaryFilter::New(); MP2Filter->SetInput1(ti_1->GetOutput()); MP2Filter->SetInput2(ti_2->GetOutput()); const float &beta = beta_arg.Get(); MP2Filter->SetFunctor([&](const std::complex<float> &p1, const std::complex<float> &p2) { return MP2Contrast(p1, p2, beta); }); MP2Filter->Update(); const std::string out_prefix = outarg ? outarg.Get() : QI::StripExt(input_path.Get()); QI::WriteImage(MP2Filter->GetOutput(), out_prefix + "_MP2" + QI::OutExt(), verbose); if (t1) { QI::Log(verbose, "Reading sequence information"); rapidjson::Document input = json_file ? QI::ReadJSON(json_file.Get()) : QI::ReadJSON(std::cin); QI::MP2RAGESequence mp2rage_sequence(input["MP2RAGE"]); QI::Log(verbose, "Building look-up spline"); int num_entries = 100; Eigen::ArrayXd T1_values = Eigen::ArrayXd::LinSpaced(num_entries, 0.25, 4.0); Eigen::ArrayXd MP2_values(num_entries); for (int i = 0; i < num_entries; i++) { const auto sig = One_MP2RAGE(1., T1_values[i], 1., mp2rage_sequence); const float mp2 = MP2Contrast(sig[0], sig[1]); if ((i > 0) && (mp2 > MP2_values[i - 1])) { num_entries = i; break; } else { MP2_values[i] = mp2; } } QI::Log(verbose, "Lookup table length = {}", num_entries); QI::SplineInterpolator mp2_to_t1(MP2_values.head(num_entries), T1_values.head(num_entries)); if (beta) { QI::Log(verbose, "Recalculating unregularised MP2 image"); MP2Filter->SetFunctor( [&](const std::complex<float> &p1, const std::complex<float> &p2) { return MP2Contrast(p1, p2, 0.0); }); MP2Filter->Update(); } using UnaryFilter = itk::UnaryGeneratorImageFilter<QI::VolumeF, QI::VolumeF>; auto T1LookupFilter = UnaryFilter::New(); T1LookupFilter->SetInput(MP2Filter->GetOutput()); auto lookup = [&](const float &p) { return mp2_to_t1(p); }; T1LookupFilter->SetFunctor(lookup); QI::Log(verbose, "Calculating T1"); T1LookupFilter->Update(); QI::WriteImage(T1LookupFilter->GetOutput(), out_prefix + "_MP2_T1" + QI::OutExt(), verbose); } QI::Log(verbose, "Finished."); return EXIT_SUCCESS; }
int main(int argc, char** argv) { if (argc < 5) { PCL17_INFO ("Usage %s -input_dir /dir/with/models -output_dir /output/dir [options]\n", argv[0]); PCL17_INFO (" * where options are:\n" " -height <X> : simulate scans with sensor mounted on height X\n" " -noise_std <X> : std of gaussian noise added to pointcloud. Default value 0.0001.\n" " -distance <X> : simulate scans with object located on a distance X. Can be used multiple times. Default value 4.\n" " -tilt <X> : tilt sensor for X degrees. X == 0 - sensor looks strait. X < 0 Sensor looks down. X > 0 Sensor looks up . Can be used multiple times. Default value -15.\n" " -shift <X> : shift object from the straight line. Can be used multiple times. Default value 0.\n" " -num_views <X> : how many times rotate the object in for every distance, tilt and shift. Default value 6.\n" ""); return -1; } std::string input_dir, output_dir; double height = 1.5; double num_views = 6; double noise_std = 0.0001; std::vector<double> distances; std::vector<double> tilt; std::vector<double> shift; int full_model_n_points = 30000; pcl17::console::parse_argument(argc, argv, "-input_dir", input_dir); pcl17::console::parse_argument(argc, argv, "-output_dir", output_dir); pcl17::console::parse_argument(argc, argv, "-num_views", num_views); pcl17::console::parse_argument(argc, argv, "-height", height); pcl17::console::parse_argument(argc, argv, "-noise_std", noise_std); pcl17::console::parse_multiple_arguments(argc, argv, "-distance", distances); pcl17::console::parse_multiple_arguments(argc, argv, "-tilt", tilt); pcl17::console::parse_multiple_arguments(argc, argv, "-shift", shift); PCL17_INFO("distances size: %d\n", distances.size()); for (size_t i = 0; i < distances.size(); i++) { PCL17_INFO("distance: %f\n", distances[i]); } // Set default values if user didn't provide any if (distances.size() == 0) distances.push_back(4); if (tilt.size() == 0) tilt.push_back(-15); if (shift.size() == 0) shift.push_back(0); // Check if input path exists boost::filesystem::path input_path(input_dir); if (!boost::filesystem::exists(input_path)) { PCL17_ERROR("Input directory doesnt exists."); return -1; } // Check if input path is a directory if (!boost::filesystem::is_directory(input_path)) { PCL17_ERROR("%s is not directory.", input_path.c_str()); return -1; } // Check if output directory exists boost::filesystem::path output_path(output_dir); if (!boost::filesystem::exists(output_path) || !boost::filesystem::is_directory(output_path)) { if (!boost::filesystem::create_directories(output_path)) { PCL17_ERROR ("Error creating directory %s.\n", output_path.c_str ()); return -1; } } // Find all .vtk files in the input directory std::vector<std::string> files_to_process; PCL17_INFO("Processing following files:\n"); boost::filesystem::directory_iterator end_iter; for (boost::filesystem::directory_iterator iter(input_path); iter != end_iter; iter++) { boost::filesystem::path class_dir_path(*iter); for (boost::filesystem::directory_iterator iter2(class_dir_path); iter2 != end_iter; iter2++) { boost::filesystem::path file(*iter2); if (file.extension() == ".vtk") { files_to_process.push_back(file.c_str()); PCL17_INFO("\t%s\n", file.c_str()); } } } // Check if there are any .vtk files to process if (files_to_process.size() == 0) { PCL17_ERROR("Directory %s has no .vtk files.", input_path.c_str()); return -1; } // Iterate over all files for (size_t i = 0; i < files_to_process.size(); i++) { vtkSmartPointer<vtkPolyData> model; vtkSmartPointer<vtkPolyDataReader> reader = vtkPolyDataReader::New(); vtkSmartPointer<vtkTransform> transform = vtkTransform::New(); pcl17::PointCloud<pcl17::PointXYZ>::Ptr cloud(new pcl17::PointCloud<pcl17::PointXYZ>()); // Compute output directory for this model std::vector<std::string> st; boost::split(st, files_to_process.at(i), boost::is_any_of("/"), boost::token_compress_on); std::string class_dirname = st.at(st.size() - 2); std::string dirname = st.at(st.size() - 1); dirname = dirname.substr(0, dirname.size() - 4); dirname = output_dir + class_dirname + "/" + dirname; // Check if output directory for this model exists. If not create boost::filesystem::path dirpath(dirname); if (!boost::filesystem::exists(dirpath)) { if (!boost::filesystem::create_directories(dirpath)) { PCL17_ERROR ("Error creating directory %s.\n", dirpath.c_str ()); return -1; } } // Load model from file reader->SetFileName(files_to_process.at(i).c_str()); reader->Update(); model = reader->GetOutput(); PCL17_INFO("Number of points %d\n",model->GetNumberOfPoints()); // Coumpute bounds and center of the model double bounds[6]; model->GetBounds(bounds); double min_z_value = bounds[4]; double center[3]; model->GetCenter(center); createFullModelPointcloud(model, full_model_n_points, *cloud); pcl17::io::savePCDFile(dirname + "/full.pcd", *cloud); // Initialize PCLVisualizer. Add model to scene. pcl17::visualization::PCLVisualizer viz; viz.initCameraParameters(); viz.updateCamera(); viz.setCameraPosition(0, 0, 0, 1, 0, 0, 0, 0, 1); viz.addModelFromPolyData(model, transform); viz.setRepresentationToSurfaceForAllActors(); // Iterate over all shifts for (size_t shift_index = 0; shift_index < shift.size(); shift_index++) { // Iterate over all tilts for (size_t tilt_index = 0; tilt_index < tilt.size(); tilt_index++) { // Iterate over all distances for (size_t distance_index = 0; distance_index < distances.size(); distance_index++) { // Iterate over all angles double angle = 0; double angle_step = 360.0 / num_views; for (int angle_index = 0; angle_index < num_views; angle_index++) { // Set transformation with distance, shift, tilt and angle parameters. transform->Identity(); transform->RotateY(tilt[tilt_index]); transform->Translate(distances[distance_index], shift[shift_index], -(height + min_z_value)); transform->RotateZ(angle); /* // Render pointcloud viz.renderView(640, 480, cloud); //Add noise addNoise(cloud, noise_std); // Compute new coordinates of the model center double new_center[3]; transform->TransformPoint(center, new_center); // Shift origin of the poincloud to the model center and align with initial coordinate system. pcl17::PointCloud<pcl17::PointXYZ>::Ptr cloud_transformed(new pcl17::PointCloud<pcl17::PointXYZ>()); moveToNewCenterAndAlign(cloud, cloud_transformed, new_center, tilt[tilt_index]); // Compute file name for this pointcloud and save it std::stringstream ss; ss << dirname << "/rotation" << angle << "_distance" << distances[distance_index] << "_tilt" << tilt[tilt_index] << "_shift" << shift[shift_index] << ".pcd"; PCL17_INFO("Writing %d points to file %s\n", cloud->points.size(), ss.str().c_str()); pcl17::io::savePCDFile(ss.str(), *cloud_transformed); */ // increment angle by step angle += angle_step; } } } } } return 0; }
int main(int argc, char **argv) { args::ArgumentParser parser("Generates masks in stages.\n" "Stage 1 - Otsu thresholding to generate binary mask\n" "Stage 2 - RATs (optional)\n" "Stage 3 - Hole filling (optional)\n" "http://github.com/spinicist/QUIT"); args::Positional<std::string> input_path(parser, "INPUT_FILE", "Input file"); args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"}); args::Flag verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"}); args::ValueFlag<std::string> outarg( parser, "OUTPUT FILE", "Set output filename, default is input + _mask", {'o', "out"}); args::ValueFlag<int> volume( parser, "VOLUME", "Choose volume to mask in multi-volume file. Default 1, -1 selects last volume", {'v', "volume"}, 0); args::Flag is_complex(parser, "COMPLEX", "Input data is complex, take magnitude first", {'x', "complex"}); args::ValueFlag<float> lower_threshold( parser, "LOWER THRESHOLD", "Specify lower intensity threshold for 1st stage, otherwise Otsu's method is used", {'l', "lower"}, 0.); args::ValueFlag<float> upper_threshold( parser, "UPPER THRESHOLD", "Specify upper intensity threshold for 1st stage, otherwise Otsu's method is used", {'u', "upper"}, std::numeric_limits<float>::infinity()); args::ValueFlag<float> rats( parser, "RATS", "Perform the RATS step, argument is size threshold for connected component", {'r', "rats"}, 0.); args::ValueFlag<int> fillh_radius( parser, "FILL HOLES", "Fill holes in thresholded mask with radius N", {'F', "fillh"}, 0); QI::ParseArgs(parser, argc, argv, verbose); QI::SeriesF::Pointer vols = ITK_NULLPTR; if (is_complex) { vols = QI::ReadMagnitudeImage<QI::SeriesF>(QI::CheckPos(input_path), verbose); } else { vols = QI::ReadImage<QI::SeriesF>(QI::CheckPos(input_path), verbose); } std::string out_path; if (outarg.Get() == "") { out_path = QI::StripExt(input_path.Get()) + "_mask" + QI::OutExt(); } else { out_path = outarg.Get(); } // Extract one volume to process auto region = vols->GetLargestPossibleRegion(); if (static_cast<size_t>(std::abs(volume.Get())) < region.GetSize()[3]) { int volume_to_get = (region.GetSize()[3] + volume.Get()) % region.GetSize()[3]; QI::Log(verbose, "Masking volume {}...", volume_to_get); region.GetModifiableIndex()[3] = volume_to_get; } else { QI::Fail("Specified mask volume was invalid {} ", volume.Get()); } region.GetModifiableSize()[3] = 0; auto vol = itk::ExtractImageFilter<QI::SeriesF, QI::VolumeF>::New(); vol->SetExtractionRegion(region); vol->SetInput(vols); vol->SetDirectionCollapseToSubmatrix(); vol->Update(); QI::VolumeF::Pointer intensity_image = vol->GetOutput(); intensity_image->DisconnectPipeline(); /* * Stage 1 - Otsu or Threshold */ QI::VolumeI::Pointer mask_image = ITK_NULLPTR; if (lower_threshold || upper_threshold) { QI::Log(verbose, "Thresholding range: {}-{}", lower_threshold.Get(), upper_threshold.Get()); mask_image = QI::ThresholdMask(intensity_image, lower_threshold.Get(), upper_threshold.Get()); } else { QI::Log(verbose, "Generating Otsu mask"); mask_image = QI::OtsuMask(intensity_image); } /* * Stage 2 - RATS */ if (rats) { typedef itk::BinaryBallStructuringElement<int, 3> TBall; typedef itk::BinaryErodeImageFilter<QI::VolumeI, QI::VolumeI, TBall> TErode; typedef itk::BinaryDilateImageFilter<QI::VolumeI, QI::VolumeI, TBall> TDilate; float mask_volume = std::numeric_limits<float>::infinity(); float voxel_volume = QI::VoxelVolume(mask_image); QI::Log(verbose, "Voxel volume: {}", voxel_volume); int radius = 0; QI::VolumeI::Pointer mask_rats; while (mask_volume > rats.Get()) { radius++; TBall ball; TBall::SizeType radii; radii.Fill(radius); ball.SetRadius(radii); ball.CreateStructuringElement(); TErode::Pointer erode = TErode::New(); erode->SetInput(mask_image); erode->SetForegroundValue(1); erode->SetBackgroundValue(0); erode->SetKernel(ball); erode->Update(); std::vector<float> kept_sizes = QI::FindLabels(erode->GetOutput(), 0, 1, mask_rats); mask_volume = kept_sizes[0] * voxel_volume; auto dilate = TDilate::New(); dilate->SetKernel(ball); dilate->SetInput(mask_rats); dilate->SetForegroundValue(1); dilate->SetBackgroundValue(0); dilate->Update(); mask_rats = dilate->GetOutput(); mask_rats->DisconnectPipeline(); QI::Log(verbose, "Ran RATS iteration, radius = {} volume = {}", radius, mask_volume); } mask_image = mask_rats; } /* * Stage 3 - Hole Filling */ QI::VolumeI::Pointer finalMask = ITK_NULLPTR; if (fillh_radius) { QI::Log(verbose, "Filling holes"); auto fillHoles = itk::VotingBinaryIterativeHoleFillingImageFilter<QI::VolumeI>::New(); itk::VotingBinaryIterativeHoleFillingImageFilter<QI::VolumeI>::InputSizeType radius; radius.Fill(fillh_radius.Get()); fillHoles->SetInput(mask_image); fillHoles->SetRadius(radius); fillHoles->SetMajorityThreshold(2); // Corresponds to (rad^3-1)/2 + 2 threshold fillHoles->SetBackgroundValue(0); fillHoles->SetForegroundValue(1); fillHoles->SetMaximumNumberOfIterations(3); fillHoles->Update(); mask_image = fillHoles->GetOutput(); mask_image->DisconnectPipeline(); } QI::WriteImage(mask_image, out_path, verbose); QI::Log(verbose, "Finished."); return EXIT_SUCCESS; }