Parallelize itk::ImageSeriesReader (ITK 4.12)

threads
dicom
gdcmio
io

(Dženan Zukić) #21

Recipe for concurrent disaster:

ReaderType::Pointer reader = ReaderType::New(); // global reader instance
void threadFunction()
{
  unsigned i = getMyIndexSomehow();
  reader->SetFileName(filenames[i]);
  reader->Update();
  reader->GetOutput();
}

but this should work:

void threadFunction()
{
  unsigned i = getMyIndexSomehow();
  ReaderType::Pointer reader = ReaderType::New(); //thread-local reader instance
  reader->SetFileName(filenames[i]);
  reader->Update();
  reader->GetOutput();
}

If you took the approach that should work, please share the code of your small example so we can diagnose the problem.


(Simon) #22

Of course I did not create the reader globally.

I created a worker class, when spawned workers and gave them to a thread pool. Here is an example of how I did in QT:

class Worker : public QRunnable
{
private:
    QString mFilePath;

public:
    Worker(QString filePath)
    {
        mFilePath = filePath;

    }

    void run()
    {

            ReaderType::Pointer reader = ReaderType::New();

            typedef itk::GDCMImageIO       ImageIOType;

            ImageIOType::Pointer dicomIO = ImageIOType::New();

            dicomIO->SetLoadPrivateTags(true);
            dicomIO->SetKeepOriginalUID(true);

            reader->SetImageIO( dicomIO );

            std::vector<std::string> fileNames;
            fileNames.push_back(mFilePath.toStdString());

            reader->SetFileNames( fileNames );

            try {
                reader->Update();
            }
            catch(itk::ExceptionObject& err) {
                qDebug() << mFilePath;
                qDebug() << err.GetDescription();
                return;
            }


            // Write file
            typedef itk::ImageSeriesWriter<FloatImageType4D, FloatImageType2D>  SeriesWriterType;

            SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();

            seriesWriter->SetImageIO( reader->GetImageIO() );

            QString writePath = "/mnt/e357c8aa-9d7c-4668-bac6-fc6b286ff9f6/dicomfiles/output/";
            QString fileName = QFileInfo(QFile(mFilePath)).fileName();

            std::vector<std::string> outputFileNames;
            outputFileNames.push_back(QString(writePath + fileName).toStdString());
            seriesWriter->SetFileNames(outputFileNames);

            seriesWriter->SetInput(reader->GetOutput());

            try
            {
                seriesWriter->SetDebug(true);
                seriesWriter->Update();
            }
            catch( itk::ExceptionObject & excp )
            {
                qDebug() << writePath + fileName;
                qDebug() << excp.GetDescription();
                return;
            }
    }
};

Please note that this code has not been run, I just made it from my test code that had several modifications from my testing…


(Dženan Zukić) #23

Since you are reading/writing just one file at a time, why do you use Series reader/writer instead of the plain reader/writer? And if you are just copying, why not use fread/fwrite or fstream read/write?

Still, I don’t quite see a problem with this code. To check whether it is a bug in the rest of the code, can you replace ITK-specific code by fread/fwrite or fstream read/write? If it is still problematic, the problem is in your code.