90 : options_(options) {}
100 "SOPClassUID is required to determine SR type",
142 for (
const auto& finding : result.
findings) {
175 for (
const auto& finding : result.
findings) {
213 for (
const auto& finding : result.
findings) {
251 "CurrentRequestedProcedureEvidenceSequence is required for Key Object Selection",
257 for (
const auto& finding : result.
findings) {
278 for (
const auto& finding : result.
findings) {
295 for (
const auto& finding : result.
findings) {
317 if (modality !=
"SR")
return false;
352 std::vector<validation_finding>& findings)
const {
364 std::vector<validation_finding>& findings)
const {
381 std::vector<validation_finding>& findings)
const {
396 std::vector<validation_finding>& findings)
const {
398 constexpr dicom_tag manufacturer{0x0008, 0x0070};
406 std::vector<validation_finding>& findings)
const {
432 "VerifyingObserverSequence is required when VerificationFlag is VERIFIED",
441 std::vector<validation_finding>& findings)
const {
452 if (value_type !=
"CONTAINER") {
456 "Root content item ValueType must be CONTAINER, found: " + value_type,
465 if (concept_elem && concept_elem->is_sequence() && !concept_elem->sequence_items().empty()) {
478 std::vector<validation_finding>& findings)
const {
492 "SOPClassUID is not a recognized SR Storage SOP Class: " + sop_class,
501 std::vector<validation_finding>& findings)
const {
511 "No evidence sequences present - SR may not properly link to source images",
512 "SR-EVIDENCE-INFO-001"
519 std::vector<validation_finding>& findings)
const {
525 "ContentSequence not present - SR document has no content items",
526 "SR-CONTENT-INFO-001"
532 if (!content_elem || !content_elem->is_sequence() || content_elem->sequence_items().empty()) {
536 "ContentSequence is empty",
537 "SR-CONTENT-INFO-002"
546 const auto& content_seq = content_elem->sequence_items();
547 for (
size_t i = 0; i < content_seq.size(); ++i) {
555 [[maybe_unused]] std::string_view parent_value_type,
556 std::vector<validation_finding>& findings)
const {
563 "Content tree depth exceeds 100 - possible circular reference",
564 "SR-CONTENT-WARN-001"
574 "RelationshipType missing in content item at depth " + std::to_string(depth),
583 "ValueType missing in content item at depth " + std::to_string(depth),
596 "Invalid ValueType: " + value_type,
629 if (nested_elem && nested_elem->is_sequence()) {
630 const auto& nested_seq = nested_elem->sequence_items();
631 for (
size_t i = 0; i < nested_seq.size(); ++i) {
640 std::string_view context,
641 std::vector<validation_finding>& findings)
const {
648 std::string(context) +
": CodeValue is required",
658 std::string(context) +
": CodingSchemeDesignator is required",
668 std::string(context) +
": CodeMeaning is required",
676 std::vector<validation_finding>& findings)
const {
682 "TextValue is required for TEXT content item",
690 std::vector<validation_finding>& findings)
const {
696 "ConceptNameCodeSequence is required for CODE content item",
697 "SR-CODE-ITEM-ERR-001"
704 std::vector<validation_finding>& findings)
const {
710 "MeasuredValueSequence is required for NUM content item",
717 if (measured_elem && measured_elem->is_sequence() && !measured_elem->sequence_items().empty()) {
718 const auto& mv_item = measured_elem->sequence_items()[0];
724 "NumericValue is required in MeasuredValueSequence",
733 "MeasurementUnitsCodeSequence is required in MeasuredValueSequence",
742 std::vector<validation_finding>& findings)
const {
748 "ReferencedSOPSequence is required for IMAGE content item",
755 if (ref_elem && ref_elem->is_sequence() && !ref_elem->sequence_items().empty()) {
756 const auto& ref_item = ref_elem->sequence_items()[0];
762 "ReferencedSOPClassUID is required in IMAGE reference",
771 "ReferencedSOPInstanceUID is required in IMAGE reference",
780 std::vector<validation_finding>& findings)
const {
786 "GraphicType is required for SCOORD content item",
795 "GraphicData is required for SCOORD content item",
803 std::vector<validation_finding>& findings)
const {
809 "GraphicType is required for SCOORD3D content item",
810 "SR-SCOORD3D-ERR-001"
818 "GraphicData is required for SCOORD3D content item",
819 "SR-SCOORD3D-ERR-002"
827 "ReferencedFrameOfReferenceUID is required for SCOORD3D content item",
828 "SR-SCOORD3D-ERR-003"
840 std::string_view
name,
841 std::vector<validation_finding>& findings)
const {
847 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
852 const auto* element = dataset.
get(tag);
853 if (element !=
nullptr) {
855 if (element->is_sequence()) {
856 if (element->sequence_items().empty()) {
860 std::string(
"Type 1 sequence has no items: ") +
872 std::string(
"Type 1 attribute has empty value: ") +
885 std::string_view
name,
886 std::vector<validation_finding>& findings)
const {
892 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
901 std::vector<validation_finding>& findings)
const {
908 if (modality !=
"SR") {
912 "Modality must be 'SR' for Structured Report objects, found: " + modality,
920 std::vector<validation_finding>& findings)
const {
927 if (flag !=
"PARTIAL" && flag !=
"COMPLETE") {
931 "Invalid CompletionFlag value: " + flag +
" (must be PARTIAL or COMPLETE)",
939 std::vector<validation_finding>& findings)
const {
946 if (flag !=
"UNVERIFIED" && flag !=
"VERIFIED") {
950 "Invalid VerificationFlag value: " + flag +
" (must be UNVERIFIED or VERIFIED)",
971 constexpr dicom_tag completion_flag{0x0040, 0xA491};
972 if (!dataset.
contains(completion_flag)) {
975 return dataset.
get_string(completion_flag) ==
"COMPLETE";
979 constexpr dicom_tag verification_flag{0x0040, 0xA493};
980 if (!dataset.
contains(verification_flag)) {
983 return dataset.
get_string(verification_flag) ==
"VERIFIED";
987 constexpr dicom_tag content_sequence{0x0040, 0xA730};
988 const auto* element = dataset.
get(content_sequence);
989 if (element && element->is_sequence()) {
990 return element->sequence_items().size();
996 constexpr dicom_tag concept_name_code_sequence{0x0040, 0xA043};
997 constexpr dicom_tag code_meaning{0x0008, 0x0104};
999 const auto* element = dataset.
get(concept_name_code_sequence);
1000 if (element && element->is_sequence() && !element->sequence_items().empty()) {
1001 const auto& item = element->sequence_items()[0];
1002 if (item.contains(code_meaning)) {
1003 return item.get_string(code_meaning);
auto get(dicom_tag tag) noexcept -> dicom_element *
Get a pointer to the element with the given tag.
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_image_content_item(const core::dicom_dataset &item, std::vector< validation_finding > &findings) const
sr_iod_validator()=default
Construct validator with default options.
const sr_validation_options & options() const noexcept
Get the validation options.
void check_verification_flag(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_num_content_item(const core::dicom_dataset &item, std::vector< validation_finding > &findings) const
validation_result validate(const core::dicom_dataset &dataset) const
Validate a DICOM dataset against SR IOD.
void validate_coded_entry(const core::dicom_dataset &coded_entry, std::string_view context, std::vector< validation_finding > &findings) const
validation_result validate_key_object_selection(const core::dicom_dataset &dataset) const
Validate a Key Object Selection document.
void validate_text_content_item(const core::dicom_dataset &item, std::vector< validation_finding > &findings) const
void set_options(const sr_validation_options &options)
Set validation options.
void validate_evidence_sequences(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 validate_scoord_content_item(const core::dicom_dataset &item, 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_modality(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate_content_tree(const core::dicom_dataset &dataset) const
Validate content tree structure.
void validate_patient_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_content_item(const core::dicom_dataset &item, size_t depth, std::string_view parent_value_type, std::vector< validation_finding > &findings) const
void validate_code_content_item(const core::dicom_dataset &item, std::vector< validation_finding > &findings) const
void validate_scoord3d_content_item(const core::dicom_dataset &item, 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_basic_text_sr(const core::dicom_dataset &dataset) const
Validate a Basic Text SR dataset.
void validate_content_sequence(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_completion_flag(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_sr_document_general_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate_comprehensive_sr(const core::dicom_dataset &dataset) const
Validate a Comprehensive SR dataset.
void validate_sr_document_content_module(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
validation_result validate_references(const core::dicom_dataset &dataset) const
Validate referenced instances.
void validate_sr_document_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate_enhanced_sr(const core::dicom_dataset &dataset) const
Validate an Enhanced SR dataset.
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void validate_general_equipment_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
sr_validation_options options_
Compile-time constants for commonly used DICOM tags.
sr_document_type get_sr_document_type(std::string_view uid) noexcept
Get SR document type for a SOP Class UID.
bool is_sr_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is an SR Storage SOP Class.
@ enhanced
Enhanced SR - References to images/waveforms.
@ comprehensive
Comprehensive SR - Complex with spatial coords.
@ comprehensive_3d
Comprehensive 3D SR - 3D spatial coordinates.
@ basic_text
Basic Text SR - Simple text reports.
@ key_object_selection
Key Object Selection - Image selection.
sr_value_type parse_sr_value_type(std::string_view value) noexcept
Parse SR value type from DICOM string.
@ num
NUM - Numeric measurement.
@ scoord
SCOORD - Spatial coordinates (2D)
@ image
IMAGE - Reference to image.
@ unknown
Unknown value type.
@ code
CODE - Coded entry.
@ scoord3d
SCOORD3D - Spatial coordinates (3D)
size_t get_content_item_count(const core::dicom_dataset &dataset)
Get content item count from dataset.
bool is_sr_complete(const core::dicom_dataset &dataset)
Check if SR document is complete.
validation_result validate_sr_iod(const core::dicom_dataset &dataset)
Validate an SR dataset with default options.
bool is_sr_verified(const core::dicom_dataset &dataset)
Check if SR document is verified.
std::string get_sr_document_title(const core::dicom_dataset &dataset)
Get SR document title from Concept Name Code Sequence.
@ warning
Non-critical - IOD may have issues.
@ info
Informational - suggestion for improvement.
@ error
Critical - IOD is non-compliant.
bool is_valid_sr_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid SR document.
Structured Report IOD Validator.
Structured Report (SR) Storage SOP Classes.
Options for SR IOD validation.
bool validate_key_object_selection
Allow Key Object Selection document specific validation.
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.
bool validate_coded_entries
Validate coded entries (concept name codes, etc.)
bool strict_mode
Strict mode - treat warnings as errors.
bool validate_value_types
Validate content item value types.
bool check_type1
Check Type 1 (required) attributes.
bool validate_references
Validate referenced SOP instances.
bool validate_content_sequence
Validate Content Sequence structure.
bool validate_document_status
Validate completion and verification flags.
bool check_type2
Check Type 2 (required, can be empty) attributes.
Result of IOD validation.
std::vector< validation_finding > findings
All findings during validation.
bool is_valid
Overall validation status.