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

#include <dx_iod_validator.h>

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

Public Member Functions

 dx_iod_validator ()=default
 Construct validator with default options.
 
 dx_iod_validator (const dx_validation_options &options)
 Construct validator with custom options.
 
validation_result validate (const core::dicom_dataset &dataset) const
 Validate a DICOM dataset against DX IOD.
 
validation_result validate_for_presentation (const core::dicom_dataset &dataset) const
 Validate a For Presentation DX dataset.
 
validation_result validate_for_processing (const core::dicom_dataset &dataset) const
 Validate a For Processing DX dataset.
 
bool quick_check (const core::dicom_dataset &dataset) const
 Quick check if dataset has minimum required attributes.
 
const dx_validation_optionsoptions () const noexcept
 Get the validation options.
 
void set_options (const dx_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_dx_anatomy_imaged_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_dx_image_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_dx_positioning_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 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_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

dx_validation_options options_
 

Detailed Description

Definition at line 116 of file dx_iod_validator.h.

Constructor & Destructor Documentation

◆ dx_iod_validator() [1/2]

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

◆ dx_iod_validator() [2/2]

kcenon::pacs::services::validation::dx_iod_validator::dx_iod_validator ( const dx_validation_options & options)
explicit

Construct validator with custom options.

Parameters
optionsValidation options

Definition at line 66 of file dx_iod_validator.cpp.

Member Function Documentation

◆ check_modality()

void kcenon::pacs::services::validation::dx_iod_validator::check_modality ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 573 of file dx_iod_validator.cpp.

575 {
576
577 if (!dataset.contains(tags::modality)) {
578 return; // Already reported as Type 1 missing
579 }
580
581 auto modality = dataset.get_string(tags::modality);
582 if (modality != "DX") {
583 findings.push_back({
586 "Modality must be 'DX' for digital X-ray images, found: " + modality,
587 "DX-ERR-002"
588 });
589 }
590}
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::dx_iod_validator::check_photometric_interpretation ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 651 of file dx_iod_validator.cpp.

653 {
654
655 if (!dataset.contains(tags::photometric_interpretation)) {
656 return; // Already reported as missing
657 }
658
659 auto photometric = dataset.get_string(tags::photometric_interpretation);
660 if (!sop_classes::is_valid_dx_photometric(photometric)) {
661 findings.push_back({
664 "DX images must use MONOCHROME1 or MONOCHROME2, found: " + photometric,
665 "DX-ERR-007"
666 });
667 }
668}
constexpr dicom_tag photometric_interpretation
Photometric Interpretation.
bool is_valid_dx_photometric(std::string_view value) noexcept
Check if photometric interpretation is valid for DX.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::sop_classes::is_valid_dx_photometric(), 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::dx_iod_validator::check_pixel_data_consistency ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 592 of file dx_iod_validator.cpp.

594 {
595
596 // Check BitsStored <= BitsAllocated
597 auto bits_allocated = dataset.get_numeric<uint16_t>(tags::bits_allocated);
598 auto bits_stored = dataset.get_numeric<uint16_t>(tags::bits_stored);
599 auto high_bit = dataset.get_numeric<uint16_t>(tags::high_bit);
600
601 if (bits_allocated && bits_stored) {
602 if (*bits_stored > *bits_allocated) {
603 findings.push_back({
606 "BitsStored (" + std::to_string(*bits_stored) +
607 ") exceeds BitsAllocated (" + std::to_string(*bits_allocated) + ")",
608 "DX-ERR-005"
609 });
610 }
611
612 // DX typically uses 10-16 bits stored
613 if (*bits_stored < 10 || *bits_stored > 16) {
614 findings.push_back({
617 "DX images typically use 10-16 bits, found: " +
618 std::to_string(*bits_stored),
619 "DX-INFO-003"
620 });
621 }
622 }
623
624 // Check HighBit == BitsStored - 1
625 if (bits_stored && high_bit) {
626 if (*high_bit != *bits_stored - 1) {
627 findings.push_back({
630 "HighBit (" + std::to_string(*high_bit) +
631 ") should typically be BitsStored - 1 (" +
632 std::to_string(*bits_stored - 1) + ")",
633 "DX-WARN-007"
634 });
635 }
636 }
637
638 // DX must be grayscale - check SamplesPerPixel
639 auto samples = dataset.get_numeric<uint16_t>(tags::samples_per_pixel);
640 if (samples && *samples != 1) {
641 findings.push_back({
644 "DX images must be grayscale (SamplesPerPixel = 1), found: " +
645 std::to_string(*samples),
646 "DX-ERR-006"
647 });
648 }
649}
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.
@ warning
Non-critical - IOD may have issues.
@ info
Informational - suggestion for improvement.

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::dx_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
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 526 of file dx_iod_validator.cpp.

530 {
531
532 if (!dataset.contains(tag)) {
533 findings.push_back({
535 tag,
536 std::string("Type 1 attribute missing: ") + std::string(name) +
537 " (" + tag.to_string() + ")",
538 "DX-TYPE1-MISSING"
539 });
540 } else {
541 // Type 1 must have a value (cannot be empty)
542 auto value = dataset.get_string(tag);
543 if (value.empty()) {
544 findings.push_back({
546 tag,
547 std::string("Type 1 attribute has empty value: ") +
548 std::string(name) + " (" + tag.to_string() + ")",
549 "DX-TYPE1-EMPTY"
550 });
551 }
552 }
553}
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_dx_image_module(), validate_general_series_module(), validate_general_study_module(), validate_image_pixel_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::dx_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
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 555 of file dx_iod_validator.cpp.

559 {
560
561 // Type 2 must be present but can be empty
562 if (!dataset.contains(tag)) {
563 findings.push_back({
565 tag,
566 std::string("Type 2 attribute missing: ") + std::string(name) +
567 " (" + tag.to_string() + ")",
568 "DX-TYPE2-MISSING"
569 });
570 }
571}

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:

◆ options()

const dx_validation_options & kcenon::pacs::services::validation::dx_iod_validator::options ( ) const
nodiscardnoexcept

Get the validation options.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 222 of file dx_iod_validator.cpp.

222 {
223 return options_;
224}

References options_.

Referenced by set_options().

Here is the caller graph for this function:

◆ quick_check()

bool kcenon::pacs::services::validation::dx_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.

Parameters
datasetThe dataset to check
Returns
true if all critical Type 1 attributes are present
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 190 of file dx_iod_validator.cpp.

190 {
191 // Check only critical Type 1 attributes for quick validation
192
193 // General Study Module Type 1
194 if (!dataset.contains(tags::study_instance_uid)) return false;
195
196 // General Series Module Type 1
197 if (!dataset.contains(tags::modality)) return false;
198 if (!dataset.contains(tags::series_instance_uid)) return false;
199
200 // Check modality is DX
201 auto modality = dataset.get_string(tags::modality);
202 if (modality != "DX") return false;
203
204 // Image Pixel Module Type 1
205 if (!dataset.contains(tags::samples_per_pixel)) return false;
206 if (!dataset.contains(tags::photometric_interpretation)) return false;
207 if (!dataset.contains(tags::rows)) return false;
208 if (!dataset.contains(tags::columns)) return false;
209 if (!dataset.contains(tags::bits_allocated)) return false;
210 if (!dataset.contains(tags::bits_stored)) return false;
211 if (!dataset.contains(tags::high_bit)) return false;
212 if (!dataset.contains(tags::pixel_representation)) return false;
213 if (!dataset.contains(tags::pixel_data)) return false;
214
215 // SOP Common Module Type 1
216 if (!dataset.contains(tags::sop_class_uid)) return false;
217 if (!dataset.contains(tags::sop_instance_uid)) return false;
218
219 return true;
220}
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::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_dx_dataset().

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

◆ set_options()

void kcenon::pacs::services::validation::dx_iod_validator::set_options ( const dx_validation_options & options)

Set validation options.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 226 of file dx_iod_validator.cpp.

226 {
228}
const dx_validation_options & options() const noexcept
Get the validation options.

References options(), and options_.

Here is the call graph for this function:

◆ validate()

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

Validate a DICOM dataset against DX IOD.

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

Parameters
datasetThe dataset to validate
Returns
Validation result with all findings
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 69 of file dx_iod_validator.cpp.

69 {
70 validation_result result;
71 result.is_valid = true;
72
73 // Validate mandatory modules
75 validate_patient_module(dataset, result.findings);
76 validate_general_study_module(dataset, result.findings);
77 validate_general_series_module(dataset, result.findings);
78 validate_sop_common_module(dataset, result.findings);
79 }
80
82 validate_image_pixel_module(dataset, result.findings);
83 }
84
86 validate_dx_image_module(dataset, result.findings);
87 validate_dx_detector_module(dataset, result.findings);
88 }
89
91 validate_dx_anatomy_imaged_module(dataset, result.findings);
92 validate_dx_positioning_module(dataset, result.findings);
93 }
94
95 // Check for errors
96 for (const auto& finding : result.findings) {
97 if (finding.severity == validation_severity::error) {
98 result.is_valid = false;
99 break;
100 }
101 if (options_.strict_mode && finding.severity == validation_severity::warning) {
102 result.is_valid = false;
103 break;
104 }
105 }
106
107 return result;
108}
void validate_dx_anatomy_imaged_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_study_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_dx_image_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_dx_detector_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_dx_positioning_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool validate_pixel_data
Validate pixel data consistency (rows, columns, bits)
bool check_type1
Check Type 1 (required) attributes.
bool check_type2
Check Type 2 (required, can be empty) attributes.
bool validate_anatomy
Validate body part and view position.
bool strict_mode
Strict mode - treat warnings as errors.
bool validate_dx_specific
Validate DX-specific attributes (detector, acquisition)

