25 : options_(options) {}
54 for (
const auto& finding : result.
findings) {
77 for (
const auto& finding : result.findings) {
79 result.is_valid =
false;
99 if (modality !=
"XA" && modality !=
"XRF")
return false;
129 for (
const auto& finding : result.
findings) {
153 std::vector<validation_finding>& findings)
const {
166 std::vector<validation_finding>& findings)
const {
185 std::vector<validation_finding>& findings)
const {
204 std::vector<validation_finding>& findings)
const {
215 "FieldOfViewShape (0018,1147) not present - FOV information unavailable",
225 "PositionerMotion (0018,1500) not present - motion type unknown",
234 std::vector<validation_finding>& findings)
const {
247 std::vector<validation_finding>& findings)
const {
270 std::vector<validation_finding>& findings)
const {
282 if (!has_frame_time && !has_frame_time_vector) {
286 "Neither FrameTime (0018,1063) nor FrameTimeVector (0018,1065) present - "
287 "frame timing information missing for cine playback",
298 "Neither CineRate nor RecommendedDisplayFrameRate present - "
299 "display timing may be incorrect",
308 std::vector<validation_finding>& findings)
const {
318 if (!has_imager_spacing) {
322 "ImagerPixelSpacing (0018,1164) not present - "
323 "quantitative measurements not possible",
329 if (has_imager_spacing && (!has_sid || !has_sod)) {
333 "DistanceSourceToDetector or DistanceSourceToPatient missing - "
334 "magnification correction not possible for QCA",
340 if (has_sid && has_sod) {
344 if (sid && sod && *sid <= *sod) {
348 "DistanceSourceToDetector (" + std::to_string(*sid) +
349 ") must be greater than DistanceSourceToPatient (" +
350 std::to_string(*sod) +
")",
359 std::vector<validation_finding>& findings)
const {
374 "SOPClassUID is not a recognized XA/XRF Storage SOP Class: " + sop_class,
388 std::string_view
name,
389 std::vector<validation_finding>& findings)
const {
395 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
406 std::string(
"Type 1 attribute has empty value: ") +
417 std::string_view
name,
418 std::vector<validation_finding>& findings)
const {
425 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
434 std::vector<validation_finding>& findings)
const {
441 if (modality !=
"XA" && modality !=
"XRF") {
445 "Modality must be 'XA' or 'XRF' for angiographic images, found: " + modality,
453 std::vector<validation_finding>& findings)
const {
464 "Invalid photometric interpretation for XA: " + photometric +
465 " (must be MONOCHROME1 or MONOCHROME2)",
473 std::vector<validation_finding>& findings)
const {
480 if (bits_allocated && bits_stored) {
481 if (*bits_stored > *bits_allocated) {
485 "BitsStored (" + std::to_string(*bits_stored) +
486 ") exceeds BitsAllocated (" + std::to_string(*bits_allocated) +
")",
492 if (*bits_stored != 8 && *bits_stored != 10 &&
493 *bits_stored != 12 && *bits_stored != 16) {
497 "Unusual BitsStored for XA: " + std::to_string(*bits_stored) +
498 " (expected 8, 10, 12, or 16)",
505 if (bits_stored && high_bit) {
506 if (*high_bit != *bits_stored - 1) {
510 "HighBit (" + std::to_string(*high_bit) +
511 ") should typically be BitsStored - 1 (" +
512 std::to_string(*bits_stored - 1) +
")",
520 if (samples && *samples != 1) {
524 "XA images must be grayscale (SamplesPerPixel = 1), found: " +
525 std::to_string(*samples),
532 if (pixel_rep && *pixel_rep != 0) {
536 "XA images typically use unsigned integers (PixelRepresentation = 0)",
544 std::vector<validation_finding>& findings)
const {
550 if (has_primary != has_secondary) {
555 "Only one positioner angle present - complete geometry unavailable",
560 if (!has_primary && !has_secondary) {
564 "No positioner angle information - geometry reconstruction not possible",
572 if (angle && (*angle < -180.0 || *angle > 180.0)) {
576 "PositionerPrimaryAngle (" + std::to_string(*angle) +
577 ") outside typical range [-180, 180]",
585 if (angle && (*angle < -90.0 || *angle > 90.0)) {
589 "PositionerSecondaryAngle (" + std::to_string(*angle) +
590 ") outside typical range [-90, 90]",
621 if (!sid || !sod || *sid <= *sod)
return false;
auto get_numeric(dicom_tag tag) const -> std::optional< T >
Get the numeric value of an element.
auto contains(dicom_tag tag) const noexcept -> bool
Check if the dataset contains an element with the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
auto to_string() const -> std::string
Convert to string representation.
void validate_calibration_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 check_pixel_data_consistency(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate_calibration(const core::dicom_dataset &dataset) const
Validate calibration data for quantitative analysis.
void set_options(const xa_validation_options &options)
Set validation options.
validation_result validate_multiframe(const core::dicom_dataset &dataset) const
Validate a multi-frame XA dataset.
void validate_sop_common_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
const xa_validation_options & options() const noexcept
Get the validation options.
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_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 check_xa_photometric(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
xa_iod_validator()=default
Construct validator with default options.
bool quick_check(const core::dicom_dataset &dataset) const
Quick check if dataset has minimum required XA attributes.
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
xa_validation_options options_
validation_result validate(const core::dicom_dataset &dataset) const
Validate a DICOM dataset against XA IOD.
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void validate_general_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
Compile-time constants for commonly used DICOM tags.
bool is_valid_xa_photometric(std::string_view value) noexcept
Check if photometric interpretation is valid for XA.
bool is_xa_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is an XA/XRF Storage SOP Class.
bool is_valid_xa_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid XA image.
@ warning
Non-critical - IOD may have issues.
@ info
Informational - suggestion for improvement.
@ error
Critical - IOD is non-compliant.
bool has_qca_calibration(const core::dicom_dataset &dataset)
Check if dataset has valid QCA calibration data.
validation_result validate_xa_iod(const core::dicom_dataset &dataset)
Validate an XA dataset with default options.
Result of IOD validation.
std::vector< validation_finding > findings
All findings during validation.
bool is_valid
Overall validation status.
Options for XA IOD validation.
bool strict_mode
Strict mode - treat warnings as errors.
bool validate_calibration
Validate calibration data for QCA.
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.
bool check_type1
Check Type 1 (required) attributes.
bool validate_pixel_data
Validate pixel data consistency (rows, columns, bits)
bool validate_positioner
Validate positioner angle data.
bool check_type2
Check Type 2 (required, can be empty) attributes.
bool validate_multiframe_timing
Validate multi-frame timing information.
X-Ray Angiographic Image IOD Validator.
X-Ray Angiographic (XA) Image Storage SOP Classes.