File: gdcmEquipmentManufacturer.cxx

package info (click to toggle)
gdcm 3.0.21-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 26,880 kB
  • sloc: cpp: 203,477; ansic: 78,582; xml: 48,129; python: 3,459; cs: 2,308; java: 1,629; lex: 1,290; sh: 334; php: 128; makefile: 117
file content (251 lines) | stat: -rw-r--r-- 11,017 bytes parent folder | download
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