29 mitk::DICOMFileReader::Pointer
33 TiXmlDocument doc (filename);
36 return this->CreateFromTiXmlDocument( doc );
40 MITK_ERROR <<
"Unable to load file at '" << filename <<
"'";
41 return DICOMFileReader::Pointer();
45 mitk::DICOMFileReader::Pointer
50 doc.Parse(xmlContents.c_str(),
nullptr, TIXML_ENCODING_UTF8);
52 return this->CreateFromTiXmlDocument( doc );
55 mitk::DICOMFileReader::Pointer
56 mitk::DICOMReaderConfigurator
57 ::CreateFromTiXmlDocument(TiXmlDocument& doc)
const 59 TiXmlHandle root(doc.RootElement());
61 if (TiXmlElement* rootElement = root.ToElement())
63 if (strcmp(rootElement->Value(),
"DICOMFileReader"))
65 MITK_ERROR <<
"File should contain a <DICOMFileReader> tag at top-level! Found '" 66 << (rootElement->Value() ? std::string(rootElement->Value()) : std::string(
"!nothing!")) <<
"' instead";
70 const char* classnameC = rootElement->Attribute(
"class");
73 MITK_ERROR <<
"File should name a reader class in the class attribute: <DICOMFileReader class=\"...\">. Found nothing instead";
78 if ( rootElement->QueryIntAttribute(
"version", &version) == TIXML_SUCCESS)
82 MITK_WARN <<
"Warning the given configuration is for DICOMFileReaders of version 1. " 83 <<
"This old version may be interpreted differently. Reason: " 84 <<
"The default values for the following xml settings have been changed: " 85 <<
"FixTiltByShearing (false -> true); StrictSorting (true -> false); ExpectDistanceOne (true -> false).";
89 MITK_WARN <<
"This reader is only capable of creating DICOMFileReaders of version 1 and 2. " 90 <<
"Will not continue, because given configuration is meant for version " << version <<
".";
96 MITK_ERROR <<
"File should name the version of the reader class in the version attribute: <DICOMFileReader class=\"" << classnameC <<
"\" version=\"...\">." 97 <<
" Found nothing instead, assuming version 1!";
101 std::string classname(classnameC);
104 bool useDecimalPlacesForOrientation(
false);
105 useDecimalPlacesForOrientation =
106 rootElement->QueryDoubleAttribute(
"decimalPlacesForOrientation", &decimalPlacesForOrientation) == TIXML_SUCCESS;
108 if (classname ==
"ClassicDICOMSeriesReader")
111 this->ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(reader.GetPointer(), rootElement);
112 this->ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(reader.GetPointer(), rootElement);
113 return reader.GetPointer();
115 if (classname ==
"ThreeDnTDICOMSeriesReader")
117 mitk::ThreeDnTDICOMSeriesReader::Pointer reader;
118 if (useDecimalPlacesForOrientation)
123 return ConfigureThreeDnTDICOMSeriesReader(reader, rootElement).GetPointer();
126 if (classname ==
"DICOMITKSeriesGDCMReader")
130 mitk::DICOMITKSeriesGDCMReader::Pointer reader;
131 if (useDecimalPlacesForOrientation)
138 return ConfigureDICOMITKSeriesGDCMReader(reader, rootElement).GetPointer();
142 MITK_ERROR <<
"DICOMFileReader tag names unknown class '" << classname <<
"'";
148 MITK_ERROR <<
"Great confusion: no root element in XML document. Expecting a DICOMFileReader tag at top-level.";
153 #define boolStringTrue(s) \ 154 ( s == "true" || s == "on" || s == "1" \ 155 || s == "TRUE" || s == "ON") 158 mitk::DICOMReaderConfigurator
159 ::QueryBooleanAttribute(
const TiXmlElement* element,
const char* attributeName,
bool defaultValue)
const 161 bool value(defaultValue);
162 const char* valueC = element->Attribute(attributeName);
165 std::string valueS(valueC);
172 mitk::DICOMReaderConfigurator
173 ::ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, TiXmlElement* element)
const 178 reader->SetGroup3DandT( group3DnT );
181 mitk::ThreeDnTDICOMSeriesReader::Pointer
182 mitk::DICOMReaderConfigurator
183 ::ConfigureThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, TiXmlElement* element)
const 188 if (this->ConfigureDICOMITKSeriesGDCMReader( reader.GetPointer(), element ).IsNull())
193 this->ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(reader,element);
198 mitk::DICOMReaderConfigurator
199 ::ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, TiXmlElement* element)
const 203 const char* configLabelC = element->Attribute(
"label");
206 std::string configLabel(configLabelC);
207 reader->SetConfigurationLabel(configLabel);
210 const char* configDescriptionC = element->Attribute(
"description");
211 if (configDescriptionC)
213 reader->SetConfigurationDescription(configDescriptionC);
219 reader->SetFixTiltByShearing( fixTiltByShearing );
222 mitk::DICOMITKSeriesGDCMReader::Pointer
223 mitk::DICOMReaderConfigurator
224 ::ConfigureDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, TiXmlElement* element)
const 228 this->ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(reader, element);
231 bool acceptTwoSlicesGroups = QueryBooleanAttribute(element,
"acceptTwoSlicesGroups",
true);
233 reader->SetAcceptTwoSlicesGroups( acceptTwoSlicesGroups );
236 bool toleratedOriginErrorIsAbsolute = QueryBooleanAttribute(element,
"toleratedOriginErrorIsAbsolute",
false);
238 double toleratedOriginError(0.3);
239 if (element->QueryDoubleAttribute(
"toleratedOriginError", &toleratedOriginError) == TIXML_SUCCESS)
241 if (toleratedOriginErrorIsAbsolute)
243 reader->SetToleratedOriginOffset( toleratedOriginError );
247 reader->SetToleratedOriginOffsetToAdaptive( toleratedOriginError );
253 TiXmlElement* dElement = element->FirstChildElement(
"DICOMDatasetSorter");
256 const char* classnameC = dElement->Attribute(
"class");
259 MITK_ERROR <<
"File should name a DICOMDatasetSorter class in the class attribute of <DICOMDatasetSorter class=\"...\">. Found nothing instead";
263 std::string classname(classnameC);
265 if (classname ==
"DICOMTagBasedSorter")
267 DICOMTagBasedSorter::Pointer tagSorter = CreateDICOMTagBasedSorter(dElement);
268 if (tagSorter.IsNotNull())
270 reader->AddSortingElement( tagSorter );
275 MITK_ERROR <<
"DICOMDatasetSorter tag names unknown class '" << classname <<
"'";
283 mitk::DICOMTagBasedSorter::Pointer
284 mitk::DICOMReaderConfigurator
285 ::CreateDICOMTagBasedSorter(TiXmlElement* element)
const 291 tagSorter->SetStrictSorting(strictSorting);
295 tagSorter->SetExpectDistanceOne(expectDistanceOne);
297 TiXmlElement* dElement = element->FirstChildElement(
"Distinguishing");
300 for ( TiXmlElement* tChild = dElement->FirstChildElement();
302 tChild = tChild->NextSiblingElement() )
308 if (tChild->QueryIntAttribute(
"cutDecimalPlaces", &i) == TIXML_SUCCESS)
314 tagSorter->AddDistinguishingTag( tag );
325 TiXmlElement* sElement = element->FirstChildElement(
"Sorting");
328 DICOMSortCriterion::Pointer previousCriterion;
329 DICOMSortCriterion::Pointer currentCriterion;
331 for ( TiXmlNode* tChildNode = sElement->LastChild();
332 tChildNode !=
nullptr;
333 tChildNode = tChildNode->PreviousSibling() )
335 TiXmlElement* tChild = tChildNode->ToElement();
336 if (!tChild)
continue;
338 if (!strcmp(tChild->Value(),
"Tag"))
342 currentCriterion = this->CreateDICOMSortByTag(tChild, previousCriterion);
346 std::stringstream ss;
347 ss <<
"Could not parse <Tag> element at (input line " << tChild->Row() <<
", col. " << tChild->Column() <<
")!";
353 if (!strcmp(tChild->Value(),
"ImagePositionPatient"))
357 currentCriterion = this->CreateSortByImagePositionPatient(tChild, previousCriterion);
361 std::stringstream ss;
362 ss <<
"Could not parse <ImagePositionPatient> element at (input line " << tChild->Row() <<
", col. " << tChild->Column() <<
")!";
369 MITK_ERROR <<
"File contain unknown tag <" << tChild->Value() <<
"> tag as child to <Sorting>! Cannot interpret...";
372 previousCriterion = currentCriterion;
375 tagSorter->SetSortCriterion( currentCriterion.GetPointer() );
382 mitk::DICOMReaderConfigurator
383 ::requiredStringAttribute(TiXmlElement* xmlElement,
const std::string& key)
const 387 const char* gC = xmlElement->Attribute(key.c_str());
395 std::stringstream ss;
396 ss <<
"Expected an attribute '" << key <<
"' at this position " 397 "(input line " << xmlElement->Row() <<
", col. " << xmlElement->Column() <<
")!";
399 throw std::invalid_argument( ss.str() );
404 mitk::DICOMReaderConfigurator
405 ::hexStringToUInt(
const std::string& s)
const 407 std::stringstream converter(s);
409 converter >> std::hex >> ui;
410 MITK_DEBUG <<
"Converted string '" << s <<
"' to unsigned int " << ui;
415 mitk::DICOMReaderConfigurator
416 ::tagFromXMLElement(TiXmlElement* xmlElement)
const 420 if (strcmp(xmlElement->Value(),
"Tag"))
422 std::stringstream ss;
423 ss <<
"Expected a <Tag group=\"..\" element=\"..\"> tag at this position " 424 "(input line " << xmlElement->Row() <<
", col. " << xmlElement->Column() <<
")!";
426 throw std::invalid_argument( ss.str() );
429 std::string groupS = requiredStringAttribute(xmlElement,
"group");
430 std::string elementS = requiredStringAttribute(xmlElement,
"element");
435 unsigned int group = hexStringToUInt(groupS);
436 unsigned int element = hexStringToUInt(elementS);
437 return DICOMTag(group, element);
441 std::stringstream ss;
442 ss <<
"Expected group and element values in <Tag group=\"..\" element=\"..\"> to be hexadecimal with leading 0x, e.g. '0x0020'" 443 "(input line " << xmlElement->Row() <<
", col. " << xmlElement->Column() <<
")!";
445 throw std::invalid_argument( ss.str() );
449 mitk::DICOMSortCriterion::Pointer
450 mitk::DICOMReaderConfigurator
451 ::CreateDICOMSortByTag(TiXmlElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion)
const 454 return DICOMSortByTag::New(tag, secondaryCriterion).GetPointer();
457 mitk::DICOMSortCriterion::Pointer
458 mitk::DICOMReaderConfigurator
459 ::CreateSortByImagePositionPatient(TiXmlElement*, DICOMSortCriterion::Pointer secondaryCriterion)
const 461 return SortByImagePositionPatient::New(secondaryCriterion).GetPointer();
473 if (
const auto* specificReader = dynamic_cast<const ClassicDICOMSeriesReader*>(cPointer))
478 if (
const auto* specificReader = dynamic_cast<const ThreeDnTDICOMSeriesReader*>(cPointer))
483 if (
const auto* specificReader = dynamic_cast<const DICOMITKSeriesGDCMReader*>(cPointer))
489 MITK_WARN <<
"Unknown reader class passed to DICOMReaderConfigurator::CreateConfigStringFromReader(). Cannot serialize.";
495 TiXmlDocument document;
496 document.LinkEndChild( root );
498 TiXmlPrinter printer;
499 printer.SetIndent(
" " );
501 document.Accept( &printer );
502 std::string xmltext = printer.CStr();
507 MITK_WARN <<
"DICOMReaderConfigurator::CreateConfigStringFromReader() created empty serialization. Problem?";
516 TiXmlElement* root = this->CreateDICOMFileReaderTag(reader);
527 for(
auto sorterIter = sorterList.begin();
528 sorterIter != sorterList.end();
532 if (
const auto* specificSorter = dynamic_cast<const DICOMTagBasedSorter*>(sorter))
534 TiXmlElement* sorterTag = this->CreateConfigStringFromDICOMDatasetSorter(specificSorter);
535 root->LinkEndChild(sorterTag);
539 MITK_WARN <<
"Unknown DICOMDatasetSorter class passed to DICOMReaderConfigurator::CreateConfigStringFromReader(). Cannot serialize.";
548 mitk::DICOMReaderConfigurator
553 auto sorterTag =
new TiXmlElement(
"DICOMDatasetSorter");
554 sorterTag->SetAttribute(
"class", sorter->GetNameOfClass());
555 sorterTag->SetAttribute(
"strictSorting", toString(sorter->
GetStrictSorting()));
558 auto distinguishingTagsElement =
new TiXmlElement(
"Distinguishing");
559 sorterTag->LinkEndChild(distinguishingTagsElement);
561 for (
auto tagIter = distinguishingTags.begin();
562 tagIter != distinguishingTags.end();
565 TiXmlElement* tag = this->CreateConfigStringFromDICOMTag(*tagIter);
566 distinguishingTagsElement->LinkEndChild(tag);
569 if (
const auto* specificProcessor = dynamic_cast<const DICOMTagBasedSorter::CutDecimalPlaces*>(processor))
571 tag->SetDoubleAttribute(
"cutDecimalPlaces", specificProcessor->GetPrecision());
575 auto sortingElement =
new TiXmlElement(
"Sorting");
576 sorterTag->LinkEndChild(sortingElement);
577 mitk::DICOMSortCriterion::ConstPointer sortCriterion = sorter->
GetSortCriterion();
578 while (sortCriterion.IsNotNull())
580 std::string classname = sortCriterion->GetNameOfClass();
581 if (classname ==
"SortByImagePositionPatient")
583 sortingElement->LinkEndChild(
new TiXmlElement(
"ImagePositionPatient") );
586 if (classname ==
"DICOMSortByTag")
588 DICOMTagList pseudoTagList = sortCriterion->GetTagsOfInterest();
589 if (pseudoTagList.size() == 1)
591 DICOMTag firstTag = pseudoTagList.front();
593 TiXmlElement* tagElement = this->CreateConfigStringFromDICOMTag(firstTag);
595 sortingElement->LinkEndChild( tagElement );
599 MITK_ERROR <<
"Encountered SortByTag class with MULTIPLE tag in CreateConfigStringFromDICOMDatasetSorter. Cannot serialize.";
605 MITK_ERROR <<
"Encountered unknown class '" << classname <<
"' in CreateConfigStringFromDICOMDatasetSorter. Cannot serialize.";
609 sortCriterion = sortCriterion->GetSecondaryCriterion();
616 mitk::DICOMReaderConfigurator
617 ::CreateConfigStringFromDICOMTag(
const DICOMTag& tag)
const 619 auto tagElement =
new TiXmlElement(
"Tag");
620 tagElement->SetAttribute(
"name", tag.
GetName().c_str());
621 tagElement->SetAttribute(
"group", toHexString(tag.
GetGroup()));
622 tagElement->SetAttribute(
"element", toHexString(tag.
GetElement()));
627 mitk::DICOMReaderConfigurator
628 ::toHexString(
unsigned int i)
const 630 std::stringstream ss;
631 ss <<
"0x" << std::setfill (
'0') << std::setw(4) << std::hex << i;
643 root->SetAttribute(
"group3DnT", toString(reader->
GetGroup3DandT()));
649 mitk::DICOMReaderConfigurator
650 ::toString(
bool b)
const 652 return b ?
"true" :
"false";
659 return this->CreateDICOMFileReaderTag(reader);
663 mitk::DICOMReaderConfigurator
666 auto readerTag =
new TiXmlElement(
"DICOMFileReader");
667 readerTag->SetAttribute(
"class", reader->GetNameOfClass());
670 readerTag->SetAttribute(
"version",
"1");
static bool GetDefaultExpectDistanceOne()
Sorting and grouping like mitk::DicomSeriesReader until 2013.
unsigned int GetElement() const
double GetToleratedOriginError() const
#define boolStringTrue(s)
The sorting/splitting building-block of DICOMITKSeriesGDCMReader.
const TagValueProcessor * GetTagValueProcessorForDistinguishingTag(const DICOMTag &) const
Flexible reader based on itk::ImageSeriesReader and GDCM, for single-slice modalities like CT...
static bool GetDefaultFixTiltByShearing()
std::vector< DICOMTag > DICOMTagList
ConstSorterList GetFreelyConfiguredSortingElements() const
Representation of a DICOM tag.
double GetDecimalPlacesForOrientation() const
DICOMFileReader::Pointer CreateFromConfigFile(const std::string &filename) const
~DICOMReaderConfigurator() override
bool GetAcceptTwoSlicesGroups() const
bool GetExpectDistanceOne() const
std::string CreateConfigStringFromReader(DICOMFileReader::ConstPointer reader) const
static int GetDefaultDecimalPlacesForOrientation()
const std::list< DICOMDatasetSorter::ConstPointer > ConstSorterList
std::string GetConfigurationDescription() const
One-sentence description of the reader's loading "strategy".
DICOMReaderConfigurator()
bool IsToleratedOriginOffsetAbsolute() const
static bool GetDefaultGroup3DandT()
DICOMTagList GetDistinguishingTags() const
DICOMSortCriterion::ConstPointer GetSortCriterion() const
Extends DICOMITKSeriesGDCMReader by sorting/grouping into 3D+t image blocks.
std::string GetConfigurationLabel() const
Short label/name to describe this reader.
static bool GetDefaultSimpleVolumeImport()
bool GetStrictSorting() const
bool GetGroup3DandT() const
Cuts a number after configured number of decimal places. An instance of this class can be used to avo...
std::string GetName() const
Return the name of this tag (e.g. "SeriesDescription" instead of "(0008,103e)")
Sort DICOM datasets based on configurable tags.
Processes tag values before they are compared. These classes could do some kind of normalization such...
Interface for DICOM readers that produce mitk::Images.
unsigned int GetGroup() const
static bool GetDefaultStrictSorting()
bool GetFixTiltByShearing() const
DICOMFileReader::Pointer CreateFromUTF8ConfigString(const std::string &xmlContents) const