References kcenon::pacs::services::validation::dx_validation_options::check_type1, kcenon::pacs::services::validation::dx_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::dx_validation_options::strict_mode, kcenon::pacs::services::validation::dx_validation_options::validate_anatomy, validate_dx_anatomy_imaged_module(), validate_dx_detector_module(), validate_dx_image_module(), validate_dx_positioning_module(), kcenon::pacs::services::validation::dx_validation_options::validate_dx_specific, validate_general_series_module(), validate_general_study_module(), validate_image_pixel_module(), validate_patient_module(), kcenon::pacs::services::validation::dx_validation_options::validate_pixel_data, validate_sop_common_module(), and kcenon::pacs::services::validation::warning.

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

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

◆ validate_dx_anatomy_imaged_module()

void kcenon::pacs::services::validation::dx_iod_validator::validate_dx_anatomy_imaged_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 285 of file dx_iod_validator.cpp.

287 {
288
289 // Body Part Examined (0018,0015) - Type 2
290 if (options_.check_type2) {
291 check_type2_attribute(dataset, dx_tags::body_part_examined, "BodyPartExamined", findings);
292 }
293
294 // Anatomic Region Sequence (0008,2218) - Type 1C
295 // Required if Body Part Examined is not sufficient to describe the anatomy
297 if (!dataset.contains(dx_tags::body_part_examined) &&
298 !dataset.contains(dx_tags::anatomic_region_sequence)) {
299 findings.push_back({
302 "Neither Body Part Examined nor Anatomic Region Sequence present - "
303 "anatomy information may be insufficient for clinical use",
304 "DX-WARN-001"
305 });
306 }
307 }
308}
void check_type2_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.

