PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
nm_storage.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11
12#include <algorithm>
13#include <array>
14
16
17// =============================================================================
18// Transfer Syntaxes
19// =============================================================================
20
21std::vector<std::string> get_nm_transfer_syntaxes() {
22 return {
23 // Explicit VR Little Endian (preferred for interoperability)
24 "1.2.840.10008.1.2.1",
25 // Implicit VR Little Endian (universal baseline)
26 "1.2.840.10008.1.2",
27 // HTJ2K Lossless (high-throughput lossless, preserves count values)
28 "1.2.840.10008.1.2.4.201",
29 // JPEG Lossless (for diagnostic quality - important for quantitative data)
30 "1.2.840.10008.1.2.4.70",
31 // JPEG 2000 Lossless (better compression, preserves count values)
32 "1.2.840.10008.1.2.4.90",
33 // RLE Lossless
34 "1.2.840.10008.1.2.5"
35 };
36}
37
38// =============================================================================
39// Photometric Interpretation
40// =============================================================================
41
42std::string_view to_string(nm_photometric_interpretation interp) noexcept {
43 switch (interp) {
45 return "MONOCHROME2";
47 return "PALETTE COLOR";
48 }
49 return "MONOCHROME2";
50}
51
53parse_nm_photometric_interpretation(std::string_view value) noexcept {
54 if (value == "PALETTE COLOR") {
56 }
58}
59
60bool is_valid_nm_photometric(std::string_view value) noexcept {
61 return value == "MONOCHROME2" || value == "PALETTE COLOR";
62}
63
64// =============================================================================
65// SOP Class Information
66// =============================================================================
67
68namespace {
69
70// Static array of NM SOP class information
71constexpr std::array<nm_sop_class_info, 2> nm_sop_classes = {{
72 {
74 "NM Image Storage",
75 "Nuclear medicine planar, SPECT, and gated images",
76 false,
77 true // supports multiframe (dynamic, gated, SPECT)
78 },
79 {
81 "NM Image Storage (Retired)",
82 "Legacy nuclear medicine image storage",
83 true,
84 true
85 }
86}};
87
88} // namespace
89
90std::vector<std::string> get_nm_storage_sop_classes(bool include_retired) {
91 std::vector<std::string> result;
92 result.reserve(nm_sop_classes.size());
93
94 for (const auto& info : nm_sop_classes) {
95 if (!info.is_retired || include_retired) {
96 result.emplace_back(info.uid);
97 }
98 }
99
100 return result;
101}
102
103const nm_sop_class_info*
104get_nm_sop_class_info(std::string_view uid) noexcept {
105 auto it = std::find_if(
106 nm_sop_classes.begin(),
107 nm_sop_classes.end(),
108 [uid](const auto& info) { return info.uid == uid; }
109 );
110
111 if (it != nm_sop_classes.end()) {
112 return &(*it);
113 }
114 return nullptr;
115}
116
117bool is_nm_storage_sop_class(std::string_view uid) noexcept {
118 return get_nm_sop_class_info(uid) != nullptr;
119}
120
121bool is_nm_multiframe_sop_class(std::string_view uid) noexcept {
122 const auto* info = get_nm_sop_class_info(uid);
123 return info != nullptr && info->supports_multiframe;
124}
125
126// =============================================================================
127// Type of Data Conversion
128// =============================================================================
129
130std::string_view to_string(nm_type_of_data type) noexcept {
131 switch (type) {
133 return "STATIC";
135 return "DYNAMIC";
137 return "GATED";
139 return "WHOLE BODY";
141 return "RECON TOMO";
143 return "RECON GATED TOMO";
145 return "TOMO";
147 return "GATED TOMO";
148 }
149 return "STATIC";
150}
151
152nm_type_of_data parse_nm_type_of_data(std::string_view value) noexcept {
153 if (value == "STATIC") {
155 }
156 if (value == "DYNAMIC") {
158 }
159 if (value == "GATED") {
161 }
162 if (value == "WHOLE BODY") {
164 }
165 if (value == "RECON TOMO") {
167 }
168 if (value == "RECON GATED TOMO") {
170 }
171 if (value == "TOMO") {
173 }
174 if (value == "GATED TOMO") {
176 }
178}
179
180// =============================================================================
181// Collimator Type Conversion
182// =============================================================================
183
184std::string_view to_string(nm_collimator_type collimator) noexcept {
185 switch (collimator) {
187 return "PARA";
189 return "FANB";
191 return "CONE";
193 return "PINH";
195 return "DIVG";
197 return "CVGB";
199 return "NONE";
200 }
201 return "PARA";
202}
203
204nm_collimator_type parse_nm_collimator_type(std::string_view value) noexcept {
205 if (value == "PARA" || value == "PARALLEL") {
207 }
208 if (value == "FANB" || value == "FAN BEAM") {
210 }
211 if (value == "CONE" || value == "CONE BEAM") {
213 }
214 if (value == "PINH" || value == "PINHOLE") {
216 }
217 if (value == "DIVG" || value == "DIVERGING") {
219 }
220 if (value == "CVGB" || value == "CONVERGING") {
222 }
223 if (value == "NONE") {
225 }
227}
228
229// =============================================================================
230// Radioisotope Conversion
231// =============================================================================
232
233std::string_view to_string(nm_radioisotope isotope) noexcept {
234 switch (isotope) {
236 return "Tc-99m";
238 return "I-131";
240 return "I-123";
242 return "Tl-201";
244 return "Ga-67";
246 return "In-111";
248 return "F-18";
250 return "Other";
251 }
252 return "Other";
253}
254
255double get_primary_energy_kev(nm_radioisotope isotope) noexcept {
256 switch (isotope) {
258 return 140.0;
260 return 364.0;
262 return 159.0;
264 return 71.0; // Primary peak (also 167 keV)
266 return 93.0; // Primary peak (also 185, 300 keV)
268 return 171.0; // Primary peak (also 245 keV)
270 return 511.0; // Annihilation photons
272 return 0.0;
273 }
274 return 0.0;
275}
276
277// =============================================================================
278// Whole Body Technique Conversion
279// =============================================================================
280
281std::string_view to_string(nm_whole_body_technique technique) noexcept {
282 switch (technique) {
284 return "1PASS";
286 return "2PASS";
288 return "STEP";
289 }
290 return "1PASS";
291}
292
293} // namespace kcenon::pacs::services::sop_classes
nm_collimator_type
NM collimator type.
Definition nm_storage.h:205
nm_photometric_interpretation
Supported photometric interpretations for NM images.
Definition nm_storage.h:76
@ palette_color
Pseudo-color via lookup table (for display)
bool is_valid_nm_photometric(std::string_view value) noexcept
Check if photometric interpretation is valid for NM.
nm_type_of_data parse_nm_type_of_data(std::string_view value) noexcept
Parse NM type of data from DICOM string.
nm_radioisotope
Common radioisotopes used in NM imaging.
Definition nm_storage.h:245
nm_photometric_interpretation parse_nm_photometric_interpretation(std::string_view value) noexcept
Parse DICOM photometric interpretation string.
constexpr std::string_view nm_image_storage_retired_uid
Nuclear Medicine Image Storage (Retired) - for legacy systems.
Definition nm_storage.h:46
bool is_nm_multiframe_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID supports multi-frame.
nm_whole_body_technique
Patient orientation for whole body scan.
Definition nm_storage.h:293
@ multi_pass
2PASS - Multiple pass (anterior/posterior)
std::vector< std::string > get_nm_transfer_syntaxes()
Get recommended transfer syntaxes for NM images.
double get_primary_energy_kev(nm_radioisotope isotope) noexcept
Get primary photopeak energy for radioisotope.
bool is_nm_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a NM Storage SOP Class.
nm_type_of_data
NM image type (Type of Data)
Definition nm_storage.h:162
@ gated
GATED - cardiac gated acquisition.
@ gated_tomo
GATED TOMO - gated SPECT projections.
@ dynamic
DYNAMIC - dynamic study (time series)
@ tomo
TOMO - SPECT raw projection data.
@ recon_tomo
RECON TOMO - reconstructed SPECT.
@ recon_gated_tomo
RECON GATED TOMO - reconstructed gated SPECT.
constexpr std::string_view nm_image_storage_uid
Nuclear Medicine Image Storage SOP Class UID.
Definition nm_storage.h:37
std::vector< std::string > get_nm_storage_sop_classes(bool include_retired=true)
Get all NM Storage SOP Class UIDs.
nm_collimator_type parse_nm_collimator_type(std::string_view value) noexcept
Parse collimator type from DICOM string.
std::string_view to_string(dx_photometric_interpretation interp) noexcept
Convert photometric interpretation enum to DICOM string.
const nm_sop_class_info * get_nm_sop_class_info(std::string_view uid) noexcept
Get information about a specific NM SOP Class.
Nuclear Medicine (NM) Image Storage SOP Classes.
std::string_view uid