DCMTK库说,当dcmump显示标签时,没有找到它



对于使用DCMTK 3.6.4-2的Ubuntu 20系统,我的程序读取dicom文件(系列)并从相应的标签中获取刻度斜率,首先测试它们是否存在:

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() ) ) );
}

在我使用的文件中,dcmump不返回DCM_RescaleSlope标记的任何内容,但返回DCM_RealWorldValueSlope标记的任何内容:

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

当我使用

std::cout << getItemString ( tmpdata, DCM_RescaleSlope )        << std::endl; 
std::cout << getItemString ( tmpdata, DCM_RealWorldValueSlope ) << std::endl;
std::cout << getItemString ( tmpdata, DCM_Modality )            << std::endl;

(其中getItemString是方便的函数)并使用调试器查看第二行中发生的事情,然后:

  1. 标签转换为g = 64,e = 37413
  2. OFStatus s = theCondition.theStatus;设置为false(这就是所有的,除了theText = "Tag not found")

我不明白,因为(I)标签的值是由程序知道的-否则它不会编译,(ii)标签在图像中显示为dcmdump和(iii)其他标签处理OK:DCM_Modality打印为MR

是我做错了什么,还是这些特殊标签需要特殊处理?

编辑我尝试了评论中的一个建议:在测试中使用findAndGetFloat64而不是findAndGetOFString

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;

导致

A0
B0
C297.6

theStatus中读取B行的错误仍然相同:theText = "Tag not found"

(我一直在使用字符串,因为到目前为止大多数双值标签都是DS,感谢您让我意识到差异!)

您正在寻找的标记是在序列(RealWorldValueMappingSequence)内。要获取标签,首先必须获取序列,如以下所示:

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);
...
}

请注意,这是我的想法,所以它可能不准确,但这基本上是您需要做的,以获得序列项内部的标记。默认情况下,所有findAndGet...方法都只适用于当前项,它可能是根数据集,但也可能是序列项-您必须在DICOM标准中检查实际查找标记的位置。

UPDATE:
写完这些,我才意识到我忘记了searchIntoSub参数,所以可能这样做就足够了:

result = tmpData->findAndGetFloat64(DCM_RealWorldValueSlope, value, 0, OFTrue);

其中searchIntoSub=OfTrue表示,包含的序列也被搜索。无论如何,我保留了上面的内容,因为如果在特定序列中搜索标签,其他人也可能需要它。

旁注:
如果使用此参数,您使用findAndGetOFString的第一种方法也应该有效。它在您的情况下没有意义,因为您需要实际的双精度值,但是如果您只需要标记值的字符串表示,则可以使用它。findAndGetOFString的文档:

适用于以下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

最新更新