DCMTK 库表示未找到标记,而 dcmdump 显示它

问题描述

我的程序,对于使用 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() ) ) );
}

在我使用的文件中,dcmdump 不会为 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) 其他标签处理正常: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 标准中检查实际在哪里找到标签。

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

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

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

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...