References kcenon::pacs::services::validation::dx_tags::anatomic_region_sequence, kcenon::pacs::services::validation::dx_tags::body_part_examined, kcenon::pacs::services::validation::dx_validation_options::check_conditional, kcenon::pacs::services::validation::dx_validation_options::check_type2, check_type2_attribute(), kcenon::pacs::core::dicom_dataset::contains(), 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::dx_iod_validator::validate_dx_detector_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 385 of file dx_iod_validator.cpp.

387 {
388
389 // Detector Type (0018,7004) - Type 2
390 if (options_.check_type2) {
391 check_type2_attribute(dataset, dx_tags::detector_type, "DetectorType", findings);
392
393 if (dataset.contains(dx_tags::detector_type)) {
394 auto type = dataset.get_string(dx_tags::detector_type);
395 if (type != "DIRECT" && type != "SCINTILLATOR" &&
396 type != "STORAGE" && type != "FILM") {
397 findings.push_back({
400 "Unusual Detector Type for DX: " + type,
401 "DX-WARN-004"
402 });
403 }
404 }
405 }
406
407 // Imager Pixel Spacing (0018,1164) - Type 1 for DX
408 if (options_.check_type1) {
410 "ImagerPixelSpacing", findings);
411 }
412}
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::dx_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::dx_validation_options::check_type2, check_type2_attribute(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::dx_tags::detector_type, kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::dx_tags::imager_pixel_spacing, 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_image_module()

void kcenon::pacs::services::validation::dx_iod_validator::validate_dx_image_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 310 of file dx_iod_validator.cpp.

312 {
313
314 // Image Type (0008,0008) - Type 1
315 if (options_.check_type1) {
316 check_type1_attribute(dataset, dx_tags::image_type, "ImageType", findings);
317
318 // Validate Image Type values for DX
319 if (dataset.contains(dx_tags::image_type)) {
320 auto image_type = dataset.get_string(dx_tags::image_type);
321 // First value should be ORIGINAL or DERIVED
322 if (image_type.find("ORIGINAL") == std::string::npos &&
323 image_type.find("DERIVED") == std::string::npos) {
324 findings.push_back({
327 "Image Type first value should be ORIGINAL or DERIVED",
328 "DX-WARN-002"
329 });
330 }
331 // Second value should be PRIMARY or SECONDARY
332 if (image_type.find("PRIMARY") == std::string::npos &&
333 image_type.find("SECONDARY") == std::string::npos) {
334 findings.push_back({
337 "Image Type second value should be PRIMARY or SECONDARY",
338 "DX-WARN-003"
339 });
340 }
341 }
342 }
343
344 // Acquisition Device Processing Description (0018,1400) - Type 3
345 // No validation required, but informational if missing for presentation images
346
347 // Pixel Intensity Relationship (0028,1040) - Type 1 for DX
348 if (options_.check_type1) {
350 "PixelIntensityRelationship", findings);
351
352 if (dataset.contains(dx_tags::pixel_intensity_relationship)) {
353 auto relationship = dataset.get_string(dx_tags::pixel_intensity_relationship);
354 if (relationship != "LIN" && relationship != "LOG") {
355 findings.push_back({
358 "Pixel Intensity Relationship must be LIN or LOG, found: " + relationship,
359 "DX-ERR-003"
360 });
361 }
362 }
363 }
364
365 // Pixel Intensity Relationship Sign (0028,1041) - Type 1 for DX
366 if (options_.check_type1) {
368 "PixelIntensityRelationshipSign", findings);
369
370 if (dataset.contains(dx_tags::pixel_intensity_relationship_sign)) {
371 auto sign = dataset.get_numeric<int16_t>(dx_tags::pixel_intensity_relationship_sign);
372 if (sign && *sign != 1 && *sign != -1) {
373 findings.push_back({
376 "Pixel Intensity Relationship Sign must be 1 or -1, found: " +
377 std::to_string(*sign),
378 "DX-ERR-004"
379 });
380 }
381 }
382 }
383}
constexpr dicom_tag image_type
Image Type.

References kcenon::pacs::services::validation::dx_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_numeric(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::dx_tags::image_type, options_, kcenon::pacs::services::validation::dx_tags::pixel_intensity_relationship, kcenon::pacs::services::validation::dx_tags::pixel_intensity_relationship_sign, 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_positioning_module()

void kcenon::pacs::services::validation::dx_iod_validator::validate_dx_positioning_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 414 of file dx_iod_validator.cpp.

416 {
417
418 // View Position (0018,5101) - Type 2C
419 // Required if Patient Orientation (0020,0020) is not present
421 if (!dataset.contains(dx_tags::patient_orientation) &&
422 !dataset.contains(dx_tags::view_position)) {
423 findings.push_back({
426 "Neither Patient Orientation nor View Position present - "
427 "image orientation may be unclear",
428 "DX-WARN-005"
429 });
430 }
431 }
432
433 // Patient Orientation (0020,0020) - Type 2C
435 auto orientation = dataset.get_string(dx_tags::patient_orientation);
436 if (orientation.empty()) {
437 findings.push_back({
440 "Patient Orientation is present but empty",
441 "DX-INFO-001"
442 });
443 }
444 }
445
446 // Distance Source to Detector (0018,1110) - Type 3, but useful for calibration
447 // Distance Source to Patient (0018,1111) - Type 3, but useful for calibration
448}

References kcenon::pacs::services::validation::dx_validation_options::check_conditional, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::validation::info, options_, kcenon::pacs::services::validation::dx_tags::patient_orientation, kcenon::pacs::services::validation::dx_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_for_presentation()

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

Validate a For Presentation DX 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
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 111 of file dx_iod_validator.cpp.

111 {
112 auto result = validate(dataset);
113
114 // Additional For Presentation validation
116 validate_voi_lut_module(dataset, result.findings);
117
118 // Check Presentation Intent Type
119 if (dataset.contains(dx_tags::presentation_intent_type)) {
120 auto intent = dataset.get_string(dx_tags::presentation_intent_type);
121 if (intent != "FOR PRESENTATION") {
122 result.findings.push_back({
125 "Presentation Intent Type should be 'FOR PRESENTATION' "
126 "for this SOP Class, found: " + intent,
127 "DX-ERR-010"
128 });
129 }
130 }
131 }
132
133 // Re-check validity
134 for (const auto& finding : result.findings) {
135 if (finding.severity == validation_severity::error) {
136 result.is_valid = false;
137 break;
138 }
139 }
140
141 return result;
142}
void validate_voi_lut_module(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 DX IOD.
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::dx_tags::presentation_intent_type, validate(), kcenon::pacs::services::validation::dx_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::dx_iod_validator::validate_for_processing ( const core::dicom_dataset & dataset) const
nodiscard

Validate a For Processing DX dataset.

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

Parameters
datasetThe dataset to validate
Returns
Validation result with all findings
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 145 of file dx_iod_validator.cpp.

145 {
146 auto result = validate(dataset);
147
148 // Additional For Processing validation
150 // Check Presentation Intent Type
151 if (dataset.contains(dx_tags::presentation_intent_type)) {
152 auto intent = dataset.get_string(dx_tags::presentation_intent_type);
153 if (intent != "FOR PROCESSING") {
154 result.findings.push_back({
157 "Presentation Intent Type should be 'FOR PROCESSING' "
158 "for this SOP Class, found: " + intent,
159 "DX-ERR-011"
160 });
161 }
162 }
163
164 // For Processing images should have linear pixel intensity relationship
165 if (dataset.contains(dx_tags::pixel_intensity_relationship)) {
166 auto relationship = dataset.get_string(dx_tags::pixel_intensity_relationship);
167 if (relationship != "LIN") {
168 result.findings.push_back({
171 "For Processing images typically have linear (LIN) pixel "
172 "intensity relationship, found: " + relationship,
173 "DX-INFO-002"
174 });
175 }
176 }
177 }
178
179 // Re-check validity
180 for (const auto& finding : result.findings) {
181 if (finding.severity == validation_severity::error) {
182 result.is_valid = false;
183 break;
184 }
185 }
186
187 return result;
188}
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::dx_tags::pixel_intensity_relationship, kcenon::pacs::services::validation::dx_tags::presentation_intent_type, validate(), and kcenon::pacs::services::validation::dx_validation_options::validate_processing_requirements.

Here is the call graph for this function:

◆ validate_general_series_module()

void kcenon::pacs::services::validation::dx_iod_validator::validate_general_series_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 266 of file dx_iod_validator.cpp.

268 {
269
270 // Type 1
271 if (options_.check_type1) {
272 check_type1_attribute(dataset, tags::modality, "Modality", findings);
273 check_type1_attribute(dataset, tags::series_instance_uid, "SeriesInstanceUID", findings);
274
275 // Special check: Modality must be "DX"
276 check_modality(dataset, findings);
277 }
278
279 // Type 2
280 if (options_.check_type2) {
281 check_type2_attribute(dataset, tags::series_number, "SeriesNumber", findings);
282 }
283}
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::dx_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::dx_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::dx_iod_validator::validate_general_study_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 247 of file dx_iod_validator.cpp.

249 {
250
251 // Type 1
252 if (options_.check_type1) {
253 check_type1_attribute(dataset, tags::study_instance_uid, "StudyInstanceUID", findings);
254 }
255
256 // Type 2
257 if (options_.check_type2) {
258 check_type2_attribute(dataset, tags::study_date, "StudyDate", findings);
259 check_type2_attribute(dataset, tags::study_time, "StudyTime", findings);
260 check_type2_attribute(dataset, tags::referring_physician_name, "ReferringPhysicianName", findings);
261 check_type2_attribute(dataset, tags::study_id, "StudyID", findings);
262 check_type2_attribute(dataset, tags::accession_number, "AccessionNumber", findings);
263 }
264}
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::dx_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::dx_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::dx_iod_validator::validate_image_pixel_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 450 of file dx_iod_validator.cpp.

452 {
453
454 // Type 1 attributes
455 if (options_.check_type1) {
456 check_type1_attribute(dataset, tags::samples_per_pixel, "SamplesPerPixel", findings);
457 check_type1_attribute(dataset, tags::photometric_interpretation, "PhotometricInterpretation", findings);
458 check_type1_attribute(dataset, tags::rows, "Rows", findings);
459 check_type1_attribute(dataset, tags::columns, "Columns", findings);
460 check_type1_attribute(dataset, tags::bits_allocated, "BitsAllocated", findings);
461 check_type1_attribute(dataset, tags::bits_stored, "BitsStored", findings);
462 check_type1_attribute(dataset, tags::high_bit, "HighBit", findings);
463 check_type1_attribute(dataset, tags::pixel_representation, "PixelRepresentation", findings);
464 check_type1_attribute(dataset, tags::pixel_data, "PixelData", findings);
465 }
466
467 // Validate pixel data consistency
469 check_pixel_data_consistency(dataset, findings);
470 check_photometric_interpretation(dataset, findings);
471 }
472}
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::dx_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::dx_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_patient_module()

void kcenon::pacs::services::validation::dx_iod_validator::validate_patient_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 234 of file dx_iod_validator.cpp.

236 {
237
238 // Patient Module - All attributes are Type 2
239 if (options_.check_type2) {
240 check_type2_attribute(dataset, tags::patient_name, "PatientName", findings);
241 check_type2_attribute(dataset, tags::patient_id, "PatientID", findings);
242 check_type2_attribute(dataset, tags::patient_birth_date, "PatientBirthDate", findings);
243 check_type2_attribute(dataset, tags::patient_sex, "PatientSex", findings);
244 }
245}
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::dx_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::dx_iod_validator::validate_sop_common_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 498 of file dx_iod_validator.cpp.

500 {
501
502 // Type 1
503 if (options_.check_type1) {
504 check_type1_attribute(dataset, tags::sop_class_uid, "SOPClassUID", findings);
505 check_type1_attribute(dataset, tags::sop_instance_uid, "SOPInstanceUID", findings);
506 }
507
508 // Validate SOP Class UID is a DX storage class
509 if (dataset.contains(tags::sop_class_uid)) {
510 auto sop_class = dataset.get_string(tags::sop_class_uid);
511 if (!sop_classes::is_dx_storage_sop_class(sop_class)) {
512 findings.push_back({
515 "SOPClassUID is not a recognized DX Storage SOP Class: " + sop_class,
516 "DX-ERR-001"
517 });
518 }
519 }
520}
bool is_dx_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a DX Storage SOP Class.

References kcenon::pacs::services::validation::dx_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_dx_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_voi_lut_module()

void kcenon::pacs::services::validation::dx_iod_validator::validate_voi_lut_module ( const core::dicom_dataset & dataset,
std::vector< validation_finding > & findings ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/dx_iod_validator.h.

Definition at line 474 of file dx_iod_validator.cpp.

476 {
477
478 // Window Center (0028,1050) and Window Width (0028,1051) - Type 1C for For Presentation
480 bool has_window = dataset.contains(tags::window_center) &&
481 dataset.contains(tags::window_width);
482
483 constexpr dicom_tag voi_lut_sequence{0x0028, 0x3010};
484 bool has_voi_lut = dataset.contains(voi_lut_sequence);
485
486 if (!has_window && !has_voi_lut) {
487 findings.push_back({
490 "For Presentation images should have Window Center/Width or VOI LUT Sequence "
491 "for proper display",
492 "DX-WARN-006"
493 });
494 }
495 }
496}
constexpr dicom_tag window_width
Window Width.
constexpr dicom_tag window_center
Window Center.

References kcenon::pacs::services::validation::dx_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: