Pixel/label consistency scan backing MultiLabelSegmentation.validate(). Group images are always uint16, so the buffer is read directly (no ITK type dispatch). Checks two cases per group: pixel values present in the image but not declared as a label, and labels declared but absent from the pixel data.
| 233 | // dispatch). Checks two cases per group: pixel values present in the image but |
| 234 | // not declared as a label, and labels declared but absent from the pixel data. |
| 235 | std::vector<std::string> ValidateConsistency(const MultiLabelSegmentation& seg) |
| 236 | { |
| 237 | std::vector<std::string> warnings; |
| 238 | const auto n = seg.GetNumberOfGroups(); |
| 239 | for (unsigned int g = 0; g < n; ++g) |
| 240 | { |
| 241 | const auto declaredVec = seg.GetLabelValuesByGroup(g); |
| 242 | const std::set<Label::PixelType> declared(declaredVec.begin(), declaredVec.end()); |
| 243 | |
| 244 | std::set<Label::PixelType> present; |
| 245 | const Image* img = seg.GetGroupImage(g); |
| 246 | const auto steps = img->GetTimeSteps(); |
| 247 | for (unsigned int t = 0; t < steps; ++t) |
| 248 | { |
| 249 | auto imageTimeStep = SelectImageByTimeStep(img, t); |
| 250 | std::unique_ptr<ImageReadAccessor> acc; |
| 251 | { |
| 252 | // The accessor takes the image read lock; release the GIL around its |
| 253 | // construction, matching AsNumpyAccessor. The buffer scan below touches |
| 254 | // no Python objects. |
| 255 | py::gil_scoped_release release; |
| 256 | acc = std::make_unique<ImageReadAccessor>(imageTimeStep); |
| 257 | } |
| 258 | const auto* buf = static_cast<const Label::PixelType*>(acc->GetData()); |
| 259 | const std::size_t count = static_cast<std::size_t>(imageTimeStep->GetDimension(0)) * |
| 260 | imageTimeStep->GetDimension(1) * imageTimeStep->GetDimension(2); |
| 261 | for (std::size_t i = 0; i < count; ++i) |
| 262 | if (buf[i] != MultiLabelSegmentation::UNLABELED_VALUE) |
| 263 | present.insert(buf[i]); |
| 264 | } |
| 265 | |
| 266 | for (auto v : present) |
| 267 | if (!declared.count(v)) |
| 268 | warnings.push_back("Group " + std::to_string(g) + ": pixel value " + |
| 269 | std::to_string(v) + " is present in the image but not declared as a label"); |
| 270 | |
| 271 | for (auto v : declared) |
| 272 | if (!present.count(v)) |
| 273 | { |
| 274 | const auto lbl = seg.GetLabel(v); |
| 275 | const std::string name = lbl.IsNotNull() ? lbl->GetName() : "?"; |
| 276 | warnings.push_back("Group " + std::to_string(g) + ": label " + |
| 277 | std::to_string(v) + " ('" + name + "') is declared but not present in the pixel data"); |
| 278 | } |
| 279 | } |
| 280 | return warnings; |
| 281 | } |
| 282 | |
| 283 | } // anonymous namespace |
| 284 |
no test coverage detected