bool mitk::SlicedData::VerifyRequestedRegion() { if(GetTimeGeometry() == NULL) return false; unsigned int i; // Is the requested region within the LargestPossibleRegion? // Note that the test is indeed against the largest possible region // rather than the buffered region; see DataObject::VerifyRequestedRegion. const IndexType &requestedRegionIndex = m_RequestedRegion.GetIndex(); const IndexType &largestPossibleRegionIndex = GetLargestPossibleRegion().GetIndex(); const SizeType& requestedRegionSize = m_RequestedRegion.GetSize(); const SizeType& largestPossibleRegionSize = GetLargestPossibleRegion().GetSize(); for (i=0; i< RegionDimension; ++i) { if ( (requestedRegionIndex[i] < largestPossibleRegionIndex[i]) || ((requestedRegionIndex[i] + static_cast<long>(requestedRegionSize[i])) > (largestPossibleRegionIndex[i]+static_cast<long>(largestPossibleRegionSize[i])))) { return false; } } return true; }
void mitk::SlicedData::SetRequestedRegionToLargestPossibleRegion() { m_UseLargestPossibleRegion = true; if(GetGeometry()==NULL) return; unsigned int i; const RegionType::IndexType & index = GetLargestPossibleRegion().GetIndex(); const RegionType::SizeType & size = GetLargestPossibleRegion().GetSize(); for(i=0;i<RegionDimension;++i) { m_RequestedRegion.SetIndex(i, index[i]); m_RequestedRegion.SetSize(i, size[i]); } }
bool mitk::SlicedData::RequestedRegionIsOutsideOfTheBufferedRegion() { // Is the requested region within the currently buffered data? // SlicedData and subclasses store entire volumes or slices. The // methods IsVolumeSet() and IsSliceSet are provided to check, // a volume or slice, respectively, is available. Thus, these // methods used here. const IndexType &requestedRegionIndex = m_RequestedRegion.GetIndex(); const SizeType &requestedRegionSize = m_RequestedRegion.GetSize(); const SizeType &largestPossibleRegionSize = GetLargestPossibleRegion().GetSize(); // are whole channels requested? int c, cEnd; c = requestedRegionIndex[4]; cEnd = c + static_cast<long>(requestedRegionSize[4]); if (requestedRegionSize[3] == largestPossibleRegionSize[3]) { for (; c < cEnd; ++c) if (IsChannelSet(c) == false) return true; return false; } // are whole volumes requested? int t, tEnd; t = requestedRegionIndex[3]; tEnd = t + static_cast<long>(requestedRegionSize[3]); if (requestedRegionSize[2] == largestPossibleRegionSize[2]) { for (; c < cEnd; ++c) for (; t < tEnd; ++t) if (IsVolumeSet(t, c) == false) return true; return false; } // ok, only slices are requested. Check if they are available. int s, sEnd; s = requestedRegionIndex[2]; sEnd = s + static_cast<long>(requestedRegionSize[2]); for (; c < cEnd; ++c) for (; t < tEnd; ++t) for (; s < sEnd; ++s) if (IsSliceSet(s, t, c) == false) return true; return false; }
static void CreateNoNaNMask(itk::Image<TPixel, VImageDimension>* itkValue, mitk::Image::Pointer mask, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LFloatImageType; typedef itk::Image< unsigned short, VImageDimension> LMaskImageType; typename LMaskImageType::Pointer itkMask = LMaskImageType::New(); mitk::CastToItkImage(mask, itkMask); typedef itk::ImageDuplicator< LMaskImageType > DuplicatorType; typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(itkMask); duplicator->Update(); auto tmpMask = duplicator->GetOutput(); itk::ImageRegionIterator<LMaskImageType> mask1Iter(itkMask, itkMask->GetLargestPossibleRegion()); itk::ImageRegionIterator<LMaskImageType> mask2Iter(tmpMask, tmpMask->GetLargestPossibleRegion()); itk::ImageRegionIterator<LFloatImageType> imageIter(itkValue, itkValue->GetLargestPossibleRegion()); while (!mask1Iter.IsAtEnd()) { mask2Iter.Set(0); if (mask1Iter.Value() > 0) { // Is not NaN if (imageIter.Value() == imageIter.Value()) { mask2Iter.Set(1); } } ++mask1Iter; ++mask2Iter; ++imageIter; } newMask->InitializeByItk(tmpMask); mitk::GrabItkImageMemory(tmpMask, newMask); }
std::vector<cleaver::AbstractScalarField*> NRRDTools::segmentationToIndicatorFunctions(std::string filename, double sigma) { // read file using ITK if (filename.find(".nrrd") != std::string::npos) { itk::NrrdImageIOFactory::RegisterOneFactory(); } else if (filename.find(".mha") != std::string::npos) { itk::MetaImageIOFactory::RegisterOneFactory(); } ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(filename); reader->Update(); ImageType::Pointer image = reader->GetOutput(); //determine the number of labels in the segmentations ImageCalculatorFilterType::Pointer imageCalculatorFilter = ImageCalculatorFilterType::New(); imageCalculatorFilter->SetImage(reader->GetOutput()); imageCalculatorFilter->Compute(); auto maxLabel = static_cast<size_t>(imageCalculatorFilter->GetMaximum()); auto minLabel = static_cast<size_t>(imageCalculatorFilter->GetMinimum()); std::vector<cleaver::AbstractScalarField*> fields; //extract images from each label for an indicator function for (size_t i = minLabel, num = 0; i <= maxLabel; i++, num++) { //pull out this label ThreshType::Pointer thresh = ThreshType::New(); thresh->SetInput(image); thresh->SetOutsideValue(0); thresh->ThresholdOutside(static_cast<double>(i) - 0.001, static_cast<double>(i) + 0.001); thresh->Update(); //change the values to be from 0 to 1 MultiplyImageFilterType::Pointer multiplyImageFilter = MultiplyImageFilterType::New(); multiplyImageFilter->SetInput(thresh->GetOutput()); multiplyImageFilter->SetConstant(1. / static_cast<double>(i)); multiplyImageFilter->Update(); //do some blurring GaussianBlurType::Pointer blur = GaussianBlurType::New(); blur->SetInput(multiplyImageFilter->GetOutput()); blur->SetVariance(sigma * sigma); blur->Update(); //find the average value between ImageCalculatorFilterType::Pointer calc = ImageCalculatorFilterType::New(); calc->SetImage(blur->GetOutput()); calc->Compute(); float mx = calc->GetMaximum(); float mn = calc->GetMinimum(); auto md = (mx + mn) / 2.f; //create a distance map with that minimum value as the levelset DMapType::Pointer dm = DMapType::New(); dm->SetInput(blur->GetOutput()); dm->SetInsideValue(md + 0.1f); dm->SetOutsideValue(md -0.1f); dm->Update(); //MultiplyImageFilterType::Pointer mult = // MultiplyImageFilterType::New(); //mult->SetInput(blur->GetOutput()); //mult->SetConstant(-20. / (mx - mn)); //mult->Update(); /*SubtractImageFilterType::Pointer subtractFilter = SubtractImageFilterType::New(); subtractFilter->SetInput1(mult->GetOutput()); subtractFilter->SetConstant2(1.); subtractFilter->Update();*/ //convert the image to a cleaver "abstract field" auto img = dm->GetOutput(); auto region = img->GetLargestPossibleRegion(); auto numPixel = region.GetNumberOfPixels(); float *data = new float[numPixel]; auto x = region.GetSize()[0], y = region.GetSize()[1], z = region.GetSize()[2]; fields.push_back(new cleaver::FloatField(data, x, y, z)); auto beg = filename.find_last_of("/") + 1; auto name = filename.substr(beg, filename.size() - beg); auto fin = name.find_last_of("."); name = name.substr(0, fin); std::stringstream ss; ss << name << i; fields[num]->setName(ss.str()); itk::ImageRegionConstIterator<ImageType> imageIterator(img, region); size_t pixel = 0; while (!imageIterator.IsAtEnd()) { // Get the value of the current pixel float val = static_cast<float>(imageIterator.Get()); ((cleaver::FloatField*)fields[num])->data()[pixel++] = -val; ++imageIterator; } auto spacing = img->GetSpacing(); ((cleaver::FloatField*)fields[num])->setScale( cleaver::vec3(spacing[0], spacing[1], spacing[2])); //NRRDTools::saveNRRDFile(fields[num], "a" + std::to_string(num)); } return fields; }
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; }