[Rtk-users] Issue in ITK-RTK reconstruction with Shepp-Logan phantom
Simon Rit
simon.rit at creatis.insa-lyon.fr
Sat Feb 24 09:18:46 CET 2024
Hi,
Please avoid multiple posts, one is enough (ref
https://discourse.itk.org/t/issue-in-itk-rtk-reconstruction-with-shepp-logan-phantom/6464
).
Simon
On Sat, Feb 24, 2024 at 9:17 AM Navami S <navamisnair30 at gmail.com> wrote:
> Hi,
> I was trying to do a comparative study between TIGRE and RTK for which I
> have extracted the Shepp-Logan Raw projection data from TIGRE and I am
> trying to reconstruct it in RTK. Initially I tried to read the raw data as
> such but was not successful. So I generated MetaImage Header file of the
> raw data and tried to read it instead and was successful. Now my code has
> run completely and an output image is generated in mhd format but
> unfortunately when I try to visualize the output using 3D Slicer, the image
> is completely black, ie, there are no pixel values. So I tried to print the
> pixel values of both projection and reconstrued images and found that the
> pixel values of projection images had both zero and non-zero values but
> reconstructed images had both zero and negative values. So I have done some
> post processing which resulted in pixel values with zeros and values like
> 1, 2 or 3. But still no image can be seen. I don't know what to do and how
> to rectify this issue. I will provide my code below.
>
> #include <iostream>
> #include <itkCudaImage.h>
> #include <rtkConstantImageSource.h>
> #include <rtkThreeDCircularProjectionGeometryXMLFileWriter.h>
> #include <rtkCudaFDKConeBeamReconstructionFilter.h>
> #include <rtkFieldOfViewImageFilter.h>
> #include <itkImageFileReader.h>
> #include <itkTimeProbe.h>
> #include <rtkThreeDCircularProjectionGeometryXMLFileReader.h>
> #include <QtWidgets>
> #include <itkImage.h>
> #include <itkMetaImageIO.h>
> #include <itkImageIOFactory.h>
> #include <itkCastImageFilter.h>
> #include <itkIntensityWindowingImageFilter.h>
>
>
>
> int main(int argc, char **argv)
> {
> if (argc < 3)
> {
> std::cout << "Usage: FirstReconstruction <outputimage> <outputgeometry>" << std::endl;
> return EXIT_FAILURE;
> }
>
>
>
> // Create a time probe
> itk::TimeProbe clock;
>
> // Defines the image type
> using ImageType = itk::CudaImage<uint16_t, 3>;
>
> // Defines the RTK geometry object
> using GeometryType = rtk::ThreeDCircularProjectionGeometry;
> GeometryType::Pointer geometry = GeometryType::New();
> unsigned int numberOfProjections = 100;
>
>
> for (unsigned int noProj = 0; noProj < numberOfProjections; noProj++)
> {
> //double angle = static_cast<double>(noProj) * 360. / static_cast<double>(numberOfProjections);
> const int num_angles = 100;
> const double start_angle = 0.0;
> const double end_angle = 2.0 * M_PI;
>
> // Create an array of angles
> double angles[num_angles];
>
> // Calculate evenly spaced angles
> for (int i = 0; i < num_angles; ++i) {
> double fraction = static_cast<double>(i) / (num_angles - 1);
> angles[i] = start_angle + fraction * (end_angle - start_angle);
>
> geometry->AddProjection(1000, 1536, angles[i]);
> }
>
> }
> // Write the geometry to disk
> rtk::ThreeDCircularProjectionGeometryXMLFileWriter::Pointer xmlWriter;
> xmlWriter = rtk::ThreeDCircularProjectionGeometryXMLFileWriter::New();
> xmlWriter->SetFilename(argv[2]);
> xmlWriter->SetObject(geometry);
> xmlWriter->WriteFile();
>
>
> //using ProjectionImageType = rtk::CudaFDKBackProjectionImageFilter::ProjectionImageType;
> using ProjectionImageType = itk::CudaImage<uint16_t, 3>;
>
> // Read the projection data from the .mha file
> using ReaderType = itk::ImageFileReader<ImageType>;
> ReaderType::Pointer reader = ReaderType::New();
>
> // Create MetaImageIO object and set component type explicitly
> using MetaImageIOType = itk::MetaImageIO;
> MetaImageIOType::Pointer metaImageIO = MetaImageIOType::New();
> metaImageIO->SetComponentType(itk::ImageIOBase::USHORT); // Set the component type to unsigned short (16-bit)
> reader->SetImageIO(metaImageIO);
>
> reader->SetFileName("D:/Navami/TIGRE_OUT_NEW/SheppLoganTrial_projections.mhd"); // Update the path accordingly
>
> try {
> reader->Update();
>
> // // // Accessing the image
> // ImageType::Pointer image = reader->GetOutput();
>
>
> // // Define an iterator to iterate over the image
> // itk::ImageRegionIterator<ImageType> it(image, image->GetLargestPossibleRegion());
>
> // // Iterate through the image and print pixel values
> // for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
> // std::cout << "Pixel value: " << static_cast<int>(it.Get()) << std::endl;
> // }
> // // Print projection image pixel values after reading
> // std::cout << "Projection image pixel values after reading:" << std::endl;
> // itk::ImageRegionIterator<ImageType> itUint16(reader->GetOutput(), reader->GetOutput()->GetLargestPossibleRegion());
> // for (itUint16.GoToBegin(); !itUint16.IsAtEnd(); ++itUint16) {
> // std::cout << "Pixel value: " << itUint16.Get() << std::endl;
> // }
>
> } catch (itk::ExceptionObject &ex) {
> std::cerr << "Error reading the .mhd file: " << ex << std::endl;
> return EXIT_FAILURE;
> }
>
>
> ////// TO WRITE PROJECTION DATA //////
>
> // // Writer for projection data
> // using ProjectionWriterType = itk::ImageFileWriter<ImageType>;
> // ProjectionWriterType::Pointer projectionWriter = ProjectionWriterType::New();
> // projectionWriter->SetFileName("D:/Navami/TIGRE_OUT_NEW/projection_data.mha"); // Set the filename for the projection data
> // projectionWriter->SetInput(reader->GetOutput()); // Set the input as the projection data
> // try
> // {
> // std::cout << "Writing projection data..." << std::endl;
> // projectionWriter->Update(); // Write the projection data
> // std::cout << "Projection data written successfully." << std::endl;
> // }
> // catch (itk::ExceptionObject &ex)
> // {
> // std::cerr << "Error writing projection data: " << ex << std::endl;
> // return EXIT_FAILURE;
> // }
>
>
>
> using CastFilterType = itk::CastImageFilter<ImageType, itk::CudaImage<float, 3>>;
> CastFilterType::Pointer castFilter = CastFilterType::New();
> castFilter->SetInput(reader->GetOutput());
> castFilter->Update();
>
> // Define the type of the output image after casting
> using FloatImageType = itk::CudaImage<float, 3>;
> // Get the output image after casting
> FloatImageType::Pointer castOutputImage = castFilter->GetOutput();
>
> // // Define an iterator to iterate over the output image after casting
> // using FloatIteratorType = itk::ImageRegionIterator<FloatImageType>;
> // FloatIteratorType it(castOutputImage, castOutputImage->GetLargestPossibleRegion());
>
> // // Print the pixel values after casting
> // std::cout << "Pixel values after casting to float:" << std::endl;
> // for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
> // std::cout << "Pixel value: " << it.Get() << std::endl;
> // }
>
> // Create reconstructed image
> using ConstantImageSourceType = rtk::ConstantImageSource<ImageType>;
> ConstantImageSourceType::Pointer constantImageSource2 = ConstantImageSourceType::New();
>
> ConstantImageSourceType::PointType origin;
> origin.Fill(0);
>
> ConstantImageSourceType::SpacingType spacing;
> spacing.Fill(1.6);
>
> ConstantImageSourceType::SizeType sizeOutput;
> sizeOutput[0] = 128;
> sizeOutput[1] = 128;
> sizeOutput[2] = 128;
>
> constantImageSource2->SetOrigin(origin);
> constantImageSource2->SetSpacing(spacing);
> constantImageSource2->SetSize(sizeOutput);
> constantImageSource2->SetConstant(0.0);
> constantImageSource2->Update();
>
>
> // Define the type of the output image after casting for constantImageSource2
> using FloatConstantImageType = itk::CudaImage<float, 3>;
>
> // Define the casting filter for constantImageSource2
> using ConstantImageCastFilterType = itk::CastImageFilter<ImageType, FloatConstantImageType>;
> ConstantImageCastFilterType::Pointer constantImageCastFilter = ConstantImageCastFilterType::New();
> constantImageCastFilter->SetInput(constantImageSource2->GetOutput());
> constantImageCastFilter->Update(); // Perform the conversion
>
>
> // FDK reconstruction
> std::cout << "Reconstructing..." << std::endl;
> // Start the clock
> clock.Start();
> using FDKGPUType = rtk::CudaFDKConeBeamReconstructionFilter;
> FDKGPUType::Pointer feldkamp = FDKGPUType::New();
>
> // try {
> //using FDKGPUType = rtk::CudaFDKConeBeamReconstructionFilter;
> //FDKGPUType::Pointer feldkamp = FDKGPUType::New();
> feldkamp->SetInput(0, constantImageCastFilter->GetOutput());
> feldkamp->SetInput(1, castFilter->GetOutput());
> feldkamp->SetGeometry(geometry);
> feldkamp->GetRampFilter()->SetTruncationCorrection(300.);
> feldkamp->GetRampFilter()->SetHannCutFrequency(1.5);
>
>
> // FDK reconstruction
> feldkamp->Update();
>
>
>
>
>
>
> // Normalize the reconstructed image
> using OutputImageType = itk::CudaImage<float, 3>;
> using IntensityWindowingFilterType = itk::IntensityWindowingImageFilter<OutputImageType, ImageType>;
> IntensityWindowingFilterType::Pointer windowingFilter = IntensityWindowingFilterType::New();
> windowingFilter->SetInput(feldkamp->GetOutput());
> windowingFilter->SetWindowMinimum(0);
> windowingFilter->SetWindowMaximum(65535);
> windowingFilter->SetOutputMinimum(0);
> windowingFilter->SetOutputMaximum(65535);
> windowingFilter->Update();
>
> // Accessing the normalized output image
> ImageType::Pointer normalizedOutputImage = windowingFilter->GetOutput();
>
> // Define an iterator to iterate over the image and print pixel values
> itk::ImageRegionIterator<ImageType> it(normalizedOutputImage, normalizedOutputImage->GetLargestPossibleRegion());
> for (it.GoToBegin(); !it.IsAtEnd(); ++it) {
> std::cout << "Normalized Pixel value: " << it.Get() << std::endl;
> }
>
> // Stop the clock after the reconstruction
> clock.Stop();
> // Output the time taken
> std::cout << "Time taken for reconstruction: " << clock.GetTotal() << " seconds." << std::endl;
>
> // Define the type for the output of the FDK reconstruction
> using FloatImageType = itk::CudaImage<float, 3>;
>
> // Define the type of the output image after casting for FOV filter
> using UShortImageType = itk::CudaImage<unsigned short, 3>;
>
> // Define the type for the output of the FDK reconstruction
> // using FloatImageType = itk::CudaImage<float, 3>;
>
> // Define the casting filter for the output of the FDK reconstruction
> using FOVCastFilterType = itk::CastImageFilter<FloatImageType, UShortImageType>;
> FOVCastFilterType::Pointer fovCastFilter = FOVCastFilterType::New();
> fovCastFilter->SetInput(feldkamp->GetOutput());
> fovCastFilter->Update(); // Perform the conversion
>
>
>
>
> // Field-of-view masking
> using FOVFilterType = rtk::FieldOfViewImageFilter<ImageType, ImageType>;
> FOVFilterType::Pointer fieldofview = FOVFilterType::New();
> fieldofview->SetInput(fovCastFilter->GetOutput());
> fieldofview->SetProjectionsStack(reader->GetOutput());
> fieldofview->SetGeometry(geometry);
> fieldofview->Update();
>
> // Writer
> std::cout << "Writing output image..." << std::endl;
> using WriterType = itk::ImageFileWriter<ImageType>;
> WriterType::Pointer writer = WriterType::New();
> writer->SetFileName(argv[1]);
> writer->SetInput(fieldofview->GetOutput());
> writer->Update();
> std::cout << "Done!" << std::endl;
>
>
> return EXIT_SUCCESS;
> }
>
> Please help me with a solution. Thanks in advance.
> _______________________________________________
> Rtk-users mailing list
> rtk-users at openrtk.org
> https://www.creatis.insa-lyon.fr/mailman/listinfo/rtk-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.creatis.insa-lyon.fr/pipermail/rtk-users/attachments/20240224/0ead3bd7/attachment-0001.htm>
More information about the Rtk-users
mailing list