Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: apply transform to single slice of time series #1800

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion Examples/antsApplyTransforms.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,18 @@ antsApplyTransforms(itk::ants::CommandLineParser::Pointer & parser, unsigned int
typename itk::ants::CommandLineParser::OptionType::Pointer inputOption = parser->GetOption("input");
typename itk::ants::CommandLineParser::OptionType::Pointer outputOption = parser->GetOption("output");

// Time-index to extract from time-series image
unsigned long extractTimeIndex = 0;

bool extractTimeIndexSet = false;

typename itk::ants::CommandLineParser::OptionType::Pointer timeIndexOption = parser->GetOption("time-index");
if (timeIndexOption && timeIndexOption->GetNumberOfFunctions())
{
extractTimeIndexSet = true;
extractTimeIndex = parser->Convert<unsigned int>(timeIndexOption->GetFunction(0)->GetName());
}

if (inputImageType == 5 && inputOption && inputOption->GetNumberOfFunctions())
{
if (verbose)
Expand All @@ -235,8 +247,48 @@ antsApplyTransforms(itk::ants::CommandLineParser::Pointer & parser, unsigned int
if (verbose)
{
std::cout << "Input time-series image: " << inputOption->GetFunction(0)->GetName() << std::endl;
if (extractTimeIndexSet)
{
std::cout << "Extracting time index: " << extractTimeIndex << std::endl;
}
}
if (!extractTimeIndexSet)
{
ReadImage<TimeSeriesImageType>(timeSeriesImage, (inputOption->GetFunction(0)->GetName()).c_str());
}
else
{
// Modifying inputImageType, because we're going to extract a single time point
// if we don't do this, the code will try to read from timeSeriesImage below and output a time series
inputImageType = 0;

// Set up the image reader with streaming support
using ReaderType = itk::ImageFileReader<TimeSeriesImageType>;
typename ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName((inputOption->GetFunction(0)->GetName()).c_str());

// Update the reader's output information without loading the entire image into memory
reader->UpdateOutputInformation();
typename TimeSeriesImageType::RegionType extractRegion = reader->GetOutput()->GetLargestPossibleRegion();
typename TimeSeriesImageType::SizeType size = extractRegion.GetSize();

// Check if the extractTimeIndex is within range
if (extractTimeIndex >= size[3])
{
std::cerr << "Error: time index to extract is out of range [0, " << (size[3] - 1) << "]" << std::endl;
return EXIT_FAILURE;
}

extractRegion.SetIndex(Dimension, extractTimeIndex);
extractRegion.SetSize(Dimension, 0);
using ExtracterType = itk::ExtractImageFilter<TimeSeriesImageType, ImageType>;
typename ExtracterType::Pointer extracter = ExtracterType::New();
extracter->SetInput(reader->GetOutput());
extracter->SetExtractionRegion(extractRegion);
extracter->SetDirectionCollapseToSubmatrix();
extracter->Update();
inputImages.push_back(extracter->GetOutput());
}
ReadImage<TimeSeriesImageType>(timeSeriesImage, (inputOption->GetFunction(0)->GetName()).c_str());
}
else if (inputImageType == 2 && inputOption && inputOption->GetNumberOfFunctions())
{
Expand Down Expand Up @@ -896,6 +948,18 @@ antsApplyTransformsInitializeCommandLineOptions(itk::ants::CommandLineParser * p
parser->AddOption(option);
}

{
std::string description = std::string("Time index to extract from time series input (-e 3). ") +
std::string("This selects a single slice from time series input without reading ") +
std::string("the entire dataset into memory.");

OptionType::Pointer option = OptionType::New();
option->SetLongName("time-index");
option->SetUsageOption(0, "<timeIndex>");
option->SetDescription(description);
parser->AddOption(option);
}

{
std::string description = std::string("Currently, the only input objects supported are image ") +
std::string("objects. However, the current framework allows for ") +
Expand Down