57 : options_(options) {}
90 for (
const auto& finding : result.
findings) {
115 if (type.find(
"TOMO") != std::string::npos) {
118 if (type.find(
"GATED") != std::string::npos) {
124 for (
const auto& finding : result.findings) {
126 result.is_valid =
false;
146 if (modality !=
"NM")
return false;
180 std::vector<validation_finding>& findings)
const {
193 std::vector<validation_finding>& findings)
const {
212 std::vector<validation_finding>& findings)
const {
231 std::vector<validation_finding>& findings)
const {
242 if (type !=
"STATIC" && type !=
"DYNAMIC" && type !=
"GATED" &&
243 type !=
"WHOLE BODY" && type !=
"TOMO" && type !=
"GATED TOMO" &&
244 type !=
"RECON TOMO" && type !=
"RECON GATED TOMO") {
248 "Unusual TypeOfData value for NM: " + type,
257 std::vector<validation_finding>& findings)
const {
272 if (image_type.find(
'\\') == std::string::npos) {
276 "ImageType should contain backslash separators",
285 std::vector<validation_finding>& findings)
const {
291 "EnergyWindowInformationSequence", findings);
297 "RadiopharmaceuticalInformationSequence", findings);
303 std::vector<validation_finding>& findings)
const {
308 "DetectorInformationSequence", findings);
316 "CollimatorType not specified - helps with interpretation",
322 if (collimator !=
"PARA" && collimator !=
"FANB" && collimator !=
"CONE" &&
323 collimator !=
"PINH" && collimator !=
"DIVG" && collimator !=
"NONE") {
327 "Non-standard CollimatorType: " + collimator,
336 std::vector<validation_finding>& findings)
const {
341 "RotationInformationSequence", findings);
349 "StartAngle not specified for SPECT acquisition",
358 "ScanArc not specified for SPECT acquisition",
366 if (direction !=
"CW" && direction !=
"CC") {
370 "Invalid RotationDirection: " + direction +
" (expected CW or CC)",
379 std::vector<validation_finding>& findings)
const {
384 "GatedInformationSequence", findings);
392 "TriggerSourceOrType not specified for gated acquisition",
402 "NumberOfTimeSlots not specified for gated acquisition",
410 std::vector<validation_finding>& findings)
const {
416 "PhotometricInterpretation", findings);
434 std::vector<validation_finding>& findings)
const {
444 if (num_frames && *num_frames > 1) {
449 "FrameIncrementPointer recommended for multi-frame NM images",
459 std::vector<validation_finding>& findings)
const {
474 "SOPClassUID is not a recognized NM Storage SOP Class: " + sop_class,
487 std::vector<validation_finding>& findings)
const {
500 "EnergyWindowRangeSequence not present - energy window details missing",
508 std::vector<validation_finding>& findings)
const {
517 "RadionuclideTotalDose not specified",
527 "RadionuclideHalfLife not specified",
537 "RadiopharmaceuticalStartTime not specified",
551 std::string_view
name,
552 std::vector<validation_finding>& findings)
const {
558 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
569 std::string(
"Type 1 attribute has empty value: ") +
580 std::string_view
name,
581 std::vector<validation_finding>& findings)
const {
588 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
597 std::vector<validation_finding>& findings)
const {
604 if (modality !=
"NM") {
608 "Modality must be 'NM' for nuclear medicine images, found: " + modality,
616 std::vector<validation_finding>& findings)
const {
623 if (bits_allocated && bits_stored) {
624 if (*bits_stored > *bits_allocated) {
628 "BitsStored (" + std::to_string(*bits_stored) +
629 ") exceeds BitsAllocated (" + std::to_string(*bits_allocated) +
")",
636 if (bits_stored && high_bit) {
637 if (*high_bit != *bits_stored - 1) {
641 "HighBit (" + std::to_string(*high_bit) +
642 ") should typically be BitsStored - 1 (" +
643 std::to_string(*bits_stored - 1) +
")",
656 "Unusual photometric interpretation for NM: " + photometric +
657 " (expected MONOCHROME2 or PALETTE COLOR)",
665 if (samples && *samples != 1) {
669 "NM images should have SamplesPerPixel = 1, found: " +
670 std::to_string(*samples),
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_energy_window_info(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
validation_result validate_multiframe(const core::dicom_dataset &dataset) const
Validate a multi-frame NM dataset.
void check_pixel_data_consistency(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
nm_iod_validator()=default
Construct validator with default options.
validation_result validate(const core::dicom_dataset &dataset) const
Validate a DICOM dataset against NM IOD.
void validate_general_study_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void set_options(const nm_validation_options &options)
Set validation options.
void validate_multiframe_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_nm_isotope_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
nm_validation_options options_
void validate_nm_tomo_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_nm_gated_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_nm_detector_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
const nm_validation_options & options() const noexcept
Get the validation options.
void validate_patient_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_nm_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool quick_check(const core::dicom_dataset &dataset) const
Quick check if dataset has minimum required attributes.
void validate_image_pixel_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_modality(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_nm_image_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_radiopharmaceutical_info(const core::dicom_dataset &dataset, 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 validate_sop_common_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
Compile-time constants for commonly used DICOM tags.
bool is_valid_nm_photometric(std::string_view value) noexcept
Check if photometric interpretation is valid for NM.
bool is_nm_storage_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is a NM Storage SOP Class.
bool is_valid_nm_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid NM image.
@ warning
Non-critical - IOD may have issues.
@ info
Informational - suggestion for improvement.
@ error
Critical - IOD is non-compliant.
validation_result validate_nm_iod(const core::dicom_dataset &dataset)
Validate a NM dataset with default options.
Nuclear Medicine (NM) Image IOD Validator.
Nuclear Medicine (NM) Image Storage SOP Classes.
Options for NM IOD validation.
bool validate_pixel_data
Validate pixel data consistency (rows, columns, bits)
bool validate_energy_windows
Validate energy window information.
bool validate_nm_specific
Validate NM-specific attributes (detector, collimator, etc.)
bool check_type2
Check Type 2 (required, can be empty) attributes.
bool validate_isotope
Validate isotope information.
bool check_type1
Check Type 1 (required) attributes.
bool check_conditional
Check Type 1C/2C (conditionally required) attributes.
bool strict_mode
Strict mode - treat warnings as errors.
Result of IOD validation.
std::vector< validation_finding > findings
All findings during validation.
bool is_valid
Overall validation status.