PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::services::validation::mg_iod_validator Class Reference

Validator for Digital Mammography X-Ray Image IODs. More...

#include <mg_iod_validator.h>

Collaboration diagram for kcenon::pacs::services::validation::mg_iod_validator:
Collaboration graph

Public Member Functions

 mg_iod_validator ()=default
 Construct validator with default options.
 
 mg_iod_validator (const mg_validation_options &options)
 Construct validator with custom options.
 
validation_result validate (const core::dicom_dataset &dataset) const
 Validate a DICOM dataset against Mammography IOD.
 
validation_result validate_for_presentation (const core::dicom_dataset &dataset) const
 Validate a For Presentation mammography dataset.
 
validation_result validate_for_processing (const core::dicom_dataset &dataset) const
 Validate a For Processing mammography dataset.
 
validation_result validate_laterality (const core::dicom_dataset &dataset) const
 Validate breast laterality attribute.
 
validation_result validate_view_position (const core::dicom_dataset &dataset) const
 Validate mammography view position.
 
validation_result validate_compression_force (const core::dicom_dataset &dataset) const
 Validate compression force.
 
bool quick_check (const core::dicom_dataset &dataset) const
 Quick check if dataset has minimum required attributes.
 
const mg_validation_options & options () const noexcept
 Get the validation options.
 
void set_options (const mg_validation_options &options)
 Set validation options.
 

Private Member Functions

void validate_patient_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
 
void validate_general_series_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_mammography_series_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_mammography_image_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_dx_anatomy_imaged_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_dx_detector_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_acquisition_dose_module (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_voi_lut_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
 
void validate_breast_implant_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void check_type1_attribute (const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, 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_modality (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void check_laterality_consistency (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void check_view_position_validity (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void check_compression_force_range (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void check_pixel_data_consistency (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void check_photometric_interpretation (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 

Private Attributes

mg_validation_options options_
 

Detailed Description

Validator for Digital Mammography X-Ray Image IODs.

Validates DICOM datasets against the Digital Mammography X-Ray Image IOD specification. This validator extends standard DX validation with mammography-specific requirements.

Validated Modules

Mandatory Modules (M)

  • Patient Module
  • General Study Module
  • Patient Study Module
  • General Series Module
  • General Equipment Module
  • General Image Module
  • Image Pixel Module
  • DX Anatomy Imaged Module (with breast-specific requirements)
  • Mammography Image Module
  • DX Detector Module
  • SOP Common Module

Mammography-Specific Modules (M/C)

  • Mammography Series Module (M)
  • Mammography Image Module (M) - includes laterality, view position
  • X-Ray Acquisition Dose Module (C) - compression force, dose
  • Breast Implant Module (C) - if implants present

Conditional Modules (C)

  • DX Positioning Module
  • VOI LUT Module (For Presentation images)

Mammography-Specific Validations

  1. Breast Laterality (0020,0060):
    • Must be L, R, or B
    • Should match Image Laterality (0020,0062) if present
  2. View Position (0018,5101):
    • Must be valid mammography view code (CC, MLO, ML, LM, etc.)
    • View Code Sequence (0054,0220) preferred for coded values
  3. Compression Force (0018,11A2):
    • Validated against typical range (50-200 N)
    • Warning if outside normal range
Example:
mg_iod_validator validator;
auto result = validator.validate(dataset);
if (!result.is_valid) {
for (const auto& finding : result.findings) {
if (finding.code.starts_with("MG-")) {
// Mammography-specific issue
std::cerr << finding.code << ": " << finding.message << "\n";
}
}
}
Validator for Digital Mammography X-Ray Image IODs.
validation_result validate(const core::dicom_dataset &dataset) const
Validate a DICOM dataset against Mammography IOD.

Definition at line 162 of file mg_iod_validator.h.

Constructor & Destructor Documentation

◆ mg_iod_validator() [1/2]

kcenon::pacs::services::validation::mg_iod_validator::mg_iod_validator ( )
default

Construct validator with default options.

◆ mg_iod_validator() [2/2]

kcenon::pacs::services::validation::mg_iod_validator::mg_iod_validator ( const mg_validation_options & options)
explicit

Construct validator with custom options.

Parameters
optionsValidation options

Definition at line 87 of file mg_iod_validator.cpp.

88 : options_(options) {}
const mg_validation_options & options() const noexcept
Get the validation options.

Member Function Documentation

◆ check_compression_force_range()

void kcenon::pacs::services::validation::mg_iod_validator::check_compression_force_range ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 866 of file mg_iod_validator.cpp.

868 {
869
870 if (!dataset.contains(mg_tags::compression_force)) {
871 // Compression force is Type 3 but important for mammography QC
872 findings.push_back({
875 "Compression Force (0018,11A2) is not present. "
876 "This information is valuable for quality control and patient safety.",
877 "MG-INFO-008"
878 });
879 return;
880 }
881
882 auto force = dataset.get_numeric<double>(mg_tags::compression_force);
883 if (!force) {
884 findings.push_back({
887 "Compression Force is present but could not be parsed as a number.",
888 "MG-WARN-012"
889 });
890 return;
891 }
892
893 auto [min_typical, max_typical] = get_typical_compression_force_range();
894
895 if (!is_valid_compression_force(*force)) {
896 findings.push_back({
899 "Compression Force (" + std::to_string(*force) +
900 " N) is outside the typical range (20-300 N). "
901 "This may indicate a measurement error or non-standard technique.",
902 "MG-WARN-013"
903 });
904 } else if (*force < min_typical || *force > max_typical) {
905 findings.push_back({
908 "Compression Force (" + std::to_string(*force) +
909 " N) is outside the typical screening range (" +
910 std::to_string(min_typical) + "-" + std::to_string(max_typical) + " N).",
911 "MG-INFO-009"
912 });
913 }
914}
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.
std::pair< double, double > get_typical_compression_force_range() noexcept
Get typical compression force range.
bool is_valid_compression_force(double force_n) noexcept
Validate compression force value.
@ warning
Non-critical - IOD may have issues.
@ info
Informational - suggestion for improvement.

References kcenon::pacs::services::validation::mg_tags::compression_force, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_numeric(), kcenon::pacs::services::sop_classes::get_typical_compression_force_range(), kcenon::pacs::services::validation::info, kcenon::pacs::services::sop_classes::is_valid_compression_force(), and kcenon::pacs::services::validation::warning.

Referenced by validate_acquisition_dose_module(), and validate_compression_force().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_laterality_consistency()

void kcenon::pacs::services::validation::mg_iod_validator::check_laterality_consistency ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 734 of file mg_iod_validator.cpp.

736 {
737
738 // Check Laterality (0020,0060) - Series level
739 bool has_series_laterality = dataset.contains(mg_tags::laterality);
740 // Check Image Laterality (0020,0062) - Image level
741 bool has_image_laterality = dataset.contains(mg_tags::image_laterality);
742
743 // At least one should be present for mammography
744 if (!has_series_laterality && !has_image_laterality) {
745 findings.push_back({
748 "Neither Laterality (0020,0060) nor Image Laterality (0020,0062) is present. "
749 "Breast laterality must be specified for mammography images.",
750 "MG-ERR-003"
751 });
752 return;
753 }
754
755 // Validate Laterality value if present
756 if (has_series_laterality) {
757 auto lat = dataset.get_string(mg_tags::laterality);
758 if (!is_valid_breast_laterality(lat)) {
759 findings.push_back({
762 "Invalid Laterality value: '" + lat +
763 "'. Must be 'L' (left), 'R' (right), or 'B' (bilateral).",
764 "MG-ERR-004"
765 });
766 }
767 }
768
769 // Validate Image Laterality value if present
770 if (has_image_laterality) {
771 auto img_lat = dataset.get_string(mg_tags::image_laterality);
772 if (!is_valid_breast_laterality(img_lat)) {
773 findings.push_back({
776 "Invalid Image Laterality value: '" + img_lat +
777 "'. Must be 'L' (left), 'R' (right), or 'B' (bilateral).",
778 "MG-ERR-005"
779 });
780 }
781 }
782
783 // Check consistency between series and image laterality if both present
784 if (has_series_laterality && has_image_laterality) {
785 auto series_lat = dataset.get_string(mg_tags::laterality);
786 auto image_lat = dataset.get_string(mg_tags::image_laterality);
787
788 if (series_lat != image_lat) {
789 findings.push_back({
792 "Laterality mismatch: Series Laterality is '" + series_lat +
793 "' but Image Laterality is '" + image_lat + "'.",
794 "MG-WARN-001"
795 });
796 }
797 }
798}
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
bool is_valid_breast_laterality(std::string_view value) noexcept
Check if a laterality value is valid for mammography.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::mg_tags::image_laterality, kcenon::pacs::services::sop_classes::is_valid_breast_laterality(), kcenon::pacs::services::validation::mg_tags::laterality, and kcenon::pacs::services::validation::warning.

Referenced by validate_laterality(), and validate_mammography_image_module().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_modality()

void kcenon::pacs::services::validation::mg_iod_validator::check_modality ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 715 of file mg_iod_validator.cpp.

717 {
718
719 if (!dataset.contains(tags::modality)) {
720 return; // Already reported as Type 1 missing
721 }
722
723 auto modality = dataset.get_string(tags::modality);
724 if (modality != "MG") {
725 findings.push_back({
728 "Modality must be 'MG' for mammography images, found: " + modality,
729 "MG-ERR-002"
730 });
731 }
732}
constexpr dicom_tag modality
Modality.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), and kcenon::pacs::core::tags::modality.

Referenced by validate_general_series_module().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_photometric_interpretation()

void kcenon::pacs::services::validation::mg_iod_validator::check_photometric_interpretation ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 975 of file mg_iod_validator.cpp.

977 {
978
980 return; // Already reported as missing
981 }
982
983 auto photometric = dataset.get_string(tags::photometric_interpretation);
984 if (photometric != "MONOCHROME1" && photometric != "MONOCHROME2") {
985 findings.push_back({
988 "Mammography images must use MONOCHROME1 or MONOCHROME2, found: " + photometric,
989 "MG-ERR-008"
990 });
991 }
992}
constexpr dicom_tag photometric_interpretation
Photometric Interpretation.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), and kcenon::pacs::core::tags::photometric_interpretation.

Referenced by validate_image_pixel_module().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_pixel_data_consistency()

void kcenon::pacs::services::validation::mg_iod_validator::check_pixel_data_consistency ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 916 of file mg_iod_validator.cpp.

918 {
919
920 // Check BitsStored <= BitsAllocated
921 auto bits_allocated = dataset.get_numeric<uint16_t>(tags::bits_allocated);
922 auto bits_stored = dataset.get_numeric<uint16_t>(tags::bits_stored);
923 auto high_bit = dataset.get_numeric<uint16_t>(tags::high_bit);
924
925 if (bits_allocated && bits_stored) {
926 if (*bits_stored > *bits_allocated) {
927 findings.push_back({
930 "BitsStored (" + std::to_string(*bits_stored) +
931 ") exceeds BitsAllocated (" + std::to_string(*bits_allocated) + ")",
932 "MG-ERR-006"
933 });
934 }
935
936 // Mammography typically uses 12-16 bits stored for high dynamic range
937 if (*bits_stored < 12 || *bits_stored > 16) {
938 findings.push_back({
941 "Mammography images typically use 12-16 bits, found: " +
942 std::to_string(*bits_stored),
943 "MG-INFO-010"
944 });
945 }
946 }
947
948 // Check HighBit == BitsStored - 1
949 if (bits_stored && high_bit) {
950 if (*high_bit != *bits_stored - 1) {
951 findings.push_back({
954 "HighBit (" + std::to_string(*high_bit) +
955 ") should typically be BitsStored - 1 (" +
956 std::to_string(*bits_stored - 1) + ")",
957 "MG-WARN-014"
958 });
959 }
960 }
961
962 // Mammography must be grayscale - check SamplesPerPixel
963 auto samples = dataset.get_numeric<uint16_t>(tags::samples_per_pixel);
964 if (samples && *samples != 1) {
965 findings.push_back({
968 "Mammography images must be grayscale (SamplesPerPixel = 1), found: " +
969 std::to_string(*samples),
970 "MG-ERR-007"
971 });
972 }
973}
constexpr dicom_tag high_bit
High Bit.
constexpr dicom_tag bits_allocated
Bits Allocated.
constexpr dicom_tag bits_stored
Bits Stored.
constexpr dicom_tag samples_per_pixel
Samples per Pixel.

References kcenon::pacs::core::tags::bits_allocated, kcenon::pacs::core::tags::bits_stored, kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_numeric(), kcenon::pacs::core::tags::high_bit, kcenon::pacs::services::validation::info, kcenon::pacs::core::tags::samples_per_pixel, and kcenon::pacs::services::validation::warning.

Referenced by validate_image_pixel_module().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_type1_attribute()

void kcenon::pacs::services::validation::mg_iod_validator::check_type1_attribute ( const core::dicom_dataset & dataset,
core::dicom_tag tag,
std::string_view name,
std::vector< validation_finding > & findings ) const
private

Definition at line 668 of file mg_iod_validator.cpp.

672 {
673
674 if (!dataset.contains(tag)) {
675 findings.push_back({
677 tag,
678 std::string("Type 1 attribute missing: ") + std::string(name) +
679 " (" + tag.to_string() + ")",
680 "MG-TYPE1-MISSING"
681 });
682 } else {
683 // Type 1 must have a value (cannot be empty)
684 auto value = dataset.get_string(tag);
685 if (value.empty()) {
686 findings.push_back({
688 tag,
689 std::string("Type 1 attribute has empty value: ") +
690 std::string(name) + " (" + tag.to_string() + ")",
691 "MG-TYPE1-EMPTY"
692 });
693 }
694 }
695}
auto to_string() const -> std::string
Convert to string representation.
std::string_view name

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), name, and kcenon::pacs::core::dicom_tag::to_string().

Referenced by validate_dx_detector_module(), validate_general_series_module(), validate_general_study_module(), validate_image_pixel_module(), validate_mammography_image_module(), and validate_sop_common_module().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_type2_attribute()

void kcenon::pacs::services::validation::mg_iod_validator::check_type2_attribute ( const core::dicom_dataset & dataset,
core::dicom_tag tag,
std::string_view name,
std::vector< validation_finding > & findings ) const
private

Definition at line 697 of file mg_iod_validator.cpp.

701 {
702
703 // Type 2 must be present but can be empty
704 if (!dataset.contains(tag)) {
705 findings.push_back({
707 tag,
708 std::string("Type 2 attribute missing: ") + std::string(name) +
709 " (" + tag.to_string() + ")",
710 "MG-TYPE2-MISSING"
711 });
712 }
713}

References kcenon::pacs::core::dicom_dataset::contains(), name, kcenon::pacs::core::dicom_tag::to_string(), and kcenon::pacs::services::validation::warning.

Referenced by validate_dx_anatomy_imaged_module(), validate_dx_detector_module(), validate_general_series_module(), validate_general_study_module(), and validate_patient_module().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_view_position_validity()

void kcenon::pacs::services::validation::mg_iod_validator::check_view_position_validity ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 800 of file mg_iod_validator.cpp.

802 {
803
804 // View Position (0018,5101) - Type 2 for mammography
805 if (!dataset.contains(mg_tags::view_position)) {
806 findings.push_back({
809 "View Position (0018,5101) is not present. "
810 "This attribute should be specified for mammography images.",
811 "MG-WARN-005"
812 });
813 return;
814 }
815
816 auto view_str = dataset.get_string(mg_tags::view_position);
817 if (view_str.empty()) {
818 findings.push_back({
821 "View Position is present but empty.",
822 "MG-WARN-006"
823 });
824 return;
825 }
826
827 // Parse and validate view position
828 auto view = parse_mg_view_position(view_str);
829 if (view == mg_view_position::other) {
830 // Check if it's a valid view we just don't recognize
831 auto valid_views = get_valid_mg_view_positions();
832 std::string valid_list;
833 for (size_t i = 0; i < valid_views.size(); ++i) {
834 if (i > 0) valid_list += ", ";
835 valid_list += std::string(valid_views[i]);
836 }
837
838 findings.push_back({
841 "Unrecognized View Position: '" + view_str +
842 "'. Common mammography views include: " + valid_list,
843 "MG-WARN-010"
844 });
845 }
846
847 // Additional validation: check laterality-view consistency
849 auto lat_str = dataset.contains(mg_tags::image_laterality)
852
853 auto laterality = parse_breast_laterality(lat_str);
854
855 if (!is_valid_laterality_view_combination(laterality, view)) {
856 findings.push_back({
859 "Unusual laterality-view combination: " + lat_str + " / " + view_str,
860 "MG-WARN-011"
861 });
862 }
863 }
864}
mg_view_position parse_mg_view_position(std::string_view value) noexcept
Parse DICOM view position string to mammography view enum.
bool is_valid_laterality_view_combination(breast_laterality laterality, mg_view_position view) noexcept
Check if laterality and view position are consistent.
breast_laterality parse_breast_laterality(std::string_view value) noexcept
Parse DICOM laterality string to enum.
std::vector< std::string_view > get_valid_mg_view_positions() noexcept
Get all valid mammography view position strings.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::sop_classes::get_valid_mg_view_positions(), kcenon::pacs::services::validation::mg_tags::image_laterality, kcenon::pacs::services::sop_classes::is_valid_laterality_view_combination(), kcenon::pacs::services::validation::mg_tags::laterality, kcenon::pacs::services::sop_classes::parse_breast_laterality(), kcenon::pacs::services::sop_classes::parse_mg_view_position(), kcenon::pacs::services::validation::mg_tags::view_position, and kcenon::pacs::services::validation::warning.

Referenced by validate_mammography_image_module(), and validate_view_position().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ options()

const mg_validation_options & kcenon::pacs::services::validation::mg_iod_validator::options ( ) const
nodiscardnoexcept

Get the validation options.

Definition at line 307 of file mg_iod_validator.cpp.

307 {
308 return options_;
309}

References options_.

Referenced by set_options().

Here is the caller graph for this function:

◆ quick_check()

bool kcenon::pacs::services::validation::mg_iod_validator::quick_check ( const core::dicom_dataset & dataset) const
nodiscard

Quick check if dataset has minimum required attributes.

Faster than full validation - only checks critical Type 1 attributes and mammography-specific requirements.

Parameters
datasetThe dataset to check
Returns
true if all critical attributes are present

Definition at line 269 of file mg_iod_validator.cpp.

269 {
270 // Check only critical Type 1 attributes for quick validation
271
272 // General Study Module Type 1
273 if (!dataset.contains(tags::study_instance_uid)) return false;
274
275 // General Series Module Type 1
276 if (!dataset.contains(tags::modality)) return false;
277 if (!dataset.contains(tags::series_instance_uid)) return false;
278
279 // Check modality is MG
280 auto modality = dataset.get_string(tags::modality);
281 if (modality != "MG") return false;
282
283 // Image Pixel Module Type 1
284 if (!dataset.contains(tags::samples_per_pixel)) return false;
285 if (!dataset.contains(tags::photometric_interpretation)) return false;
286 if (!dataset.contains(tags::rows)) return false;
287 if (!dataset.contains(tags::columns)) return false;
288 if (!dataset.contains(tags::bits_allocated)) return false;
289 if (!dataset.contains(tags::bits_stored)) return false;
290 if (!dataset.contains(tags::high_bit)) return false;
291 if (!dataset.contains(tags::pixel_representation)) return false;
292 if (!dataset.contains(tags::pixel_data)) return false;
293
294 // SOP Common Module Type 1
295 if (!dataset.contains(tags::sop_class_uid)) return false;
296 if (!dataset.contains(tags::sop_instance_uid)) return false;
297
298 // Mammography-specific: Laterality should be present
299 if (!dataset.contains(mg_tags::laterality) &&
301 return false;
302 }
303
304 return true;
305}
constexpr dicom_tag rows
Rows.
constexpr dicom_tag columns
Columns.
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr dicom_tag pixel_data
Pixel Data.
constexpr dicom_tag pixel_representation
Pixel Representation.
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag sop_class_uid
SOP Class UID.
constexpr dicom_tag series_instance_uid
Series Instance UID.

References kcenon::pacs::core::tags::bits_allocated, kcenon::pacs::core::tags::bits_stored, kcenon::pacs::core::tags::columns, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::core::tags::high_bit, kcenon::pacs::services::validation::mg_tags::image_laterality, kcenon::pacs::services::validation::mg_tags::laterality, kcenon::pacs::core::tags::modality, kcenon::pacs::core::tags::photometric_interpretation, kcenon::pacs::core::tags::pixel_data, kcenon::pacs::core::tags::pixel_representation, kcenon::pacs::core::tags::rows, kcenon::pacs::core::tags::samples_per_pixel, kcenon::pacs::core::tags::series_instance_uid, kcenon::pacs::core::tags::sop_class_uid, kcenon::pacs::core::tags::sop_instance_uid, and kcenon::pacs::core::tags::study_instance_uid.

Referenced by kcenon::pacs::services::validation::is_valid_mg_dataset().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_options()

void kcenon::pacs::services::validation::mg_iod_validator::set_options ( const mg_validation_options & options)

Set validation options.

Definition at line 311 of file mg_iod_validator.cpp.

311 {
313}

References options(), and options_.

Here is the call graph for this function:

◆ validate()

validation_result kcenon::pacs::services::validation::mg_iod_validator::validate ( const core::dicom_dataset & dataset) const
nodiscard

Validate a DICOM dataset against Mammography IOD.

Performs comprehensive validation including patient, study, series, image, and mammography-specific modules.

Parameters
datasetThe dataset to validate
Returns
Validation result with all findings

Definition at line 90 of file mg_iod_validator.cpp.

90 {
91 validation_result result;
92 result.is_valid = true;
93
94 // Validate standard modules
96 validate_patient_module(dataset, result.findings);
97 validate_general_study_module(dataset, result.findings);
98 validate_general_series_module(dataset, result.findings);
99 validate_sop_common_module(dataset, result.findings);
100 }
101
102 // Validate mammography series module
103 validate_mammography_series_module(dataset, result.findings);
104
106 validate_image_pixel_module(dataset, result.findings);
107 }
108
110 validate_mammography_image_module(dataset, result.findings);
111 validate_dx_anatomy_imaged_module(dataset, result.findings);
112 validate_dx_detector_module(dataset, result.findings);
113 }
114
116 validate_acquisition_dose_module(dataset, result.findings);
117 }
118
120 validate_breast_implant_module(dataset, result.findings);
121 }
122
123 // Check for errors
124 for (const auto& finding : result.findings) {
125 if (finding.severity == validation_severity::error) {
126 result.is_valid = false;
127 break;
128 }
129 if (options_.strict_mode && finding.severity == validation_severity::warning) {
130 result.is_valid = false;
131 break;
132 }
133 }
134
135 return result;
136}
void validate_general_series_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
void validate_breast_implant_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_dx_anatomy_imaged_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_dx_detector_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_mammography_image_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_mammography_series_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
void validate_image_pixel_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_acquisition_dose_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool validate_pixel_data
Validate pixel data consistency (rows, columns, bits)
bool validate_dose_parameters
Validate acquisition dose parameters.
bool validate_mg_specific
Validate mammography-specific attributes.
bool check_type1
Check Type 1 (required) attributes.
bool strict_mode
Strict mode - treat warnings as errors.
bool check_type2
Check Type 2 (required, can be empty) attributes.
bool validate_compression
Validate compression force (0018,11A2)
bool validate_implant_attributes
Validate breast implant attributes.

References kcenon::pacs::services::validation::mg_validation_options::check_type1, kcenon::pacs::services::validation::mg_validation_options::check_type2, kcenon::pacs::services::validation::error, kcenon::pacs::services::validation::validation_result::findings, kcenon::pacs::services::validation::validation_result::is_valid, options_, kcenon::pacs::services::validation::mg_validation_options::strict_mode, validate_acquisition_dose_module(), validate_breast_implant_module(), kcenon::pacs::services::validation::mg_validation_options::validate_compression, kcenon::pacs::services::validation::mg_validation_options::validate_dose_parameters, validate_dx_anatomy_imaged_module(), validate_dx_detector_module(), validate_general_series_module(), validate_general_study_module(), validate_image_pixel_module(), kcenon::pacs::services::validation::mg_validation_options::validate_implant_attributes, validate_mammography_image_module(), validate_mammography_series_module(), kcenon::pacs::services::validation::mg_validation_options::validate_mg_specific, validate_patient_module(), kcenon::pacs::services::validation::mg_validation_options::validate_pixel_data, validate_sop_common_module(), and kcenon::pacs::services::validation::warning.

Referenced by validate_for_presentation(), validate_for_processing(), and kcenon::pacs::services::validation::validate_mg_iod().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_acquisition_dose_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_acquisition_dose_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 507 of file mg_iod_validator.cpp.

509 {
510
511 // Compression Force (0018,11A2) - Type 3 but important for mammography
513 check_compression_force_range(dataset, findings);
514 }
515
516 // Body Part Thickness (0018,11A0) - Type 3
519 auto thickness = dataset.get_numeric<double>(mg_tags::body_part_thickness);
520 if (thickness && !is_valid_compressed_breast_thickness(*thickness)) {
521 findings.push_back({
524 "Compressed breast thickness outside typical range (10-150mm): " +
525 std::to_string(*thickness) + " mm",
526 "MG-WARN-007"
527 });
528 }
529 } else {
530 // Recommend including thickness for quality assessment
531 findings.push_back({
534 "Compressed breast thickness not documented - "
535 "recommended for dose assessment and quality control",
536 "MG-INFO-005"
537 });
538 }
539
540 // KVP (0018,0060) - Type 3 but important for dose
541 if (!dataset.contains(mg_tags::kvp)) {
542 findings.push_back({
545 "KVP not documented - recommended for dose assessment",
546 "MG-INFO-006"
547 });
548 }
549
550 // Entrance Dose (0040,0302) - Type 3
551 // Organ Dose (0040,0316) - Type 3 but important for breast dose tracking
552 }
553}
void check_compression_force_range(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool is_valid_compressed_breast_thickness(double thickness_mm) noexcept
Validate compressed breast thickness.

References kcenon::pacs::services::validation::mg_tags::body_part_thickness, check_compression_force_range(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_numeric(), kcenon::pacs::services::validation::info, kcenon::pacs::services::sop_classes::is_valid_compressed_breast_thickness(), kcenon::pacs::services::validation::mg_tags::kvp, options_, kcenon::pacs::services::validation::mg_validation_options::validate_compression, kcenon::pacs::services::validation::mg_validation_options::validate_dose_parameters, and kcenon::pacs::services::validation::warning.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_breast_implant_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_breast_implant_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 627 of file mg_iod_validator.cpp.

629 {
630
631 // Breast Implant Present (0028,1300) - Type 3
634 if (implant != "YES" && implant != "NO") {
635 findings.push_back({
638 "Breast Implant Present should be 'YES' or 'NO', found: " + implant,
639 "MG-WARN-009"
640 });
641 }
642
643 // If implant is present, check for implant displaced views
644 if (implant == "YES") {
645 // Informational: implant displacement technique (Eklund) may be needed
646 if (dataset.contains(mg_tags::view_position)) {
647 auto view = dataset.get_string(mg_tags::view_position);
648 auto parsed_view = parse_mg_view_position(view);
649 if (parsed_view != mg_view_position::implant &&
650 parsed_view != mg_view_position::id) {
651 findings.push_back({
654 "Breast implant present but view is not implant-displaced (ID). "
655 "Implant displacement technique (Eklund) may improve visualization.",
656 "MG-INFO-007"
657 });
658 }
659 }
660 }
661 }
662}
@ implant
Implant displaced view (Eklund technique)

References kcenon::pacs::services::validation::mg_tags::breast_implant_present, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::sop_classes::implant, kcenon::pacs::services::validation::info, kcenon::pacs::services::sop_classes::parse_mg_view_position(), kcenon::pacs::services::validation::mg_tags::view_position, and kcenon::pacs::services::validation::warning.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_compression_force()

validation_result kcenon::pacs::services::validation::mg_iod_validator::validate_compression_force ( const core::dicom_dataset & dataset) const
nodiscard

Validate compression force.

Checks compression force is present and within typical range.

Parameters
datasetThe dataset to validate
Returns
Validation result for compression force

Definition at line 253 of file mg_iod_validator.cpp.

253 {
254 validation_result result;
255 result.is_valid = true;
256
257 check_compression_force_range(dataset, result.findings);
258
259 for (const auto& finding : result.findings) {
260 if (finding.severity == validation_severity::error) {
261 result.is_valid = false;
262 break;
263 }
264 }
265
266 return result;
267}

References check_compression_force_range(), kcenon::pacs::services::validation::error, kcenon::pacs::services::validation::validation_result::findings, and kcenon::pacs::services::validation::validation_result::is_valid.

Here is the call graph for this function:

◆ validate_dx_anatomy_imaged_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_dx_anatomy_imaged_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 438 of file mg_iod_validator.cpp.

440 {
441
442 // Body Part Examined (0018,0015) - Type 2
443 if (options_.check_type2) {
444 check_type2_attribute(dataset, mg_tags::body_part_examined, "BodyPartExamined", findings);
445
448 if (body_part != "BREAST") {
449 findings.push_back({
452 "Body Part Examined should be 'BREAST' for mammography, found: " + body_part,
453 "MG-WARN-003"
454 });
455 }
456 }
457 }
458
459 // Anatomic Region Sequence (0008,2218) - Type 1C
463 findings.push_back({
466 "Neither Body Part Examined nor Anatomic Region Sequence present - "
467 "anatomy information may be insufficient for clinical use",
468 "MG-WARN-004"
469 });
470 }
471 }
472}
void check_type2_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
@ body_part
(0018,0015) Body Part Examined
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.

References kcenon::pacs::services::validation::mg_tags::anatomic_region_sequence, kcenon::pacs::services::validation::mg_tags::body_part_examined, kcenon::pacs::services::validation::mg_validation_options::check_conditional, kcenon::pacs::services::validation::mg_validation_options::check_type2, check_type2_attribute(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_string(), options_, and kcenon::pacs::services::validation::warning.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_dx_detector_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_dx_detector_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 474 of file mg_iod_validator.cpp.

476 {
477
478 // Detector Type (0018,7004) - Type 2
479 if (options_.check_type2) {
480 check_type2_attribute(dataset, mg_tags::detector_type, "DetectorType", findings);
481
482 if (dataset.contains(mg_tags::detector_type)) {
483 auto type = dataset.get_string(mg_tags::detector_type);
484 // Mammography typically uses DIRECT (a-Se) or SCINTILLATOR (CsI)
485 if (type != "DIRECT" && type != "SCINTILLATOR" && type != "STORAGE") {
486 findings.push_back({
489 "Unusual Detector Type for mammography: " + type +
490 " (typical: DIRECT, SCINTILLATOR)",
491 "MG-INFO-004"
492 });
493 }
494 }
495 }
496
497 // Imager Pixel Spacing (0018,1164) - Type 1 for DX/MG
498 if (options_.check_type1) {
500 "ImagerPixelSpacing", findings);
501
502 // Mammography typically has very fine pixel spacing (< 0.1 mm)
503 // This is informational only
504 }
505}
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const

References kcenon::pacs::services::validation::mg_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::mg_validation_options::check_type2, check_type2_attribute(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::mg_tags::detector_type, kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::mg_tags::imager_pixel_spacing, kcenon::pacs::services::validation::info, and options_.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_for_presentation()

validation_result kcenon::pacs::services::validation::mg_iod_validator::validate_for_presentation ( const core::dicom_dataset & dataset) const
nodiscard

Validate a For Presentation mammography dataset.

Performs additional validation for For Presentation specific requirements including VOI LUT and display parameters.

Parameters
datasetThe dataset to validate
Returns
Validation result with all findings

Definition at line 139 of file mg_iod_validator.cpp.

139 {
140 auto result = validate(dataset);
141
142 // Additional For Presentation validation
144 validate_voi_lut_module(dataset, result.findings);
145
146 // Check Presentation Intent Type
148 auto intent = dataset.get_string(mg_tags::presentation_intent_type);
149 if (intent != "FOR PRESENTATION") {
150 result.findings.push_back({
153 "Presentation Intent Type should be 'FOR PRESENTATION' "
154 "for this SOP Class, found: " + intent,
155 "MG-ERR-010"
156 });
157 }
158 }
159 }
160
161 // Re-check validity
162 for (const auto& finding : result.findings) {
163 if (finding.severity == validation_severity::error) {
164 result.is_valid = false;
165 break;
166 }
167 }
168
169 return result;
170}
void validate_voi_lut_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool validate_presentation_requirements
Validate For Presentation specific requirements.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), options_, kcenon::pacs::services::validation::mg_tags::presentation_intent_type, validate(), kcenon::pacs::services::validation::mg_validation_options::validate_presentation_requirements, and validate_voi_lut_module().

Here is the call graph for this function:

◆ validate_for_processing()

validation_result kcenon::pacs::services::validation::mg_iod_validator::validate_for_processing ( const core::dicom_dataset & dataset) const
nodiscard

Validate a For Processing mammography dataset.

Performs validation for For Processing specific requirements including raw data attributes.

Parameters
datasetThe dataset to validate
Returns
Validation result with all findings

Definition at line 173 of file mg_iod_validator.cpp.

173 {
174 auto result = validate(dataset);
175
176 // Additional For Processing validation
178 // Check Presentation Intent Type
180 auto intent = dataset.get_string(mg_tags::presentation_intent_type);
181 if (intent != "FOR PROCESSING") {
182 result.findings.push_back({
185 "Presentation Intent Type should be 'FOR PROCESSING' "
186 "for this SOP Class, found: " + intent,
187 "MG-ERR-011"
188 });
189 }
190 }
191
192 // For Processing images should have linear pixel intensity relationship
194 auto relationship = dataset.get_string(mg_tags::pixel_intensity_relationship);
195 if (relationship != "LIN") {
196 result.findings.push_back({
199 "For Processing mammography images typically have linear (LIN) "
200 "pixel intensity relationship, found: " + relationship,
201 "MG-INFO-002"
202 });
203 }
204 }
205 }
206
207 // Re-check validity
208 for (const auto& finding : result.findings) {
209 if (finding.severity == validation_severity::error) {
210 result.is_valid = false;
211 break;
212 }
213 }
214
215 return result;
216}
bool validate_processing_requirements
Validate For Processing specific requirements.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::info, options_, kcenon::pacs::services::validation::mg_tags::pixel_intensity_relationship, kcenon::pacs::services::validation::mg_tags::presentation_intent_type, validate(), and kcenon::pacs::services::validation::mg_validation_options::validate_processing_requirements.

Here is the call graph for this function:

◆ validate_general_series_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_general_series_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 351 of file mg_iod_validator.cpp.

353 {
354
355 // Type 1
356 if (options_.check_type1) {
357 check_type1_attribute(dataset, tags::modality, "Modality", findings);
358 check_type1_attribute(dataset, tags::series_instance_uid, "SeriesInstanceUID", findings);
359
360 // Special check: Modality must be "MG"
361 check_modality(dataset, findings);
362 }
363
364 // Type 2
365 if (options_.check_type2) {
366 check_type2_attribute(dataset, tags::series_number, "SeriesNumber", findings);
367 }
368}
void check_modality(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
constexpr dicom_tag series_number
Series Number.

References check_modality(), kcenon::pacs::services::validation::mg_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::mg_validation_options::check_type2, check_type2_attribute(), kcenon::pacs::core::tags::modality, options_, kcenon::pacs::core::tags::series_instance_uid, and kcenon::pacs::core::tags::series_number.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_general_study_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_general_study_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 332 of file mg_iod_validator.cpp.

334 {
335
336 // Type 1
337 if (options_.check_type1) {
338 check_type1_attribute(dataset, tags::study_instance_uid, "StudyInstanceUID", findings);
339 }
340
341 // Type 2
342 if (options_.check_type2) {
343 check_type2_attribute(dataset, tags::study_date, "StudyDate", findings);
344 check_type2_attribute(dataset, tags::study_time, "StudyTime", findings);
345 check_type2_attribute(dataset, tags::referring_physician_name, "ReferringPhysicianName", findings);
346 check_type2_attribute(dataset, tags::study_id, "StudyID", findings);
347 check_type2_attribute(dataset, tags::accession_number, "AccessionNumber", findings);
348 }
349}
constexpr dicom_tag referring_physician_name
Referring Physician's Name.
constexpr dicom_tag accession_number
Accession Number.
constexpr dicom_tag study_time
Study Time.
constexpr dicom_tag study_id
Study ID.
constexpr dicom_tag study_date
Study Date.

References kcenon::pacs::core::tags::accession_number, kcenon::pacs::services::validation::mg_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::mg_validation_options::check_type2, check_type2_attribute(), options_, kcenon::pacs::core::tags::referring_physician_name, kcenon::pacs::core::tags::study_date, kcenon::pacs::core::tags::study_id, kcenon::pacs::core::tags::study_instance_uid, and kcenon::pacs::core::tags::study_time.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_image_pixel_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_image_pixel_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 555 of file mg_iod_validator.cpp.

557 {
558
559 // Type 1 attributes
560 if (options_.check_type1) {
561 check_type1_attribute(dataset, tags::samples_per_pixel, "SamplesPerPixel", findings);
562 check_type1_attribute(dataset, tags::photometric_interpretation, "PhotometricInterpretation", findings);
563 check_type1_attribute(dataset, tags::rows, "Rows", findings);
564 check_type1_attribute(dataset, tags::columns, "Columns", findings);
565 check_type1_attribute(dataset, tags::bits_allocated, "BitsAllocated", findings);
566 check_type1_attribute(dataset, tags::bits_stored, "BitsStored", findings);
567 check_type1_attribute(dataset, tags::high_bit, "HighBit", findings);
568 check_type1_attribute(dataset, tags::pixel_representation, "PixelRepresentation", findings);
569 check_type1_attribute(dataset, tags::pixel_data, "PixelData", findings);
570 }
571
572 // Validate pixel data consistency
574 check_pixel_data_consistency(dataset, findings);
575 check_photometric_interpretation(dataset, findings);
576 }
577}
void check_photometric_interpretation(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_pixel_data_consistency(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const

References kcenon::pacs::core::tags::bits_allocated, kcenon::pacs::core::tags::bits_stored, check_photometric_interpretation(), check_pixel_data_consistency(), kcenon::pacs::services::validation::mg_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::core::tags::columns, kcenon::pacs::core::tags::high_bit, options_, kcenon::pacs::core::tags::photometric_interpretation, kcenon::pacs::core::tags::pixel_data, kcenon::pacs::core::tags::pixel_representation, kcenon::pacs::core::tags::rows, kcenon::pacs::core::tags::samples_per_pixel, and kcenon::pacs::services::validation::mg_validation_options::validate_pixel_data.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_laterality()

validation_result kcenon::pacs::services::validation::mg_iod_validator::validate_laterality ( const core::dicom_dataset & dataset) const
nodiscard

Validate breast laterality attribute.

Checks that laterality is present, valid, and consistent with related attributes.

Parameters
datasetThe dataset to validate
Returns
Validation result for laterality

Definition at line 219 of file mg_iod_validator.cpp.

219 {
220 validation_result result;
221 result.is_valid = true;
222
223 check_laterality_consistency(dataset, result.findings);
224
225 for (const auto& finding : result.findings) {
226 if (finding.severity == validation_severity::error) {
227 result.is_valid = false;
228 break;
229 }
230 }
231
232 return result;
233}
void check_laterality_consistency(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const

References check_laterality_consistency(), kcenon::pacs::services::validation::error, kcenon::pacs::services::validation::validation_result::findings, and kcenon::pacs::services::validation::validation_result::is_valid.

Here is the call graph for this function:

◆ validate_mammography_image_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_mammography_image_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 390 of file mg_iod_validator.cpp.

392 {
393
394 // Image Type (0008,0008) - Type 1
395 if (options_.check_type1) {
396 check_type1_attribute(dataset, mg_tags::image_type, "ImageType", findings);
397
398 if (dataset.contains(mg_tags::image_type)) {
400 // First value should be ORIGINAL or DERIVED
401 if (image_type.find("ORIGINAL") == std::string::npos &&
402 image_type.find("DERIVED") == std::string::npos) {
403 findings.push_back({
406 "Image Type first value should be ORIGINAL or DERIVED",
407 "MG-WARN-002"
408 });
409 }
410 }
411 }
412
413 // Validate laterality if enabled
415 check_laterality_consistency(dataset, findings);
416 }
417
418 // Validate view position if enabled
420 check_view_position_validity(dataset, findings);
421 }
422
423 // Partial View (0028,1350) - Type 3
424 if (dataset.contains(mg_tags::partial_view)) {
426 if (partial == "YES" && !dataset.contains(mg_tags::partial_view_description) &&
428 findings.push_back({
431 "Partial View is YES but no description or code sequence provided",
432 "MG-INFO-003"
433 });
434 }
435 }
436}
void check_view_position_validity(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
constexpr dicom_tag image_type
Image Type.
@ partial
PARTIAL - Document is not complete.
bool validate_view_position
Validate mammography view position (0018,5101)
bool validate_laterality
Validate breast laterality (0020,0060)

References check_laterality_consistency(), kcenon::pacs::services::validation::mg_validation_options::check_type1, check_type1_attribute(), check_view_position_validity(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::mg_tags::image_type, kcenon::pacs::services::validation::info, options_, kcenon::pacs::services::sop_classes::partial, kcenon::pacs::services::validation::mg_tags::partial_view, kcenon::pacs::services::validation::mg_tags::partial_view_code_sequence, kcenon::pacs::services::validation::mg_tags::partial_view_description, kcenon::pacs::services::validation::mg_validation_options::validate_laterality, kcenon::pacs::services::validation::mg_validation_options::validate_view_position, and kcenon::pacs::services::validation::warning.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_mammography_series_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_mammography_series_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 370 of file mg_iod_validator.cpp.

372 {
373
374 // Mammography Series Module includes Request Attributes Sequence (0040,0275)
375 // which is Type 3, so no validation required but informational
376
378 // The Request Attributes Sequence is useful for workflow integration
380 findings.push_back({
383 "Request Attributes Sequence not present - may limit workflow integration",
384 "MG-INFO-001"
385 });
386 }
387 }
388}

References kcenon::pacs::services::validation::mg_validation_options::check_conditional, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::info, options_, and kcenon::pacs::services::validation::mg_tags::request_attributes_sequence.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_patient_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_patient_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 319 of file mg_iod_validator.cpp.

321 {
322
323 // Patient Module - All attributes are Type 2
324 if (options_.check_type2) {
325 check_type2_attribute(dataset, tags::patient_name, "PatientName", findings);
326 check_type2_attribute(dataset, tags::patient_id, "PatientID", findings);
327 check_type2_attribute(dataset, tags::patient_birth_date, "PatientBirthDate", findings);
328 check_type2_attribute(dataset, tags::patient_sex, "PatientSex", findings);
329 }
330}
constexpr dicom_tag patient_id
Patient ID.
constexpr dicom_tag patient_birth_date
Patient's Birth Date.
constexpr dicom_tag patient_sex
Patient's Sex.
constexpr dicom_tag patient_name
Patient's Name.

References kcenon::pacs::services::validation::mg_validation_options::check_type2, check_type2_attribute(), options_, kcenon::pacs::core::tags::patient_birth_date, kcenon::pacs::core::tags::patient_id, kcenon::pacs::core::tags::patient_name, and kcenon::pacs::core::tags::patient_sex.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_sop_common_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_sop_common_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 603 of file mg_iod_validator.cpp.

605 {
606
607 // Type 1
608 if (options_.check_type1) {
609 check_type1_attribute(dataset, tags::sop_class_uid, "SOPClassUID", findings);
610 check_type1_attribute(dataset, tags::sop_instance_uid, "SOPInstanceUID", findings);
611 }
612
613 // Validate SOP Class UID is a mammography storage class
614 if (dataset.contains(tags::sop_class_uid)) {
615 auto sop_class = dataset.get_string(tags::sop_class_uid);
616 if (!is_mg_storage_sop_class(sop_class)) {
617 findings.push_back({
620 "SOPClassUID is not a recognized Mammography Storage SOP Class: " + sop_class,
621 "MG-ERR-001"
622 });
623 }
624 }
625}
bool is_mg_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a Mammography Storage SOP Class.

References kcenon::pacs::services::validation::mg_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::sop_classes::is_mg_storage_sop_class(), options_, kcenon::pacs::core::tags::sop_class_uid, and kcenon::pacs::core::tags::sop_instance_uid.

Referenced by validate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_view_position()

validation_result kcenon::pacs::services::validation::mg_iod_validator::validate_view_position ( const core::dicom_dataset & dataset) const
nodiscard

Validate mammography view position.

Checks that view position is present and contains a valid mammography view code.

Parameters
datasetThe dataset to validate
Returns
Validation result for view position

Definition at line 236 of file mg_iod_validator.cpp.

236 {
237 validation_result result;
238 result.is_valid = true;
239
240 check_view_position_validity(dataset, result.findings);
241
242 for (const auto& finding : result.findings) {
243 if (finding.severity == validation_severity::error) {
244 result.is_valid = false;
245 break;
246 }
247 }
248
249 return result;
250}

References check_view_position_validity(), kcenon::pacs::services::validation::error, kcenon::pacs::services::validation::validation_result::findings, and kcenon::pacs::services::validation::validation_result::is_valid.

Here is the call graph for this function:

◆ validate_voi_lut_module()

void kcenon::pacs::services::validation::mg_iod_validator::validate_voi_lut_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private

Definition at line 579 of file mg_iod_validator.cpp.

581 {
582
583 // Window Center (0028,1050) and Window Width (0028,1051) - Type 1C for For Presentation
585 bool has_window = dataset.contains(tags::window_center) &&
587
588 constexpr dicom_tag voi_lut_sequence{0x0028, 0x3010};
589 bool has_voi_lut = dataset.contains(voi_lut_sequence);
590
591 if (!has_window && !has_voi_lut) {
592 findings.push_back({
595 "For Presentation mammography images should have Window Center/Width "
596 "or VOI LUT Sequence for proper display",
597 "MG-WARN-008"
598 });
599 }
600 }
601}
constexpr dicom_tag window_width
Window Width.
constexpr dicom_tag window_center
Window Center.

References kcenon::pacs::services::validation::mg_validation_options::check_conditional, kcenon::pacs::core::dicom_dataset::contains(), options_, kcenon::pacs::services::validation::warning, kcenon::pacs::core::tags::window_center, and kcenon::pacs::core::tags::window_width.

Referenced by validate_for_presentation().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ options_


The documentation for this class was generated from the following files: