Skip to content

Instantly share code, notes, and snippets.

@cnd
Created December 18, 2020 12:10
Show Gist options
  • Save cnd/45d1eafb41dd00571c830aca73537c5b to your computer and use it in GitHub Desktop.
Save cnd/45d1eafb41dd00571c830aca73537c5b to your computer and use it in GitHub Desktop.
template <typename TPixelType>
void AutoplanExporterDicom::doExport(mitk::Image* image, AutoplanExporter::ExportParams& exportParams, std::vector<boost::filesystem::path>& exportedFolders, const DoExportParams& params)
{
std::vector<itk::MetaDataDictionary*> dicomMetaDataDictionaryArray = params.originalImage->GetMetaDataDictionaryArray();
std::vector<itk::MetaDataDictionary*>* workDictionaryArray = &dicomMetaDataDictionaryArray;
std::unique_ptr<DicomAnonimizer> anonimizer = nullptr;
if (exportParams.m_Anonimize) {
anonimizer.reset(new DicomAnonimizer(dicomMetaDataDictionaryArray));
workDictionaryArray = &anonimizer->getAnonimizedDictionaries();
}
mitk::Image::Pointer exportedImage = image->Clone();
int timeSteps = params.originalImage->GetTimeSteps();
int numberOfComponents = params.originalImage->GetPixelType().GetNumberOfComponents();
int size = (timeSteps > 1) ? timeSteps : numberOfComponents;
int arraySize = workDictionaryArray->size() / size;
auto itkImage = autoplan::castToItkImageReduce4D<TPixelType, 3>(exportedImage);
if (!itkImage) {
MITK_WARN << "Error transforming mitk image to itk image";
return;
}
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
typedef typename itk::ImageSeriesWriter<itk::Image<TPixelType, 3>, itk::Image<TPixelType, 2>> SeriesWriterType;
typename SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(itkImage);
AutoplanGDCMImageIO::Pointer gdcmIO = AutoplanGDCMImageIO::New();
seriesWriter->SetImageIO(gdcmIO);
OutputNamesGeneratorType::Pointer outputNames = OutputNamesGeneratorType::New();
outputNames->SetSeriesFormat(params.seriesFormat.c_str());
int startIndex = arraySize * params.component + 1;
int endIndex = arraySize * (params.component + 1);
outputNames->SetStartIndex(startIndex);
outputNames->SetEndIndex(endIndex);
seriesWriter->SetFileNames(outputNames->GetFileNames());
// Check if exported serie has serie uid
itk::MetaDataObject<std::string>::Pointer newSeriesUID = itk::MetaDataObject<std::string>::New();
char uid[100];
dcmGenerateUniqueIdentifier(uid, autoplan::AUTOPLAN_ORG_ROOT.c_str());
newSeriesUID->SetMetaDataObjectValue(uid);
itk::MetaDataObject<std::string>::Pointer seriesDate, seriesTime;
itk::MetaDataObject<std::string>::Pointer encoding = itk::MetaDataObject<std::string>::New();
encoding->SetMetaDataObjectValue("ISO_IR 192"); //< UTF-8
if (!exportParams.m_Anonimize) {
seriesDate = itk::MetaDataObject<std::string>::New();
seriesDate->SetMetaDataObjectValue(autoplan::getCurrentDateDICOMString());
seriesTime = itk::MetaDataObject<std::string>::New();
seriesTime->SetMetaDataObjectValue(autoplan::getCurrentTimeDICOMString());
}
std::vector<itk::MetaDataDictionary*> timeStepDictionaryArray;
for (int j = startIndex - 1; j < endIndex; j++) {
timeStepDictionaryArray.push_back(workDictionaryArray->at(j));
// Always set new series uid to never change the original series
timeStepDictionaryArray.back()->Set("0020|000e", newSeriesUID);
if (!exportParams.m_Anonimize) { // Set current date/time to series
static const char* dateTags[] = {"0008|0021", "0008|0023"};
static const char* timeTags[] = {"0008|0031", "0008|0033"};
for (auto tag: dateTags) {
timeStepDictionaryArray.back()->Set(tag, seriesDate);
}
for (auto tag: timeTags) {
timeStepDictionaryArray.back()->Set(tag, seriesTime);
}
timeStepDictionaryArray.back()->Set("0008|0005", encoding);
}
}
autoplan::DataStorageUtils::replaceMetadataByKey(timeStepDictionaryArray, "0028|1052", std::to_string(0));
autoplan::DataStorageUtils::replaceMetadataByKey(timeStepDictionaryArray, "0028|1053", std::to_string(1));
seriesWriter->SetMetaDataDictionaryArray(&timeStepDictionaryArray);
params.progressMonitor->addFilter(seriesWriter);
try {
seriesWriter->Update();
}
catch (itk::ExceptionObject& excp) {
std::cerr << "Exception thrwon while writing the series " << std::endl;
std::cerr << excp << std::endl;
return;
}
params.progressMonitor->clear();
}
template <typename TPixelType>
void AutoplanExporterDicom::doExportSegmentation(mitk::Image* parentImage
, AutoplanExporter::ExportParams& exportParams
, std::vector<boost::filesystem::path>& exportedFolders
, const DoExportSegmentationParams& params
)
{
mitk::Image::Pointer resultImage(nullptr);
typedef typename itk::Image<TPixelType, 3> ImageType;
typename ImageType::Pointer resultItk = autoplan::ItkMitkImageConverter<ImageType>::mitkToItk(parentImage);
// TODO: possibly use constant values for different structures
int valuePixel = 1000;
int maskWidth = parentImage->GetLargestPossibleRegion().GetSize()[0];
int maskHeight = parentImage->GetLargestPossibleRegion().GetSize()[1];
int maskNumberSlice = parentImage->GetLargestPossibleRegion().GetSize()[2];
for (mitk::Image* segmentationImage : params.notLungsSegmentations) {
int width = segmentationImage->GetLargestPossibleRegion().GetSize()[0];
int height = segmentationImage->GetLargestPossibleRegion().GetSize()[1];
int numberSlice = segmentationImage->GetLargestPossibleRegion().GetSize()[2];
if (width <= maskWidth
&& height <= maskHeight
&& numberSlice <= maskNumberSlice) {
try
{
typename ImageType::IndexType index;
typename ImageType::Pointer itkSeg = autoplan::ItkMitkImageConverter<ImageType>::mitkToItk(segmentationImage);
for (int k = 0; k < numberSlice; k++) {
index[2] = k;
for (int j = 0; j < height; j++) {
index[1] = j;
for (int i = 0; i < width; i++) {
index[0] = i;
TPixelType oldValue = itkSeg->GetPixel(index);
if (oldValue >= static_cast<TPixelType>(1)) {
resultItk->SetPixel(index, valuePixel);
}
}
}
}
valuePixel += 250;
}
catch (mitk::Exception& e)
{
AUTOPLAN_ERROR << e.GetDescription();
return;
}
}
}
resultImage = autoplan::ItkMitkImageConverter<ImageType>::itkToMitk(resultItk);
// if we have lungs segmentation use it as mask
if (params.lungsImage) {
if (params.lungsImage->GetLargestPossibleRegion().GetSize() == parentImage->GetLargestPossibleRegion().GetSize())
{
mitk::MaskImageFilter::Pointer maskFilter = mitk::MaskImageFilter::New();
maskFilter->SetInput(parentImage);
maskFilter->SetMask(params.lungsImage);
maskFilter->OverrideOutsideValueOn();
maskFilter->SetOutsideValue(parentImage->GetStatistics()->GetScalarValueMin());
try
{
maskFilter->Update();
}
catch (itk::ExceptionObject& excpt)
{
AUTOPLAN_ERROR << excpt.GetDescription();
return;
}
resultImage = maskFilter->GetOutput();
}
}
if (resultImage.IsNull()) {
return;
}
resultImage->SetGeometry(parentImage->GetGeometry());
if (parentImage->GetTimeGeometry()) {
mitk::TimeGeometry::Pointer originalGeometry = parentImage->GetTimeGeometry()->Clone();
resultImage->SetTimeGeometry(originalGeometry);
}
autoplan::DataStorageUtils::copyAndMergeImageProperties(parentImage, resultImage);
auto imageProp = parentImage->GetPropertyList();
resultImage->SetPropertyList(imageProp);
resultImage->SetSpacing(parentImage->GetGeometry()->GetSpacing());
resultImage->SetOrigin(parentImage->GetGeometry()->GetOrigin());
if (params.lungsImage) {
autoplan::DataStorageUtils::replacePropertiesAndMetadataByKey(resultImage, "0008|0060", "SC");
}
resultImage->CopyInformation(parentImage);
DoExportParams eparams;
eparams.component = params.component;
eparams.originalImage = resultImage;
eparams.seriesFormat = params.seriesFormat;
eparams.progressMonitor = params.progressMonitor;
doExport<TPixelType>(resultImage, exportParams, exportedFolders, eparams);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment