PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1
25
26#include <algorithm>
27#include <filesystem>
28#include <iomanip>
29#include <iostream>
30#include <sstream>
31#include <string>
32#include <vector>
33
34namespace {
35
39enum class output_format { text, json };
40
44struct options {
45 std::vector<std::filesystem::path> paths;
46 output_format format{output_format::text};
47 bool recursive{false};
48 bool verbose{false};
49 bool quiet{false};
50 bool show_file_info{true};
51};
52
56struct dicom_summary {
57 // File info
58 std::string file_path;
59 std::uintmax_t file_size{0};
60 std::string transfer_syntax;
61 std::string transfer_syntax_uid;
62 std::string sop_class_uid;
63 std::string sop_instance_uid;
64
65 // Patient info
66 std::string patient_name;
67 std::string patient_id;
68 std::string patient_birth_date;
69 std::string patient_sex;
70
71 // Study info
72 std::string study_date;
73 std::string study_time;
74 std::string study_description;
75 std::string study_instance_uid;
76 std::string accession_number;
77
78 // Series info
79 std::string modality;
80 std::string series_number;
81 std::string series_description;
82 std::string series_instance_uid;
83
84 // Instance info
85 std::string instance_number;
86 std::string acquisition_date;
87 std::string acquisition_time;
88
89 // Image info
90 uint16_t rows{0};
91 uint16_t columns{0};
92 uint16_t bits_allocated{0};
93 uint16_t bits_stored{0};
94 uint16_t samples_per_pixel{0};
95 std::string photometric_interpretation;
96 std::string number_of_frames;
97 size_t pixel_data_size{0};
98 bool has_pixel_data{false};
99};
100
105void print_usage(const char* program_name) {
106 std::cout << R"(
107DICOM Info - File Summary Utility
108
109Usage: )" << program_name
110 << R"( <path> [path2 ...] [options]
111
112Arguments:
113 path DICOM file(s) or directory to inspect
114
115Options:
116 -h, --help Show this help message
117 -v, --verbose Verbose output (show all available fields)
118 -q, --quiet Minimal output (file path and basic info only)
119 -f, --format <f> Output format: text (default), json
120 -r, --recursive Recursively scan directories
121 --no-file-info Don't show file information (size, transfer syntax)
122
123Examples:
124 )" << program_name
125 << R"( image.dcm
126 )" << program_name
127 << R"( image1.dcm image2.dcm image3.dcm
128 )" << program_name
129 << R"( image.dcm --format json
130 )" << program_name
131 << R"( ./dicom_folder/ --recursive
132 )" << program_name
133 << R"( ./dicom_folder/ -r -q
134
135Output:
136 Displays summary information organized by:
137 - File: Path, size, transfer syntax
138 - Patient: Name, ID, birth date, sex
139 - Study: Date, description, accession number
140 - Series: Modality, number, description
141 - Image: Dimensions, bits, photometric interpretation
142
143Exit Codes:
144 0 Success
145 1 Error - Invalid arguments
146 2 Error - File not found or invalid DICOM file
147)";
148}
149
157bool parse_arguments(int argc, char* argv[], options& opts) {
158 if (argc < 2) {
159 return false;
160 }
161
162 for (int i = 1; i < argc; ++i) {
163 std::string arg = argv[i];
164
165 if (arg == "--help" || arg == "-h") {
166 return false;
167 } else if (arg == "--verbose" || arg == "-v") {
168 opts.verbose = true;
169 } else if (arg == "--quiet" || arg == "-q") {
170 opts.quiet = true;
171 } else if (arg == "--recursive" || arg == "-r") {
172 opts.recursive = true;
173 } else if (arg == "--no-file-info") {
174 opts.show_file_info = false;
175 } else if ((arg == "--format" || arg == "-f") && i + 1 < argc) {
176 std::string fmt = argv[++i];
177 if (fmt == "json") {
178 opts.format = output_format::json;
179 } else if (fmt == "text") {
180 opts.format = output_format::text;
181 } else {
182 std::cerr << "Error: Unknown format '" << fmt
183 << "'. Use: text, json\n";
184 return false;
185 }
186 } else if (arg[0] == '-') {
187 std::cerr << "Error: Unknown option '" << arg << "'\n";
188 return false;
189 } else {
190 opts.paths.emplace_back(arg);
191 }
192 }
193
194 if (opts.paths.empty()) {
195 std::cerr << "Error: No path specified\n";
196 return false;
197 }
198
199 if (opts.quiet) {
200 opts.verbose = false;
201 }
202
203 return true;
204}
205
211std::string json_escape(const std::string& str) {
212 std::ostringstream oss;
213 for (char c : str) {
214 switch (c) {
215 case '"':
216 oss << "\\\"";
217 break;
218 case '\\':
219 oss << "\\\\";
220 break;
221 case '\b':
222 oss << "\\b";
223 break;
224 case '\f':
225 oss << "\\f";
226 break;
227 case '\n':
228 oss << "\\n";
229 break;
230 case '\r':
231 oss << "\\r";
232 break;
233 case '\t':
234 oss << "\\t";
235 break;
236 default:
237 if (static_cast<unsigned char>(c) < 0x20) {
238 oss << "\\u" << std::hex << std::setfill('0') << std::setw(4)
239 << static_cast<int>(c);
240 } else {
241 oss << c;
242 }
243 }
244 }
245 return oss.str();
246}
247
253std::string format_file_size(std::uintmax_t size) {
254 std::ostringstream oss;
255 if (size >= 1024 * 1024 * 1024) {
256 oss << std::fixed << std::setprecision(2)
257 << static_cast<double>(size) / (1024 * 1024 * 1024) << " GB";
258 } else if (size >= 1024 * 1024) {
259 oss << std::fixed << std::setprecision(2)
260 << static_cast<double>(size) / (1024 * 1024) << " MB";
261 } else if (size >= 1024) {
262 oss << std::fixed << std::setprecision(2)
263 << static_cast<double>(size) / 1024 << " KB";
264 } else {
265 oss << size << " bytes";
266 }
267 return oss.str();
268}
269
276bool extract_summary(const std::filesystem::path& file_path,
277 dicom_summary& summary) {
278 using namespace kcenon::pacs::core;
279
280 auto result = dicom_file::open(file_path);
281 if (result.is_err()) {
282 return false;
283 }
284
285 auto& file = result.value();
286 const auto& dataset = file.dataset();
287
288 // File info
289 summary.file_path = file_path.string();
290 summary.file_size = std::filesystem::file_size(file_path);
291 summary.transfer_syntax = file.transfer_syntax().name();
292 summary.transfer_syntax_uid = file.transfer_syntax().uid();
293 summary.sop_class_uid = file.sop_class_uid();
294 summary.sop_instance_uid = file.sop_instance_uid();
295
296 // Patient info
297 summary.patient_name = dataset.get_string(tags::patient_name);
298 summary.patient_id = dataset.get_string(tags::patient_id);
299 summary.patient_birth_date = dataset.get_string(tags::patient_birth_date);
300 summary.patient_sex = dataset.get_string(tags::patient_sex);
301
302 // Study info
303 summary.study_date = dataset.get_string(tags::study_date);
304 summary.study_time = dataset.get_string(tags::study_time);
305 summary.study_description = dataset.get_string(tags::study_description);
306 summary.study_instance_uid = dataset.get_string(tags::study_instance_uid);
307 summary.accession_number = dataset.get_string(tags::accession_number);
308
309 // Series info
310 summary.modality = dataset.get_string(tags::modality);
311 summary.series_number = dataset.get_string(tags::series_number);
312 summary.series_description = dataset.get_string(tags::series_description);
313 summary.series_instance_uid = dataset.get_string(tags::series_instance_uid);
314
315 // Instance info
316 summary.instance_number = dataset.get_string(tags::instance_number);
317 summary.acquisition_date = dataset.get_string(dicom_tag{0x0008, 0x0022});
318 summary.acquisition_time = dataset.get_string(dicom_tag{0x0008, 0x0032});
319
320 // Image info
321 if (auto val = dataset.get_numeric<uint16_t>(tags::rows)) {
322 summary.rows = *val;
323 }
324 if (auto val = dataset.get_numeric<uint16_t>(tags::columns)) {
325 summary.columns = *val;
326 }
327 if (auto val = dataset.get_numeric<uint16_t>(dicom_tag{0x0028, 0x0100})) {
328 summary.bits_allocated = *val;
329 }
330 if (auto val = dataset.get_numeric<uint16_t>(dicom_tag{0x0028, 0x0101})) {
331 summary.bits_stored = *val;
332 }
333 if (auto val = dataset.get_numeric<uint16_t>(dicom_tag{0x0028, 0x0002})) {
334 summary.samples_per_pixel = *val;
335 }
336 summary.photometric_interpretation =
337 dataset.get_string(dicom_tag{0x0028, 0x0004});
338 summary.number_of_frames = dataset.get_string(dicom_tag{0x0028, 0x0008});
339
340 // Pixel data
341 auto* pixel_data = dataset.get(dicom_tag{0x7FE0, 0x0010});
342 if (pixel_data != nullptr) {
343 summary.has_pixel_data = true;
344 summary.pixel_data_size = pixel_data->length();
345 }
346
347 return true;
348}
349
355void print_summary_text(const dicom_summary& summary, const options& opts) {
356 // Quiet mode: minimal output
357 if (opts.quiet) {
358 std::cout << summary.file_path;
359 if (!summary.modality.empty()) {
360 std::cout << " [" << summary.modality << "]";
361 }
362 if (summary.rows > 0 && summary.columns > 0) {
363 std::cout << " " << summary.columns << "x" << summary.rows;
364 }
365 std::cout << "\n";
366 return;
367 }
368
369 const int label_width = 24;
370
371 std::cout << "========================================\n";
372
373 // File Information
374 if (opts.show_file_info) {
375 std::cout << "File Information\n";
376 std::cout << "----------------------------------------\n";
377 std::cout << std::left << std::setw(label_width) << " Path:"
378 << summary.file_path << "\n";
379 std::cout << std::left << std::setw(label_width) << " Size:"
380 << format_file_size(summary.file_size) << " ("
381 << summary.file_size << " bytes)\n";
382 std::cout << std::left << std::setw(label_width) << " Transfer Syntax:"
383 << summary.transfer_syntax << "\n";
384 if (opts.verbose) {
385 std::cout << std::left << std::setw(label_width) << " TS UID:"
386 << summary.transfer_syntax_uid << "\n";
387 std::cout << std::left << std::setw(label_width) << " SOP Class:"
388 << summary.sop_class_uid << "\n";
389 std::cout << std::left << std::setw(label_width) << " SOP Instance:"
390 << summary.sop_instance_uid << "\n";
391 }
392 std::cout << "\n";
393 }
394
395 // Patient Information
396 std::cout << "Patient Information\n";
397 std::cout << "----------------------------------------\n";
398 std::cout << std::left << std::setw(label_width) << " Name:"
399 << (summary.patient_name.empty() ? "(not specified)"
400 : summary.patient_name)
401 << "\n";
402 std::cout << std::left << std::setw(label_width) << " ID:"
403 << (summary.patient_id.empty() ? "(not specified)"
404 : summary.patient_id)
405 << "\n";
406 if (opts.verbose || !summary.patient_birth_date.empty()) {
407 std::cout << std::left << std::setw(label_width) << " Birth Date:"
408 << (summary.patient_birth_date.empty() ? "(not specified)"
409 : summary.patient_birth_date)
410 << "\n";
411 }
412 if (opts.verbose || !summary.patient_sex.empty()) {
413 std::cout << std::left << std::setw(label_width) << " Sex:"
414 << (summary.patient_sex.empty() ? "(not specified)"
415 : summary.patient_sex)
416 << "\n";
417 }
418 std::cout << "\n";
419
420 // Study Information
421 std::cout << "Study Information\n";
422 std::cout << "----------------------------------------\n";
423 std::cout << std::left << std::setw(label_width) << " Date:"
424 << (summary.study_date.empty() ? "(not specified)"
425 : summary.study_date)
426 << "\n";
427 if (opts.verbose || !summary.study_time.empty()) {
428 std::cout << std::left << std::setw(label_width) << " Time:"
429 << (summary.study_time.empty() ? "(not specified)"
430 : summary.study_time)
431 << "\n";
432 }
433 if (opts.verbose || !summary.study_description.empty()) {
434 std::cout << std::left << std::setw(label_width) << " Description:"
435 << (summary.study_description.empty() ? "(not specified)"
436 : summary.study_description)
437 << "\n";
438 }
439 if (opts.verbose || !summary.accession_number.empty()) {
440 std::cout << std::left << std::setw(label_width) << " Accession #:"
441 << (summary.accession_number.empty() ? "(not specified)"
442 : summary.accession_number)
443 << "\n";
444 }
445 if (opts.verbose) {
446 std::cout << std::left << std::setw(label_width) << " Study UID:"
447 << summary.study_instance_uid << "\n";
448 }
449 std::cout << "\n";
450
451 // Series Information
452 std::cout << "Series Information\n";
453 std::cout << "----------------------------------------\n";
454 std::cout << std::left << std::setw(label_width) << " Modality:"
455 << (summary.modality.empty() ? "(not specified)"
456 : summary.modality)
457 << "\n";
458 if (opts.verbose || !summary.series_number.empty()) {
459 std::cout << std::left << std::setw(label_width) << " Series #:"
460 << (summary.series_number.empty() ? "(not specified)"
461 : summary.series_number)
462 << "\n";
463 }
464 if (opts.verbose || !summary.series_description.empty()) {
465 std::cout << std::left << std::setw(label_width) << " Description:"
466 << (summary.series_description.empty() ? "(not specified)"
467 : summary.series_description)
468 << "\n";
469 }
470 if (opts.verbose) {
471 std::cout << std::left << std::setw(label_width) << " Series UID:"
472 << summary.series_instance_uid << "\n";
473 }
474 std::cout << "\n";
475
476 // Instance Information (verbose only)
477 if (opts.verbose) {
478 std::cout << "Instance Information\n";
479 std::cout << "----------------------------------------\n";
480 std::cout << std::left << std::setw(label_width) << " Instance #:"
481 << (summary.instance_number.empty() ? "(not specified)"
482 : summary.instance_number)
483 << "\n";
484 if (!summary.acquisition_date.empty()) {
485 std::cout << std::left << std::setw(label_width) << " Acquisition Date:"
486 << summary.acquisition_date << "\n";
487 }
488 if (!summary.acquisition_time.empty()) {
489 std::cout << std::left << std::setw(label_width) << " Acquisition Time:"
490 << summary.acquisition_time << "\n";
491 }
492 std::cout << "\n";
493 }
494
495 // Image Information
496 if (summary.rows > 0 || summary.columns > 0 || summary.has_pixel_data) {
497 std::cout << "Image Information\n";
498 std::cout << "----------------------------------------\n";
499 if (summary.rows > 0 && summary.columns > 0) {
500 std::cout << std::left << std::setw(label_width) << " Dimensions:"
501 << summary.columns << " x " << summary.rows << " pixels\n";
502 }
503 if (summary.bits_allocated > 0) {
504 std::cout << std::left << std::setw(label_width) << " Bits:"
505 << summary.bits_stored << " stored / "
506 << summary.bits_allocated << " allocated\n";
507 }
508 if (summary.samples_per_pixel > 0) {
509 std::cout << std::left << std::setw(label_width) << " Samples/Pixel:"
510 << summary.samples_per_pixel << "\n";
511 }
512 if (!summary.photometric_interpretation.empty()) {
513 std::cout << std::left << std::setw(label_width) << " Photometric:"
514 << summary.photometric_interpretation << "\n";
515 }
516 if (!summary.number_of_frames.empty()) {
517 std::cout << std::left << std::setw(label_width) << " Frames:"
518 << summary.number_of_frames << "\n";
519 }
520 if (summary.has_pixel_data) {
521 std::cout << std::left << std::setw(label_width) << " Pixel Data:"
522 << format_file_size(summary.pixel_data_size) << "\n";
523 }
524 std::cout << "\n";
525 }
526
527 std::cout << "========================================\n";
528}
529
536void print_summary_json(const dicom_summary& summary, const options& opts,
537 bool is_last = true) {
538 std::cout << "{\n";
539
540 // File info
541 if (opts.show_file_info) {
542 std::cout << " \"file\": {\n";
543 std::cout << " \"path\": \"" << json_escape(summary.file_path) << "\",\n";
544 std::cout << " \"size\": " << summary.file_size << ",\n";
545 std::cout << " \"sizeFormatted\": \"" << format_file_size(summary.file_size)
546 << "\",\n";
547 std::cout << " \"transferSyntax\": \"" << json_escape(summary.transfer_syntax)
548 << "\",\n";
549 std::cout << " \"transferSyntaxUID\": \""
550 << json_escape(summary.transfer_syntax_uid) << "\",\n";
551 std::cout << " \"sopClassUID\": \"" << json_escape(summary.sop_class_uid)
552 << "\",\n";
553 std::cout << " \"sopInstanceUID\": \"" << json_escape(summary.sop_instance_uid)
554 << "\"\n";
555 std::cout << " },\n";
556 }
557
558 // Patient info
559 std::cout << " \"patient\": {\n";
560 std::cout << " \"name\": \"" << json_escape(summary.patient_name) << "\",\n";
561 std::cout << " \"id\": \"" << json_escape(summary.patient_id) << "\",\n";
562 std::cout << " \"birthDate\": \"" << json_escape(summary.patient_birth_date)
563 << "\",\n";
564 std::cout << " \"sex\": \"" << json_escape(summary.patient_sex) << "\"\n";
565 std::cout << " },\n";
566
567 // Study info
568 std::cout << " \"study\": {\n";
569 std::cout << " \"date\": \"" << json_escape(summary.study_date) << "\",\n";
570 std::cout << " \"time\": \"" << json_escape(summary.study_time) << "\",\n";
571 std::cout << " \"description\": \"" << json_escape(summary.study_description)
572 << "\",\n";
573 std::cout << " \"instanceUID\": \"" << json_escape(summary.study_instance_uid)
574 << "\",\n";
575 std::cout << " \"accessionNumber\": \"" << json_escape(summary.accession_number)
576 << "\"\n";
577 std::cout << " },\n";
578
579 // Series info
580 std::cout << " \"series\": {\n";
581 std::cout << " \"modality\": \"" << json_escape(summary.modality) << "\",\n";
582 std::cout << " \"number\": \"" << json_escape(summary.series_number) << "\",\n";
583 std::cout << " \"description\": \"" << json_escape(summary.series_description)
584 << "\",\n";
585 std::cout << " \"instanceUID\": \"" << json_escape(summary.series_instance_uid)
586 << "\"\n";
587 std::cout << " },\n";
588
589 // Instance info
590 std::cout << " \"instance\": {\n";
591 std::cout << " \"number\": \"" << json_escape(summary.instance_number) << "\",\n";
592 std::cout << " \"acquisitionDate\": \"" << json_escape(summary.acquisition_date)
593 << "\",\n";
594 std::cout << " \"acquisitionTime\": \"" << json_escape(summary.acquisition_time)
595 << "\"\n";
596 std::cout << " },\n";
597
598 // Image info
599 std::cout << " \"image\": {\n";
600 std::cout << " \"rows\": " << summary.rows << ",\n";
601 std::cout << " \"columns\": " << summary.columns << ",\n";
602 std::cout << " \"bitsAllocated\": " << summary.bits_allocated << ",\n";
603 std::cout << " \"bitsStored\": " << summary.bits_stored << ",\n";
604 std::cout << " \"samplesPerPixel\": " << summary.samples_per_pixel << ",\n";
605 std::cout << " \"photometricInterpretation\": \""
606 << json_escape(summary.photometric_interpretation) << "\",\n";
607 std::cout << " \"numberOfFrames\": \"" << json_escape(summary.number_of_frames)
608 << "\",\n";
609 std::cout << " \"hasPixelData\": " << (summary.has_pixel_data ? "true" : "false")
610 << ",\n";
611 std::cout << " \"pixelDataSize\": " << summary.pixel_data_size << "\n";
612 std::cout << " }\n";
613
614 std::cout << "}" << (is_last ? "" : ",") << "\n";
615}
616
624int process_file(const std::filesystem::path& file_path, const options& opts,
625 bool is_last = true) {
626 dicom_summary summary;
627
628 if (!extract_summary(file_path, summary)) {
629 if (!opts.quiet) {
630 std::cerr << "Error: Failed to read DICOM file: " << file_path.string()
631 << "\n";
632 }
633 return 2;
634 }
635
636 if (opts.format == output_format::json) {
637 print_summary_json(summary, opts, is_last);
638 } else {
639 print_summary_text(summary, opts);
640 }
641
642 return 0;
643}
644
651std::vector<std::filesystem::path> collect_files(
652 const std::filesystem::path& dir_path, bool recursive) {
653 std::vector<std::filesystem::path> files;
654
655 auto is_dicom_file = [](const std::filesystem::path& p) {
656 auto ext = p.extension().string();
657 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
658 return ext == ".dcm" || ext == ".dicom" || ext.empty();
659 };
660
661 if (recursive) {
662 for (const auto& entry :
663 std::filesystem::recursive_directory_iterator(dir_path)) {
664 if (entry.is_regular_file() && is_dicom_file(entry.path())) {
665 files.push_back(entry.path());
666 }
667 }
668 } else {
669 for (const auto& entry : std::filesystem::directory_iterator(dir_path)) {
670 if (entry.is_regular_file() && is_dicom_file(entry.path())) {
671 files.push_back(entry.path());
672 }
673 }
674 }
675
676 std::sort(files.begin(), files.end());
677 return files;
678}
679
680} // namespace
681
682int main(int argc, char* argv[]) {
683 options opts;
684
685 if (!parse_arguments(argc, argv, opts)) {
686 std::cout << R"(
687 ____ ____ __ __ ___ _ _ _____ ___
688 | _ \ / ___| \/ | |_ _| \ | | ___/ _ \
689 | | | | | | |\/| | | || \| | |_ | | | |
690 | |_| | |___| | | | | || |\ | _|| |_| |
691 |____/ \____|_| |_| |___|_| \_|_| \___/
692
693 DICOM File Summary Utility
694)" << "\n";
695 print_usage(argv[0]);
696 return 1;
697 }
698
699 // Collect all files to process
700 std::vector<std::filesystem::path> all_files;
701 for (const auto& path : opts.paths) {
702 if (!std::filesystem::exists(path)) {
703 std::cerr << "Error: Path does not exist: " << path.string() << "\n";
704 return 2;
705 }
706
707 if (std::filesystem::is_directory(path)) {
708 auto dir_files = collect_files(path, opts.recursive);
709 all_files.insert(all_files.end(), dir_files.begin(), dir_files.end());
710 } else {
711 all_files.push_back(path);
712 }
713 }
714
715 if (all_files.empty()) {
716 std::cerr << "Error: No DICOM files found\n";
717 return 2;
718 }
719
720 // Print banner for text format (non-quiet)
721 if (opts.format == output_format::text && !opts.quiet) {
722 std::cout << R"(
723 ____ ____ __ __ ___ _ _ _____ ___
724 | _ \ / ___| \/ | |_ _| \ | | ___/ _ \
725 | | | | | | |\/| | | || \| | |_ | | | |
726 | |_| | |___| | | | | || |\ | _|| |_| |
727 |____/ \____|_| |_| |___|_| \_|_| \___/
728
729 DICOM File Summary Utility
730)" << "\n";
731
732 if (all_files.size() > 1) {
733 std::cout << "Processing " << all_files.size() << " files...\n\n";
734 }
735 }
736
737 // JSON array wrapper
738 if (opts.format == output_format::json && all_files.size() > 1) {
739 std::cout << "[\n";
740 }
741
742 int exit_code = 0;
743 for (size_t i = 0; i < all_files.size(); ++i) {
744 bool is_last = (i == all_files.size() - 1);
745 if (process_file(all_files[i], opts, is_last) != 0) {
746 exit_code = 2;
747 }
748
749 // Add newline between files for text format
750 if (opts.format == output_format::text && !is_last && !opts.quiet) {
751 std::cout << "\n";
752 }
753 }
754
755 // Close JSON array
756 if (opts.format == output_format::json && all_files.size() > 1) {
757 std::cout << "]\n";
758 }
759
760 return exit_code;
761}
DICOM Part 10 file handling for reading/writing DICOM files.
Compile-time constants for commonly used DICOM tags.
int main()
Definition main.cpp:84
constexpr dicom_tag study_description
Study Description.
constexpr dicom_tag patient_id
Patient ID.
constexpr dicom_tag bits_allocated
Bits Allocated.
constexpr dicom_tag rows
Rows.
constexpr dicom_tag columns
Columns.
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr dicom_tag bits_stored
Bits Stored.
constexpr dicom_tag acquisition_date
Acquisition Date.
constexpr dicom_tag patient_birth_date
Patient's Birth Date.
constexpr dicom_tag pixel_data
Pixel Data.
constexpr dicom_tag accession_number
Accession Number.
constexpr dicom_tag modality
Modality.
constexpr dicom_tag study_time
Study Time.
constexpr dicom_tag patient_sex
Patient's Sex.
constexpr dicom_tag samples_per_pixel
Samples per Pixel.
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag series_number
Series Number.
constexpr dicom_tag acquisition_time
Acquisition Time.
constexpr dicom_tag series_description
Series Description.
constexpr dicom_tag transfer_syntax_uid
Transfer Syntax UID.
constexpr dicom_tag sop_class_uid
SOP Class UID.
constexpr dicom_tag patient_name
Patient's Name.
constexpr dicom_tag study_date
Study Date.
constexpr dicom_tag series_instance_uid
Series Instance UID.
constexpr dicom_tag instance_number
Instance Number.
@ summary
Statistical summary (min, max, mean, percentiles)
constexpr core::dicom_tag number_of_frames
Number of Frames (0028,0008)