| 190 | } |
| 191 | |
| 192 | std::vector<mitk::DICOMSegmentationPropertyHelper::MissingItem> |
| 193 | mitk::DICOMSegmentationPropertyHelper::Validate(const MultiLabelSegmentation* seg) |
| 194 | { |
| 195 | if (seg == nullptr) |
| 196 | mitkThrow() << "DICOMSegmentationPropertyHelper::Validate: seg must not be nullptr."; |
| 197 | |
| 198 | std::vector<MissingItem> missing; |
| 199 | |
| 200 | for (const auto& req : kSegmentationLevelTags) |
| 201 | { |
| 202 | if (!HasProperty(seg, DICOMTagKey(req.group, req.element))) |
| 203 | AddSegmentationLevelMissing(missing, req.description); |
| 204 | } |
| 205 | |
| 206 | // Source-image relation is not checked here. ReferencedSeriesSequence is |
| 207 | // type 1C in the SEG IOD (conditional on DerivationImageSequence) so a |
| 208 | // source-less SEG is DICOM-legal; an ID-layer-only relation is also |
| 209 | // fine for in-session use. The writer decides what to emit at export |
| 210 | // time. |
| 211 | |
| 212 | // Algorithm Type (0062,0008) is reported as missing when the label is still Undefined, i.e. no |
| 213 | // creation path declared an origin. This is intentional: Validate surfaces the undeclared field to |
| 214 | // the caller. Complete() backfills such a label to MANUAL (only when its synthesizeMissingIdentity |
| 215 | // option is enabled), and the DICOM SEG writer defaults a still-Undefined type to MANUAL at export |
| 216 | // regardless. |
| 217 | const auto labels = seg->GetLabels(); |
| 218 | for (const auto& label : labels) |
| 219 | { |
| 220 | if (label->GetValue() == Label::UNLABELED_VALUE) |
| 221 | continue; |
| 222 | |
| 223 | const auto algoType = label->GetAlgorithmType(); |
| 224 | if (algoType == Label::AlgorithmType::Undefined) |
| 225 | AddLabelMissing(missing, label->GetValue(), "Algorithm Type (0062,0008)"); |
| 226 | |
| 227 | // SegmentAlgorithmName (0062,0009) is DICOM Type 1C: required only when |
| 228 | // SegmentAlgorithmType is AUTOMATIC or SEMIAUTOMATIC. dcmqi correctly |
| 229 | // omits the tag for MANUAL labels, so requiring a name unconditionally |
| 230 | // would block a legitimate round trip on Validate. We test for the property |
| 231 | // being present (HasAlgorithmName), not GetAlgorithmName().empty(): the latter |
| 232 | // never reports empty because it falls back to the "MITK Segmentation" prefix. |
| 233 | if ((algoType == Label::AlgorithmType::AUTOMATIC |
| 234 | || algoType == Label::AlgorithmType::SEMIAUTOMATIC) |
| 235 | && !label->HasAlgorithmName()) |
| 236 | AddLabelMissing(missing, label->GetValue(), "Algorithm Name (0062,0009)"); |
| 237 | |
| 238 | // Tracking ID/UID (0062,0020/0062,0021) are Type 3 in the SEG IOD's |
| 239 | // Segment Description Macro, so absence is DICOM-legal. Segmented |
| 240 | // Property Category/Type (0062,0003/0062,000F) are Type 1, but the |
| 241 | // writer fills them with an explicit "unknown" code when absent so |
| 242 | // strict mode does not need to demand a user-supplied value here. |
| 243 | } |
| 244 | |
| 245 | return missing; |
| 246 | } |
| 247 | |
| 248 | std::vector<mitk::DICOMSegmentationPropertyHelper::MissingItem> |
| 249 | mitk::DICOMSegmentationPropertyHelper::Complete(MultiLabelSegmentation* seg, |
nothing calls this directly
no test coverage detected