36 TiXmlDocument doc (filename);
39 return this->CreateFromTiXmlDocument( doc );
43 MITK_ERROR <<
"Unable to load file at '" << filename <<
"'";
53 doc.Parse(xmlContents.c_str(),
nullptr, TIXML_ENCODING_UTF8);
55 return this->CreateFromTiXmlDocument( doc );
59 mitk::DICOMReaderConfigurator
60 ::CreateFromTiXmlDocument(TiXmlDocument& doc)
const
62 TiXmlHandle root(doc.RootElement());
64 if (TiXmlElement* rootElement = root.ToElement())
66 if (strcmp(rootElement->Value(),
"DICOMFileReader"))
68 MITK_ERROR <<
"File should contain a <DICOMFileReader> tag at top-level! Found '"
69 << (rootElement->Value() ? std::string(rootElement->Value()) : std::string(
"!nothing!")) <<
"' instead";
73 const char* classnameC = rootElement->Attribute(
"class");
76 MITK_ERROR <<
"File should name a reader class in the class attribute: <DICOMFileReader class=\"...\">. Found nothing instead";
81 if ( rootElement->QueryIntAttribute(
"version", &version) == TIXML_SUCCESS)
85 MITK_WARN <<
"This reader is only capable of creating DICOMFileReaders of version 1. "
86 <<
"Will not continue, because given configuration is meant for version " << version <<
".";
92 MITK_ERROR <<
"File should name the version of the reader class in the version attribute: <DICOMFileReader class=\"" << classnameC <<
"\" version=\"...\">."
93 <<
" Found nothing instead, assuming version 1!";
97 std::string classname(classnameC);
99 double decimalPlacesForOrientation(5);
100 bool useDecimalPlacesForOrientation(
false);
101 useDecimalPlacesForOrientation =
102 rootElement->QueryDoubleAttribute(
"decimalPlacesForOrientation", &decimalPlacesForOrientation) == TIXML_SUCCESS;
104 if (classname ==
"ClassicDICOMSeriesReader")
107 this->ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(reader.GetPointer(), rootElement);
108 this->ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(reader.GetPointer(), rootElement);
109 return reader.GetPointer();
111 if (classname ==
"ThreeDnTDICOMSeriesReader")
114 if (useDecimalPlacesForOrientation)
119 return ConfigureThreeDnTDICOMSeriesReader(reader, rootElement).GetPointer();
122 if (classname ==
"DICOMITKSeriesGDCMReader")
125 if (useDecimalPlacesForOrientation)
130 return ConfigureDICOMITKSeriesGDCMReader(reader, rootElement).GetPointer();
134 MITK_ERROR <<
"DICOMFileReader tag names unknown class '" << classname <<
"'";
140 MITK_ERROR <<
"Great confusion: no root element in XML document. Expecting a DICOMFileReader tag at top-level.";
145 #define boolStringTrue(s) \
146 ( s == "true" || s == "on" || s == "1" \
147 || s == "TRUE" || s == "ON")
150 mitk::DICOMReaderConfigurator
154 bool group3DnT(
true);
155 const char* group3DnTC = element->Attribute(
"group3DnT");
158 std::string group3DnTS(group3DnTC);
162 reader->SetGroup3DandT( group3DnT );
166 mitk::DICOMReaderConfigurator
172 if (this->ConfigureDICOMITKSeriesGDCMReader( reader.GetPointer(), element ).IsNull())
177 this->ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(reader,element);
182 mitk::DICOMReaderConfigurator
187 const char* configLabelC = element->Attribute(
"label");
190 std::string configLabel(configLabelC);
191 reader->SetConfigurationLabel(configLabel);
194 const char* configDescriptionC = element->Attribute(
"description");
195 if (configDescriptionC)
197 std::string configDescription(configDescriptionC);
198 reader->SetConfigurationDescription(configDescriptionC);
202 bool fixTiltByShearing(
false);
203 const char* fixTiltByShearingC = element->Attribute(
"fixTiltByShearing");
204 if (fixTiltByShearingC)
206 std::string fixTiltByShearingS(fixTiltByShearingC);
210 reader->SetFixTiltByShearing( fixTiltByShearing );
215 mitk::DICOMReaderConfigurator
220 this->ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(reader, element);
223 bool acceptTwoSlicesGroups(
true);
224 const char* acceptTwoSlicesGroupsC = element->Attribute(
"acceptTwoSlicesGroups");
225 if (acceptTwoSlicesGroupsC)
227 std::string acceptTwoSlicesGroupsS(acceptTwoSlicesGroupsC);
231 reader->SetAcceptTwoSlicesGroups( acceptTwoSlicesGroups );
234 bool toleratedOriginErrorIsAbsolute(
false);
235 const char* toleratedOriginErrorIsAbsoluteC = element->Attribute(
"toleratedOriginErrorIsAbsolute");
236 if (toleratedOriginErrorIsAbsoluteC)
238 std::string toleratedOriginErrorIsAbsoluteS(toleratedOriginErrorIsAbsoluteC);
239 toleratedOriginErrorIsAbsolute =
boolStringTrue(toleratedOriginErrorIsAbsoluteS);
242 double toleratedOriginError(0.3);
243 if (element->QueryDoubleAttribute(
"toleratedOriginError", &toleratedOriginError) == TIXML_SUCCESS)
245 if (toleratedOriginErrorIsAbsolute)
247 reader->SetToleratedOriginOffset( toleratedOriginError );
251 reader->SetToleratedOriginOffsetToAdaptive( toleratedOriginError );
257 TiXmlElement* dElement = element->FirstChildElement(
"DICOMDatasetSorter");
260 const char* classnameC = dElement->Attribute(
"class");
263 MITK_ERROR <<
"File should name a DICOMDatasetSorter class in the class attribute of <DICOMDatasetSorter class=\"...\">. Found nothing instead";
267 std::string classname(classnameC);
269 if (classname ==
"DICOMTagBasedSorter")
272 if (tagSorter.IsNotNull())
274 reader->AddSortingElement( tagSorter );
279 MITK_ERROR <<
"DICOMDatasetSorter tag names unknown class '" << classname <<
"'";
288 mitk::DICOMReaderConfigurator
289 ::CreateDICOMTagBasedSorter(TiXmlElement* element)
const
294 bool strictSorting(
true);
295 const char* strictSortingC = element->Attribute(
"strictSorting");
298 std::string strictSortingS(strictSortingC);
301 tagSorter->SetStrictSorting(strictSorting);
304 bool expectDistanceOne(
true);
305 const char* expectDistanceOneC = element->Attribute(
"expectDistanceOne");
306 if (expectDistanceOneC)
308 std::string expectDistanceOneS(expectDistanceOneC);
311 tagSorter->SetExpectDistanceOne(expectDistanceOne);
313 TiXmlElement* dElement = element->FirstChildElement(
"Distinguishing");
316 for ( TiXmlElement* tChild = dElement->FirstChildElement();
318 tChild = tChild->NextSiblingElement() )
324 if (tChild->QueryIntAttribute(
"cutDecimalPlaces", &i) == TIXML_SUCCESS)
330 tagSorter->AddDistinguishingTag( tag );
341 TiXmlElement* sElement = element->FirstChildElement(
"Sorting");
347 for ( TiXmlNode* tChildNode = sElement->LastChild();
348 tChildNode !=
nullptr;
349 tChildNode = tChildNode->PreviousSibling() )
351 TiXmlElement* tChild = tChildNode->ToElement();
352 if (!tChild)
continue;
354 if (!strcmp(tChild->Value(),
"Tag"))
358 currentCriterion = this->CreateDICOMSortByTag(tChild, previousCriterion);
362 std::stringstream ss;
363 ss <<
"Could not parse <Tag> element at (input line " << tChild->Row() <<
", col. " << tChild->Column() <<
")!";
369 if (!strcmp(tChild->Value(),
"ImagePositionPatient"))
373 currentCriterion = this->CreateSortByImagePositionPatient(tChild, previousCriterion);
377 std::stringstream ss;
378 ss <<
"Could not parse <ImagePositionPatient> element at (input line " << tChild->Row() <<
", col. " << tChild->Column() <<
")!";
385 MITK_ERROR <<
"File contain unknown tag <" << tChild->Value() <<
"> tag as child to <Sorting>! Cannot interpret...";
388 previousCriterion = currentCriterion;
391 tagSorter->SetSortCriterion( currentCriterion.GetPointer() );
398 mitk::DICOMReaderConfigurator
399 ::requiredStringAttribute(TiXmlElement* xmlElement,
const std::string& key)
const
403 const char* gC = xmlElement->Attribute(key.c_str());
411 std::stringstream ss;
412 ss <<
"Expected an attribute '" << key <<
"' at this position "
413 "(input line " << xmlElement->Row() <<
", col. " << xmlElement->Column() <<
")!";
415 throw std::invalid_argument( ss.str() );
420 mitk::DICOMReaderConfigurator
421 ::hexStringToUInt(
const std::string& s)
const
423 std::stringstream converter(s);
425 converter >> std::hex >> ui;
426 MITK_DEBUG <<
"Converted string '" << s <<
"' to unsigned int " << ui;
431 mitk::DICOMReaderConfigurator
432 ::tagFromXMLElement(TiXmlElement* xmlElement)
const
436 if (strcmp(xmlElement->Value(),
"Tag"))
438 std::stringstream ss;
439 ss <<
"Expected a <Tag group=\"..\" element=\"..\"> tag at this position "
440 "(input line " << xmlElement->Row() <<
", col. " << xmlElement->Column() <<
")!";
442 throw std::invalid_argument( ss.str() );
445 std::string name = requiredStringAttribute(xmlElement,
"name");
446 std::string groupS = requiredStringAttribute(xmlElement,
"group");
447 std::string elementS = requiredStringAttribute(xmlElement,
"element");
452 unsigned int group = hexStringToUInt(groupS);
453 unsigned int element = hexStringToUInt(elementS);
454 return DICOMTag(group, element);
458 std::stringstream ss;
459 ss <<
"Expected group and element values in <Tag group=\"..\" element=\"..\"> to be hexadecimal with leading 0x, e.g. '0x0020'"
460 "(input line " << xmlElement->Row() <<
", col. " << xmlElement->Column() <<
")!";
462 throw std::invalid_argument( ss.str() );
467 mitk::DICOMReaderConfigurator
475 mitk::DICOMReaderConfigurator
492 root = this->CreateConfigStringFromReader(specificReader);
497 root = this->CreateConfigStringFromReader(specificReader);
502 root = this->CreateConfigStringFromReader(specificReader);
506 MITK_WARN <<
"Unknown reader class passed to DICOMReaderConfigurator::CreateConfigStringFromReader(). Cannot serialize.";
512 TiXmlDocument document;
513 document.LinkEndChild( root );
515 TiXmlPrinter printer;
516 printer.SetIndent(
" " );
518 document.Accept( &printer );
519 std::string xmltext = printer.CStr();
524 MITK_WARN <<
"DICOMReaderConfigurator::CreateConfigStringFromReader() created empty serialization. Problem?";
533 TiXmlElement* root = this->CreateDICOMFileReaderTag(reader);
544 for(
auto sorterIter = sorterList.begin();
545 sorterIter != sorterList.end();
549 if (
const DICOMTagBasedSorter* specificSorter = dynamic_cast<const DICOMTagBasedSorter*>(sorter))
551 TiXmlElement* sorterTag = this->CreateConfigStringFromDICOMDatasetSorter(specificSorter);
552 root->LinkEndChild(sorterTag);
556 MITK_WARN <<
"Unknown DICOMDatasetSorter class passed to DICOMReaderConfigurator::CreateConfigStringFromReader(). Cannot serialize.";
565 mitk::DICOMReaderConfigurator
566 ::CreateConfigStringFromDICOMDatasetSorter(
const DICOMTagBasedSorter* sorter)
const
570 auto sorterTag =
new TiXmlElement(
"DICOMDatasetSorter");
571 sorterTag->SetAttribute(
"class", sorter->GetNameOfClass());
572 sorterTag->SetAttribute(
"strictSorting", toString(sorter->GetStrictSorting()));
573 sorterTag->SetAttribute(
"expectDistanceOne", toString(sorter->GetExpectDistanceOne()));
575 auto distinguishingTagsElement =
new TiXmlElement(
"Distinguishing");
576 sorterTag->LinkEndChild(distinguishingTagsElement);
578 for (
auto tagIter = distinguishingTags.begin();
579 tagIter != distinguishingTags.end();
582 TiXmlElement* tag = this->CreateConfigStringFromDICOMTag(*tagIter);
583 distinguishingTagsElement->LinkEndChild(tag);
585 const DICOMTagBasedSorter::TagValueProcessor* processor = sorter->GetTagValueProcessorForDistinguishingTag(*tagIter);
586 if (
const DICOMTagBasedSorter::CutDecimalPlaces* specificProcessor = dynamic_cast<const DICOMTagBasedSorter::CutDecimalPlaces*>(processor))
588 tag->SetDoubleAttribute(
"cutDecimalPlaces", specificProcessor->GetPrecision());
592 auto sortingElement =
new TiXmlElement(
"Sorting");
593 sorterTag->LinkEndChild(sortingElement);
595 while (sortCriterion.IsNotNull())
597 std::string classname = sortCriterion->GetNameOfClass();
598 if (classname ==
"SortByImagePositionPatient")
600 sortingElement->LinkEndChild(
new TiXmlElement(
"ImagePositionPatient") );
603 if (classname ==
"DICOMSortByTag")
605 DICOMTagList pseudoTagList = sortCriterion->GetTagsOfInterest();
606 if (pseudoTagList.size() == 1)
608 DICOMTag firstTag = pseudoTagList.front();
610 TiXmlElement* tagElement = this->CreateConfigStringFromDICOMTag(firstTag);
612 sortingElement->LinkEndChild( tagElement );
616 MITK_ERROR <<
"Encountered SortByTag class with MULTIPLE tag in CreateConfigStringFromDICOMDatasetSorter. Cannot serialize.";
622 MITK_ERROR <<
"Encountered unknown class '" << classname <<
"' in CreateConfigStringFromDICOMDatasetSorter. Cannot serialize.";
626 sortCriterion = sortCriterion->GetSecondaryCriterion();
633 mitk::DICOMReaderConfigurator
634 ::CreateConfigStringFromDICOMTag(
const DICOMTag& tag)
const
636 auto tagElement =
new TiXmlElement(
"Tag");
637 tagElement->SetAttribute(
"name", tag.GetName().c_str());
638 tagElement->SetAttribute(
"group", toHexString(tag.GetGroup()));
639 tagElement->SetAttribute(
"element", toHexString(tag.GetElement()));
644 mitk::DICOMReaderConfigurator
645 ::toHexString(
unsigned int i)
const
647 std::stringstream ss;
648 ss <<
"0x" << std::setfill (
'0') << std::setw(4) << std::hex << i;
657 TiXmlElement* root = this->CreateConfigStringFromReader(static_cast<const DICOMITKSeriesGDCMReader*>(reader));
660 root->SetAttribute(
"group3DnT", toString(reader->GetGroup3DandT()));
666 mitk::DICOMReaderConfigurator
667 ::toString(
bool b)
const
669 return b ?
"true" :
"false";
676 return this->CreateDICOMFileReaderTag(reader);
680 mitk::DICOMReaderConfigurator
681 ::CreateDICOMFileReaderTag(
const DICOMFileReader* reader)
const
683 auto readerTag =
new TiXmlElement(
"DICOMFileReader");
684 readerTag->SetAttribute(
"class", reader->GetNameOfClass());
685 readerTag->SetAttribute(
"label", reader->GetConfigurationLabel().c_str());
686 readerTag->SetAttribute(
"description", reader->GetConfigurationDescription().c_str());
687 readerTag->SetAttribute(
"version",
"1");
Sorting and grouping like mitk::DicomSeriesReader until 2013.
itk::SmartPointer< Self > Pointer
#define boolStringTrue(s)
The sorting/splitting building-block of DICOMITKSeriesGDCMReader.
Flexible reader based on itk::ImageSeriesReader and GDCM, for single-slice modalities like CT...
std::vector< DICOMTag > DICOMTagList
virtual ~DICOMReaderConfigurator()
Representation of a DICOM tag.
ConstSorterList GetFreelyConfiguredSortingElements() const
std::string CreateConfigStringFromReader(DICOMFileReader::ConstPointer reader) const
itk::SmartPointer< const Self > ConstPointer
bool IsToleratedOriginOffsetAbsolute() const
const std::list< DICOMDatasetSorter::ConstPointer > ConstSorterList
DICOMReaderConfigurator()
static const std::string filename
DICOMFileReader::Pointer CreateFromUTF8ConfigString(const std::string &xmlContents) const
DICOMFileReader::Pointer CreateFromConfigFile(const std::string &filename) const
Extends DICOMITKSeriesGDCMReader by sorting/grouping into 3D+t image blocks.
Cuts a number after configured number of decimal places. An instance of this class can be used to avo...
double GetToleratedOriginError() const
Sort DICOM datasets based on configurable tags.
bool GetAcceptTwoSlicesGroups() const
Interface for DICOM readers that produce mitk::Images.
bool GetFixTiltByShearing() const
double GetDecimalPlacesForOrientation() const
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.