comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1695:a691ab50d416

support of series with instances of varying resolutions - LSD-479
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 26 Nov 2020 19:46:33 +0100
parents 7226b68e2742
children b5a8bf32d969
comparison
equal deleted inserted replaced
1694:7226b68e2742 1695:a691ab50d416
103 // We are not running ParseWebAssemblyExports.py, but we're compiling the wasm 103 // We are not running ParseWebAssemblyExports.py, but we're compiling the wasm
104 # define STONE_WEB_VIEWER_EXPORT 104 # define STONE_WEB_VIEWER_EXPORT
105 #endif 105 #endif
106 106
107 107
108 #define FIX_LSD_479 1
109
110
108 enum STONE_WEB_VIEWER_EXPORT ThumbnailType 111 enum STONE_WEB_VIEWER_EXPORT ThumbnailType
109 { 112 {
110 ThumbnailType_Image, 113 ThumbnailType_Image,
111 ThumbnailType_NoPreview, 114 ThumbnailType_NoPreview,
112 ThumbnailType_Pdf, 115 ThumbnailType_Pdf,
1404 bool fitNextContent_; 1407 bool fitNextContent_;
1405 std::list<PrefetchItem> prefetchQueue_; 1408 std::list<PrefetchItem> prefetchQueue_;
1406 bool serverSideTranscoding_; 1409 bool serverSideTranscoding_;
1407 OrthancStone::Vector synchronizationOffset_; 1410 OrthancStone::Vector synchronizationOffset_;
1408 bool synchronizationEnabled_; 1411 bool synchronizationEnabled_;
1409 1412 double centralPhysicalWidth_; // LSD-479
1413 double centralPhysicalHeight_;
1410 1414
1411 bool hasFocusOnInstance_; 1415 bool hasFocusOnInstance_;
1412 std::string focusSopInstanceUid_; 1416 std::string focusSopInstanceUid_;
1413 size_t focusFrameNumber_; 1417 size_t focusFrameNumber_;
1414 1418
1517 1521
1518 void RenderCurrentScene(const Orthanc::ImageAccessor& frame, 1522 void RenderCurrentScene(const Orthanc::ImageAccessor& frame,
1519 const OrthancStone::DicomInstanceParameters& instance, 1523 const OrthancStone::DicomInstanceParameters& instance,
1520 const OrthancStone::CoordinateSystem3D& plane) 1524 const OrthancStone::CoordinateSystem3D& plane)
1521 { 1525 {
1526 /**
1527 * IMPORTANT - DO NOT use "instance.GetWidth()" and
1528 * "instance.GetHeight()" in this method. Use the information from
1529 * "frame" instead. Indeed, the "instance" information is taken
1530 * from DICOMweb "/studies/.../series/.../metadata". But,
1531 * "SeriesMetadataExtrapolatedTags" includes the "Columns" and
1532 * "Rows" DICOM tags for performance, which make this information
1533 * unreliable if the series includes instances with varying sizes
1534 * (cf. LSD-479).
1535 **/
1536
1522 SaveCurrentWindowing(); 1537 SaveCurrentWindowing();
1523 1538
1524 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() == 1539 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() ==
1525 Orthanc::PhotometricInterpretation_Monochrome1); 1540 Orthanc::PhotometricInterpretation_Monochrome1);
1526 1541
1527 std::unique_ptr<OrthancStone::TextureBaseSceneLayer> layer; 1542 std::unique_ptr<OrthancStone::TextureBaseSceneLayer> layer;
1528 1543
1552 layer->SetFlipX(flipX_); 1567 layer->SetFlipX(flipX_);
1553 layer->SetFlipY(flipY_); 1568 layer->SetFlipY(flipY_);
1554 1569
1555 double pixelSpacingX, pixelSpacingY; 1570 double pixelSpacingX, pixelSpacingY;
1556 OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX, pixelSpacingY, instance.GetTags()); 1571 OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX, pixelSpacingY, instance.GetTags());
1557 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY); 1572
1573 if (FIX_LSD_479)
1574 {
1575 /**
1576 * Some series contain a first instance (secondary capture) that
1577 * is completely different from others wrt. to resolution and
1578 * pixel spacing. We make sure to rescale each frame to fit in a
1579 * square that corresponds to the extent of the frame in the
1580 * middle of the series.
1581 **/
1582 double physicalWidth = pixelSpacingX * static_cast<double>(frame.GetWidth());
1583 double physicalHeight = pixelSpacingY * static_cast<double>(frame.GetHeight());
1584
1585 if (OrthancStone::LinearAlgebra::IsCloseToZero(physicalWidth) ||
1586 OrthancStone::LinearAlgebra::IsCloseToZero(physicalHeight))
1587 {
1588 // Numerical instability, don't try further processing
1589 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY);
1590 }
1591 else
1592 {
1593 double scale = std::max(centralPhysicalWidth_ / physicalWidth,
1594 centralPhysicalHeight_ / physicalHeight);
1595 layer->SetPixelSpacing(pixelSpacingX * scale, pixelSpacingY * scale);
1596 layer->SetOrigin((centralPhysicalWidth_ - physicalWidth * scale) / 2.0,
1597 (centralPhysicalHeight_ - physicalHeight * scale) / 2.0);
1598 }
1599 }
1600 else
1601 {
1602 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY);
1603 }
1558 1604
1559 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsLayer; 1605 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsLayer;
1560 1606
1561 if (annotations_) 1607 if (annotations_)
1562 { 1608 {
1791 flipX_(false), 1837 flipX_(false),
1792 flipY_(false), 1838 flipY_(false),
1793 hasFocusOnInstance_(false), 1839 hasFocusOnInstance_(false),
1794 focusFrameNumber_(0), 1840 focusFrameNumber_(0),
1795 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)), 1841 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)),
1796 synchronizationEnabled_(false) 1842 synchronizationEnabled_(false),
1843 centralPhysicalWidth_(1),
1844 centralPhysicalHeight_(1)
1797 { 1845 {
1798 if (!framesCache_) 1846 if (!framesCache_)
1799 { 1847 {
1800 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); 1848 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
1801 } 1849 }
1949 if (observer_.get() != NULL) 1997 if (observer_.get() != NULL)
1950 { 1998 {
1951 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(), 1999 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(),
1952 frames_->GetFramesCount(), DisplayedFrameQuality_None); 2000 frames_->GetFramesCount(), DisplayedFrameQuality_None);
1953 } 2001 }
2002
2003 centralPhysicalWidth_ = 1;
2004 centralPhysicalHeight_ = 1;
1954 2005
1955 if (frames_->GetFramesCount() != 0) 2006 if (frames_->GetFramesCount() != 0)
1956 { 2007 {
1957 const OrthancStone::DicomInstanceParameters& centralInstance = frames_->GetInstanceOfFrame(cursor_->GetCurrentIndex()); 2008 const OrthancStone::DicomInstanceParameters& centralInstance = frames_->GetInstanceOfFrame(cursor_->GetCurrentIndex());
1958 2009
1975 "/instances/" + centralInstance.GetSopInstanceUid() + "/metadata"); 2026 "/instances/" + centralInstance.GetSopInstanceUid() + "/metadata");
1976 2027
1977 loader_->ScheduleGetDicomWeb( 2028 loader_->ScheduleGetDicomWeb(
1978 boost::make_shared<OrthancStone::LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID), 2029 boost::make_shared<OrthancStone::LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID),
1979 0, source_, uri, new LoadSeriesDetailsFromInstance(GetSharedObserver())); 2030 0, source_, uri, new LoadSeriesDetailsFromInstance(GetSharedObserver()));
2031 }
2032
2033 if (centralInstance.GetPixelSpacingX() != 0 &&
2034 centralInstance.GetPixelSpacingY() != 0 &&
2035 centralInstance.GetWidth() != 0 &&
2036 centralInstance.GetHeight())
2037 {
2038 centralPhysicalWidth_ = (centralInstance.GetPixelSpacingX() *
2039 static_cast<double>(centralInstance.GetWidth()));
2040 centralPhysicalHeight_ = (centralInstance.GetPixelSpacingY() *
2041 static_cast<double>(centralInstance.GetHeight()));
1980 } 2042 }
1981 } 2043 }
1982 2044
1983 ApplyScheduledFocus(); 2045 ApplyScheduledFocus();
1984 } 2046 }