comparison Framework/Deprecated/Loaders/OrthancMultiframeVolumeLoader.cpp @ 1279:7ec8fea061b9 broker

integration mainline->broker
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 04 Feb 2020 15:20:08 +0100
parents Framework/Loaders/OrthancMultiframeVolumeLoader.cpp@2d8ab34c8c91 Framework/Loaders/OrthancMultiframeVolumeLoader.cpp@0ca50d275b9a
children 6ab03e429f06
comparison
equal deleted inserted replaced
1271:0ca50d275b9a 1279:7ec8fea061b9
261 uint16_t* targetUp = reinterpret_cast<uint16_t*>(&target); 261 uint16_t* targetUp = reinterpret_cast<uint16_t*>(&target);
262 CopyPixel(*targetUp, source); 262 CopyPixel(*targetUp, source);
263 } 263 }
264 264
265 template <typename T> 265 template <typename T>
266 void OrthancMultiframeVolumeLoader::CopyPixelData(const std::string& pixelData) 266 void OrthancMultiframeVolumeLoader::CopyPixelDataAndComputeDistribution(
267 const std::string& pixelData, std::map<T,uint64_t>& distribution)
267 { 268 {
268 OrthancStone::ImageBuffer3D& target = volume_->GetPixelData(); 269 OrthancStone::ImageBuffer3D& target = volume_->GetPixelData();
269 270
270 const unsigned int bpp = target.GetBytesPerPixel(); 271 const unsigned int bpp = target.GetBytesPerPixel();
271 const unsigned int width = target.GetWidth(); 272 const unsigned int width = target.GetWidth();
281 if (pixelData.empty()) 282 if (pixelData.empty())
282 { 283 {
283 return; 284 return;
284 } 285 }
285 286
286 const uint8_t* source = reinterpret_cast<const uint8_t*>(pixelData.c_str()); 287 // first pass to initialize map
287 288 {
288 for (unsigned int z = 0; z < depth; z++) 289 const uint8_t* source = reinterpret_cast<const uint8_t*>(pixelData.c_str());
289 { 290
290 OrthancStone::ImageBuffer3D::SliceWriter writer(target, OrthancStone::VolumeProjection_Axial, z); 291 for (unsigned int z = 0; z < depth; z++)
291 292 {
292 assert (writer.GetAccessor().GetWidth() == width && 293 for (unsigned int y = 0; y < height; y++)
293 writer.GetAccessor().GetHeight() == height);
294
295 for (unsigned int y = 0; y < height; y++)
296 {
297 assert(sizeof(T) == Orthanc::GetBytesPerPixel(target.GetFormat()));
298
299 T* target = reinterpret_cast<T*>(writer.GetAccessor().GetRow(y));
300
301 for (unsigned int x = 0; x < width; x++)
302 { 294 {
303 CopyPixel(*target, source); 295 for (unsigned int x = 0; x < width; x++)
304 target ++; 296 {
305 source += bpp; 297 T value;
298 CopyPixel(value, source);
299 distribution[value] = 0;
300 source += bpp;
301 }
306 } 302 }
307 } 303 }
308 } 304 }
305
306 {
307 const uint8_t* source = reinterpret_cast<const uint8_t*>(pixelData.c_str());
308
309 for (unsigned int z = 0; z < depth; z++)
310 {
311 OrthancStone::ImageBuffer3D::SliceWriter writer(target, OrthancStone::VolumeProjection_Axial, z);
312
313 assert(writer.GetAccessor().GetWidth() == width &&
314 writer.GetAccessor().GetHeight() == height);
315
316 for (unsigned int y = 0; y < height; y++)
317 {
318 assert(sizeof(T) == Orthanc::GetBytesPerPixel(target.GetFormat()));
319
320 T* target = reinterpret_cast<T*>(writer.GetAccessor().GetRow(y));
321
322 for (unsigned int x = 0; x < width; x++)
323 {
324 CopyPixel(*target, source);
325
326 distribution[*target] += 1;
327
328 target++;
329 source += bpp;
330 }
331 }
332 }
333 }
334 }
335
336 template <typename T>
337 void OrthancMultiframeVolumeLoader::ComputeMinMaxWithOutlierRejection(
338 const std::map<T, uint64_t>& distribution)
339 {
340 if (distribution.size() == 0)
341 {
342 LOG(ERROR) << "ComputeMinMaxWithOutlierRejection -- Volume image empty.";
343 }
344 else
345 {
346 OrthancStone::ImageBuffer3D& target = volume_->GetPixelData();
347
348 const uint64_t bpp = target.GetBytesPerPixel();
349 const uint64_t width = target.GetWidth();
350 const uint64_t height = target.GetHeight();
351 const uint64_t depth = target.GetDepth();
352 const uint64_t voxelCount = width * height * depth;
353
354 // now that we have distribution[pixelValue] == numberOfPixelsWithValue
355 // compute number of values and check (assertion) that it is equal to
356 // width * height * depth
357 {
358 typename std::map<T, uint64_t>::const_iterator it = distribution.begin();
359 uint64_t totalCount = 0;
360 distributionRawMin_ = static_cast<float>(it->first);
361
362 while (it != distribution.end())
363 {
364 T pixelValue = it->first;
365 uint64_t count = it->second;
366 totalCount += count;
367 it++;
368 if (it == distribution.end())
369 distributionRawMax_ = static_cast<float>(pixelValue);
370 }
371 LOG(INFO) << "Volume image. First distribution value = "
372 << static_cast<float>(distributionRawMin_)
373 << " | Last distribution value = "
374 << static_cast<float>(distributionRawMax_);
375
376 if (totalCount != voxelCount)
377 {
378 LOG(ERROR) << "Internal error in dose distribution computation. TC ("
379 << totalCount << ") != VoxC (" << voxelCount;
380 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
381 }
382 }
383
384 // compute the number of voxels to reject at each end of the distribution
385 uint64_t endRejectionCount = static_cast<uint64_t>(
386 outliersHalfRejectionRate_ * voxelCount);
387
388 if (endRejectionCount > voxelCount)
389 {
390 LOG(ERROR) << "Internal error in dose distribution computation."
391 << " endRejectionCount = " << endRejectionCount
392 << " | voxelCount = " << voxelCount;
393 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
394 }
395
396 // this will contain the actual distribution minimum after outlier
397 // rejection
398 T resultMin = 0;
399
400 // then start from start and remove pixel values up to
401 // endRejectionCount voxels rejected
402 {
403 typename std::map<T, uint64_t>::const_iterator it = distribution.begin();
404
405 uint64_t currentCount = 0;
406
407 while (it != distribution.end())
408 {
409 T pixelValue = it->first;
410 uint64_t count = it->second;
411
412 // if this pixelValue crosses the rejection threshold, let's set it
413 // and exit the loop
414 if ((currentCount <= endRejectionCount) &&
415 (currentCount + count > endRejectionCount))
416 {
417 resultMin = pixelValue;
418 break;
419 }
420 else
421 {
422 currentCount += count;
423 }
424 // and continue walking along the distribution
425 it++;
426 }
427 }
428
429 // this will contain the actual distribution maximum after outlier
430 // rejection
431 T resultMax = 0;
432 // now start from END and remove pixel values up to
433 // endRejectionCount voxels rejected
434 {
435 typename std::map<T, uint64_t>::const_reverse_iterator it = distribution.rbegin();
436
437 uint64_t currentCount = 0;
438
439 while (it != distribution.rend())
440 {
441 T pixelValue = it->first;
442 uint64_t count = it->second;
443
444 if ((currentCount <= endRejectionCount) &&
445 (currentCount + count > endRejectionCount))
446 {
447 resultMax = pixelValue;
448 break;
449 }
450 else
451 {
452 currentCount += count;
453 }
454 // and continue walking along the distribution
455 it++;
456 }
457 }
458 if (resultMin > resultMax)
459 {
460 LOG(ERROR) << "Internal error in dose distribution computation! " <<
461 "resultMin (" << resultMin << ") > resultMax (" << resultMax << ")";
462 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
463 }
464 computedDistributionMin_ = static_cast<float>(resultMin);
465 computedDistributionMax_ = static_cast<float>(resultMax);
466 }
467 }
468
469 template <typename T>
470 void OrthancMultiframeVolumeLoader::CopyPixelDataAndComputeMinMax(
471 const std::string& pixelData)
472 {
473 std::map<T, uint64_t> distribution;
474 CopyPixelDataAndComputeDistribution(pixelData, distribution);
475 ComputeMinMaxWithOutlierRejection(distribution);
309 } 476 }
310 477
311 void OrthancMultiframeVolumeLoader::SetUncompressedPixelData(const std::string& pixelData) 478 void OrthancMultiframeVolumeLoader::SetUncompressedPixelData(const std::string& pixelData)
312 { 479 {
313 switch (volume_->GetPixelData().GetFormat()) 480 switch (volume_->GetPixelData().GetFormat())
314 { 481 {
315 case Orthanc::PixelFormat_Grayscale32: 482 case Orthanc::PixelFormat_Grayscale32:
316 CopyPixelData<uint32_t>(pixelData); 483 CopyPixelDataAndComputeMinMax<uint32_t>(pixelData);
317 break; 484 break;
318 case Orthanc::PixelFormat_Grayscale16: 485 case Orthanc::PixelFormat_Grayscale16:
319 CopyPixelData<uint16_t>(pixelData); 486 CopyPixelDataAndComputeMinMax<uint16_t>(pixelData);
320 break; 487 break;
321 case Orthanc::PixelFormat_SignedGrayscale16: 488 case Orthanc::PixelFormat_SignedGrayscale16:
322 CopyPixelData<int16_t>(pixelData); 489 CopyPixelDataAndComputeMinMax<int16_t>(pixelData);
323 break; 490 break;
324 default: 491 default:
325 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 492 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
326 } 493 }
327 494
339 const OrthancStone::VolumeImageGeometry& OrthancMultiframeVolumeLoader::GetImageGeometry() const 506 const OrthancStone::VolumeImageGeometry& OrthancMultiframeVolumeLoader::GetImageGeometry() const
340 { 507 {
341 return volume_->GetGeometry(); 508 return volume_->GetGeometry();
342 } 509 }
343 510
344 OrthancMultiframeVolumeLoader::OrthancMultiframeVolumeLoader(boost::shared_ptr<OrthancStone::DicomVolumeImage> volume, 511 OrthancMultiframeVolumeLoader::OrthancMultiframeVolumeLoader(
345 OrthancStone::IOracle& oracle, 512 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume,
346 OrthancStone::IObservable& oracleObservable) : 513 OrthancStone::IOracle& oracle,
514 OrthancStone::IObservable& oracleObservable,
515 float outliersHalfRejectionRate) :
347 LoaderStateMachine(oracle, oracleObservable), 516 LoaderStateMachine(oracle, oracleObservable),
348 volume_(volume), 517 volume_(volume),
349 pixelDataLoaded_(false) 518 pixelDataLoaded_(false),
519 outliersHalfRejectionRate_(outliersHalfRejectionRate),
520 distributionRawMin_(0),
521 distributionRawMax_(0),
522 computedDistributionMin_(0),
523 computedDistributionMax_(0)
350 { 524 {
351 if (volume.get() == NULL) 525 if (volume.get() == NULL)
352 { 526 {
353 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); 527 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
354 } 528 }
355 } 529 }
356 530
357 OrthancMultiframeVolumeLoader::~OrthancMultiframeVolumeLoader() 531 OrthancMultiframeVolumeLoader::~OrthancMultiframeVolumeLoader()
358 { 532 {
359 LOG(TRACE) << "OrthancMultiframeVolumeLoader::~OrthancMultiframeVolumeLoader()"; 533 LOG(TRACE) << "OrthancMultiframeVolumeLoader::~OrthancMultiframeVolumeLoader()";
534 }
535
536
537 void OrthancMultiframeVolumeLoader::GetDistributionMinMax
538 (float& minValue, float& maxValue) const
539 {
540 if (distributionRawMin_ == 0 && distributionRawMax_ == 0)
541 {
542 LOG(WARNING) << "GetDistributionMinMaxWithOutliersRejection called before computation!";
543 }
544 minValue = distributionRawMin_;
545 maxValue = distributionRawMax_;
546 }
547
548 void OrthancMultiframeVolumeLoader::GetDistributionMinMaxWithOutliersRejection
549 (float& minValue, float& maxValue) const
550 {
551 if (computedDistributionMin_ == 0 && computedDistributionMax_ == 0)
552 {
553 LOG(WARNING) << "GetDistributionMinMaxWithOutliersRejection called before computation!";
554 }
555 minValue = computedDistributionMin_;
556 maxValue = computedDistributionMax_;
360 } 557 }
361 558
362 void OrthancMultiframeVolumeLoader::LoadInstance(const std::string& instanceId) 559 void OrthancMultiframeVolumeLoader::LoadInstance(const std::string& instanceId)
363 { 560 {
364 Start(); 561 Start();