82 : options_(options) {}
118 for (
const auto& finding : result.
findings) {
139 for (
const auto& finding : result.
findings) {
156 for (
const auto& finding : result.
findings) {
178 if (modality !=
"SEG")
return false;
209 std::vector<validation_finding>& findings)
const {
221 std::vector<validation_finding>& findings)
const {
238 std::vector<validation_finding>& findings)
const {
256 [[maybe_unused]] std::vector<validation_finding>& findings)
const {
264 std::vector<validation_finding>& findings)
const {
273 std::vector<validation_finding>& findings)
const {
285 std::vector<validation_finding>& findings)
const {
288 constexpr dicom_tag instance_number{0x0020, 0x0013};
295 std::vector<validation_finding>& findings)
const {
314 std::vector<validation_finding>& findings)
const {
328 if (seg_type ==
"FRACTIONAL") {
334 "MaxFractionalValue (0062,000E) is required when SegmentationType is FRACTIONAL",
344 "SegmentationFractionalType (0062,0010) is required when SegmentationType is FRACTIONAL",
354 std::vector<validation_finding>& findings)
const {
363 if (!element || !element->is_sequence() || element->sequence_items().empty()) {
367 "SegmentSequence must contain at least one 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];
383 size_t segment_index,
384 std::vector<validation_finding>& findings)
const {
386 std::string prefix =
"Segment[" + std::to_string(segment_index) +
"]: ";
393 prefix +
"SegmentNumber (0062,0004) is required",
402 prefix +
"SegmentLabel (0062,0005) is required",
411 prefix +
"SegmentAlgorithmType (0062,0008) is required",
420 prefix +
"Invalid SegmentAlgorithmType value: " + algo_type,
431 prefix +
"SegmentedPropertyCategoryCodeSequence (0062,0003) is required",
441 prefix +
"SegmentedPropertyTypeCodeSequence (0062,000F) is required",
453 prefix +
"SegmentLabel should not be empty",
462 std::vector<validation_finding>& findings)
const {
467 "SharedFunctionalGroupsSequence", findings);
469 "PerFrameFunctionalGroupsSequence", findings);
475 std::vector<validation_finding>& findings)
const {
479 "DimensionOrganizationSequence", findings);
481 "DimensionIndexSequence", findings);
487 std::vector<validation_finding>& findings)
const {
495 "ReferencedSeriesSequence (0008,1115) should be present for source image references",
504 std::vector<validation_finding>& findings)
const {
518 "SOPClassUID is not a recognized SEG Storage SOP Class: " + sop_class,
532 std::string_view
name,
533 std::vector<validation_finding>& findings)
const {
539 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
544 const auto* element = dataset.
get(tag);
545 if (element !=
nullptr) {
547 if (element->is_sequence()) {
548 if (element->sequence_items().empty()) {
552 std::string(
"Type 1 sequence has no items: ") +
564 std::string(
"Type 1 attribute has empty value: ") +
577 std::string_view
name,
578 std::vector<validation_finding>& findings)
const {
584 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
593 std::vector<validation_finding>& findings)
const {
600 if (modality !=
"SEG") {
604 "Modality must be 'SEG' for Segmentation objects, found: " + modality,
612 std::vector<validation_finding>& findings)
const {
623 "Invalid SegmentationType value: " + seg_type +
" (must be BINARY or FRACTIONAL)",
631 std::vector<validation_finding>& findings)
const {
635 if (samples && *samples != 1) {
639 "SamplesPerPixel must be 1 for Segmentation objects",
647 if (photometric !=
"MONOCHROME2") {
651 "PhotometricInterpretation must be MONOCHROME2 for Segmentation",
661 if (bits_allocated && !seg_type.empty()) {
662 if (seg_type ==
"BINARY" && *bits_allocated != 1) {
666 "BitsAllocated is typically 1 for BINARY segmentation, found: " +
667 std::to_string(*bits_allocated),
672 if (seg_type ==
"FRACTIONAL" && *bits_allocated != 8) {
676 "BitsAllocated is typically 8 for FRACTIONAL segmentation, found: " +
677 std::to_string(*bits_allocated),
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();
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_validation_options options_
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.
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)
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)
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.
@ error
Critical - IOD is non-compliant.
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.
Options for SEG IOD validation.
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.
Result of IOD validation.
std::vector< validation_finding > findings
All findings during validation.
bool is_valid
Overall validation status.