PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
seg_iod_validator.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
13
14#include <sstream>
15
17
18using namespace kcenon::pacs::core;
19
20// =============================================================================
21// SEG-specific DICOM Tags
22// =============================================================================
23
24namespace seg_tags {
25
26// Segmentation Series Module
27[[maybe_unused]] constexpr dicom_tag modality{0x0008, 0x0060};
28
29// Segmentation Image Module
30constexpr dicom_tag segmentation_type{0x0062, 0x0001};
31constexpr dicom_tag segmentation_fractional_type{0x0062, 0x0010};
32constexpr dicom_tag max_fractional_value{0x0062, 0x000E};
33constexpr dicom_tag segment_sequence{0x0062, 0x0002};
34[[maybe_unused]] constexpr dicom_tag segments_overlap{0x0062, 0x0013};
35
36// Segment Sequence Item attributes
37constexpr dicom_tag segment_number{0x0062, 0x0004};
38constexpr dicom_tag segment_label{0x0062, 0x0005};
39[[maybe_unused]] constexpr dicom_tag segment_description{0x0062, 0x0006};
40constexpr dicom_tag segment_algorithm_type{0x0062, 0x0008};
41[[maybe_unused]] constexpr dicom_tag segment_algorithm_name{0x0062, 0x0009};
44[[maybe_unused]] constexpr dicom_tag anatomic_region_sequence{0x0008, 0x2218};
45[[maybe_unused]] constexpr dicom_tag recommended_display_cieLab_value{0x0062, 0x000D};
46[[maybe_unused]] constexpr dicom_tag tracking_id{0x0062, 0x0020};
47[[maybe_unused]] constexpr dicom_tag tracking_uid{0x0062, 0x0021};
48
49// Multi-frame related
50constexpr dicom_tag number_of_frames{0x0028, 0x0008};
54constexpr dicom_tag dimension_index_sequence{0x0020, 0x9222};
55
56// Referenced Series Sequence
57[[maybe_unused]] constexpr dicom_tag referenced_series_sequence{0x0008, 0x1115};
58[[maybe_unused]] constexpr dicom_tag referenced_instance_sequence{0x0008, 0x114A};
59
60// Common Instance Reference Module
61constexpr dicom_tag referenced_series_sequence_cir{0x0008, 0x1115};
62[[maybe_unused]] constexpr dicom_tag studies_containing_other_referenced_instances_sequence{0x0008, 0x1200};
63
64// Enhanced General Equipment Module
65constexpr dicom_tag manufacturer{0x0008, 0x0070};
66constexpr dicom_tag manufacturer_model_name{0x0008, 0x1090};
67constexpr dicom_tag device_serial_number{0x0018, 0x1000};
68constexpr dicom_tag software_versions{0x0018, 0x1020};
69
70// Code Sequence attributes
71[[maybe_unused]] constexpr dicom_tag code_value{0x0008, 0x0100};
72[[maybe_unused]] constexpr dicom_tag coding_scheme_designator{0x0008, 0x0102};
73[[maybe_unused]] constexpr dicom_tag code_meaning{0x0008, 0x0104};
74
75} // namespace seg_tags
76
77// =============================================================================
78// seg_iod_validator Implementation
79// =============================================================================
80
82 : options_(options) {}
83
85 validation_result result;
86 result.is_valid = true;
87
88 // Validate mandatory modules
90 validate_patient_module(dataset, result.findings);
98 validate_sop_common_module(dataset, result.findings);
99 }
100
102 validate_segment_sequence(dataset, result.findings);
103 }
104
106 validate_image_pixel_module(dataset, result.findings);
107 }
108
111 }
112
113 // Multi-frame validation
116
117 // Check for errors
118 for (const auto& finding : result.findings) {
119 if (finding.severity == validation_severity::error) {
120 result.is_valid = false;
121 break;
122 }
123 if (options_.strict_mode && finding.severity == validation_severity::warning) {
124 result.is_valid = false;
125 break;
126 }
127 }
128
129 return result;
130}
131
134 validation_result result;
135 result.is_valid = true;
136
137 validate_segment_sequence(dataset, result.findings);
138
139 for (const auto& finding : result.findings) {
140 if (finding.severity == validation_severity::error) {
141 result.is_valid = false;
142 break;
143 }
144 }
145
146 return result;
147}
148
151 validation_result result;
152 result.is_valid = true;
153
155
156 for (const auto& finding : result.findings) {
157 if (finding.severity == validation_severity::error) {
158 result.is_valid = false;
159 break;
160 }
161 }
162
163 return result;
164}
165
167 // Check essential Type 1 attributes for SEG
168
169 // General Study Module
170 if (!dataset.contains(tags::study_instance_uid)) return false;
171
172 // General Series Module
173 if (!dataset.contains(tags::modality)) return false;
174 if (!dataset.contains(tags::series_instance_uid)) return false;
175
176 // Check modality is SEG
177 auto modality = dataset.get_string(tags::modality);
178 if (modality != "SEG") return false;
179
180 // Segmentation Image Module
181 if (!dataset.contains(seg_tags::segmentation_type)) return false;
182 if (!dataset.contains(seg_tags::segment_sequence)) return false;
183
184 // SOP Common Module
185 if (!dataset.contains(tags::sop_class_uid)) return false;
186 if (!dataset.contains(tags::sop_instance_uid)) return false;
187
188 // Verify SOP Class is SEG
189 auto sop_class = dataset.get_string(tags::sop_class_uid);
190 if (!sop_classes::is_seg_storage_sop_class(sop_class)) return false;
191
192 return true;
193}
194
196 return options_;
197}
198
202
203// =============================================================================
204// Module Validation Methods
205// =============================================================================
206
208 const dicom_dataset& dataset,
209 std::vector<validation_finding>& findings) const {
210
211 if (options_.check_type2) {
212 check_type2_attribute(dataset, tags::patient_name, "PatientName", findings);
213 check_type2_attribute(dataset, tags::patient_id, "PatientID", findings);
214 check_type2_attribute(dataset, tags::patient_birth_date, "PatientBirthDate", findings);
215 check_type2_attribute(dataset, tags::patient_sex, "PatientSex", findings);
216 }
217}
218
220 const dicom_dataset& dataset,
221 std::vector<validation_finding>& findings) const {
222
223 if (options_.check_type1) {
224 check_type1_attribute(dataset, tags::study_instance_uid, "StudyInstanceUID", findings);
225 }
226
227 if (options_.check_type2) {
228 check_type2_attribute(dataset, tags::study_date, "StudyDate", findings);
229 check_type2_attribute(dataset, tags::study_time, "StudyTime", findings);
230 check_type2_attribute(dataset, tags::referring_physician_name, "ReferringPhysicianName", findings);
231 check_type2_attribute(dataset, tags::study_id, "StudyID", findings);
232 check_type2_attribute(dataset, tags::accession_number, "AccessionNumber", findings);
233 }
234}
235
237 const dicom_dataset& dataset,
238 std::vector<validation_finding>& findings) const {
239
240 if (options_.check_type1) {
241 check_type1_attribute(dataset, tags::modality, "Modality", findings);
242 check_type1_attribute(dataset, tags::series_instance_uid, "SeriesInstanceUID", findings);
243 check_modality(dataset, findings);
244
245 // Frame of Reference Module - Type 1 for SEG
246 check_type1_attribute(dataset, tags::frame_of_reference_uid, "FrameOfReferenceUID", findings);
247 }
248
249 if (options_.check_type2) {
250 check_type2_attribute(dataset, tags::series_number, "SeriesNumber", findings);
251 }
252}
253
255 [[maybe_unused]] const dicom_dataset& dataset,
256 [[maybe_unused]] std::vector<validation_finding>& findings) const {
257
258 // Modality must be "SEG" - already checked in general series validation
259 // This module primarily constrains Modality to SEG
260}
261
263 const dicom_dataset& dataset,
264 std::vector<validation_finding>& findings) const {
265
266 if (options_.check_type2) {
267 check_type2_attribute(dataset, seg_tags::manufacturer, "Manufacturer", findings);
268 }
269}
270
272 const dicom_dataset& dataset,
273 std::vector<validation_finding>& findings) const {
274
275 if (options_.check_type1) {
276 check_type1_attribute(dataset, seg_tags::manufacturer, "Manufacturer", findings);
277 check_type1_attribute(dataset, seg_tags::manufacturer_model_name, "ManufacturerModelName", findings);
278 check_type1_attribute(dataset, seg_tags::device_serial_number, "DeviceSerialNumber", findings);
279 check_type1_attribute(dataset, seg_tags::software_versions, "SoftwareVersions", findings);
280 }
281}
282
284 const dicom_dataset& dataset,
285 std::vector<validation_finding>& findings) const {
286
287 if (options_.check_type2) {
288 constexpr dicom_tag instance_number{0x0020, 0x0013};
289 check_type2_attribute(dataset, instance_number, "InstanceNumber", findings);
290 }
291}
292
294 const dicom_dataset& dataset,
295 std::vector<validation_finding>& findings) const {
296
297 if (options_.check_type1) {
298 check_type1_attribute(dataset, tags::samples_per_pixel, "SamplesPerPixel", findings);
299 check_type1_attribute(dataset, tags::photometric_interpretation, "PhotometricInterpretation", findings);
300 check_type1_attribute(dataset, tags::rows, "Rows", findings);
301 check_type1_attribute(dataset, tags::columns, "Columns", findings);
302 check_type1_attribute(dataset, tags::bits_allocated, "BitsAllocated", findings);
303 check_type1_attribute(dataset, tags::bits_stored, "BitsStored", findings);
304 check_type1_attribute(dataset, tags::high_bit, "HighBit", findings);
305 check_type1_attribute(dataset, tags::pixel_representation, "PixelRepresentation", findings);
306 }
307
308 // SEG-specific pixel data constraints
309 check_pixel_data_consistency(dataset, findings);
310}
311
313 const dicom_dataset& dataset,
314 std::vector<validation_finding>& findings) const {
315
316 if (options_.check_type1) {
317 check_type1_attribute(dataset, seg_tags::segmentation_type, "SegmentationType", findings);
318 check_type1_attribute(dataset, seg_tags::segment_sequence, "SegmentSequence", findings);
319 }
320
321 // Validate segmentation type value
322 check_segmentation_type(dataset, findings);
323
324 // Check conditional attributes based on segmentation type
326 auto seg_type = dataset.get_string(seg_tags::segmentation_type);
327
328 if (seg_type == "FRACTIONAL") {
329 // MaxFractionalValue is Type 1 for FRACTIONAL
331 findings.push_back({
334 "MaxFractionalValue (0062,000E) is required when SegmentationType is FRACTIONAL",
335 "SEG-ERR-002"
336 });
337 }
338
339 // SegmentationFractionalType is Type 1 for FRACTIONAL
341 findings.push_back({
344 "SegmentationFractionalType (0062,0010) is required when SegmentationType is FRACTIONAL",
345 "SEG-ERR-003"
346 });
347 }
348 }
349 }
350}
351
353 const dicom_dataset& dataset,
354 std::vector<validation_finding>& findings) const {
355
356 if (!dataset.contains(seg_tags::segment_sequence)) {
357 // Already reported as Type 1 missing
358 return;
359 }
360
361 // Get sequence items
362 const auto* element = dataset.get(seg_tags::segment_sequence);
363 if (!element || !element->is_sequence() || element->sequence_items().empty()) {
364 findings.push_back({
367 "SegmentSequence must contain at least one segment",
368 "SEG-ERR-004"
369 });
370 return;
371 }
372
373 // Validate each segment
374 const auto& sequence = element->sequence_items();
375 for (size_t i = 0; i < sequence.size(); ++i) {
376 const auto& segment_item = sequence[i];
377 validate_single_segment(segment_item, i, findings);
378 }
379}
380
382 const dicom_dataset& segment_item,
383 size_t segment_index,
384 std::vector<validation_finding>& findings) const {
385
386 std::string prefix = "Segment[" + std::to_string(segment_index) + "]: ";
387
388 // Type 1 attributes within segment
389 if (!segment_item.contains(seg_tags::segment_number)) {
390 findings.push_back({
393 prefix + "SegmentNumber (0062,0004) is required",
394 "SEG-SEQ-ERR-001"
395 });
396 }
397
398 if (!segment_item.contains(seg_tags::segment_label)) {
399 findings.push_back({
402 prefix + "SegmentLabel (0062,0005) is required",
403 "SEG-SEQ-ERR-002"
404 });
405 }
406
407 if (!segment_item.contains(seg_tags::segment_algorithm_type)) {
408 findings.push_back({
411 prefix + "SegmentAlgorithmType (0062,0008) is required",
412 "SEG-SEQ-ERR-003"
413 });
415 auto algo_type = segment_item.get_string(seg_tags::segment_algorithm_type);
417 findings.push_back({
420 prefix + "Invalid SegmentAlgorithmType value: " + algo_type,
421 "SEG-SEQ-WARN-001"
422 });
423 }
424 }
425
426 // Segmented Property Category Code Sequence is Type 1
428 findings.push_back({
431 prefix + "SegmentedPropertyCategoryCodeSequence (0062,0003) is required",
432 "SEG-SEQ-ERR-004"
433 });
434 }
435
436 // Segmented Property Type Code Sequence is Type 1
438 findings.push_back({
441 prefix + "SegmentedPropertyTypeCodeSequence (0062,000F) is required",
442 "SEG-SEQ-ERR-005"
443 });
444 }
445
446 // Validate segment label is not empty
448 auto label = segment_item.get_string(seg_tags::segment_label);
449 if (label.empty()) {
450 findings.push_back({
453 prefix + "SegmentLabel should not be empty",
454 "SEG-SEQ-WARN-002"
455 });
456 }
457 }
458}
459
461 const dicom_dataset& dataset,
462 std::vector<validation_finding>& findings) const {
463
464 if (options_.check_type1) {
465 check_type1_attribute(dataset, seg_tags::number_of_frames, "NumberOfFrames", findings);
467 "SharedFunctionalGroupsSequence", findings);
469 "PerFrameFunctionalGroupsSequence", findings);
470 }
471}
472
474 const dicom_dataset& dataset,
475 std::vector<validation_finding>& findings) const {
476
477 if (options_.check_type1) {
479 "DimensionOrganizationSequence", findings);
481 "DimensionIndexSequence", findings);
482 }
483}
484
486 const dicom_dataset& dataset,
487 std::vector<validation_finding>& findings) const {
488
489 // Referenced Series Sequence is Type 1C - required if references exist
492 findings.push_back({
495 "ReferencedSeriesSequence (0008,1115) should be present for source image references",
496 "SEG-REF-WARN-001"
497 });
498 }
499 }
500}
501
503 const dicom_dataset& dataset,
504 std::vector<validation_finding>& findings) const {
505
506 if (options_.check_type1) {
507 check_type1_attribute(dataset, tags::sop_class_uid, "SOPClassUID", findings);
508 check_type1_attribute(dataset, tags::sop_instance_uid, "SOPInstanceUID", findings);
509 }
510
511 // Validate SOP Class UID is a SEG storage class
512 if (dataset.contains(tags::sop_class_uid)) {
513 auto sop_class = dataset.get_string(tags::sop_class_uid);
515 findings.push_back({
518 "SOPClassUID is not a recognized SEG Storage SOP Class: " + sop_class,
519 "SEG-ERR-005"
520 });
521 }
522 }
523}
524
525// =============================================================================
526// Attribute Validation Helpers
527// =============================================================================
528
530 const dicom_dataset& dataset,
531 dicom_tag tag,
532 std::string_view name,
533 std::vector<validation_finding>& findings) const {
534
535 if (!dataset.contains(tag)) {
536 findings.push_back({
538 tag,
539 std::string("Type 1 attribute missing: ") + std::string(name) +
540 " (" + tag.to_string() + ")",
541 "SEG-TYPE1-MISSING"
542 });
543 } else {
544 const auto* element = dataset.get(tag);
545 if (element != nullptr) {
546 // For sequences, check if the sequence has items
547 if (element->is_sequence()) {
548 if (element->sequence_items().empty()) {
549 findings.push_back({
551 tag,
552 std::string("Type 1 sequence has no items: ") +
553 std::string(name) + " (" + tag.to_string() + ")",
554 "SEG-TYPE1-EMPTY"
555 });
556 }
557 } else {
558 // For non-sequence elements, check if the value is empty
559 auto value = dataset.get_string(tag);
560 if (value.empty()) {
561 findings.push_back({
563 tag,
564 std::string("Type 1 attribute has empty value: ") +
565 std::string(name) + " (" + tag.to_string() + ")",
566 "SEG-TYPE1-EMPTY"
567 });
568 }
569 }
570 }
571 }
572}
573
575 const dicom_dataset& dataset,
576 dicom_tag tag,
577 std::string_view name,
578 std::vector<validation_finding>& findings) const {
579
580 if (!dataset.contains(tag)) {
581 findings.push_back({
583 tag,
584 std::string("Type 2 attribute missing: ") + std::string(name) +
585 " (" + tag.to_string() + ")",
586 "SEG-TYPE2-MISSING"
587 });
588 }
589}
590
592 const dicom_dataset& dataset,
593 std::vector<validation_finding>& findings) const {
594
595 if (!dataset.contains(tags::modality)) {
596 return; // Already reported
597 }
598
599 auto modality = dataset.get_string(tags::modality);
600 if (modality != "SEG") {
601 findings.push_back({
604 "Modality must be 'SEG' for Segmentation objects, found: " + modality,
605 "SEG-ERR-001"
606 });
607 }
608}
609
611 const dicom_dataset& dataset,
612 std::vector<validation_finding>& findings) const {
613
615 return; // Already reported
616 }
617
618 auto seg_type = dataset.get_string(seg_tags::segmentation_type);
620 findings.push_back({
623 "Invalid SegmentationType value: " + seg_type + " (must be BINARY or FRACTIONAL)",
624 "SEG-ERR-006"
625 });
626 }
627}
628
630 const dicom_dataset& dataset,
631 std::vector<validation_finding>& findings) const {
632
633 // For SEG, SamplesPerPixel must be 1
634 auto samples = dataset.get_numeric<uint16_t>(tags::samples_per_pixel);
635 if (samples && *samples != 1) {
636 findings.push_back({
639 "SamplesPerPixel must be 1 for Segmentation objects",
640 "SEG-PXL-ERR-001"
641 });
642 }
643
644 // PhotometricInterpretation must be MONOCHROME2
646 auto photometric = dataset.get_string(tags::photometric_interpretation);
647 if (photometric != "MONOCHROME2") {
648 findings.push_back({
651 "PhotometricInterpretation must be MONOCHROME2 for Segmentation",
652 "SEG-PXL-ERR-002"
653 });
654 }
655 }
656
657 // Check BitsAllocated based on SegmentationType
658 auto bits_allocated = dataset.get_numeric<uint16_t>(tags::bits_allocated);
659 auto seg_type = dataset.get_string(seg_tags::segmentation_type);
660
661 if (bits_allocated && !seg_type.empty()) {
662 if (seg_type == "BINARY" && *bits_allocated != 1) {
663 findings.push_back({
666 "BitsAllocated is typically 1 for BINARY segmentation, found: " +
667 std::to_string(*bits_allocated),
668 "SEG-PXL-WARN-001"
669 });
670 }
671
672 if (seg_type == "FRACTIONAL" && *bits_allocated != 8) {
673 findings.push_back({
676 "BitsAllocated is typically 8 for FRACTIONAL segmentation, found: " +
677 std::to_string(*bits_allocated),
678 "SEG-PXL-WARN-002"
679 });
680 }
681 }
682}
683
684// =============================================================================
685// Convenience Functions
686// =============================================================================
687
689 seg_iod_validator validator;
690 return validator.validate(dataset);
691}
692
694 seg_iod_validator validator;
695 return validator.quick_check(dataset);
696}
697
699 constexpr dicom_tag segmentation_type{0x0062, 0x0001};
700 if (!dataset.contains(segmentation_type)) {
701 return false;
702 }
703 return dataset.get_string(segmentation_type) == "BINARY";
704}
705
707 constexpr dicom_tag segmentation_type{0x0062, 0x0001};
708 if (!dataset.contains(segmentation_type)) {
709 return false;
710 }
711 return dataset.get_string(segmentation_type) == "FRACTIONAL";
712}
713
714size_t get_segment_count(const dicom_dataset& dataset) {
715 constexpr dicom_tag segment_sequence{0x0062, 0x0002};
716 const auto* element = dataset.get(segment_sequence);
717 if (element && element->is_sequence()) {
718 return element->sequence_items().size();
719 }
720 return 0;
721}
722
723} // namespace kcenon::pacs::services::validation
auto get(dicom_tag tag) noexcept -> dicom_element *
Get a pointer to the element with the given tag.
auto get_numeric(dicom_tag tag) const -> std::optional< T >
Get the numeric value of an element.
auto contains(dicom_tag tag) const noexcept -> bool
Check if the dataset contains an element with the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
auto to_string() const -> std::string
Convert to string representation.
void validate_segmentation_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_type2_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void check_segmentation_type(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_single_segment(const core::dicom_dataset &segment_item, size_t segment_index, std::vector< validation_finding > &findings) const
void validate_general_image_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_sop_common_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate_references(const core::dicom_dataset &dataset) const
Validate referenced instances.
void validate_general_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
seg_iod_validator()=default
Construct validator with default options.
const seg_validation_options & options() const noexcept
Get the validation options.
void check_modality(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_general_study_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_common_instance_reference_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_patient_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_general_equipment_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_multiframe_functional_groups_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_segment_sequence(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate(const core::dicom_dataset &dataset) const
Validate a DICOM dataset against SEG IOD.
validation_result validate_segments(const core::dicom_dataset &dataset) const
Validate segment sequence completeness.
void validate_enhanced_general_equipment_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void set_options(const seg_validation_options &options)
Set validation options.
void check_pixel_data_consistency(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_image_pixel_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_multiframe_dimension_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_segmentation_image_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool quick_check(const core::dicom_dataset &dataset) const
Quick check if dataset has minimum required attributes.
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
Compile-time constants for commonly used DICOM tags.
constexpr dicom_tag high_bit
High Bit.
constexpr dicom_tag referring_physician_name
Referring Physician's Name.
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 frame_of_reference_uid
Frame of Reference UID.
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr dicom_tag bits_stored
Bits Stored.
constexpr dicom_tag patient_birth_date
Patient's Birth Date.
constexpr dicom_tag pixel_representation
Pixel Representation.
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 photometric_interpretation
Photometric Interpretation.
constexpr dicom_tag sop_class_uid
SOP Class UID.
constexpr dicom_tag study_id
Study ID.
constexpr dicom_tag patient_name
Patient's Name.
constexpr dicom_tag study_date
Study Date.
constexpr dicom_tag series_instance_uid
Series Instance UID.
segment_algorithm_type
Segment algorithm type (0062,0008)
bool is_valid_segmentation_type(std::string_view value) noexcept
Check if segmentation type string is valid.
bool is_valid_segment_algorithm_type(std::string_view value) noexcept
Check if segment algorithm type string is valid.
segmentation_type
Segmentation type (0062,0001)
Definition seg_storage.h:79
bool is_seg_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a SEG Storage SOP Class.
segmentation_fractional_type
Segmentation fractional type (0062,0010)
constexpr dicom_tag studies_containing_other_referenced_instances_sequence
bool is_fractional_segmentation(const core::dicom_dataset &dataset)
Check if dataset is fractional segmentation.
bool is_binary_segmentation(const core::dicom_dataset &dataset)
Check if dataset is binary segmentation.
validation_result validate_seg_iod(const core::dicom_dataset &dataset)
Validate a SEG dataset with default options.
@ warning
Non-critical - IOD may have issues.
size_t get_segment_count(const core::dicom_dataset &dataset)
Get segment count from dataset.
bool is_valid_seg_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid SEG object.
Segmentation IOD Validator.
Segmentation (SEG) Storage SOP Classes.
bool validate_segment_labels
Validate segment labels and descriptions.
bool validate_pixel_data
Validate pixel data matches segmentation type.
bool check_type1
Check Type 1 (required) attributes.
bool validate_segment_sequence
Validate Segment Sequence structure.
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.
bool validate_references
Validate referenced series/instances.
bool strict_mode
Strict mode - treat warnings as errors.
bool check_type2
Check Type 2 (required, can be empty) attributes.
bool validate_algorithm_info
Validate segment algorithm identification.
std::vector< validation_finding > findings
All findings during validation.
std::string_view name