My program, for a Ubuntu 20 system using DCMTK 3.6.4-2, reads a dicom file (series) and gets the scale slopes from the corresponding tags, testing first whether they exist:
tmpfile.loadFile ( filename );
tmpdata = tmpfile.getDataset();
tmpdata -> findAndGetOFString ( DCM_RescaleSlope, tmpstring );
if ( !tmpstring.empty() ) {
mydcm.scl_slope = static_cast <float> ( stof ( std::string ( tmpstring.c_str() ) ) );
tmpdata -> findAndGetOFString ( DCM_RescaleIntercept, tmpstring );
mydcm.scl_inter = static_cast <float> ( stof ( std::string ( tmpstring.c_str() ) ) );
} else {
tmpdata -> findAndGetOFString ( DCM_RealWorldValueSlope, tmpstring );
mydcm.scl_slope = static_cast <float> ( stof ( std::string ( tmpstring.c_str() ) ) );
tmpdata -> findAndGetOFString ( DCM_RealWorldValueIntercept, tmpstring );
mydcm.scl_inter = static_cast <float> ( stof ( std::string ( tmpstring.c_str() ) ) );
}
In the file I use, dcmdump does not return anything for the DCM_RescaleSlope
tag, but it does for the DCM_RealWorldValueSlope
tag:
dcmdump filename | grep RealWorld
(0040,9096) SQ (Sequence with undefined length #=1) # u/l, 1 RealWorldValueMappingSequence
(0040,9224) FD 0 # 8, 1 RealWorldValueIntercept
(0040,9225) FD 4.1318681318681323 # 8, 1 RealWorldValueSlope
When I use
std::cout << getItemString ( tmpdata, DCM_RescaleSlope ) << std::endl;
std::cout << getItemString ( tmpdata, DCM_RealWorldValueSlope ) << std::endl;
std::cout << getItemString ( tmpdata, DCM_Modality ) << std::endl;
(where getItemString
is a function for convenience) and use the debugger to look what happens in the second line, then:
g = 64
, e = 37413
OFStatus s = theCondition.theStatus;
is set to false
(that's all there is, apart from theText = "Tag not found"
)which I don't understand because (i) the value of the tag is known by the program -- otherwise it wouldn't compile, (ii) the tag is in the image as shown by dcmdump
and (iii) other tags are processed OK: DCM_Modality
is printed as MR
.
Am I doing something wrong, or do these special tags need special treatment?
EDIT
I tried one suggestion from the comments: using findAndGetFloat64
instead of findAndGetOFString
, in a test
double tmpdbl;
tmpdata -> findAndGetFloat64 ( DCM_RescaleSlope, tmpdbl );
std::cout << "A" << tmpdbl << std::endl;
tmpdata -> findAndGetFloat64 ( DCM_RealWorldValueSlope, tmpdbl );
std::cout << "B" << tmpdbl << std::endl;
tmpdata -> findAndGetFloat64 ( DCM_AcquisitionDuration, tmpdbl );
std::cout << "C" << tmpdbl << std::endl;
which resulted in
A0
B0
C297.6
and the error in theStatus
during the line for reading B
is still the same: theText = "Tag not found"
(I had been using strings because most of the double-valued tags so far had been DS
, thanks for making me aware of the difference!)
The tag you are looking for is inside a sequence (RealWorldValueMappingSequence
). To get to the tag, you first have to get the sequence, something like this:
DcmSequenceOfItems* sequence;
OFResult result = tmpData->findAndGetSequence(DCM_RealWorldValueMappingSequence, sequence);
if (result.good() && sequence && !sequence->isEmpty())
{
DcmItem* item = sequence->getItem(0); // you may have to iterate over the items instead
double value;
result = item->findAndGetFloat64(DCM_RealWorldValueSlope, value);
...
}
Note that this is out of my head, so it may not be accurate, but this is basically what you need to do to get the tags inside of sequence items. All findAndGet...
methods by default only work on the current item, which may be the root dataset, but may also be a sequence item - you have to check in the DICOM standard where actually to find the tags.
UPDATE:
Having written that, I just realized that I forgot about the searchIntoSub
parameter, so probably it would be sufficient to do:
result = tmpData->findAndGetFloat64(DCM_RealWorldValueSlope, value, 0, OFTrue);
where searchIntoSub=OfTrue
means, that contained sequences are also searched.
I leave the above anyway, as it may also be needed by someone else if searching for tags in specific sequences.
Side note:
Your first approach to use findAndGetOFString
should also work, if you use this parameter. It does not make sense in your case, as you need the actual double value, but it can be used if you need only the string representation of the tag values. From the documentation for findAndGetOFString
:
Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF, OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV