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

#include <xa_iod_validator.h>

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

Public Member Functions

 xa_iod_validator ()=default
 Construct validator with default options.
 
 xa_iod_validator (const xa_validation_options &options)
 Construct validator with custom options.
 
validation_result validate (const core::dicom_dataset &dataset) const
 Validate a DICOM dataset against XA IOD.
 
validation_result validate_multiframe (const core::dicom_dataset &dataset) const
 Validate a multi-frame XA dataset.
 
bool quick_check (const core::dicom_dataset &dataset) const
 Quick check if dataset has minimum required XA attributes.
 
validation_result validate_calibration (const core::dicom_dataset &dataset) const
 Validate calibration data for quantitative analysis.
 
const xa_validation_optionsoptions () const noexcept
 Get the validation options.
 
void set_options (const xa_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_xa_acquisition_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_xa_image_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_multiframe_module (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 
void validate_calibration_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_xa_photometric (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_positioner_angles (const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
 

Private Attributes

xa_validation_options options_
 

Detailed Description

Definition at line 181 of file xa_iod_validator.h.

Constructor & Destructor Documentation

◆ xa_iod_validator() [1/2]

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

◆ xa_iod_validator() [2/2]

kcenon::pacs::services::validation::xa_iod_validator::xa_iod_validator ( const xa_validation_options & options)
explicit

Construct validator with custom options.

Parameters
optionsValidation options

Definition at line 24 of file xa_iod_validator.cpp.

Member Function Documentation

◆ check_modality()

void kcenon::pacs::services::validation::xa_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/xa_iod_validator.h.

Definition at line 432 of file xa_iod_validator.cpp.

434 {
435
436 if (!dataset.contains(tags::modality)) {
437 return; // Already reported as Type 1 missing
438 }
439
440 auto modality = dataset.get_string(tags::modality);
441 if (modality != "XA" && modality != "XRF") {
442 findings.push_back({
445 "Modality must be 'XA' or 'XRF' for angiographic images, found: " + modality,
446 "XA-ERR-003"
447 });
448 }
449}
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_pixel_data_consistency()

void kcenon::pacs::services::validation::xa_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/xa_iod_validator.h.

Definition at line 471 of file xa_iod_validator.cpp.

473 {
474
475 // Check BitsStored <= BitsAllocated
476 auto bits_allocated = dataset.get_numeric<uint16_t>(tags::bits_allocated);
477 auto bits_stored = dataset.get_numeric<uint16_t>(tags::bits_stored);
478 auto high_bit = dataset.get_numeric<uint16_t>(tags::high_bit);
479
480 if (bits_allocated && bits_stored) {
481 if (*bits_stored > *bits_allocated) {
482 findings.push_back({
485 "BitsStored (" + std::to_string(*bits_stored) +
486 ") exceeds BitsAllocated (" + std::to_string(*bits_allocated) + ")",
487 "XA-ERR-005"
488 });
489 }
490
491 // XA typically uses 8, 10, 12, or 16 bits
492 if (*bits_stored != 8 && *bits_stored != 10 &&
493 *bits_stored != 12 && *bits_stored != 16) {
494 findings.push_back({
497 "Unusual BitsStored for XA: " + std::to_string(*bits_stored) +
498 " (expected 8, 10, 12, or 16)",
499 "XA-WARN-004"
500 });
501 }
502 }
503
504 // Check HighBit == BitsStored - 1
505 if (bits_stored && high_bit) {
506 if (*high_bit != *bits_stored - 1) {
507 findings.push_back({
510 "HighBit (" + std::to_string(*high_bit) +
511 ") should typically be BitsStored - 1 (" +
512 std::to_string(*bits_stored - 1) + ")",
513 "XA-WARN-005"
514 });
515 }
516 }
517
518 // XA must be grayscale (SamplesPerPixel = 1)
519 auto samples = dataset.get_numeric<uint16_t>(tags::samples_per_pixel);
520 if (samples && *samples != 1) {
521 findings.push_back({
524 "XA images must be grayscale (SamplesPerPixel = 1), found: " +
525 std::to_string(*samples),
526 "XA-ERR-006"
527 });
528 }
529
530 // XA uses unsigned integers (PixelRepresentation = 0)
531 auto pixel_rep = dataset.get_numeric<uint16_t>(tags::pixel_representation);
532 if (pixel_rep && *pixel_rep != 0) {
533 findings.push_back({
536 "XA images typically use unsigned integers (PixelRepresentation = 0)",
537 "XA-WARN-006"
538 });
539 }
540}
constexpr dicom_tag high_bit
High Bit.
constexpr dicom_tag bits_allocated
Bits Allocated.
constexpr dicom_tag bits_stored
Bits Stored.
constexpr dicom_tag pixel_representation
Pixel Representation.
constexpr dicom_tag samples_per_pixel
Samples per Pixel.
@ warning
Non-critical - IOD may have issues.

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::core::tags::pixel_representation, 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_positioner_angles()

void kcenon::pacs::services::validation::xa_iod_validator::check_positioner_angles ( 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/xa_iod_validator.h.

Definition at line 542 of file xa_iod_validator.cpp.

544 {
545
546 bool has_primary = dataset.contains(xa_tags::positioner_primary_angle);
547 bool has_secondary = dataset.contains(xa_tags::positioner_secondary_angle);
548
549 // Both angles should be present for proper geometry reconstruction
550 if (has_primary != has_secondary) {
551 findings.push_back({
555 "Only one positioner angle present - complete geometry unavailable",
556 "XA-WARN-007"
557 });
558 }
559
560 if (!has_primary && !has_secondary) {
561 findings.push_back({
564 "No positioner angle information - geometry reconstruction not possible",
565 "XA-INFO-004"
566 });
567 }
568
569 // Validate angle ranges if present
570 if (has_primary) {
571 auto angle = dataset.get_numeric<double>(xa_tags::positioner_primary_angle);
572 if (angle && (*angle < -180.0 || *angle > 180.0)) {
573 findings.push_back({
576 "PositionerPrimaryAngle (" + std::to_string(*angle) +
577 ") outside typical range [-180, 180]",
578 "XA-WARN-008"
579 });
580 }
581 }
582
583 if (has_secondary) {
584 auto angle = dataset.get_numeric<double>(xa_tags::positioner_secondary_angle);
585 if (angle && (*angle < -90.0 || *angle > 90.0)) {
586 findings.push_back({
589 "PositionerSecondaryAngle (" + std::to_string(*angle) +
590 ") outside typical range [-90, 90]",
591 "XA-WARN-009"
592 });
593 }
594 }
595}
constexpr core::dicom_tag positioner_secondary_angle
Positioner Secondary Angle (0018,1511) - Cranial/Caudal.
constexpr core::dicom_tag positioner_primary_angle
Positioner Primary Angle (0018,1510) - LAO/RAO.
@ info
Informational - suggestion for improvement.
@ angle
Angle measurement annotation.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::core::dicom_dataset::get_numeric(), kcenon::pacs::services::validation::info, kcenon::pacs::services::validation::xa_tags::positioner_primary_angle, kcenon::pacs::services::validation::xa_tags::positioner_secondary_angle, 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:

◆ check_type1_attribute()

void kcenon::pacs::services::validation::xa_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/xa_iod_validator.h.

Definition at line 385 of file xa_iod_validator.cpp.

389 {
390
391 if (!dataset.contains(tag)) {
392 findings.push_back({
394 tag,
395 std::string("Type 1 attribute missing: ") + std::string(name) +
396 " (" + tag.to_string() + ")",
397 "XA-TYPE1-MISSING"
398 });
399 } else {
400 // Type 1 must have a value (cannot be empty)
401 auto value = dataset.get_string(tag);
402 if (value.empty()) {
403 findings.push_back({
405 tag,
406 std::string("Type 1 attribute has empty value: ") +
407 std::string(name) + " (" + tag.to_string() + ")",
408 "XA-TYPE1-EMPTY"
409 });
410 }
411 }
412}
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_general_series_module(), validate_general_study_module(), validate_image_pixel_module(), validate_multiframe_module(), validate_sop_common_module(), and validate_xa_image_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::xa_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/xa_iod_validator.h.

Definition at line 414 of file xa_iod_validator.cpp.

418 {
419
420 // Type 2 must be present but can be empty
421 if (!dataset.contains(tag)) {
422 findings.push_back({
424 tag,
425 std::string("Type 2 attribute missing: ") + std::string(name) +
426 " (" + tag.to_string() + ")",
427 "XA-TYPE2-MISSING"
428 });
429 }
430}

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

Referenced by 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_xa_photometric()

void kcenon::pacs::services::validation::xa_iod_validator::check_xa_photometric ( 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/xa_iod_validator.h.

Definition at line 451 of file xa_iod_validator.cpp.

453 {
454
455 if (!dataset.contains(tags::photometric_interpretation)) {
456 return; // Will be reported by pixel module validation
457 }
458
459 auto photometric = dataset.get_string(tags::photometric_interpretation);
460 if (!sop_classes::is_valid_xa_photometric(photometric)) {
461 findings.push_back({
464 "Invalid photometric interpretation for XA: " + photometric +
465 " (must be MONOCHROME1 or MONOCHROME2)",
466 "XA-ERR-004"
467 });
468 }
469}
constexpr dicom_tag photometric_interpretation
Photometric Interpretation.
bool is_valid_xa_photometric(std::string_view value) noexcept
Check if photometric interpretation is valid for XA.

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_xa_photometric(), and kcenon::pacs::core::tags::photometric_interpretation.

Referenced by validate_xa_image_module().

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

◆ options()

const xa_validation_options & kcenon::pacs::services::validation::xa_iod_validator::options ( ) const
nodiscardnoexcept

Get the validation options.

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

Definition at line 139 of file xa_iod_validator.cpp.

139 {
140 return options_;
141}

References options_.

Referenced by set_options().

Here is the caller graph for this function:

◆ quick_check()

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

Quick check if dataset has minimum required XA attributes.

Faster than full validation - only checks Type 1 attributes.

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

Definition at line 87 of file xa_iod_validator.cpp.

87 {
88 // Check only Type 1 required attributes for quick validation
89
90 // General Study Module Type 1
91 if (!dataset.contains(tags::study_instance_uid)) return false;
92
93 // General Series Module Type 1
94 if (!dataset.contains(tags::modality)) return false;
95 if (!dataset.contains(tags::series_instance_uid)) return false;
96
97 // Check modality is XA or XRF
98 auto modality = dataset.get_string(tags::modality);
99 if (modality != "XA" && modality != "XRF") return false;
100
101 // Image Pixel Module Type 1
102 if (!dataset.contains(tags::samples_per_pixel)) return false;
103 if (!dataset.contains(tags::photometric_interpretation)) return false;
104 if (!dataset.contains(tags::rows)) return false;
105 if (!dataset.contains(tags::columns)) return false;
106 if (!dataset.contains(tags::bits_allocated)) return false;
107 if (!dataset.contains(tags::bits_stored)) return false;
108 if (!dataset.contains(tags::high_bit)) return false;
109 if (!dataset.contains(tags::pixel_representation)) return false;
110 if (!dataset.contains(tags::pixel_data)) return false;
111
112 // XA Image Module Type 1
113 if (!dataset.contains(tags::image_type)) return false;
114
115 // SOP Common Module Type 1
116 if (!dataset.contains(tags::sop_class_uid)) return false;
117 if (!dataset.contains(tags::sop_instance_uid)) return false;
118
119 return true;
120}
constexpr dicom_tag rows
Rows.
constexpr dicom_tag columns
Columns.
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr dicom_tag image_type
Image Type.
constexpr dicom_tag pixel_data
Pixel Data.
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::image_type, 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_xa_dataset().

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

◆ set_options()

void kcenon::pacs::services::validation::xa_iod_validator::set_options ( const xa_validation_options & options)

Set validation options.

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

Definition at line 143 of file xa_iod_validator.cpp.

143 {
145}
const xa_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::xa_iod_validator::validate ( const core::dicom_dataset & dataset) const
nodiscard

Validate a DICOM dataset against XA IOD.

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

Definition at line 27 of file xa_iod_validator.cpp.

27 {
28 validation_result result;
29 result.is_valid = true;
30
31 // Validate mandatory modules
33 validate_patient_module(dataset, result.findings);
34 validate_general_study_module(dataset, result.findings);
35 validate_general_series_module(dataset, result.findings);
36 validate_xa_acquisition_module(dataset, result.findings);
37 validate_xa_image_module(dataset, result.findings);
38 validate_sop_common_module(dataset, result.findings);
39 }
40
42 validate_image_pixel_module(dataset, result.findings);
43 }
44
46 check_positioner_angles(dataset, result.findings);
47 }
48
50 validate_calibration_module(dataset, result.findings);
51 }
52
53 // Check for errors
54 for (const auto& finding : result.findings) {
55 if (finding.severity == validation_severity::error) {
56 result.is_valid = false;
57 break;
58 }
59 if (options_.strict_mode && finding.severity == validation_severity::warning) {
60 result.is_valid = false;
61 break;
62 }
63 }
64
65 return result;
66}
void validate_calibration_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_positioner_angles(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_xa_acquisition_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_image_pixel_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_xa_image_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool strict_mode
Strict mode - treat warnings as errors.
bool validate_calibration
Validate calibration data for QCA.
bool check_type1
Check Type 1 (required) attributes.
bool validate_pixel_data
Validate pixel data consistency (rows, columns, bits)
bool check_type2
Check Type 2 (required, can be empty) attributes.

References check_positioner_angles(), kcenon::pacs::services::validation::xa_validation_options::check_type1, kcenon::pacs::services::validation::xa_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::xa_validation_options::strict_mode, kcenon::pacs::services::validation::xa_validation_options::validate_calibration, validate_calibration_module(), validate_general_series_module(), validate_general_study_module(), validate_image_pixel_module(), validate_patient_module(), kcenon::pacs::services::validation::xa_validation_options::validate_pixel_data, kcenon::pacs::services::validation::xa_validation_options::validate_positioner, validate_sop_common_module(), validate_xa_acquisition_module(), validate_xa_image_module(), and kcenon::pacs::services::validation::warning.

Referenced by validate_multiframe(), and kcenon::pacs::services::validation::validate_xa_iod().

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

◆ validate_calibration()

validation_result kcenon::pacs::services::validation::xa_iod_validator::validate_calibration ( const core::dicom_dataset & dataset) const
nodiscard

Validate calibration data for quantitative analysis.

Specifically checks if the dataset has valid calibration information suitable for QCA (Quantitative Coronary Analysis) measurements.

Parameters
datasetThe dataset to check
Returns
Validation result focused on calibration attributes
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/validation/xa_iod_validator.h.

Definition at line 123 of file xa_iod_validator.cpp.

123 {
124 validation_result result;
125 result.is_valid = true;
126
127 validate_calibration_module(dataset, result.findings);
128
129 for (const auto& finding : result.findings) {
130 if (finding.severity == validation_severity::error) {
131 result.is_valid = false;
132 break;
133 }
134 }
135
136 return result;
137}

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

Here is the call graph for this function:

◆ validate_calibration_module()

void kcenon::pacs::services::validation::xa_iod_validator::validate_calibration_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/xa_iod_validator.h.

Definition at line 306 of file xa_iod_validator.cpp.

308 {
309
310 // XA Calibration Module (Conditional)
311 // Required if quantitative measurements are to be performed
312
313 bool has_imager_spacing = dataset.contains(xa_tags::imager_pixel_spacing);
314 bool has_sid = dataset.contains(xa_tags::distance_source_to_detector);
315 bool has_sod = dataset.contains(xa_tags::distance_source_to_patient);
316
317 // Imager Pixel Spacing is essential for any calibration
318 if (!has_imager_spacing) {
319 findings.push_back({
322 "ImagerPixelSpacing (0018,1164) not present - "
323 "quantitative measurements not possible",
324 "XA-WARN-002"
325 });
326 }
327
328 // SID and SOD needed for accurate isocenter calibration
329 if (has_imager_spacing && (!has_sid || !has_sod)) {
330 findings.push_back({
333 "DistanceSourceToDetector or DistanceSourceToPatient missing - "
334 "magnification correction not possible for QCA",
335 "XA-WARN-003"
336 });
337 }
338
339 // Validate SID > SOD (physical constraint)
340 if (has_sid && has_sod) {
341 auto sid = dataset.get_numeric<double>(xa_tags::distance_source_to_detector);
342 auto sod = dataset.get_numeric<double>(xa_tags::distance_source_to_patient);
343
344 if (sid && sod && *sid <= *sod) {
345 findings.push_back({
348 "DistanceSourceToDetector (" + std::to_string(*sid) +
349 ") must be greater than DistanceSourceToPatient (" +
350 std::to_string(*sod) + ")",
351 "XA-ERR-001"
352 });
353 }
354 }
355}
constexpr core::dicom_tag distance_source_to_patient
Distance Source to Patient (0018,1111) - SOD.
constexpr core::dicom_tag imager_pixel_spacing
Imager Pixel Spacing (0018,1164) - at detector plane.
constexpr core::dicom_tag distance_source_to_detector
Distance Source to Detector (0018,1110) - SID.

References kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::xa_tags::distance_source_to_detector, kcenon::pacs::services::validation::xa_tags::distance_source_to_patient, kcenon::pacs::services::validation::error, kcenon::pacs::core::dicom_dataset::get_numeric(), kcenon::pacs::services::validation::xa_tags::imager_pixel_spacing, and kcenon::pacs::services::validation::warning.

Referenced by validate(), and validate_calibration().

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

◆ validate_general_series_module()

void kcenon::pacs::services::validation::xa_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/xa_iod_validator.h.

Definition at line 183 of file xa_iod_validator.cpp.

185 {
186
187 // Type 1
188 if (options_.check_type1) {
189 check_type1_attribute(dataset, tags::modality, "Modality", findings);
190 check_type1_attribute(dataset, tags::series_instance_uid, "SeriesInstanceUID", findings);
191
192 // Special check: Modality must be "XA" or "XRF"
193 check_modality(dataset, findings);
194 }
195
196 // Type 2
197 if (options_.check_type2) {
198 check_type2_attribute(dataset, tags::series_number, "SeriesNumber", findings);
199 }
200}
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_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
constexpr dicom_tag series_number
Series Number.

References check_modality(), kcenon::pacs::services::validation::xa_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::xa_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::xa_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/xa_iod_validator.h.

Definition at line 164 of file xa_iod_validator.cpp.

166 {
167
168 // Type 1
169 if (options_.check_type1) {
170 check_type1_attribute(dataset, tags::study_instance_uid, "StudyInstanceUID", findings);
171 }
172
173 // Type 2
174 if (options_.check_type2) {
175 check_type2_attribute(dataset, tags::study_date, "StudyDate", findings);
176 check_type2_attribute(dataset, tags::study_time, "StudyTime", findings);
177 check_type2_attribute(dataset, tags::referring_physician_name, "ReferringPhysicianName", findings);
178 check_type2_attribute(dataset, tags::study_id, "StudyID", findings);
179 check_type2_attribute(dataset, tags::accession_number, "AccessionNumber", findings);
180 }
181}
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::xa_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::xa_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::xa_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/xa_iod_validator.h.

Definition at line 245 of file xa_iod_validator.cpp.

247 {
248
249 // Type 1 attributes
250 if (options_.check_type1) {
251 check_type1_attribute(dataset, tags::samples_per_pixel, "SamplesPerPixel", findings);
252 check_type1_attribute(dataset, tags::photometric_interpretation, "PhotometricInterpretation", findings);
253 check_type1_attribute(dataset, tags::rows, "Rows", findings);
254 check_type1_attribute(dataset, tags::columns, "Columns", findings);
255 check_type1_attribute(dataset, tags::bits_allocated, "BitsAllocated", findings);
256 check_type1_attribute(dataset, tags::bits_stored, "BitsStored", findings);
257 check_type1_attribute(dataset, tags::high_bit, "HighBit", findings);
258 check_type1_attribute(dataset, tags::pixel_representation, "PixelRepresentation", findings);
259 check_type1_attribute(dataset, tags::pixel_data, "PixelData", findings);
260 }
261
262 // Validate pixel data consistency
264 check_pixel_data_consistency(dataset, findings);
265 }
266}
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_pixel_data_consistency(), kcenon::pacs::services::validation::xa_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::xa_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_multiframe()

validation_result kcenon::pacs::services::validation::xa_iod_validator::validate_multiframe ( const core::dicom_dataset & dataset) const
nodiscard

Validate a multi-frame XA dataset.

Performs additional validation for multi-frame specific attributes including frame timing and per-frame calibration.

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

Definition at line 69 of file xa_iod_validator.cpp.

69 {
70 // First do standard validation
71 auto result = validate(dataset);
72
73 // Then add multi-frame specific validation
74 validate_multiframe_module(dataset, result.findings);
75
76 // Re-check validity after multi-frame validation
77 for (const auto& finding : result.findings) {
78 if (finding.severity == validation_severity::error) {
79 result.is_valid = false;
80 break;
81 }
82 }
83
84 return result;
85}
void validate_multiframe_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 XA IOD.

References kcenon::pacs::services::validation::error, validate(), and validate_multiframe_module().

Here is the call graph for this function:

◆ validate_multiframe_module()

void kcenon::pacs::services::validation::xa_iod_validator::validate_multiframe_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/xa_iod_validator.h.

Definition at line 268 of file xa_iod_validator.cpp.

270 {
271
272 // NumberOfFrames is Type 1 for multi-frame
273 if (options_.check_type1) {
274 check_type1_attribute(dataset, xa_tags::number_of_frames, "NumberOfFrames", findings);
275 }
276
277 // Frame timing validation
279 bool has_frame_time = dataset.contains(xa_tags::frame_time);
280 bool has_frame_time_vector = dataset.contains(xa_tags::frame_time_vector);
281
282 if (!has_frame_time && !has_frame_time_vector) {
283 findings.push_back({
286 "Neither FrameTime (0018,1063) nor FrameTimeVector (0018,1065) present - "
287 "frame timing information missing for cine playback",
288 "XA-WARN-001"
289 });
290 }
291
292 // CineRate is useful for proper playback
293 if (!dataset.contains(xa_tags::cine_rate) &&
294 !dataset.contains(xa_tags::recommended_display_frame_rate)) {
295 findings.push_back({
298 "Neither CineRate nor RecommendedDisplayFrameRate present - "
299 "display timing may be incorrect",
300 "XA-INFO-003"
301 });
302 }
303 }
304}
constexpr core::dicom_tag number_of_frames
Number of Frames (0028,0008) - for multi-frame.
constexpr core::dicom_tag recommended_display_frame_rate
Recommended Display Frame Rate (0008,2144)
constexpr core::dicom_tag frame_time
Frame Time (0018,1063) - time between frames in ms.
constexpr core::dicom_tag frame_time_vector
Frame Time Vector (0018,1065) - variable frame timing.
constexpr core::dicom_tag cine_rate
Cine Rate (0018,0040) - intended display rate.
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.
bool validate_multiframe_timing
Validate multi-frame timing information.

References kcenon::pacs::services::validation::xa_validation_options::check_conditional, kcenon::pacs::services::validation::xa_validation_options::check_type1, check_type1_attribute(), kcenon::pacs::services::validation::xa_tags::cine_rate, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::xa_tags::frame_time, kcenon::pacs::services::validation::xa_tags::frame_time_vector, kcenon::pacs::services::validation::info, kcenon::pacs::services::validation::xa_tags::number_of_frames, options_, kcenon::pacs::services::validation::xa_tags::recommended_display_frame_rate, kcenon::pacs::services::validation::xa_validation_options::validate_multiframe_timing, and kcenon::pacs::services::validation::warning.

Referenced by validate_multiframe().

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

◆ validate_patient_module()

void kcenon::pacs::services::validation::xa_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/xa_iod_validator.h.

Definition at line 151 of file xa_iod_validator.cpp.

153 {
154
155 // Patient Module - All attributes are Type 2
156 if (options_.check_type2) {
157 check_type2_attribute(dataset, tags::patient_name, "PatientName", findings);
158 check_type2_attribute(dataset, tags::patient_id, "PatientID", findings);
159 check_type2_attribute(dataset, tags::patient_birth_date, "PatientBirthDate", findings);
160 check_type2_attribute(dataset, tags::patient_sex, "PatientSex", findings);
161 }
162}
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::xa_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::xa_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/xa_iod_validator.h.

Definition at line 357 of file xa_iod_validator.cpp.

359 {
360
361 // Type 1
362 if (options_.check_type1) {
363 check_type1_attribute(dataset, tags::sop_class_uid, "SOPClassUID", findings);
364 check_type1_attribute(dataset, tags::sop_instance_uid, "SOPInstanceUID", findings);
365 }
366
367 // Validate SOP Class UID is an XA/XRF storage class
368 if (dataset.contains(tags::sop_class_uid)) {
369 auto sop_class = dataset.get_string(tags::sop_class_uid);
370 if (!sop_classes::is_xa_storage_sop_class(sop_class)) {
371 findings.push_back({
374 "SOPClassUID is not a recognized XA/XRF Storage SOP Class: " + sop_class,
375 "XA-ERR-002"
376 });
377 }
378 }
379}
bool is_xa_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is an XA/XRF Storage SOP Class.

References kcenon::pacs::services::validation::xa_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_xa_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_xa_acquisition_module()

void kcenon::pacs::services::validation::xa_iod_validator::validate_xa_acquisition_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/xa_iod_validator.h.

Definition at line 202 of file xa_iod_validator.cpp.

204 {
205
206 // XA/XRF Acquisition Module
207 // Most attributes are Type 3 (optional), but we can provide info findings
208
210 // Field of View info - Type 3 but useful for QA
211 if (!dataset.contains(xa_tags::field_of_view_shape)) {
212 findings.push_back({
215 "FieldOfViewShape (0018,1147) not present - FOV information unavailable",
216 "XA-INFO-001"
217 });
218 }
219
220 // Positioner motion for rotational acquisitions
221 if (!dataset.contains(xa_tags::positioner_motion)) {
222 findings.push_back({
225 "PositionerMotion (0018,1500) not present - motion type unknown",
226 "XA-INFO-002"
227 });
228 }
229 }
230}
constexpr core::dicom_tag field_of_view_shape
Field of View Shape (0018,1147)
constexpr core::dicom_tag positioner_motion
Positioner Motion (0018,1500)

References kcenon::pacs::services::validation::xa_validation_options::check_conditional, kcenon::pacs::core::dicom_dataset::contains(), kcenon::pacs::services::validation::xa_tags::field_of_view_shape, kcenon::pacs::services::validation::info, options_, and kcenon::pacs::services::validation::xa_tags::positioner_motion.

Referenced by validate().

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

◆ validate_xa_image_module()

void kcenon::pacs::services::validation::xa_iod_validator::validate_xa_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/xa_iod_validator.h.

Definition at line 232 of file xa_iod_validator.cpp.

234 {
235
236 // Type 1 - Image Type
237 if (options_.check_type1) {
238 check_type1_attribute(dataset, tags::image_type, "ImageType", findings);
239 }
240
241 // Check photometric interpretation is valid for XA
242 check_xa_photometric(dataset, findings);
243}
void check_xa_photometric(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const

References kcenon::pacs::services::validation::xa_validation_options::check_type1, check_type1_attribute(), check_xa_photometric(), kcenon::pacs::core::tags::image_type, and options_.

Referenced by validate().

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: