引起的错误
在linux含有DCMTK的程序发布后,发现读出的tag信息有错误,主要为:
- findAndGetString、findAndGetStringArray等拿到的字符串在tag为非字符串时错误,打印出来之后发现OFString存的是对应的16进制,而非正常的类似atoi函数一样的,自动转换为对应的值。例如:
TAG:DCM_PixelSpacing 值为:0.647135,0.647135
findAndGetOFStringArray(DCM_PixelSpacing, imageSpacingString)
读出应该是: “.6471354.6471354”
而读取dicom.dic错误的情况下是:“2e\36\34\37\31\33\35\34\5c\2e\36\34\37\31\33\35\34\20”
- 读取 seriesUID错误
dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesIDString)
seriesUIDString返回的值是studyUID
问题根源
问题根源是dicom.dic没有正确被读取导致,跟踪dcmtk的代码,发现这个文件可以在CMake编译时,DCMTK_DEFAULT_DICT ,选择Builtin(Unix类默认)或者External(windows下默认)。
但是根据实际测试(3.6.7发布版本),即使在linux下选择了 Builtin ,似乎也没有把dic文件内置。
最后定位到源码 dcdict.cc 的代码如下:
#define DCM_DICT_ENVIRONMENT_VARIABLE "DCMDICTPATH"
OFBool
DcmDataDictionary::loadExternalDictionaries()
{
const char* env = NULL;
size_t len;
int sepCnt = 0;
OFBool loadFailed = OFFalse;
/* if DCMDICTPATH environment variable should be considered, read it */
#ifdef DCM_DICT_USE_DCMDICTPATH
env = getenv(DCM_DICT_ENVIRONMENT_VARIABLE);
#endif
/* if DCMDICTPATH environment variable is not set or empty,
* and reading of external dictionary is generally permitted,
* try to read dictionary from default path
*/
if ((env == NULL) || (strlen(env) == 0)) {
#if DCM_DICT_DEFAULT == DCM_DICT_DEFAULT_USE_EXTERNAL
env = DCM_DICT_DEFAULT_PATH;
#endif
}
/* if any mechanism for external dictionary (environment or default external)
* is actually provided it, parse env and load all dictionaries specified therein.
*/
if ((env != NULL) && (strlen(env) != 0)) {
len = strlen(env);
for (size_t i = 0; i < len; ++i) {
if (env[i] == ENVIRONMENT_PATH_SEPARATOR) {
sepCnt++;
}
}
if (sepCnt == 0) {
if (!loadDictionary(env, OFTrue)) {
return OFFalse;
}
} else {
char** dictArray;
dictArray = OFstatic_cast(char **, malloc((sepCnt + 1) * sizeof(char*)));
int ndicts = splitFields(env, dictArray, sepCnt + 1,
ENVIRONMENT_PATH_SEPARATOR);
for (int ii = 0; ii < ndicts; ii++) {
if ((dictArray[ii] != NULL) && (strlen(dictArray[ii]) > 0)) {
if (!loadDictionary(dictArray[ii], OFTrue)) {
loadFailed = OFTrue;
}
}
free(dictArray[ii]);
}
free(dictArray);
}
}
return (loadFailed) ? (OFFalse) : (OFTrue);
}
可以看到dcmtk尝试加载环境变量DCMDICTPATH指向的路径下的dic文件,如果没有则去< datadir >/dicom.dic 去找,如果还没有则使用默认(问题出现在默认上)。
解决思路
比较推荐的是dcdict.h 使用了全局单例,可以直接访问GlobalDcmDataDictionary的单例dcmDataDict,手动调用
const DcmDataDictionary &globalDataDict = dcmDataDict.rdlock();
globalDataDict .loadExternalDictionaries()
……
dcmDataDict.rdunlock();
或者:
配置环境变量 DCMDICTPATH ,或者将dic文件拷贝到目标机器和本地同样的 < datadir >/dicom.dic 位置(不推荐,会污染目标机环境)。