1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
/*=========================================================================
Program: GDCM (Grassroots DICOM). A DICOM library
Copyright (c) 2006-2011 Mathieu Malaterre
All rights reserved.
See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "gdcmEquipmentManufacturer.h"
#include "gdcmAttribute.h"
#include "gdcmSystem.h"
namespace gdcm {
// FIXME: fuji and hitachi are the same now
static const char* TypeStrings[] = {"UNKNOWN", "FUJI", "GEMS", "HITACHI",
"KODAK", "MARCONI", "PMS", "SIEMENS",
"TOSHIBA", "AGFA", "SAMSUNG", "UIH"};
const char* EquipmentManufacturer::TypeToString(Type type) {
return TypeStrings[type];
}
struct Mapping {
EquipmentManufacturer::Type type;
size_t nstrings;
const char* const* strings;
};
static const char* const agfa[] = {"Agfa"};
static const char* const fuji[] = {"FUJI",
"FUJI PHOTO FILM Co., ltd.",
"FUJIFILM Healthcare Corporation",
"FUJIFILM SonoSite",
"FUJIFILM Corporation",
"FUJI PHOTO FILM CO. LTD."};
static const char* const gems[] = {"GE MEDICAL SYSTEMS",
"GE_MEDICAL_SYSTEMS",
"GE Healthcare",
"G.E. Medical Systems",
"GE Healthcare IT Cardiology",
"GE Healthcare Austria GmbH & Co OG",
"GE Healthcare Ultrasound",
"GE MEDICAL SYSTEMS, NUCLEAR",
"GEMS Ultrasound",
"GE OEC Medical Systems GmbH",
"GE Vingmed Ultrasound",
"\"GE Healthcare\"" /*sigh*/};
static const char* const hitachi[] = {"Hitachi Medical Corporation",
"Hitachi, Ltd.", "ALOKA CO., LTD."};
static const char* const kodak[] = {"Kodak"};
static const char* const pms[] = {
"Philips Medical Systems", "Philips Healthcare",
"Philips Medical Systems, Inc.", "Philips", "Picker International, Inc."};
static const char* const siemens[] = {"Siemens Healthineers",
"SIEMENS",
"SIEMENS NM",
"Siemens HealthCare GmbH",
"Siemens Health Services",
"Acuson"};
static const char* const marconi[] = {"Marconi Medical Systems, Inc."};
static const char* const samsung[] = {"SAMSUNG MEDISON CO., LTD.",
"SAMSUNG MEDISON CO.,LTD." /*sigh*/};
static const char* const toshiba[] = {"TOSHIBA_MEC", "CANON_MEC",
"TOSHIBA_MEC_US",
"Toshiba"}; // must include canon
static const char* const uih[] = {"UIH"}; // United Imaging Healthcare
#define ARRAY_SIZE(X) sizeof(X) / sizeof(*X)
#define MAPPING(X, Y) \
{ X, ARRAY_SIZE(Y), Y }
static const Mapping mappings[] = {
MAPPING(EquipmentManufacturer::AGFA, agfa),
MAPPING(EquipmentManufacturer::FUJI, fuji),
MAPPING(EquipmentManufacturer::GEMS, gems),
MAPPING(EquipmentManufacturer::HITACHI, hitachi),
MAPPING(EquipmentManufacturer::KODAK, kodak),
MAPPING(EquipmentManufacturer::PMS, pms),
MAPPING(EquipmentManufacturer::SIEMENS, siemens),
MAPPING(EquipmentManufacturer::MARCONI, marconi),
MAPPING(EquipmentManufacturer::SAMSUNG, samsung),
MAPPING(EquipmentManufacturer::TOSHIBA, toshiba),
MAPPING(EquipmentManufacturer::UIH, uih)};
// long story short, private creator could be moved around, what we are trying
// to achieve here is true modality check, so generally they should not have
// been moved in the process.
static bool IsPrivateCreatorFound(DataSet const& ds, Tag const& private_tag,
std::string const& creator_value) {
if (ds.FindDataElement(private_tag)) {
const DataElement& de = ds.GetDataElement(private_tag);
Element<VR::LO, VM::VM1> priv_creator;
priv_creator.SetFromDataElement(de);
if (priv_creator.GetValue().Trim() == creator_value) return true;
}
return false;
}
template <long long TVR, int TVM>
static std::string GetPrivateTagValueOrEmpty(DataSet const& ds,
PrivateTag const& pt) {
if (ds.FindDataElement(pt)) {
const DataElement& de = ds.GetDataElement(pt);
Element<TVR, TVM> value = {""};
value.SetFromDataElement(de);
return value.GetValue().Trim();
}
return "";
}
EquipmentManufacturer::Type EquipmentManufacturer::GuessFromPrivateAttributes(
DataSet const& ds) {
// try against with well known private tag:
// watch out for private creator such as ELSCINT1 which can be found in
// GEMS/PEMS and maybe even SIEMENS !
// Try to prefer those listed at:
// https://dicom.nema.org/medical/dicom/current/output/chtml/part15/sect_E.3.10.html#table_E.3.10-1
if (ds.FindDataElement(PrivateTag(0x0019, 0x0023, "GEMS_ACQU_01")) ||
ds.FindDataElement(PrivateTag(0x0043, 0x0039, "GEMS_PARM_01")) ||
ds.FindDataElement(PrivateTag(0x0045, 0x0001, "GEMS_HELIOS_01")) ||
ds.FindDataElement(PrivateTag(0x0025, 0x001b, "GEMS_SERS_01"))
/* extra */
|| ds.FindDataElement(
PrivateTag(0x6003, 0x0010, "GEMS_Ultrasound_ImageGroup_001")) ||
ds.FindDataElement(PrivateTag(0x0019, 0x0007, "DLX_SERIE_01")) ||
ds.FindDataElement(PrivateTag(0x0009, 0x0001, "GEMS_GENIE_1")) ||
ds.FindDataElement(PrivateTag(0x0011, 0x0003, "GEMS_GDXE_FALCON_04")))
return GEMS;
#if 0
if (IsPrivateCreatorFound(ds, Tag(0x0025, 0x0010), "GEMS_IDEN_01") ||
IsPrivateCreatorFound(ds, Tag(0x0009, 0x0010), "GEMS_IDEN_01") ||
IsPrivateCreatorFound(ds, Tag(0x0009, 0x0010), "GEMS_GENIE_1") ||
IsPrivateCreatorFound(ds, Tag(0x0009, 0x0010), "GEMS_PETD_01"))
return GEMS;
#endif
// Philips:
if (ds.FindDataElement(
PrivateTag(0x2005, 0x000d, "Philips MR Imaging DD 001")) ||
ds.FindDataElement(
PrivateTag(0x2005, 0x000e, "Philips MR Imaging DD 001")) ||
ds.FindDataElement(
PrivateTag(0x2001, 0x0003, "Philips Imaging DD 001")) ||
ds.FindDataElement(PrivateTag(0x2001, 0x005f, "Philips Imaging DD 001")))
return PMS;
#if 0
if (IsPrivateCreatorFound(ds, Tag(0x2005, 0x0014),
"Philips MR Imaging DD 005"))
return PMS;
#endif
if (IsPrivateCreatorFound(ds, Tag(0x0019, 0x0010), "PHILIPS MR/PART") &&
IsPrivateCreatorFound(ds, Tag(0x0021, 0x0010), "PHILIPS MR/PART"))
return PMS;
if (IsPrivateCreatorFound(ds, Tag(0x0009, 0x0010), "SPI-P Release 1") &&
IsPrivateCreatorFound(ds, Tag(0x0019, 0x0010), "SPI-P Release 1"))
return PMS;
// Siemens:
if (ds.FindDataElement(PrivateTag(0x0029, 0x0010, "SIEMENS CSA HEADER")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x0020, "SIEMENS CSA HEADER")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x0010, "SIEMENS MEDCOM OOG")) ||
ds.FindDataElement(
PrivateTag(0x7fdf, 0x0000, "ACUSON:1.2.840.113680.1.0:7ffe")) ||
ds.FindDataElement(PrivateTag(0x0019, 0x0012, "SIEMENS CM VA0 ACQU")) ||
ds.FindDataElement(PrivateTag(0x0009, 0x0010, "SIEMENS CT VA0 IDE")))
return SIEMENS;
#if 0
if (GetPrivateTagValueOrEmpty<VR::SH, VM::VM1>(
ds, PrivateTag(0x0021, 0x0022, "SIEMENS MR SDS 01")) == "SIEMENS")
return SIEMENS;
// gdcm-MR-SIEMENS-16-2.acr
if (GetPrivateTagValueOrEmpty<VR::LO, VM::VM1>(
ds, PrivateTag(0x0019, 0x0012, "SIEMENS CM VA0 ACQU")) == "SIEMENS")
return SIEMENS;
#endif
// toshiba:
if (ds.FindDataElement(PrivateTag(0x7005, 0x0008, "TOSHIBA_MEC_CT3")) ||
ds.FindDataElement(PrivateTag(0x700d, 0x0008, "TOSHIBA_MEC_MR3")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x0001, "PMTF INFORMATION DATA")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x0001, "CANON_MEC_MR3")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x0001, "TOSHIBA_MEC_MR3")))
return TOSHIBA;
// fuji
if (ds.FindDataElement(PrivateTag(0x0021, 0x0010, "FDMS 1.0"))) return FUJI;
// hitachi
if (ds.FindDataElement(PrivateTag(0x0009, 0x0000, "HMC - CT - ID")) ||
ds.FindDataElement(PrivateTag(0x0009, 0x0003, "MMCPrivate")) ||
ds.FindDataElement(PrivateTag(0x0009, 0x0050, "MMCPrivate")) ||
ds.FindDataElement(PrivateTag(0x0019, 0x000e, "MMCPrivate")) ||
ds.FindDataElement(PrivateTag(0x0019, 0x0021, "MMCPrivate")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x002f, "MMCPrivate")) ||
ds.FindDataElement(PrivateTag(0x0029, 0x00d7, "MMCPrivate")))
return HITACHI;
// UIH
if (ds.FindDataElement(PrivateTag(0x0065, 0x000a, "Image Private Header")))
return UIH;
return UNKNOWN;
}
EquipmentManufacturer::Type EquipmentManufacturer::Compute(DataSet const& ds) {
EquipmentManufacturer::Type ret = GuessFromPrivateAttributes(ds);
// proper anonymizer should not touch Manufacturer attribute value:
// http://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html#table_E.1-1
Attribute<0x0008, 0x0070> manu = {""}; // Manufacturer
std::string manufacturer;
if (ds.FindDataElement(manu.GetTag())) {
manu.SetFromDataSet(ds);
manufacturer = manu.GetValue().Trim();
// TODO: contributing equipement ?
} else {
// MFSPLIT export seems to remove the attribute completely:
manufacturer = GetPrivateTagValueOrEmpty<VR::SH, VM::VM1>(
ds, PrivateTag(0x0021, 0x0022, "SIEMENS MR SDS 01"));
}
if (!manufacturer.empty()) {
for (const Mapping* mapping = mappings;
mapping != mappings + ARRAY_SIZE(mappings); ++mapping) {
for (size_t i = 0; i < mapping->nstrings; ++i) {
// case insensitive to handle: "GE MEDICAL SYSTEMS" vs "GE Medical
// Systems"
if (System::StrCaseCmp(mapping->strings[i], manufacturer.c_str()) ==
0) {
if (ret != UNKNOWN && ret != mapping->type) {
gdcmErrorMacro(" Impossible happen: " << ret << " vs "
<< mapping->type);
return UNKNOWN;
}
return mapping->type;
}
}
}
}
gdcmWarningMacro("Unknown Manufacturer [" << manufacturer
<< "] trying guess.");
return ret;
}
} // end namespace gdcm
|