comparison OrthancServer/OrthancRestApi/OrthancRestResources.cpp @ 3600:4066998150ef

/instances/{id}/preview route now takes the windowing into account
author Alain Mazy <alain@mazy.be>
date Thu, 09 Jan 2020 18:54:40 +0100
parents 810772486249
children a77e7839012a
comparison
equal deleted inserted replaced
3599:e01900f913e7 3600:4066998150ef
37 #include "../../Core/Compression/GzipCompressor.h" 37 #include "../../Core/Compression/GzipCompressor.h"
38 #include "../../Core/DicomParsing/DicomWebJsonVisitor.h" 38 #include "../../Core/DicomParsing/DicomWebJsonVisitor.h"
39 #include "../../Core/DicomParsing/FromDcmtkBridge.h" 39 #include "../../Core/DicomParsing/FromDcmtkBridge.h"
40 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h" 40 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h"
41 #include "../../Core/HttpServer/HttpContentNegociation.h" 41 #include "../../Core/HttpServer/HttpContentNegociation.h"
42 #include "../../Core/Images/ImageProcessing.h"
42 #include "../../Core/Logging.h" 43 #include "../../Core/Logging.h"
43 #include "../DefaultDicomImageDecoder.h" 44 #include "../DefaultDicomImageDecoder.h"
44 #include "../OrthancConfiguration.h" 45 #include "../OrthancConfiguration.h"
45 #include "../Search/DatabaseLookup.h" 46 #include "../Search/DatabaseLookup.h"
46 #include "../ServerContext.h" 47 #include "../ServerContext.h"
500 } 501 }
501 }; 502 };
502 } 503 }
503 504
504 505
506 void LookupWindowingTags(const ParsedDicomFile& dicom, float& windowCenter, float& windowWidth, float& rescaleSlope, float& rescaleIntercept, bool& invert)
507 {
508 DicomMap dicomTags;
509 dicom.ExtractDicomSummary(dicomTags);
510
511
512 unsigned int bitsStored = boost::lexical_cast<unsigned int>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_BITS_STORED, "8", false));
513 windowWidth = static_cast<float>(2 << (bitsStored - 1));
514 windowCenter = windowWidth / 2;
515 rescaleSlope = 1.0f;
516 rescaleIntercept = 0.0f;
517 invert = false;
518
519 if (dicomTags.HasTag(Orthanc::DICOM_TAG_WINDOW_CENTER) && dicomTags.HasTag(Orthanc::DICOM_TAG_WINDOW_WIDTH))
520 {
521 windowCenter = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_WINDOW_CENTER, "", false));
522 windowWidth = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_WINDOW_WIDTH, "", false));
523 }
524
525 if (dicomTags.HasTag(Orthanc::DICOM_TAG_RESCALE_SLOPE) && dicomTags.HasTag(Orthanc::DICOM_TAG_RESCALE_INTERCEPT))
526 {
527 rescaleSlope = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_RESCALE_SLOPE, "", false));
528 rescaleIntercept = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_RESCALE_INTERCEPT, "", false));
529 }
530
531 PhotometricInterpretation photometric;
532 if (dicom.LookupPhotometricInterpretation(photometric))
533 {
534 invert = (photometric == PhotometricInterpretation_Monochrome1);
535 }
536 }
537
505 template <enum ImageExtractionMode mode> 538 template <enum ImageExtractionMode mode>
506 static void GetImage(RestApiGetCall& call) 539 static void GetImage(RestApiGetCall& call)
507 { 540 {
508 ServerContext& context = OrthancRestApi::GetContext(call); 541 ServerContext& context = OrthancRestApi::GetContext(call);
509 542
518 { 551 {
519 return; 552 return;
520 } 553 }
521 554
522 bool invert = false; 555 bool invert = false;
556 float windowCenter = 128.0f;
557 float windowWidth = 256.0f;
558 float rescaleSlope = 1.0f;
559 float rescaleIntercept = 0.0f;
560
523 std::auto_ptr<ImageAccessor> decoded; 561 std::auto_ptr<ImageAccessor> decoded;
524 562
525 try 563 try
526 { 564 {
527 std::string publicId = call.GetUriComponent("id", ""); 565 std::string publicId = call.GetUriComponent("id", "");
547 // TODO Optimize this lookup for photometric interpretation: 585 // TODO Optimize this lookup for photometric interpretation:
548 // It should be implemented by the plugin to avoid parsing 586 // It should be implemented by the plugin to avoid parsing
549 // twice the DICOM file 587 // twice the DICOM file
550 ParsedDicomFile parsed(dicomContent); 588 ParsedDicomFile parsed(dicomContent);
551 589
552 PhotometricInterpretation photometric; 590 LookupWindowingTags(dicomContent, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert);
553 if (parsed.LookupPhotometricInterpretation(photometric))
554 {
555 invert = (photometric == PhotometricInterpretation_Monochrome1);
556 }
557 } 591 }
558 } 592 }
559 #endif 593 #endif
560 594
561 if (decoded.get() == NULL) 595 if (decoded.get() == NULL)
562 { 596 {
563 // Use Orthanc's built-in decoder, using the cache to speed-up 597 // Use Orthanc's built-in decoder, using the cache to speed-up
564 // things on multi-frame images 598 // things on multi-frame images
565 ServerContext::DicomCacheLocker locker(context, publicId); 599 ServerContext::DicomCacheLocker locker(context, publicId);
566 decoded.reset(DicomImageDecoder::Decode(locker.GetDicom(), frame)); 600 decoded.reset(DicomImageDecoder::Decode(locker.GetDicom(), frame));
567 601 LookupWindowingTags(locker.GetDicom(), windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert);
568 PhotometricInterpretation photometric; 602
569 if (mode == ImageExtractionMode_Preview && 603 if (mode != ImageExtractionMode_Preview)
570 locker.GetDicom().LookupPhotometricInterpretation(photometric))
571 { 604 {
572 invert = (photometric == PhotometricInterpretation_Monochrome1); 605 invert = false;
573 } 606 }
574 } 607 }
575 } 608 }
576 catch (OrthancException& e) 609 catch (OrthancException& e)
577 { 610 {
589 } 622 }
590 623
591 call.GetOutput().Redirect(root + "app/images/unsupported.png"); 624 call.GetOutput().Redirect(root + "app/images/unsupported.png");
592 } 625 }
593 return; 626 return;
627 }
628
629 if (mode == ImageExtractionMode_Preview
630 && (decoded->GetFormat() == Orthanc::PixelFormat_Grayscale8 || decoded->GetFormat() == Orthanc::PixelFormat_Grayscale16))
631 {
632 ImageProcessing::ApplyWindowing(*decoded, *decoded, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert);
633 invert = false; // don't invert it later on when encoding it, it has been inverted in the ApplyWindowing function
594 } 634 }
595 635
596 ImageToEncode image(decoded, mode, invert); 636 ImageToEncode image(decoded, mode, invert);
597 637
598 HttpContentNegociation negociation; 638 HttpContentNegociation negociation;