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

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

#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_options & options () 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

Validator for Digital X-Ray Image IODs.

Validates DICOM datasets against the DX Image IOD specification. Checks required modules, attributes, and value constraints specific to digital radiography.

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
  • DX Image Module
  • DX Detector Module
  • SOP Common Module

Conditional Modules (C)

  • DX Positioning Module (required if view position is specified)
  • VOI LUT Module (For Presentation images)
Example:
dx_iod_validator validator;
auto result = validator.validate(dataset);
if (!result.is_valid) {
for (const auto& finding : result.findings) {
std::cerr << finding.code << ": " << finding.message << "\n";
}
}
Validator for Digital X-Ray Image IODs.
validation_result validate(const core::dicom_dataset &dataset) const
Validate a DICOM dataset against DX IOD.

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

Construct validator with default options.

◆ 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.

67 : options_(options) {}
const dx_validation_options & options() const noexcept
Get the validation options.

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

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}
auto contains(dicom_tag tag) const noexcept -> bool
Check if the dataset contains an element with the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
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

Definition at line 651 of file dx_iod_validator.cpp.

653 {
654
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

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}
auto get_numeric(dicom_tag tag) const -> std::optional< T >
Get the numeric value of an element.
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

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}
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_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

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.

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

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.

Definition at line 226 of file dx_iod_validator.cpp.

226 {
228}

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

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

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
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

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

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)) {
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
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
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

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
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

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
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
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

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
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
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

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

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

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

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

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

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) &&
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: