RTK
RTK copied to clipboard
ProjectionsReader support RawImageIO
Thanks a lot for this nice package. Here is a feature suggestion:
It would be useful if the class rtk::ProjectionsReader supported reading out raw data files, in the same way than itk::ImageSeriesReader does.
using ImageIOType = itk::RawImageIO<unsigned short, 3>;
using ImageType = itk::Image<unsigned short, 3>;
ImageIOType::Pointer io = ImageIOType::New();
io->SetDimensions(...);
io->SetOrigin(...);
io->SetSpacing(...);
io->SetByteOrderToLittleEndian();
using ReaderType = itk::ImageSeriesReader< ImageType >;
ReaderType::Pointer reader = ReaderType::New();
reader->SetImageIO( io );
reader->SetFileNames( nameGenerator->GetFileNames() );
reader->Update();
Currently, this cannot be done via rtk::ProjectionsReader, as it is missing the SetImageIO functionality.
I tried this modification (copy-pasted from itkImageReader) and it seems at least to compile. Not sure though about its correctness as I have no experience with RTK.
diff --git a/include/rtkProjectionsReader.h b/include/rtkProjectionsReader.h
index 3665a0d7..3301eaf2 100644
--- a/include/rtkProjectionsReader.h
+++ b/include/rtkProjectionsReader.h
@@ -258,6 +258,16 @@ public:
void
GenerateOutputInformation() override;
+ /** Set/Get the ImageIO helper class. Often this is created via the object
+ * factory mechanism that determines whether a particular ImageIO can
+ * read a certain file. This method provides a way to get the ImageIO
+ * instance that is created. Or you can directly specify the ImageIO
+ * to use to read a particular file in case the factory mechanism will
+ * not work properly (e.g., unknown or unusual extension). */
+ void
+ SetImageIO(itk::ImageIOBase * imageIO);
+ //itkGetModifiableObjectMacro(ImageIO, itk::ImageIOBase); this is somehow not working
+
protected:
ProjectionsReader();
~ProjectionsReader() override = default;
@@ -313,6 +323,9 @@ private:
/** Image IO object which is stored to create the pipe only when required */
itk::ImageIOBase::Pointer m_ImageIO{ nullptr };
+ bool m_UserSpecifiedImageIO; // keep track whether the
+ // ImageIO is user specified
+
/** Copy of parameters for the mini-pipeline. Parameters are checked and
* propagated when required in the GenerateOutputInformation. Refer to the
* documentation of the corresponding filter for more information. */
diff --git a/include/rtkProjectionsReader.hxx b/include/rtkProjectionsReader.hxx
index 9ec6367a..b08dbccc 100644
--- a/include/rtkProjectionsReader.hxx
+++ b/include/rtkProjectionsReader.hxx
@@ -120,6 +120,9 @@ ProjectionsReader<TOutputImage>::ProjectionsReader()
m_UpperBoundaryCropSize.Fill(0);
m_ShrinkFactors.Fill(1);
m_MedianRadius.Fill(0);
+
+ m_ImageIO = nullptr;
+ m_UserSpecifiedImageIO = false;
}
//--------------------------------------------------------------------
@@ -133,6 +136,7 @@ ProjectionsReader<TOutputImage>::PrintSelf(std::ostream & os, itk::Indent indent
os << indent << "RawDataReader: " << m_RawDataReader->GetNameOfClass() << std::endl;
if (m_RawToAttenuationFilter.GetPointer())
os << indent << "RawToProjectionsFilter: " << m_RawToAttenuationFilter->GetNameOfClass() << std::endl;
+ os << indent << "UserSpecifiedImageIO flag: " << m_UserSpecifiedImageIO << std::endl;
}
//--------------------------------------------------------------------
@@ -148,11 +152,22 @@ ProjectionsReader<TOutputImage>::GenerateOutputInformation()
rtk::RegisterIOFactories();
firstTime = false;
- itk::ImageIOBase::Pointer imageIO =
- itk::ImageIOFactory::CreateImageIO(m_FileNames[0].c_str(), itk::ImageIOFactory::IOFileModeEnum::ReadMode);
+ itk::ImageIOBase::Pointer imageIO = nullptr;
+
+ if (m_UserSpecifiedImageIO == false) // try creating via factory
+ {
+ imageIO = itk::ImageIOFactory::CreateImageIO(m_FileNames[0].c_str(), itk::ImageIOFactory::IOFileModeEnum::ReadMode);
- if (imageIO == nullptr)
- itkGenericExceptionMacro(<< "Cannot create ImageIOFactory for file " << m_FileNames[0].c_str());
+ if (imageIO == nullptr)
+ itkGenericExceptionMacro(<< "Cannot create ImageIOFactory for file " << m_FileNames[0].c_str());
+ }
+ else
+ {
+ imageIO = m_ImageIO;
+ using ReaderType = itk::ImageSeriesReader<OutputImageType>;
+ typename ReaderType::Pointer reader = ReaderType::New();
+ m_RawDataReader = reader;
+ }
if (m_ImageIO != imageIO)
{
@@ -728,6 +743,19 @@ ProjectionsReader<TOutputImage>::PropagateI0(itk::ImageBase<OutputImageDimension
// Pipeline connection for m_RawToAttenuationFilter is done after the call to this function
}
+template <typename TOutputImage>
+void
+ProjectionsReader<TOutputImage>::SetImageIO(itk::ImageIOBase * imageIO)
+{
+ itkDebugMacro("setting ImageIO to " << imageIO);
+ if (this->m_ImageIO != imageIO)
+ {
+ this->m_ImageIO = imageIO;
+ this->Modified();
+ }
+ m_UserSpecifiedImageIO = true;
+}
+
} // namespace rtk
#endif
Looks good to me. Can you create a pull request to test it?