diff --git a/CMakeLists.txt b/CMakeLists.txt index 753c754b..8fe4a2d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ PROJECT(DIAGPathology) SET(CMAKE_MODULE_PATH ${DIAGPathology_SOURCE_DIR}/cmakemodules) SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) +IF(NOT WIN32) +SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib:$ORIGIN/") +ENDIF(NOT WIN32) + # Use boost for cross-platform use of threading, file system and date_time handling FIND_PACKAGE(Boost REQUIRED COMPONENTS date_time filesystem program_options regex system thread) SET(Boost_DEFINITIONS "-DBOOST_ALL_DYN_LINK") diff --git a/annotation/AnnotationToMask.cpp b/annotation/AnnotationToMask.cpp index d444bd8c..e000715b 100644 --- a/annotation/AnnotationToMask.cpp +++ b/annotation/AnnotationToMask.cpp @@ -88,7 +88,7 @@ void AnnotationToMask::convert(const std::shared_ptr& annotation if (nameOrder.empty()) { buffer[y * 512 + x] = in_poly * label > buffer[y * 512 + x] ? in_poly * label : buffer[y * 512 + x]; } - else { + else if (in_poly) { buffer[y * 512 + x] = in_poly * label; } } diff --git a/imgproc/generic/ColorDeconvolutionFilter.h b/imgproc/generic/ColorDeconvolutionFilter.h index b96763dd..a009aa6e 100644 --- a/imgproc/generic/ColorDeconvolutionFilter.h +++ b/imgproc/generic/ColorDeconvolutionFilter.h @@ -124,6 +124,12 @@ class ColorDeconvolutionFilter : public ImageFilter { cosy[2] = cosy[2] / leng; cosz[2] = cosz[2] / leng; + for (int i=0; i<3; i++){ + if (cosx[i] == 0.0) cosx[i] = 0.001; + if (cosy[i] == 0.0) cosy[i] = 0.001; + if (cosz[i] == 0.0) cosz[i] = 0.001; + } + /* matrix inversion */ double A = cosy[1] - cosx[1] * cosy[0] / cosx[0]; double V = cosz[1] - cosx[1] * cosz[0] / cosx[0]; diff --git a/imgproc/generic/FilterBase.cpp b/imgproc/generic/FilterBase.cpp index 72313b78..0e405864 100644 --- a/imgproc/generic/FilterBase.cpp +++ b/imgproc/generic/FilterBase.cpp @@ -1,7 +1,8 @@ +#include #include "FilterBase.h" #include "core/ProgressMonitor.h" -FilterBase::FilterBase() : _monitor(NULL), _cancel(false), _running(false) { +FilterBase::FilterBase() : _cancel(false), _running(false) { } @@ -41,22 +42,18 @@ void FilterBase::finish() { } -const ProgressMonitor* const FilterBase::progressMonitor() const { +std::weak_ptr FilterBase::progressMonitor() const { return _monitor; } -void FilterBase::setProgressMonitor(ProgressMonitor* monitor) { - _monitorMutex.lock(); +void FilterBase::setProgressMonitor(std::shared_ptr monitor) { _monitor = monitor; - _monitorMutex.unlock(); } void FilterBase::updateProgress(float progress) { - _monitorMutex.lock(); - if (_monitor) { - _monitor->setProgress(progress); + if (std::shared_ptr shared_monitor = _monitor.lock()) { + shared_monitor->setProgress(progress); } - _monitorMutex.unlock(); } void FilterBase::cancel() { diff --git a/imgproc/generic/FilterBase.h b/imgproc/generic/FilterBase.h index 276ded41..f3142191 100644 --- a/imgproc/generic/FilterBase.h +++ b/imgproc/generic/FilterBase.h @@ -4,14 +4,14 @@ #include "config/pathology_config.h" #include #include +#include class ProgressMonitor; class EXPORT_BASICFILTERS FilterBase { - std::mutex _monitorMutex; std::mutex _cancelMutex; - ProgressMonitor* _monitor; + std::weak_ptr _monitor; bool _cancel; bool _running; @@ -24,8 +24,8 @@ class EXPORT_BASICFILTERS FilterBase { virtual std::string name() const; - const ProgressMonitor* const progressMonitor() const; - void setProgressMonitor(ProgressMonitor* monitor); + std::weak_ptr progressMonitor() const; + void setProgressMonitor(std::shared_ptr monitor); void updateProgress(float progress); void cancel(); diff --git a/io/multiresolutionimageinterface/MultiResolutionImage.h b/io/multiresolutionimageinterface/MultiResolutionImage.h index b89597da..bc31893c 100644 --- a/io/multiresolutionimageinterface/MultiResolutionImage.h +++ b/io/multiresolutionimageinterface/MultiResolutionImage.h @@ -46,7 +46,7 @@ public : //! Obtains data as a patch, which is a basic image class containing all relevant information for further processing, //! like data and colortype template - Patch* getPatch(const long long& startX, const long long& startY, const unsigned long long& width, + Patch getPatch(const long long& startX, const long long& startY, const unsigned long long& width, const unsigned long long& height, const unsigned int& level) { std::vector dims(3,0); @@ -60,8 +60,8 @@ public : for (unsigned int i = 0; i < _spacing.size(); ++i) { patchSpacing[i] = _spacing[i] * levelDownsample; } - Patch* patch = new Patch(dims, this->getColorType(), data, true); - patch->setSpacing(patchSpacing); + Patch patch = Patch(dims, this->getColorType(), data, true); + patch.setSpacing(patchSpacing); return patch; } diff --git a/io/multiresolutionimageinterface/multiresolutionimageinterface.i b/io/multiresolutionimageinterface/multiresolutionimageinterface.i index e881ca26..03ef44de 100644 --- a/io/multiresolutionimageinterface/multiresolutionimageinterface.i +++ b/io/multiresolutionimageinterface/multiresolutionimageinterface.i @@ -45,6 +45,7 @@ %include "std_map.i" %include "std_shared_ptr.i" +%shared_ptr(ImageSource) %shared_ptr(MultiResolutionImage) %shared_ptr(OpenSlideImage) %shared_ptr(VSIImage) @@ -63,8 +64,8 @@ namespace std { %template(vector_uint) vector; %template(vector_float) vector; %template(vector_double) vector; - %template(vector_annotation) vector; - %template(vector_annotation_group) vector; + %template(vector_annotation) vector >; + %template(vector_annotation_group) vector >; %template(vector_unsigned_long_long) vector; %template(vector_long_long) vector; %template(vector_string) vector; diff --git a/workstation/CMakeLists.txt b/workstation/CMakeLists.txt index 51f24377..7451025c 100644 --- a/workstation/CMakeLists.txt +++ b/workstation/CMakeLists.txt @@ -53,7 +53,7 @@ IF(BUILD_USING_QT4) resources/icons.qrc ) qt4_add_resources(RESOURCE_ADDED ${RESOURCE}) - ADD_EXECUTABLE(ASAP ${SOURCE} ${HEADERS} ${PATHOLOHWORKSTATION_MOC}) + ADD_EXECUTABLE(ASAP WIN32 ${SOURCE} ${HEADERS} ${PATHOLOHWORKSTATION_MOC}) TARGET_LINK_LIBRARIES(ASAP ${QT_LIBRARIES}) ELSE() find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL) @@ -61,7 +61,7 @@ ELSE() resources/ASAP_resources.qrc ) qt5_add_resources(RESOURCE_ADDED ${RESOURCE}) - ADD_EXECUTABLE(ASAP ${SOURCE} ${HEADERS} ${RESOURCE_ADDED}) + ADD_EXECUTABLE(ASAP WIN32 ${SOURCE} ${HEADERS} ${RESOURCE_ADDED}) QT5_USE_MODULES(ASAP Core Widgets OpenGL UiTools) ENDIF() diff --git a/workstation/MiniMap.cpp b/workstation/MiniMap.cpp index 9b16f6fd..78b495ab 100644 --- a/workstation/MiniMap.cpp +++ b/workstation/MiniMap.cpp @@ -8,7 +8,7 @@ const char* const MiniMap::coverageColors[] = { "red", "green", "yellow", "black", "purple", "orange" }; -MiniMap::MiniMap(QPixmap* overview, QWidget *parent) +MiniMap::MiniMap(const QPixmap& overview, QWidget *parent) : QWidget(parent), _overview(overview), _fieldOfView(QRectF()), @@ -21,14 +21,8 @@ MiniMap::MiniMap(QPixmap* overview, QWidget *parent) policy.setHorizontalPolicy(QSizePolicy::Fixed); policy.setVerticalPolicy(QSizePolicy::Fixed); setSizePolicy(policy); - if (_overview) { - _aspectRatio = static_cast(_overview->width()) / _overview->height(); - } -} - -MiniMap::~MiniMap() { - if (_overview) { - delete _overview; + if (!overview.isNull()) { + _aspectRatio = static_cast(_overview.width()) / _overview.height(); } } @@ -59,7 +53,7 @@ void MiniMap::onCoverageUpdated() { void MiniMap::mousePressEvent(QMouseEvent *event) { float posX = event->pos().x(); float posY = event->pos().y(); - QPointF pos((_overview->width() * posX) / width() + 1, (_overview->height() * posY) / height() + 1); + QPointF pos((_overview.width() * posX) / width() + 1, (_overview.height() * posY) / height() + 1); emit positionClicked(pos); } @@ -69,8 +63,8 @@ void MiniMap::mouseMoveEvent(QMouseEvent *event) { void MiniMap::paintEvent(QPaintEvent *event) { QPainter painter(this); - if (_overview) { - painter.drawPixmap(1, 1, width(), height(), *_overview); + if (!_overview.isNull()) { + painter.drawPixmap(1, 1, width(), height(), _overview); painter.setPen(QPen(Qt::white, 2)); painter.drawRect(1, 1, width() - 2, height() - 2); painter.setPen(QPen(Qt::black, 1)); @@ -86,7 +80,7 @@ void MiniMap::paintEvent(QPaintEvent *event) { for (std::vector::const_iterator it = pths.begin(); it != pths.end(); ++it) { if (!it->isEmpty()) { QTransform trans; - trans = trans.scale(width() / static_cast(_overview->width()), height() / static_cast(_overview->height())); + trans = trans.scale(width() / static_cast(_overview.width()), height() / static_cast(_overview.height())); QPainterPath qpf2 = trans.map(*it); unsigned int colorIndex = (it - pths.begin()) % 6; painter.setPen(QPen(QColor(coverageColors[colorIndex]))); @@ -100,10 +94,10 @@ void MiniMap::paintEvent(QPaintEvent *event) { QPen blue = QPen(QColor("blue")); blue.setWidth(3); painter.setPen(blue); - float rectX = width() * (_fieldOfView.left() / _overview->width()) + 1; - float rectY = height() * (_fieldOfView.top() / _overview->height()) + 1; - float rectW = width() * (_fieldOfView.width() / _overview->width()) - 2; - float rectH = height() * (_fieldOfView.height() / _overview->height()) - 2; + float rectX = width() * (_fieldOfView.left() / _overview.width()) + 1; + float rectY = height() * (_fieldOfView.top() / _overview.height()) + 1; + float rectW = width() * (_fieldOfView.width() / _overview.width()) - 2; + float rectH = height() * (_fieldOfView.height() / _overview.height()) - 2; if (rectW > 3 && rectH > 3) { painter.drawRect(rectX, rectY, rectW, rectH); } @@ -118,8 +112,8 @@ void MiniMap::paintEvent(QPaintEvent *event) { QSize MiniMap::sizeHint() const { QSize size(0, 0); unsigned int baseSize = 250; - if (_overview) { - if (_overview->width() > _overview->height()) { + if (!_overview.isNull()) { + if (_overview.width() > _overview.height()) { size = QSize(baseSize, baseSize / _aspectRatio); } else { diff --git a/workstation/MiniMap.h b/workstation/MiniMap.h index 9f29a300..935df1a8 100644 --- a/workstation/MiniMap.h +++ b/workstation/MiniMap.h @@ -2,6 +2,7 @@ #define MINIMAP_H #include +#include class QPixmap; class TileManager; @@ -10,8 +11,7 @@ class MiniMap : public QWidget { Q_OBJECT public: - MiniMap(QPixmap* overview, QWidget *parent = 0); - ~MiniMap(); + MiniMap(const QPixmap& overview, QWidget *parent); QSize sizeHint() const; int heightForWidth(int w) const; @@ -28,9 +28,9 @@ public slots: void paintEvent(QPaintEvent *event); private: - QPixmap* _overview; + QPixmap _overview; QRectF _fieldOfView; - TileManager* _manager; + QPointer _manager; float _aspectRatio; //Width / height static const char* const coverageColors[]; bool _drawCoverageMap; diff --git a/workstation/PathologyViewer.cpp b/workstation/PathologyViewer.cpp index b86d239d..88f71912 100644 --- a/workstation/PathologyViewer.cpp +++ b/workstation/PathologyViewer.cpp @@ -30,15 +30,14 @@ using std::vector; PathologyViewer::PathologyViewer(QWidget *parent): QGraphicsView(parent), - _img(NULL), _renderthread(NULL), _prefetchthread(NULL), _zoomSensitivity(0.5), _panSensitivity(0.5), _numScheduledScalings(0), _pan(false), - _prevPan(0,0), - _map(NULL), + _prevPan(0, 0), + _map(NULL), _cache(NULL), _cacheSize(1000 * 512 * 512 * 3), _activeTool(NULL), @@ -86,12 +85,6 @@ PathologyViewer::PathologyViewer(QWidget *parent): PathologyViewer::~PathologyViewer() { close(); - // Cleanup tools - _activeTool = NULL; - for (std::map::iterator it = _tools.begin(); it != _tools.end(); ++it) { - delete it->second; - } - _tools.clear(); } unsigned long long PathologyViewer::getCacheSize() { @@ -116,7 +109,7 @@ void PathologyViewer::resizeEvent(QResizeEvent *event) { float maxDownsample = 1. / this->_sceneScale; QGraphicsView::resizeEvent(event); if (_img) { - emit fieldOfViewChanged(FOVImage, _img, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); + emit fieldOfViewChanged(FOVImage, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); emit updateBBox(FOV); } } @@ -164,7 +157,7 @@ void PathologyViewer::scalingTime(qreal x) QPointF delta_viewport_pos = _zoomToViewPos - QPointF(width() / 2.0, height() / 2.0); QPointF viewport_center = mapFromScene(_zoomToScenePos) - delta_viewport_pos; centerOn(mapToScene(viewport_center.toPoint())); - emit fieldOfViewChanged(FOVImage, _img, _img->getBestLevelForDownSample((1. / this->_sceneScale) / this->transform().m11())); + emit fieldOfViewChanged(FOVImage, _img->getBestLevelForDownSample((1. / this->_sceneScale) / this->transform().m11())); emit updateBBox(FOV); } @@ -182,11 +175,11 @@ void PathologyViewer::moveTo(const QPointF& pos) { float maxDownsample = 1. / this->_sceneScale; QRectF FOV = this->mapToScene(this->rect()).boundingRect(); QRectF FOVImage = QRectF(FOV.left() / this->_sceneScale, FOV.top() / this->_sceneScale, FOV.width() / this->_sceneScale, FOV.height() / this->_sceneScale); - emit fieldOfViewChanged(FOVImage, _img, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); + emit fieldOfViewChanged(FOVImage, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); emit updateBBox(FOV); } -void PathologyViewer::addTool(ToolPluginInterface* tool) { +void PathologyViewer::addTool(std::shared_ptr tool) { if (tool) { _tools[tool->name()] = tool; } @@ -210,7 +203,7 @@ void PathologyViewer::setActiveTool(const std::string& toolName) { void PathologyViewer::changeActiveTool() { if (sender()) { QAction* button = qobject_cast< QAction*>(sender()); - ToolPluginInterface* newActiveTool = _tools[button->objectName().toStdString()]; + std::shared_ptr newActiveTool = _tools[button->objectName().toStdString()]; if (newActiveTool) { _activeTool = newActiveTool; } @@ -220,18 +213,17 @@ void PathologyViewer::changeActiveTool() { } } -void PathologyViewer::onFieldOfViewChanged(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level) { +void PathologyViewer::onFieldOfViewChanged(const QRectF& FOV, const unsigned int level) { if (_manager) { _manager->loadTilesForFieldOfView(FOV, level); } } -void PathologyViewer::initialize(MultiResolutionImage *img) { +void PathologyViewer::initialize(std::shared_ptr img) { close(); setEnabled(true); _img = img; unsigned int tileSize = 512; - unsigned int lastLevel = _img->getNumberOfLevels() - 1; for (int i = lastLevel; i >= 0; --i) { std::vector lastLevelDimensions = _img->getLevelDimensions(i); @@ -240,7 +232,8 @@ void PathologyViewer::initialize(MultiResolutionImage *img) { break; } } - _renderthread = new RenderThread(img); + _renderthread = new RenderThread(this); + _renderthread->setBackgroundImage(img); _manager = new TileManager(_img, tileSize, lastLevel, _renderthread, _cache, scene()); setMouseTracking(true); std::vector workers = _renderthread->getWorkers(); @@ -251,15 +244,16 @@ void PathologyViewer::initialize(MultiResolutionImage *img) { initializeGUIComponents(lastLevel); QObject::connect(this, SIGNAL(channelChanged(int)), _renderthread, SLOT(onChannelChanged(int))); QObject::connect(_cache, SIGNAL(itemEvicted(WSITileGraphicsItem*)), _manager, SLOT(onTileRemoved(WSITileGraphicsItem*))); - QObject::connect(this, SIGNAL(fieldOfViewChanged(const QRectF, MultiResolutionImage*, const unsigned int)), this, SLOT(onFieldOfViewChanged(const QRectF, MultiResolutionImage*, const unsigned int))); + QObject::connect(this, SIGNAL(fieldOfViewChanged(const QRectF, const unsigned int)), this, SLOT(onFieldOfViewChanged(const QRectF, const unsigned int))); QRectF FOV = this->mapToScene(this->rect()).boundingRect(); QRectF FOVImage = QRectF(FOV.left() / this->_sceneScale, FOV.top() / this->_sceneScale, FOV.width() / this->_sceneScale, FOV.height() / this->_sceneScale); - emit fieldOfViewChanged(FOVImage, _img, _img->getBestLevelForDownSample((1. / this->_sceneScale) / this->transform().m11())); + emit fieldOfViewChanged(FOVImage, _img->getBestLevelForDownSample((1. / this->_sceneScale) / this->transform().m11())); } -void PathologyViewer::onForegroundImageChanged(MultiResolutionImage* for_img, float scale) { +void PathologyViewer::onForegroundImageChanged(std::weak_ptr for_img, float scale) { + _for_img = for_img; if (_renderthread) { - _renderthread->setForegroundImage(for_img, scale); + _renderthread->setForegroundImage(_for_img, scale); _manager->refresh(); } } @@ -295,7 +289,7 @@ void PathologyViewer::initializeImage(QGraphicsScene* scn, unsigned int tileSize float maxDownsample = 1. / this->_sceneScale; QRectF FOV = this->mapToScene(this->rect()).boundingRect(); QRectF FOVImage = QRectF(FOV.left() / this->_sceneScale, FOV.top() / this->_sceneScale, FOV.width() / this->_sceneScale, FOV.height() / this->_sceneScale); - emit fieldOfViewChanged(FOVImage, _img, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); + emit fieldOfViewChanged(FOVImage, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); while (_renderthread->numberOfJobs() > 0) { } } @@ -313,7 +307,7 @@ void PathologyViewer::initializeGUIComponents(unsigned int level) { else if (_img->getColorType() == pathology::RGB) { ovImg = QImage(overview, overviewDimensions[0], overviewDimensions[1], overviewDimensions[0] * 3, QImage::Format_RGB888); } - QPixmap *ovPixMap = new QPixmap(QPixmap::fromImage(ovImg)); + QPixmap ovPixMap = QPixmap(QPixmap::fromImage(ovImg)); delete[] overview; if (_map) { _map->deleteLater(); @@ -353,7 +347,7 @@ void PathologyViewer::initializeGUIComponents(unsigned int level) { QObject::connect(this, SIGNAL(updateBBox(const QRectF&)), _map, SLOT(updateFieldOfView(const QRectF&))); QObject::connect(_manager, SIGNAL(coverageUpdated()), _map, SLOT(onCoverageUpdated())); QObject::connect(_map, SIGNAL(positionClicked(QPointF)), this, SLOT(moveTo(const QPointF&))); - QObject::connect(this, SIGNAL(fieldOfViewChanged(const QRectF&, MultiResolutionImage*, const unsigned int)), _scaleBar, SLOT(updateForFieldOfView(const QRectF&))); + QObject::connect(this, SIGNAL(fieldOfViewChanged(const QRectF&, const unsigned int)), _scaleBar, SLOT(updateForFieldOfView(const QRectF&))); if (this->window()) { _settings->beginGroup("ASAP"); QMenu* viewMenu = this->window()->findChild("menuView"); @@ -487,7 +481,7 @@ void PathologyViewer::pan(const QPoint& panTo) { float maxDownsample = 1. / this->_sceneScale; QRectF FOV = this->mapToScene(this->rect()).boundingRect(); QRectF FOVImage = QRectF(FOV.left() / this->_sceneScale, FOV.top() / this->_sceneScale, FOV.width() / this->_sceneScale, FOV.height() / this->_sceneScale); - emit fieldOfViewChanged(FOVImage, _img, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); + emit fieldOfViewChanged(FOVImage, _img->getBestLevelForDownSample(maxDownsample / this->transform().m11())); emit updateBBox(FOV); } diff --git a/workstation/PathologyViewer.h b/workstation/PathologyViewer.h index 92e4fd61..c8df2d45 100644 --- a/workstation/PathologyViewer.h +++ b/workstation/PathologyViewer.h @@ -27,7 +27,7 @@ class EXPORT_PATHOLOGYWORKSTATION PathologyViewer : public QGraphicsView PathologyViewer(QWidget *parent = 0); ~PathologyViewer(); - void initialize(MultiResolutionImage *img); + void initialize(std::shared_ptr img); void close(); float getZoomSensitivity() const; @@ -44,7 +44,7 @@ class EXPORT_PATHOLOGYWORKSTATION PathologyViewer : public QGraphicsView void zoom(float numSteps); bool hasTool(const std::string& toolName) const; - void addTool(ToolPluginInterface* tool); + void addTool(std::shared_ptr tool); void setActiveTool(const std::string& toolName); float getSceneScale() { return _sceneScale; } @@ -53,15 +53,15 @@ class EXPORT_PATHOLOGYWORKSTATION PathologyViewer : public QGraphicsView void setAutoUpdate(bool autoUpdate); signals : - void fieldOfViewChanged(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level); + void fieldOfViewChanged(const QRectF& FOV, const unsigned int level); void updateBBox(const QRectF& FOV); void channelChanged(int channelNr); public slots : void moveTo(const QPointF& pos); void changeActiveTool(); - void onFieldOfViewChanged(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level); - void onForegroundImageChanged(MultiResolutionImage* for_img, float scale); + void onFieldOfViewChanged(const QRectF& FOV, const unsigned int level); + void onForegroundImageChanged(std::weak_ptr for_img, float scale); private : @@ -84,10 +84,11 @@ private : // Interface to the multi-resolution image. Please note that PathologyViewer // should never modify _img (it is modified in the RenderThread due to calls // to readRegion), otherwise race conditions could occur. - MultiResolutionImage *_img; + std::shared_ptr _img; + std::weak_ptr _for_img; // Minimap - MiniMap *_map; + MiniMap* _map; // ScaleBar ScaleBar* _scaleBar; @@ -96,7 +97,7 @@ private : QSettings* _settings; // Tools - ToolPluginInterface* _activeTool; + std::shared_ptr _activeTool; // Members to track panning and zooming float _zoomSensitivity; @@ -112,7 +113,7 @@ private : unsigned long long _cacheSize; WSITileGraphicsItemCache* _cache; - std::map _tools; + std::map > _tools; private slots : void showContextMenu(const QPoint& pos); diff --git a/workstation/RenderThread.cpp b/workstation/RenderThread.cpp index e9efb504..ce208fe1 100644 --- a/workstation/RenderThread.cpp +++ b/workstation/RenderThread.cpp @@ -9,17 +9,15 @@ using namespace pathology; -RenderThread::RenderThread(MultiResolutionImage* bck_img, MultiResolutionImage* for_img, unsigned int nrThreads, QObject *parent) : +RenderThread::RenderThread(QObject *parent, unsigned int nrThreads) : QObject(parent), - _bck_img(bck_img), - _for_img(for_img), _abort(false), _channel(0), _threadsWaiting(0), _foregroundImageScale(1.) { for (int i = 0; i < nrThreads; ++i) { - RenderWorker* worker = new RenderWorker(this, _bck_img, _for_img); + RenderWorker* worker = new RenderWorker(this); worker->start(QThread::HighPriority); _workers.push_back(worker); } @@ -77,7 +75,7 @@ void RenderThread::addJob(const unsigned int tileSize, const long long imgPosX, _condition.wakeOne(); } -void RenderThread::setForegroundImage(MultiResolutionImage* for_img, float scale) { +void RenderThread::setForegroundImage(std::weak_ptr for_img, float scale) { QMutexLocker locker(&_jobListMutex); _for_img = for_img; for (unsigned int i = 0; i < _workers.size(); ++i) { @@ -85,6 +83,14 @@ void RenderThread::setForegroundImage(MultiResolutionImage* for_img, float scale } } +void RenderThread::setBackgroundImage(std::weak_ptr bck_img) { + QMutexLocker locker(&_jobListMutex); + _bck_img = bck_img; + for (unsigned int i = 0; i < _workers.size(); ++i) { + _workers[i]->setBackgroundImage(_bck_img); + } +} + unsigned int RenderThread::getWaitingThreads() { return _threadsWaiting; } diff --git a/workstation/RenderThread.h b/workstation/RenderThread.h index 5ba872b5..6ae11388 100644 --- a/workstation/RenderThread.h +++ b/workstation/RenderThread.h @@ -25,11 +25,12 @@ class RenderThread : public QObject Q_OBJECT public: - RenderThread(MultiResolutionImage* bck_img, MultiResolutionImage* for_img = NULL, unsigned int nrThreads = 2, QObject *parent = 0); + RenderThread(QObject *parent, unsigned int nrThreads = 2); ~RenderThread(); void addJob(const unsigned int tileSize, const long long imgPosX, const long long imgPosY, const unsigned int level); - void setForegroundImage(MultiResolutionImage* for_img, float scale = 1.); + void setBackgroundImage(std::weak_ptr bck_img); + void setForegroundImage(std::weak_ptr for_img, float scale = 1.); void setForegroundOpacity(const float& opacity); float getForegroundOpacity() const; @@ -53,8 +54,8 @@ private : bool _abort; QMutex _jobListMutex; QWaitCondition _condition; - MultiResolutionImage *_bck_img; - MultiResolutionImage *_for_img; + std::weak_ptr _bck_img; + std::weak_ptr _for_img; std::list _jobList; std::vector _workers; int _channel; diff --git a/workstation/RenderWorker.cpp b/workstation/RenderWorker.cpp index fda15db1..92f712d2 100644 --- a/workstation/RenderWorker.cpp +++ b/workstation/RenderWorker.cpp @@ -8,11 +8,8 @@ using namespace pathology; -RenderWorker::RenderWorker(RenderThread* thread, MultiResolutionImage* bck_img, MultiResolutionImage* for_img, QObject *parent) : - QThread(parent), - _thread(thread), - _bck_img(bck_img), - _for_img(for_img), +RenderWorker::RenderWorker(RenderThread* thread) : + QThread(thread), _abort(false), _channel(0), _opacity(1.0), @@ -35,7 +32,13 @@ void RenderWorker::setChannel(int channel) { mutex.unlock(); } -void RenderWorker::setForegroundImage(MultiResolutionImage* for_img, float scale) { +void RenderWorker::setBackgroundImage(std::weak_ptr bck_img) { + mutex.lock(); + _bck_img = bck_img; + mutex.unlock(); +} + +void RenderWorker::setForegroundImage(std::weak_ptr for_img, float scale) { mutex.lock(); _for_img = for_img; _foregroundImageScale = scale; @@ -55,93 +58,107 @@ float RenderWorker::getForegroundOpacity() const { void RenderWorker::run() { forever { - RenderJob currentJob = _thread->getJob(); + RenderJob currentJob = dynamic_cast(parent())->getJob(); if (_abort) { return; } mutex.lock(); - float levelDownsample = _bck_img->getLevelDownsample(currentJob._level); + std::shared_ptr local_bck_img = _bck_img.lock(); + float levelDownsample = local_bck_img->getLevelDownsample(currentJob._level); QPixmap _foreground; - if (_for_img) { - if (_for_img->getColorType() == pathology::ColorType::Monochrome) { - if (currentJob._level < _for_img->getNumberOfLevels()) { - if (_for_img->getDataType() == pathology::DataType::UChar) { - // Label map - unsigned char* imgBuf = new unsigned char[currentJob._tileSize*currentJob._tileSize]; - _for_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize / _foregroundImageScale, currentJob._imgPosY * levelDownsample * currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, currentJob._level, imgBuf); - QImage renderedImage = convertMonochromeToRGB(imgBuf, currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, 0, 1, 0, 255, 0); - if (_foregroundImageScale != 1) { - renderedImage = renderedImage.scaled(currentJob._tileSize, currentJob._tileSize); - } - _foreground = QPixmap::fromImage(renderedImage); + if (std::shared_ptr local_for_img = _for_img.lock()) { + int levelDifference = local_bck_img->getBestLevelForDownSample(_foregroundImageScale); + int fgImageLevel = currentJob._level - levelDifference; + float fgImageScale = 1; + if (fgImageLevel < 0) { + fgImageScale = pow(2,-1*fgImageLevel); + fgImageLevel = 0; + } + if (fgImageLevel > local_for_img->getNumberOfLevels()) { + int fgMaxLevelDifference = local_for_img->getNumberOfLevels() - fgImageLevel + 1; + fgImageLevel = local_for_img->getNumberOfLevels() - 1; + fgImageScale = 1. / pow(2, fgMaxLevelDifference); + } + float fgImageLevelDownsample = local_for_img->getLevelDownsample(fgImageLevel); + if (local_for_img->getColorType() == pathology::ColorType::Monochrome) { + if (local_for_img->getDataType() == pathology::DataType::UChar) { + // Label map + unsigned char* imgBuf = new unsigned char[currentJob._tileSize*currentJob._tileSize]; + local_for_img->getRawRegion(currentJob._imgPosX * fgImageLevelDownsample * currentJob._tileSize / fgImageScale, currentJob._imgPosY * fgImageLevelDownsample * currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, fgImageLevel, imgBuf); + QImage renderedImage = convertMonochromeToRGB(imgBuf, currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, 0, 1, 0, 255, 0); + if (_foregroundImageScale != 1) { + renderedImage = renderedImage.scaled(currentJob._tileSize, currentJob._tileSize); } - else if (_for_img->getDataType() == pathology::DataType::UInt32) { - // Label map - unsigned int* imgBuf = new unsigned int[currentJob._tileSize*currentJob._tileSize]; - _for_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize / _foregroundImageScale, currentJob._imgPosY * levelDownsample * currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, currentJob._level, imgBuf); - QImage renderedImage = convertMonochromeToRGB(imgBuf, currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, 0, 1, 0, 255, 0); - if (_foregroundImageScale != 1) { - renderedImage = renderedImage.scaled(currentJob._tileSize, currentJob._tileSize); - } - _foreground = QPixmap::fromImage(renderedImage); + _foreground = QPixmap::fromImage(renderedImage); + } + else if (local_for_img->getDataType() == pathology::DataType::UInt32) { + // Label map + unsigned int* imgBuf = new unsigned int[currentJob._tileSize*currentJob._tileSize]; + local_for_img->getRawRegion(currentJob._imgPosX * fgImageLevelDownsample * currentJob._tileSize / fgImageScale, currentJob._imgPosY * fgImageLevelDownsample * currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, fgImageLevel, imgBuf); + QImage renderedImage = convertMonochromeToRGB(imgBuf, currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, 0, 1, 0, 255, 0); + if (_foregroundImageScale != 1) { + renderedImage = renderedImage.scaled(currentJob._tileSize, currentJob._tileSize); } - else if (_for_img->getDataType() == pathology::DataType::Float) { - //Likelihood map - float* imgBuf = new float[currentJob._tileSize*currentJob._tileSize]; - _for_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize / _foregroundImageScale, currentJob._imgPosY * levelDownsample * currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, currentJob._level, imgBuf); - QImage renderedImage = convertMonochromeToRGB(imgBuf, currentJob._tileSize / _foregroundImageScale, currentJob._tileSize / _foregroundImageScale, 0, 1, 0, 255, 0); - if (_foregroundImageScale != 1) { - renderedImage = renderedImage.scaled(currentJob._tileSize, currentJob._tileSize); - } - _foreground = QPixmap::fromImage(renderedImage); + _foreground = QPixmap::fromImage(renderedImage); + } + else if (local_for_img->getDataType() == pathology::DataType::Float) { + //Likelihood map + float* imgBuf = new float[currentJob._tileSize*currentJob._tileSize]; + local_for_img->getRawRegion(currentJob._imgPosX * fgImageLevelDownsample * currentJob._tileSize / fgImageScale, currentJob._imgPosY * fgImageLevelDownsample * currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, fgImageLevel, imgBuf); + float minValue = std::numeric_limits::min() == local_for_img->getMinValue() ? 0 : local_for_img->getMinValue(); + float maxValue = std::numeric_limits::max() == local_for_img->getMaxValue() ? 1. : local_for_img->getMaxValue(); + QImage renderedImage = convertMonochromeToRGB(imgBuf, currentJob._tileSize / fgImageScale, currentJob._tileSize / fgImageScale, 0, 1, minValue, maxValue, 1); + if (_foregroundImageScale != 1) { + renderedImage = renderedImage.scaled(currentJob._tileSize, currentJob._tileSize); } + _foreground = QPixmap::fromImage(renderedImage); } } } - if (_bck_img) { - int samplesPerPixel = _bck_img->getSamplesPerPixel(); + if (local_bck_img) { + int samplesPerPixel = local_bck_img->getSamplesPerPixel(); QImage renderedImg; QPixmap temp; - if (_bck_img->getColorType() == pathology::ColorType::RGB) { + if (local_bck_img->getColorType() == pathology::ColorType::RGB) { unsigned char* imgBuf = new unsigned char[currentJob._tileSize*currentJob._tileSize*samplesPerPixel]; - _bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); + local_bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); renderedImg = QImage(imgBuf, (currentJob._tileSize), (currentJob._tileSize), (currentJob._tileSize) * 3, QImage::Format_RGB888); temp = QPixmap::fromImage(renderedImg.convertToFormat(QImage::Format_ARGB32_Premultiplied)); delete[] imgBuf; } - else if (_bck_img->getColorType() == pathology::ColorType::ARGB) { + else if (local_bck_img->getColorType() == pathology::ColorType::ARGB) { unsigned char* imgBuf = new unsigned char[currentJob._tileSize*currentJob._tileSize*samplesPerPixel]; - _bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); + local_bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); renderedImg = QImage(imgBuf, (currentJob._tileSize), (currentJob._tileSize), (currentJob._tileSize) * 4, QImage::Format_ARGB32); temp = QPixmap::fromImage(renderedImg); delete[] imgBuf; } - else if (_bck_img->getColorType() == pathology::ColorType::Monochrome || _bck_img->getColorType() == pathology::ColorType::Indexed) { - if (_bck_img->getDataType() == pathology::DataType::UChar) { + else if (local_bck_img->getColorType() == pathology::ColorType::Monochrome || local_bck_img->getColorType() == pathology::ColorType::Indexed) { + if (local_bck_img->getDataType() == pathology::DataType::UChar) { unsigned char* imgBuf = new unsigned char[currentJob._tileSize*currentJob._tileSize*samplesPerPixel]; - _bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); - renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, _bck_img->getMinValue(), _bck_img->getMaxValue()); + local_bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); + renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, local_bck_img->getMinValue(), local_bck_img->getMaxValue()); temp = QPixmap::fromImage(renderedImg); delete[] imgBuf; } - else if (_bck_img->getDataType() == pathology::DataType::Float) { + else if (local_bck_img->getDataType() == pathology::DataType::Float) { float *imgBuf = new float[currentJob._tileSize*currentJob._tileSize*samplesPerPixel]; - _bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); - renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, _bck_img->getMinValue(), _bck_img->getMaxValue()); + local_bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); + renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, local_bck_img->getMinValue(), local_bck_img->getMaxValue()); temp = QPixmap::fromImage(renderedImg); delete[] imgBuf; } - else if (_bck_img->getDataType() == pathology::DataType::UInt16) { + else if (local_bck_img->getDataType() == pathology::DataType::UInt16) { unsigned short *imgBuf = new unsigned short[currentJob._tileSize*currentJob._tileSize*samplesPerPixel]; - _bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); - renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, _bck_img->getMinValue(), _bck_img->getMaxValue()); + local_bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); + renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, local_bck_img->getMinValue(), local_bck_img->getMaxValue()); temp = QPixmap::fromImage(renderedImg); delete[] imgBuf; } - else if (_bck_img->getDataType() == pathology::DataType::UInt32) { + else if (local_bck_img->getDataType() == pathology::DataType::UInt32) { unsigned int *imgBuf = new unsigned int[currentJob._tileSize*currentJob._tileSize*samplesPerPixel]; - _bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); - renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, _bck_img->getMinValue(), _bck_img->getMaxValue()); + local_bck_img->getRawRegion(currentJob._imgPosX * levelDownsample * currentJob._tileSize, currentJob._imgPosY * levelDownsample * currentJob._tileSize, currentJob._tileSize, currentJob._tileSize, currentJob._level, imgBuf); + renderedImg = convertMonochromeToRGB(imgBuf, currentJob._tileSize, currentJob._tileSize, _channel, samplesPerPixel, local_bck_img->getMinValue(), local_bck_img->getMaxValue()); temp = QPixmap::fromImage(renderedImg); delete[] imgBuf; } diff --git a/workstation/RenderWorker.h b/workstation/RenderWorker.h index c8ff6be8..e7f6a7bb 100644 --- a/workstation/RenderWorker.h +++ b/workstation/RenderWorker.h @@ -3,6 +3,7 @@ #include #include +#include class MultiResolutionImage; class FilterInterface; @@ -14,11 +15,12 @@ class RenderWorker : public QThread Q_OBJECT public: - RenderWorker(RenderThread* thread, MultiResolutionImage* _bck_img, MultiResolutionImage* _for_img = NULL, QObject *parent = NULL); + RenderWorker(RenderThread* thread); ~RenderWorker(); void abort(); void setChannel(int channel); - void setForegroundImage(MultiResolutionImage* for_img, float scale = 1.); + void setBackgroundImage(std::weak_ptr bck_img); + void setForegroundImage(std::weak_ptr for_img, float scale = 1.); void setForegroundOpacity(const float& opacity); float getForegroundOpacity() const; @@ -27,9 +29,8 @@ protected : private : QMutex mutex; - MultiResolutionImage *_bck_img; - MultiResolutionImage *_for_img; - RenderThread *_thread; + std::weak_ptr _bck_img; + std::weak_ptr _for_img; bool _abort; int _channel; float _opacity; diff --git a/workstation/TileManager.cpp b/workstation/TileManager.cpp index 99546762..b3a2834f 100644 --- a/workstation/TileManager.cpp +++ b/workstation/TileManager.cpp @@ -5,9 +5,9 @@ #include "WSITileGraphicsItemCache.h" #include #include +#include -TileManager::TileManager(MultiResolutionImage* img, unsigned int tileSize, unsigned int lastRenderLevel, RenderThread* renderThread, WSITileGraphicsItemCache* cache, QGraphicsScene* scene) : -_img(img), +TileManager::TileManager(std::shared_ptr img, unsigned int tileSize, unsigned int lastRenderLevel, RenderThread* renderThread, WSITileGraphicsItemCache* cache, QGraphicsScene* scene) : _renderThread(renderThread), _tileSize(tileSize), _lastRenderLevel(lastRenderLevel), @@ -19,11 +19,14 @@ _scene(scene), _coverageMaps(), _coverageMapCacheMode(false) { + for (unsigned int i = 0; i < img->getNumberOfLevels(); ++i) { + _levelDownsamples.push_back(img->getLevelDownsample(i)); + _levelDimensions.push_back(img->getLevelDimensions(i)); + } } TileManager::~TileManager() { _renderThread = NULL; - _img = NULL; _cache = NULL; _scene = NULL; } @@ -36,24 +39,39 @@ void TileManager::resetCoverage(unsigned int level) { } QPoint TileManager::pixelCoordinatesToTileCoordinates(QPointF coordinate, unsigned int level) { - return QPoint(std::floor((coordinate.x() / _img->getLevelDownsample(level)) / this->_tileSize), std::floor((coordinate.y() / _img->getLevelDownsample(level)) / this->_tileSize)); + if (level < _levelDownsamples.size()) { + return QPoint(std::floor((coordinate.x() / _levelDownsamples[level]) / this->_tileSize), std::floor((coordinate.y() / _levelDownsamples[level]) / this->_tileSize)); + } + else { + return QPoint(); + } } -QPointF TileManager::tileCoordinatesToPixelCoordinates(QPoint coordinate, unsigned int level) { - return QPointF(coordinate.x() * _img->getLevelDownsample(level) * this->_tileSize, coordinate.y() * _img->getLevelDownsample(level) * this->_tileSize); +QPointF TileManager::tileCoordinatesToPixelCoordinates(QPoint coordinate, unsigned int level) { + if (level < _levelDownsamples.size()) { + return QPointF(coordinate.x() * _levelDownsamples[level] * this->_tileSize, coordinate.y() * _levelDownsamples[level] * this->_tileSize); + } + else { + return QPoint(); + } } QPoint TileManager::getLevelTiles(unsigned int level) { - if (_img) { - std::vector dims = _img->getLevelDimensions(level); + if (level < _levelDimensions.size()) { + std::vector dims = _levelDimensions[level]; return QPoint(std::ceil(dims[0] / static_cast(_tileSize)), std::ceil(dims[1] / static_cast(_tileSize))); } + else { + return QPoint(); + } } void TileManager::loadAllTilesForLevel(unsigned int level) { - if (_img && _renderThread) { - std::vector baseLevelDims = _img->getLevelDimensions(0); - this->loadTilesForFieldOfView(QRectF(0, 0, baseLevelDims[0], baseLevelDims[1]), level); + if (_renderThread) { + if (level < _levelDownsamples.size()) { + std::vector baseLevelDims = _levelDimensions[0]; + this->loadTilesForFieldOfView(QRectF(0, 0, baseLevelDims[0], baseLevelDims[1]), level); + } } } @@ -61,12 +79,12 @@ void TileManager::loadTilesForFieldOfView(const QRectF& FOV, const unsigned int if (level > _lastRenderLevel) { return; } - if (_img && _renderThread) { + if (_renderThread) { QPoint topLeftTile = this->pixelCoordinatesToTileCoordinates(FOV.topLeft(), level); QPoint bottomRightTile = this->pixelCoordinatesToTileCoordinates(FOV.bottomRight(), level); QRect FOVTile = QRect(topLeftTile, bottomRightTile); QPoint nrTiles = getLevelTiles(level); - float levelDownsample = _img->getLevelDownsample(level); + float levelDownsample = _levelDownsamples[level]; if (FOVTile != _lastFOV || level != _lastLevel) { _lastLevel = level; _lastFOV = FOVTile; @@ -87,15 +105,15 @@ void TileManager::loadTilesForFieldOfView(const QRectF& FOV, const unsigned int } void TileManager::onTileLoaded(QPixmap* tile, unsigned int tileX, unsigned int tileY, unsigned int tileSize, unsigned int tileByteSize, unsigned int tileLevel) { - WSITileGraphicsItem* item = new WSITileGraphicsItem(tile, tileX, tileY, tileSize, tileByteSize, tileLevel, _lastRenderLevel, _img, this); + WSITileGraphicsItem* item = new WSITileGraphicsItem(tile, tileX, tileY, tileSize, tileByteSize, tileLevel, _lastRenderLevel, _levelDownsamples, this); std::stringstream ss; ss << tileX << "_" << tileY << "_" << tileLevel; std::string key; ss >> key; if (_scene) { setCoverage(tileLevel, tileX, tileY, 2); - float tileDownsample = _img->getLevelDownsample(tileLevel); - float maxDownsample = _img->getLevelDownsample(_lastRenderLevel); + float tileDownsample = _levelDownsamples[tileLevel]; + float maxDownsample = _levelDownsamples[_lastRenderLevel]; float posX = (tileX * tileDownsample * tileSize) / maxDownsample + ((tileSize * tileDownsample) / (2 * maxDownsample)); float posY = (tileY * tileDownsample * tileSize) / maxDownsample + ((tileSize * tileDownsample) / (2 * maxDownsample)); _scene->addItem(item); @@ -147,7 +165,7 @@ bool TileManager::isCovered(unsigned int level, int tile_x, int tile_y) { } else { bool covered = true; - unsigned int downsample = _img->getLevelDownsample(level) / _img->getLevelDownsample(level - 1); + unsigned int downsample = _levelDownsamples[level] / _levelDownsamples[level - 1]; for (unsigned int x = 0; x < downsample; ++x) { for (unsigned int y = 0; y < downsample; ++y) { covered &= providesCoverage(level - 1, downsample * tile_x + x, downsample * tile_y + y) == 2; @@ -168,7 +186,7 @@ void TileManager::setCoverage(unsigned int level, int tile_x, int tile_y, unsign } if (level != _lastRenderLevel) { if (covers == 2 || covers == 0) { - float rectSize = _tileSize / (_img->getLevelDownsample(_lastRenderLevel) / _img->getLevelDownsample(level)); + float rectSize = _tileSize / (_levelDownsamples[_lastRenderLevel] / _levelDownsamples[level]); QPainterPath rect; rect.addRect(QRectF(tile_x * rectSize - 1, tile_y * rectSize - 1, rectSize + 1, rectSize + 1)); if (covers == 2) { @@ -189,9 +207,10 @@ std::vector TileManager::getCoverageMaps() { } void TileManager::clear() { + _renderThread->clearJobs(); while (_renderThread->getWaitingThreads() != _renderThread->getWorkers().size()) { } - _renderThread->clearJobs(); + QCoreApplication::processEvents(); _cache->clear(); QList itms = _scene->items(); for (QList::iterator it = itms.begin(); it != itms.end(); ++it) { diff --git a/workstation/TileManager.h b/workstation/TileManager.h index 9f5f0b9f..21facb5c 100644 --- a/workstation/TileManager.h +++ b/workstation/TileManager.h @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include class MultiResolutionImage; class RenderThread; @@ -17,15 +19,16 @@ class TileManager : public QObject { Q_OBJECT private: - MultiResolutionImage* _img; + std::vector _levelDownsamples; + std::vector > _levelDimensions; unsigned int _tileSize; QRect _lastFOV; unsigned int _lastLevel; unsigned int _lastRenderLevel; std::map > > _coverage; - RenderThread* _renderThread; - WSITileGraphicsItemCache* _cache; - QGraphicsScene* _scene; + QPointer _renderThread; + QPointer _cache; + QPointer _scene; std::vector _coverageMaps; bool _coverageMapCacheMode; @@ -33,7 +36,6 @@ class TileManager : public QObject { QPointF tileCoordinatesToPixelCoordinates(QPoint coordinate, unsigned int level); QPoint getLevelTiles(unsigned int level); - TileManager(const TileManager& that); signals: @@ -41,7 +43,7 @@ class TileManager : public QObject { public: // make sure to set `item` to NULL in the constructor - TileManager(MultiResolutionImage* img, unsigned int tileSize, unsigned int lastRenderLevel, RenderThread* renderThread, WSITileGraphicsItemCache* _cache, QGraphicsScene* scene); + TileManager(std::shared_ptr img, unsigned int tileSize, unsigned int lastRenderLevel, RenderThread* renderThread, WSITileGraphicsItemCache* _cache, QGraphicsScene* scene); ~TileManager(); void loadAllTilesForLevel(unsigned int level); diff --git a/workstation/WSITileGraphicsItem.cpp b/workstation/WSITileGraphicsItem.cpp index 34f3f4a7..0f78e8d3 100644 --- a/workstation/WSITileGraphicsItem.cpp +++ b/workstation/WSITileGraphicsItem.cpp @@ -13,11 +13,10 @@ #include -WSITileGraphicsItem::WSITileGraphicsItem(QPixmap* item, unsigned int tileX, unsigned int tileY, unsigned int tileSize, unsigned int tileByteSize, unsigned int itemLevel, unsigned int lastRenderLevel, const MultiResolutionImage* const img, TileManager* manager) : +WSITileGraphicsItem::WSITileGraphicsItem(QPixmap* item, unsigned int tileX, unsigned int tileY, unsigned int tileSize, unsigned int tileByteSize, unsigned int itemLevel, unsigned int lastRenderLevel, const std::vector& imgDownsamples, TileManager* manager) : QGraphicsItem(), _item(NULL), _manager(NULL), - _img(NULL), _tileX(tileX), _tileY(tileY), _tileSize(tileSize), @@ -31,10 +30,23 @@ WSITileGraphicsItem::WSITileGraphicsItem(QPixmap* item, unsigned int tileX, unsi if (manager) { _manager = manager; } - if (img) { - _img = img; + _physicalSize = _tileSize / (imgDownsamples[_lastRenderLevel] / imgDownsamples[_itemLevel]); + float lastRenderLevelDownsample = imgDownsamples[_lastRenderLevel]; + float itemLevelLOD = lastRenderLevelDownsample / imgDownsamples[_itemLevel]; + if (_itemLevel == _lastRenderLevel) { + _lowerLOD = 0.; + } + else { + float prevLevelLOD = lastRenderLevelDownsample / imgDownsamples[_itemLevel + 1]; + _lowerLOD = (prevLevelLOD + itemLevelLOD) / 2.; + } + if (_itemLevel == 0) { + _upperLOD = std::numeric_limits::max(); + } + else { + float nextLevelLOD = lastRenderLevelDownsample / imgDownsamples[_itemLevel - 1]; + _upperLOD = (nextLevelLOD + itemLevelLOD) / 2.; } - _physicalSize = _tileSize / (_img->getLevelDownsample(_lastRenderLevel) / _img->getLevelDownsample(_itemLevel)); this->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); _boundingRect = QRectF(-_physicalSize / 2., -_physicalSize / 2., _physicalSize, _physicalSize); } @@ -57,11 +69,16 @@ QRectF WSITileGraphicsItem::boundingRect() const{ void WSITileGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){ float lod = option->levelOfDetailFromTransform(painter->worldTransform()); - float maxDownsample = _img->getLevelDownsample(_lastRenderLevel); - unsigned int currentLevel = _img->getBestLevelForDownSample(maxDownsample / lod) > _lastRenderLevel ? _lastRenderLevel : _img->getBestLevelForDownSample(maxDownsample / lod); - if (currentLevel <= _itemLevel) { + if (lod > _lowerLOD) { if (_item) { - if (!_manager->isCovered(_itemLevel, _tileX, _tileY) || currentLevel == _itemLevel) { + bool draw = false; + if (lod <= _upperLOD) { + draw = true; + } + else if (!_manager->isCovered(_itemLevel, _tileX, _tileY)) { + draw = true; + } + if (draw) { QRectF pixmapArea = QRectF((option->exposedRect.left() + (_physicalSize / 2))*(_tileSize / _physicalSize), (option->exposedRect.top() + (_physicalSize / 2))*(_tileSize / _physicalSize), option->exposedRect.width()*(_tileSize / _physicalSize), option->exposedRect.height()*(_tileSize / _physicalSize)); painter->drawPixmap(option->exposedRect, *_item, pixmapArea); /* diff --git a/workstation/WSITileGraphicsItem.h b/workstation/WSITileGraphicsItem.h index 50abdc16..4e401210 100644 --- a/workstation/WSITileGraphicsItem.h +++ b/workstation/WSITileGraphicsItem.h @@ -2,6 +2,7 @@ #define WSITileGraphicsItem_H #include +#include class TileManager; class MultiResolutionImage; @@ -9,7 +10,7 @@ class MultiResolutionImage; class WSITileGraphicsItem : public QGraphicsItem { public: // make sure to set `item` to NULL in the constructor - WSITileGraphicsItem(QPixmap* item, unsigned int tileX, unsigned int tileY, unsigned int tileSize, unsigned int tileByteSize, unsigned int itemLevel, unsigned int lastRenderLevel, const MultiResolutionImage* const img, TileManager* manager); + WSITileGraphicsItem(QPixmap* item, unsigned int tileX, unsigned int tileY, unsigned int tileSize, unsigned int tileByteSize, unsigned int itemLevel, unsigned int lastRenderLevel, const std::vector& imgDownsamples, TileManager* manager); ~WSITileGraphicsItem(); // you will need to add a destructor @@ -32,6 +33,8 @@ class WSITileGraphicsItem : public QGraphicsItem { QPixmap *_item; float _physicalSize; + float _upperLOD; + float _lowerLOD; unsigned int _itemLevel; unsigned int _tileX; unsigned int _tileY; @@ -40,7 +43,6 @@ class WSITileGraphicsItem : public QGraphicsItem { unsigned int _lastRenderLevel; QRectF _boundingRect; TileManager* _manager; - const MultiResolutionImage* _img; }; diff --git a/workstation/annotation/AnnotationWorkstationExtensionPlugin.cpp b/workstation/annotation/AnnotationWorkstationExtensionPlugin.cpp index 61e5c75a..bdca82fa 100644 --- a/workstation/annotation/AnnotationWorkstationExtensionPlugin.cpp +++ b/workstation/annotation/AnnotationWorkstationExtensionPlugin.cpp @@ -40,7 +40,6 @@ unsigned int AnnotationWorkstationExtensionPlugin::_annotationGroupIndex = 0; AnnotationWorkstationExtensionPlugin::AnnotationWorkstationExtensionPlugin() : WorkstationExtensionPluginInterface(), - _annotationService(NULL), _generatedAnnotation(NULL), _activeAnnotation(NULL), _dockWidget(NULL), @@ -74,10 +73,6 @@ AnnotationWorkstationExtensionPlugin::AnnotationWorkstationExtensionPlugin() : AnnotationWorkstationExtensionPlugin::~AnnotationWorkstationExtensionPlugin() { onClearButtonPressed(); - if (_annotationService) { - delete _annotationService; - _annotationService = NULL; - } } void AnnotationWorkstationExtensionPlugin::onClearButtonPressed() { @@ -85,10 +80,10 @@ void AnnotationWorkstationExtensionPlugin::onClearButtonPressed() { PolyQtAnnotation* tmp = dynamic_cast(_generatedAnnotation); if (tmp) { if (tmp->getInterpolationType() == "spline") { - dynamic_cast(_annotationTools[2])->cancelAnnotation(); + std::dynamic_pointer_cast(_annotationTools[2])->cancelAnnotation(); } else { - dynamic_cast(_annotationTools[1])->cancelAnnotation(); + std::dynamic_pointer_cast(_annotationTools[1])->cancelAnnotation(); } } } @@ -341,66 +336,68 @@ void AnnotationWorkstationExtensionPlugin::onSaveButtonPressed() { basename += QString(".xml"); } QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save annotations"), defaultName.filePath(basename), tr("XML file (*.xml);TIF file (*.tif)")); - if (_img && fileName.endsWith(".tif")) { - std::vector > grps = this->_annotationService->getList()->getGroups(); - QDialog* nameToLabel = new QDialog(); - nameToLabel->setWindowTitle("Assign labels to annotation groups"); - QVBoxLayout* dialogLayout = new QVBoxLayout(); - QFormLayout* nameToLabelLayout = new QFormLayout(); - QHBoxLayout* buttonLayout = new QHBoxLayout(); - if (grps.empty()) { - QSpinBox* label = new QSpinBox(); - label->setMinimum(0); - label->setValue(1); - label->setObjectName("All annotations"); - nameToLabelLayout->addRow("All annotations", label); - } - else { - for (unsigned int i = 0; i < grps.size(); ++i) { - if (!grps[i]->getGroup()) { - QSpinBox* label = new QSpinBox(); - QString grpName = QString::fromStdString(grps[i]->getName()); - label->setObjectName(grpName); - label->setMinimum(0); - label->setValue(i + 1); - nameToLabelLayout->addRow(grpName, label); + if (fileName.endsWith(".tif")) { + if (std::shared_ptr local_img = _img.lock()) { + std::vector > grps = this->_annotationService->getList()->getGroups(); + QDialog* nameToLabel = new QDialog(); + nameToLabel->setWindowTitle("Assign labels to annotation groups"); + QVBoxLayout* dialogLayout = new QVBoxLayout(); + QFormLayout* nameToLabelLayout = new QFormLayout(); + QHBoxLayout* buttonLayout = new QHBoxLayout(); + if (grps.empty()) { + QSpinBox* label = new QSpinBox(); + label->setMinimum(0); + label->setValue(1); + label->setObjectName("All annotations"); + nameToLabelLayout->addRow("All annotations", label); + } + else { + for (unsigned int i = 0; i < grps.size(); ++i) { + if (!grps[i]->getGroup()) { + QSpinBox* label = new QSpinBox(); + QString grpName = QString::fromStdString(grps[i]->getName()); + label->setObjectName(grpName); + label->setMinimum(0); + label->setValue(i + 1); + nameToLabelLayout->addRow(grpName, label); + } } } - } - dialogLayout->addLayout(nameToLabelLayout); - QPushButton* cancel = new QPushButton("Cancel"); - QPushButton* ok = new QPushButton("Ok"); - cancel->setDefault(true); - connect(cancel, SIGNAL(clicked()), nameToLabel, SLOT(reject())); - connect(ok, SIGNAL(clicked()), nameToLabel, SLOT(accept())); - buttonLayout->addWidget(cancel); - buttonLayout->addWidget(ok); - dialogLayout->addLayout(buttonLayout); - nameToLabel->setLayout(dialogLayout); - int rval = nameToLabel->exec(); - if (rval) { - QList assignedLabels = nameToLabel->findChildren(); - std::map nameToLab; - for (QList::iterator it = assignedLabels.begin(); it != assignedLabels.end(); ++it) { - if ((*it)->objectName().toStdString() == "All annotations") { - continue; + dialogLayout->addLayout(nameToLabelLayout); + QPushButton* cancel = new QPushButton("Cancel"); + QPushButton* ok = new QPushButton("Ok"); + cancel->setDefault(true); + connect(cancel, SIGNAL(clicked()), nameToLabel, SLOT(reject())); + connect(ok, SIGNAL(clicked()), nameToLabel, SLOT(accept())); + buttonLayout->addWidget(cancel); + buttonLayout->addWidget(ok); + dialogLayout->addLayout(buttonLayout); + nameToLabel->setLayout(dialogLayout); + int rval = nameToLabel->exec(); + if (rval) { + QList assignedLabels = nameToLabel->findChildren(); + std::map nameToLab; + for (QList::iterator it = assignedLabels.begin(); it != assignedLabels.end(); ++it) { + if ((*it)->objectName().toStdString() == "All annotations") { + continue; + } + nameToLab[(*it)->objectName().toStdString()] = (*it)->value(); } - nameToLab[(*it)->objectName().toStdString()] = (*it)->value(); + AnnotationToMask maskConverter; + QtProgressMonitor monitor; + maskConverter.setProgressMonitor(&monitor); + QProgressDialog progressDialog; + QObject::connect(&monitor, SIGNAL(progressChanged(int)), &progressDialog, SLOT(setValue(int))); + progressDialog.setMinimum(0); + progressDialog.setMaximum(100); + progressDialog.setCancelButton(NULL); + progressDialog.setWindowModality(Qt::WindowModal); + progressDialog.setValue(0); + progressDialog.show(); + QApplication::processEvents(); + maskConverter.convert(_annotationService->getList(), fileName.toStdString(), local_img->getDimensions(), local_img->getSpacing(), nameToLab); + delete nameToLabel; } - AnnotationToMask maskConverter; - QtProgressMonitor monitor; - maskConverter.setProgressMonitor(&monitor); - QProgressDialog progressDialog; - QObject::connect(&monitor, SIGNAL(progressChanged(int)), &progressDialog, SLOT(setValue(int))); - progressDialog.setMinimum(0); - progressDialog.setMaximum(100); - progressDialog.setCancelButton(NULL); - progressDialog.setWindowModality(Qt::WindowModal); - progressDialog.setValue(0); - progressDialog.show(); - QApplication::processEvents(); - maskConverter.convert(_annotationService->getList(), fileName.toStdString(), _img->getDimensions(), _img->getSpacing(), nameToLab); - delete nameToLabel; } } else if (!fileName.isEmpty()) { @@ -500,7 +497,7 @@ QDockWidget* AnnotationWorkstationExtensionPlugin::getDockWidget() { return _dockWidget; } -void AnnotationWorkstationExtensionPlugin::onNewImageLoaded(MultiResolutionImage* img, std::string fileName) { +void AnnotationWorkstationExtensionPlugin::onNewImageLoaded(std::weak_ptr img, std::string fileName) { if (_dockWidget) { _dockWidget->setEnabled(true); } @@ -519,19 +516,21 @@ void AnnotationWorkstationExtensionPlugin::onImageClosed() { _dockWidget->setEnabled(false); } onClearButtonPressed(); - _img = NULL; } bool AnnotationWorkstationExtensionPlugin::initialize(PathologyViewer* viewer) { _viewer = viewer; - _annotationTools.push_back(new DotAnnotationTool(this, viewer)); - _annotationTools.push_back(new PolyAnnotationTool(this, viewer)); - _annotationTools.push_back(new SplineAnnotationTool(this, viewer)); - _annotationService = new AnnotationService(); + std::shared_ptr tool(new DotAnnotationTool(this, viewer)); + _annotationTools.push_back(tool); + tool.reset(new PolyAnnotationTool(this, viewer)); + _annotationTools.push_back(tool); + tool.reset(new SplineAnnotationTool(this, viewer)); + _annotationTools.push_back(tool); + _annotationService.reset(new AnnotationService()); return true; } -std::vector AnnotationWorkstationExtensionPlugin::getTools() { +std::vector > AnnotationWorkstationExtensionPlugin::getTools() { return _annotationTools; } @@ -607,7 +606,7 @@ void AnnotationWorkstationExtensionPlugin::deleteAnnotation(QtAnnotation* annota if (_treeWidget) { QTreeWidgetItemIterator it(_treeWidget); while (*it) { - if ((*it)->text(1) == QString::fromStdString(annotation->getAnnotation()->getName())) { + if ((*it)->text(1) == QString::fromStdString(annotation->getAnnotation()->getName()) && (*it)->data(1, Qt::UserRole).value().endsWith("_annotation")) { QString annotUID = (*it)->data(1, Qt::UserRole).value(); _qtAnnotations.remove(annotUID); if (_viewer) { @@ -632,7 +631,7 @@ void AnnotationWorkstationExtensionPlugin::deleteAnnotationGroup(std::shared_ptr if (_treeWidget) { QTreeWidgetItemIterator it(_treeWidget); while (*it) { - if ((*it)->text(1) == QString::fromStdString(group->getName())) { + if ((*it)->text(1) == QString::fromStdString(group->getName()) && (*it)->data(1, Qt::UserRole).value().endsWith("_group")) { if ((*it)->childCount() > 0) { for (int i = (*it)->childCount() - 1; i >= 0; --i) { QTreeWidgetItem* itm = (*it)->child(i); diff --git a/workstation/annotation/AnnotationWorkstationExtensionPlugin.h b/workstation/annotation/AnnotationWorkstationExtensionPlugin.h index d53cb8a0..3aca3cf7 100644 --- a/workstation/annotation/AnnotationWorkstationExtensionPlugin.h +++ b/workstation/annotation/AnnotationWorkstationExtensionPlugin.h @@ -25,7 +25,7 @@ class EXPORT_PATHOLOGYANNOTATIONPLUGIN AnnotationWorkstationExtensionPlugin : pu public : bool initialize(PathologyViewer* viewer); - std::vector getTools(); + std::vector > getTools(); AnnotationWorkstationExtensionPlugin(); ~AnnotationWorkstationExtensionPlugin(); void startAnnotation(float x, float y, const std::string& type); @@ -42,7 +42,7 @@ public : void clearSelection(); public slots: - void onNewImageLoaded(MultiResolutionImage* img, std::string fileName); + void onNewImageLoaded(std::weak_ptr img, std::string fileName); void onImageClosed(); void addAnnotationGroup(); void onClearButtonPressed(); @@ -56,8 +56,8 @@ private slots: void resizeOnExpand(); private : - std::vector _annotationTools; - AnnotationService* _annotationService; + std::vector > _annotationTools; + std::unique_ptr _annotationService; QtAnnotation* _generatedAnnotation; QtAnnotation* _activeAnnotation; QSet _selectedAnnotations; @@ -66,7 +66,7 @@ private : QDockWidget* _dockWidget; QTreeWidget* _treeWidget; QEvent* _oldEvent; - MultiResolutionImage* _img; + std::weak_ptr _img; void clearTreeWidget(); void clearAnnotationList(); diff --git a/workstation/filters/ColorDeconvolutionFilterPlugin.cpp b/workstation/filters/ColorDeconvolutionFilterPlugin.cpp index 4d463cf3..f436bbc6 100644 --- a/workstation/filters/ColorDeconvolutionFilterPlugin.cpp +++ b/workstation/filters/ColorDeconvolutionFilterPlugin.cpp @@ -27,7 +27,7 @@ Q_DECLARE_METATYPE(Patch*) ColorDeconvolutionFilterPlugin::ColorDeconvolutionFilterPlugin() : ImageFilterPluginInterface() { - _filter = new ColorDeconvolutionFilter(); + _filter.reset(new ColorDeconvolutionFilter()); } bool ColorDeconvolutionFilterPlugin::initialize(const ImageSource* img) { @@ -49,12 +49,11 @@ ColorDeconvolutionFilterPlugin::ColorDeconvolutionFilterPlugin(const ColorDeconv { _mutex.lock(); if (_filter) { - delete _filter; - _filter = NULL; + _filter.reset(); } - ColorDeconvolutionFilter* otherFilter = dynamic_cast* >(other._filter); + const ColorDeconvolutionFilter* otherFilter = dynamic_cast* >(other._filter.get()); if (otherFilter) { - _filter = new ColorDeconvolutionFilter(*otherFilter); + _filter.reset(new ColorDeconvolutionFilter(*otherFilter)); } _mutex.unlock(); } @@ -69,7 +68,7 @@ QIcon ColorDeconvolutionFilterPlugin::icon() const { void ColorDeconvolutionFilterPlugin::filter(const Patch &input, QVariant &output) { Patch* outImg = new Patch(); - ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter); + ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter.get()); if (filter) { if (filter->filter(input, *outImg)) { output = QVariant::fromValue*>(outImg); @@ -131,7 +130,7 @@ void ColorDeconvolutionFilterPlugin::initializeSettingsPanel() { void ColorDeconvolutionFilterPlugin::revertStainToDefault() { if (_filter) { - ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter); + ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter.get()); if (filter) { filter->revertToDefaultStain(); updateSettingsPanelFromFilter(); @@ -141,7 +140,7 @@ void ColorDeconvolutionFilterPlugin::revertStainToDefault() { } void ColorDeconvolutionFilterPlugin::updateFilterFromSettingsPanel() { - ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter); + ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter.get()); if (_settingsPanel && filter) { QDoubleSpinBox* stain1R = _settingsPanel->findChild("Stain1RSpinBox"); QDoubleSpinBox* stain1G = _settingsPanel->findChild("Stain1GSpinBox"); @@ -180,7 +179,7 @@ void ColorDeconvolutionFilterPlugin::updateFilterFromSettingsPanel() { } void ColorDeconvolutionFilterPlugin::updateSettingsPanelFromFilter() { - ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter); + ColorDeconvolutionFilter* filter = dynamic_cast* >(_filter.get()); if (_settingsPanel && filter) { _mutex.lock(); QDoubleSpinBox* stain1R = _settingsPanel->findChild("Stain1RSpinBox"); diff --git a/workstation/filters/FilterDockWidget.cpp b/workstation/filters/FilterDockWidget.cpp index 269d7225..46ba624c 100644 --- a/workstation/filters/FilterDockWidget.cpp +++ b/workstation/filters/FilterDockWidget.cpp @@ -37,8 +37,8 @@ FilterDockWidget::FilterDockWidget(QWidget *parent, Qt::WindowFlags flags) : connect(_availableFilters, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(onItemClicked(QListWidgetItem*))); _progressBar = contents->findChild("progressBar"); QObject::connect(_progressBar, SIGNAL(valueChanged(int)), this, SLOT(onProcessing())); - _monitor = new QtProgressMonitor(); - QObject::connect(_monitor, SIGNAL(progressChanged(int)), _progressBar, SLOT(setValue(int)), Qt::QueuedConnection); + _monitor.reset(new QtProgressMonitor()); + QObject::connect(_monitor.get(), SIGNAL(progressChanged(int)), _progressBar, SLOT(setValue(int)), Qt::QueuedConnection); _applyFilter = contents->findChild("applyFilterButton"); _clearFilter = contents->findChild("clearFilterButton"); _autoUpdateCheckBox = contents->findChild("autoUpdateCheckBox"); @@ -141,13 +141,14 @@ void FilterDockWidget::stopProgressTracking() { } } -void FilterDockWidget::onNewImageLoaded(MultiResolutionImage* img) { +void FilterDockWidget::onNewImageLoaded(std::weak_ptr img) { if (_availableFilters) { for (int row = 0; row < _availableFilters->count(); row++) { QListWidgetItem *item = _availableFilters->item(row); std::shared_ptr filter = item->data(Qt::UserRole).value >(); - if (!filter->initialize(img)) { + std::shared_ptr local_img = img.lock(); + if (!filter->initialize(local_img.get())) { item->setHidden(true); } else { diff --git a/workstation/filters/FilterDockWidget.h b/workstation/filters/FilterDockWidget.h index 4aed5f42..a2835901 100644 --- a/workstation/filters/FilterDockWidget.h +++ b/workstation/filters/FilterDockWidget.h @@ -28,7 +28,7 @@ private : QPushButton *_clearFilter; QCheckBox *_autoUpdateCheckBox; QProgressBar* _progressBar; - QtProgressMonitor* _monitor; + std::shared_ptr _monitor; bool _autoUpdate; @@ -43,7 +43,7 @@ private slots : void onFilterParametersChanged(); public slots : - void onNewImageLoaded(MultiResolutionImage* img); + void onNewImageLoaded(std::weak_ptr img); void onImageClosed(); signals: diff --git a/workstation/filters/FilterThread.cpp b/workstation/filters/FilterThread.cpp index 167f1fde..b97047ff 100644 --- a/workstation/filters/FilterThread.cpp +++ b/workstation/filters/FilterThread.cpp @@ -29,7 +29,6 @@ FilterThread::FilterThread(QObject *parent) : _FOV(QRectF()), _level(0), _channel(0), - _img(NULL), _filterPlugin(NULL) { } @@ -54,7 +53,7 @@ void FilterThread::updateFilterResult() { _condition.wakeOne(); } -void FilterThread::updateFilterResult(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level, int channel) +void FilterThread::updateFilterResult(const QRectF& FOV, std::weak_ptr img, const unsigned int level, int channel) { stopFilter(); @@ -98,7 +97,7 @@ void FilterThread::run() _mutex.lock(); QRectF FOV = _FOV; int level = _level; - MultiResolutionImage* img = _img; + std::shared_ptr img = _img.lock(); int channel = _channel; if (img) { @@ -110,13 +109,11 @@ void FilterThread::run() float downsample = img->getLevelDownsample(level); unsigned int width = FOV.width() / downsample; unsigned int height = FOV.height() / downsample; - Patch* input = img->getPatch(FOV.left(), FOV.top(), width, height, level); + Patch input = img->getPatch(FOV.left(), FOV.top(), width, height, level); QVariant variant; if (!_restart) { - _filterPlugin->filter(*input, variant); + _filterPlugin->filter(input, variant); } - delete input; - input = NULL; if (variant.isValid() && !variant.isNull()) { Patch* output = variant.value*>(); diff --git a/workstation/filters/FilterThread.h b/workstation/filters/FilterThread.h index 780e0b56..07dd6afe 100644 --- a/workstation/filters/FilterThread.h +++ b/workstation/filters/FilterThread.h @@ -27,7 +27,7 @@ class FilterThread : public QThread public slots : void updateFilterResult(); - void updateFilterResult(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level, int channel = -1); + void updateFilterResult(const QRectF& FOV, std::weak_ptr img, const unsigned int level, int channel = -1); signals: void filterResult(QGraphicsItem* result, QRectF size); @@ -43,7 +43,7 @@ public slots : QWaitCondition _condition; QRectF _FOV; unsigned int _level; - MultiResolutionImage *_img; + std::weak_ptr _img; // Pointer to Workstation-filter that needs to be applied std::shared_ptr _filterPlugin; diff --git a/workstation/filters/FilterWorkstationExtensionPlugin.cpp b/workstation/filters/FilterWorkstationExtensionPlugin.cpp index b0eb2694..f725cd59 100644 --- a/workstation/filters/FilterWorkstationExtensionPlugin.cpp +++ b/workstation/filters/FilterWorkstationExtensionPlugin.cpp @@ -15,7 +15,6 @@ FilterWorkstationExtensionPlugin::FilterWorkstationExtensionPlugin() : WorkstationExtensionPluginInterface(), _dockWidget(NULL), _filterThread(NULL), - _img(NULL), _filterResult(NULL), _autoUpdate(false) { @@ -65,7 +64,7 @@ FilterWorkstationExtensionPlugin::~FilterWorkstationExtensionPlugin() { bool FilterWorkstationExtensionPlugin::initialize(PathologyViewer* viewer) { _viewer = viewer; - connect(_viewer, SIGNAL(fieldOfViewChanged(const QRectF&, MultiResolutionImage*, const unsigned int)), this, SLOT(onFieldOfViewChanged(const QRectF&, MultiResolutionImage*, const unsigned int))); + connect(_viewer, SIGNAL(fieldOfViewChanged(const QRectF&, const unsigned int)), this, SLOT(onFieldOfViewChanged(const QRectF&, const unsigned int))); return true; } @@ -82,12 +81,14 @@ void FilterWorkstationExtensionPlugin::onFilterResultClearRequested() { } void FilterWorkstationExtensionPlugin::onFilterResultUpdateRequested() { - if (_img && _filterThread) { - float sceneScale = this->_viewer->getSceneScale(); - float maxDownsample = 1. / sceneScale; - QRectF FOV = this->_viewer->mapToScene(this->_viewer->rect()).boundingRect(); - QRectF FOVImage = QRectF(FOV.left() / sceneScale, FOV.top() / sceneScale, FOV.width() / sceneScale, FOV.height() / sceneScale); - _filterThread->updateFilterResult(FOVImage, _img, _img->getBestLevelForDownSample(maxDownsample / this->_viewer->transform().m11()), -1); + if (_filterThread) { + if (std::shared_ptr local_img = _img.lock()) { + float sceneScale = this->_viewer->getSceneScale(); + float maxDownsample = 1. / sceneScale; + QRectF FOV = this->_viewer->mapToScene(this->_viewer->rect()).boundingRect(); + QRectF FOVImage = QRectF(FOV.left() / sceneScale, FOV.top() / sceneScale, FOV.width() / sceneScale, FOV.height() / sceneScale); + _filterThread->updateFilterResult(FOVImage, _img, local_img->getBestLevelForDownSample(maxDownsample / this->_viewer->transform().m11()), -1); + } } } @@ -129,7 +130,7 @@ QDockWidget* FilterWorkstationExtensionPlugin::getDockWidget() { return _dockWidget; } -void FilterWorkstationExtensionPlugin::onNewImageLoaded(MultiResolutionImage* img, std::string fileName) { +void FilterWorkstationExtensionPlugin::onNewImageLoaded(std::weak_ptr img, std::string fileName) { _img = img; if (_dockWidget) { _dockWidget->setEnabled(true); @@ -138,7 +139,7 @@ void FilterWorkstationExtensionPlugin::onNewImageLoaded(MultiResolutionImage* im } } -void FilterWorkstationExtensionPlugin::onFieldOfViewChanged(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level) { +void FilterWorkstationExtensionPlugin::onFieldOfViewChanged(const QRectF& FOV, std::weak_ptr img, const unsigned int level) { onFilterResultClearRequested(); if (_filterThread && _autoUpdate) { onFilterResultUpdateRequested(); @@ -146,7 +147,7 @@ void FilterWorkstationExtensionPlugin::onFieldOfViewChanged(const QRectF& FOV, M } void FilterWorkstationExtensionPlugin::onImageClosed() { - _img = NULL; + _img.reset(); if (_filterResult) { onFilterResultClearRequested(); } diff --git a/workstation/filters/FilterWorkstationExtensionPlugin.h b/workstation/filters/FilterWorkstationExtensionPlugin.h index e873d588..39012be6 100644 --- a/workstation/filters/FilterWorkstationExtensionPlugin.h +++ b/workstation/filters/FilterWorkstationExtensionPlugin.h @@ -20,7 +20,7 @@ private : QGraphicsItem* _filterResult; FilterThread* _filterThread; bool _autoUpdate; - MultiResolutionImage* _img; + std::weak_ptr _img; public : bool initialize(PathologyViewer* viewer); @@ -29,11 +29,11 @@ public : QDockWidget* getDockWidget(); public slots: - void onNewImageLoaded(MultiResolutionImage* img, std::string fileName); + void onNewImageLoaded(std::weak_ptr img, std::string fileName); void onImageClosed(); void updateFilteredImage(QGraphicsItem* result, QRectF size); void onChangeCurrentFilter(std::shared_ptr filter); - void onFieldOfViewChanged(const QRectF& FOV, MultiResolutionImage* img, const unsigned int level); + void onFieldOfViewChanged(const QRectF& FOV, std::weak_ptr img, const unsigned int level); private slots: void onFilterResultClearRequested(); diff --git a/workstation/filters/NucleiDetectionFilterPlugin.cpp b/workstation/filters/NucleiDetectionFilterPlugin.cpp index 33e374d8..4fbbc015 100644 --- a/workstation/filters/NucleiDetectionFilterPlugin.cpp +++ b/workstation/filters/NucleiDetectionFilterPlugin.cpp @@ -28,7 +28,7 @@ Q_DECLARE_METATYPE(std::vector) NucleiDetectionFilterPlugin::NucleiDetectionFilterPlugin() : ImageFilterPluginInterface() { - _filter = new NucleiDetectionFilter(); + _filter.reset(new NucleiDetectionFilter()); } ImageFilterPluginInterface* NucleiDetectionFilterPlugin::clone() const { @@ -39,9 +39,9 @@ ImageFilterPluginInterface* NucleiDetectionFilterPlugin::clone() const { NucleiDetectionFilterPlugin::NucleiDetectionFilterPlugin(const NucleiDetectionFilterPlugin& other) : ImageFilterPluginInterface() { - NucleiDetectionFilter* otherFilter = dynamic_cast* >(other._filter); + const NucleiDetectionFilter* otherFilter = dynamic_cast* >(other._filter.get()); if (otherFilter) { - _filter = otherFilter; + _filter.reset(new NucleiDetectionFilter(*otherFilter)); initializeSettingsPanel(); updateSettingsPanelFromFilter(); } @@ -65,7 +65,7 @@ bool NucleiDetectionFilterPlugin::initialize(const ImageSource* img) { } void NucleiDetectionFilterPlugin::filter(const Patch &input, QVariant &output) { - NucleiDetectionFilter* filter = dynamic_cast* >(_filter); + NucleiDetectionFilter* filter = dynamic_cast* >(_filter.get()); if (filter) { _mutex.lock(); if (_settingsPanel) { @@ -158,7 +158,7 @@ void NucleiDetectionFilterPlugin::initializeSettingsPanel() { } void NucleiDetectionFilterPlugin::revertStainToDefault() { - NucleiDetectionFilter* filter = dynamic_cast* >(_filter); + NucleiDetectionFilter* filter = dynamic_cast* >(_filter.get()); if (filter) { filter->getColorDeconvolutionFilter()->revertToDefaultStain(); updateSettingsPanelFromFilter(); @@ -166,7 +166,7 @@ void NucleiDetectionFilterPlugin::revertStainToDefault() { } void NucleiDetectionFilterPlugin::updateFilterFromSettingsPanel() { - NucleiDetectionFilter* filter = dynamic_cast* >(_filter); + NucleiDetectionFilter* filter = dynamic_cast* >(_filter.get()); if (_settingsPanel && filter) { filter->cancel(); _mutex.lock(); @@ -219,7 +219,7 @@ void NucleiDetectionFilterPlugin::updateFilterFromSettingsPanel() { } void NucleiDetectionFilterPlugin::updateSettingsPanelFromFilter() { - NucleiDetectionFilter* filter = dynamic_cast* >(_filter); + NucleiDetectionFilter* filter = dynamic_cast* >(_filter.get()); if (_settingsPanel && filter) { _mutex.lock(); QDoubleSpinBox* stain1R = _settingsPanel->findChild("Stain1RSpinBox"); diff --git a/workstation/interfaces/interfaces.h b/workstation/interfaces/interfaces.h index b847b2e5..9c416f9a 100644 --- a/workstation/interfaces/interfaces.h +++ b/workstation/interfaces/interfaces.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -13,13 +14,12 @@ #include "core/Patch.h" #include "imgproc/generic/FilterBase.h" +#include "workstation/PathologyViewer.h" class QToolBar; class QDockWidget; class PathologyViewer; -class QAction; class QMenu; -class PathologyViewer; class ProgressMonitor; class MultiResolutionImage; @@ -28,8 +28,7 @@ class ImageFilterPluginInterface : public QObject public: ImageFilterPluginInterface() : - _settingsPanel(), - _filter(NULL) + _settingsPanel() {} virtual ~ImageFilterPluginInterface() { @@ -37,9 +36,6 @@ class ImageFilterPluginInterface : public QObject if (_settingsPanel) { delete _settingsPanel; } - if (_filter) { - delete _filter; - } _mutex.unlock(); } @@ -58,7 +54,7 @@ class ImageFilterPluginInterface : public QObject } }; - void setProgressMonitor(ProgressMonitor* monitor) { + void setProgressMonitor(std::shared_ptr monitor) { if (_filter) { _filter->setProgressMonitor(monitor); } @@ -73,7 +69,7 @@ class ImageFilterPluginInterface : public QObject protected: QPointer _settingsPanel; - FilterBase* _filter; + std::unique_ptr _filter; QMutex _mutex; }; @@ -98,8 +94,8 @@ public : virtual QAction* getToolButton() = 0; protected : - PathologyViewer* _viewer; - QAction* _button; + QPointer _viewer; + QPointer _button; }; class WorkstationExtensionPluginInterface : public QObject { @@ -109,10 +105,10 @@ public : virtual QToolBar* getToolBar() { return NULL;} virtual QMenu* getMenu() { return NULL; } virtual QDockWidget* getDockWidget() { return NULL; } - virtual std::vector getTools() { return std::vector(); } + virtual std::vector > getTools() { return std::vector >(); } protected: - PathologyViewer* _viewer; + QPointer _viewer; public slots: virtual void onNewImageLoaded(MultiResolutionImage* img, std::string fileName) {}; diff --git a/workstation/pathologyworkstation.cpp b/workstation/pathologyworkstation.cpp index e55043fa..4251153b 100644 --- a/workstation/pathologyworkstation.cpp +++ b/workstation/pathologyworkstation.cpp @@ -45,7 +45,6 @@ using namespace std; PathologyWorkstation::PathologyWorkstation(QWidget *parent) : QMainWindow(parent), - _img(NULL), _cacheMaxByteSize(1000*512*512*3), _settings(NULL) { @@ -103,7 +102,7 @@ void PathologyWorkstation::loadPlugins() { QPluginLoader loader(_pluginsDir.absoluteFilePath(fileName)); QObject *plugin = loader.instance(); if (plugin) { - ToolPluginInterface* tool = qobject_cast(plugin); + std::shared_ptr tool(qobject_cast(plugin)); if (tool) { tool->setViewer(viewer); QAction* toolAction = tool->getToolButton(); @@ -131,7 +130,7 @@ void PathologyWorkstation::loadPlugins() { std::unique_ptr extension(qobject_cast(plugin)); if (extension) { _extensionPluginFileNames.push_back(fileName.toStdString()); - connect(this, SIGNAL(newImageLoaded(MultiResolutionImage*, std::string)), &*extension, SLOT(onNewImageLoaded(MultiResolutionImage*, std::string))); + connect(this, SIGNAL(newImageLoaded(std::weak_ptr, std::string)), &*extension, SLOT(onNewImageLoaded(std::weak_ptr, std::string))); connect(this, SIGNAL(imageClosed()), &*extension, SLOT(onImageClosed())); extension->initialize(viewer); if (extension->getToolBar()) { @@ -160,7 +159,7 @@ void PathologyWorkstation::loadPlugins() { if (extension->getMenu()) { this->menuBar->addMenu(extension->getMenu()); } - std::vector tools = extension->getTools(); + std::vector > tools = extension->getTools(); if (!tools.empty()) { mainToolBar->addSeparator(); for (unsigned int i = 0; i < tools.size(); ++i) { @@ -199,13 +198,13 @@ void PathologyWorkstation::on_actionClose_triggered() if (_img) { PathologyViewer* view = this->findChild("pathologyView"); view->close(); - delete _img; - _img = NULL; + _img.reset(); statusBar->showMessage("Closed file!", 5); } } void PathologyWorkstation::openFile(const QString& fileName) { + statusBar->clearMessage(); if (!fileName.isEmpty()) { if (_img) { on_actionClose_triggered(); @@ -215,11 +214,11 @@ void PathologyWorkstation::openFile(const QString& fileName) { _settings->setValue("currentFile", QFileInfo(fileName).fileName()); this->setWindowTitle(QString("ASAP - ") + QFileInfo(fileName).fileName()); MultiResolutionImageReader imgReader; - _img = imgReader.open(fn); + _img.reset(imgReader.open(fn)); if (_img) { if (_img->valid()) { - if (dynamic_cast(_img)) { - dynamic_cast(_img)->setIgnoreAlpha(false); + if (std::shared_ptr openslide_img = dynamic_pointer_cast(_img)) { + openslide_img->setIgnoreAlpha(false); } vector dimensions = _img->getLevelDimensions(_img->getNumberOfLevels() - 1); PathologyViewer* view = this->findChild("pathologyView"); diff --git a/workstation/pathologyworkstation.h b/workstation/pathologyworkstation.h index a139ef13..124b5cbc 100644 --- a/workstation/pathologyworkstation.h +++ b/workstation/pathologyworkstation.h @@ -16,6 +16,17 @@ class WorkstationExtensionPluginInterface; class QActionGroup; class QSettings; +/* + +OWNERSHIP + +Workstation is the owner of all the PathologyViews +Workstation is the owner of all Plugins, also the ToolPlugins generated by ExtensionPlugins +Workstation is the owner of the MultiResolutionImage +Viewer is the owner of RenderThread, TileManager, ScaleBar, MiniMap, RenderWorkers and the Scene + +*/ + class PathologyWorkstation : public QMainWindow { Q_OBJECT @@ -29,7 +40,7 @@ class PathologyWorkstation : public QMainWindow unsigned long long getCacheSize() const; signals: - void newImageLoaded(MultiResolutionImage*, std::string); + void newImageLoaded(std::weak_ptr, const std::string&); void imageClosed(); private slots: @@ -38,7 +49,7 @@ private slots: private: static const char* sharedLibraryExtensions; - MultiResolutionImage *_img; + std::shared_ptr _img; unsigned long long _cacheMaxByteSize; QSettings* _settings; diff --git a/workstation/resources/aboutlogo.png b/workstation/resources/aboutlogo.png new file mode 100644 index 00000000..8a8b6ba2 Binary files /dev/null and b/workstation/resources/aboutlogo.png differ diff --git a/workstation/visualization/VisualizationWorkstationExtensionPlugin.cpp b/workstation/visualization/VisualizationWorkstationExtensionPlugin.cpp index f3cf0681..53c36846 100644 --- a/workstation/visualization/VisualizationWorkstationExtensionPlugin.cpp +++ b/workstation/visualization/VisualizationWorkstationExtensionPlugin.cpp @@ -28,15 +28,15 @@ VisualizationWorkstationExtensionPlugin::VisualizationWorkstationExtensionPlugin VisualizationWorkstationExtensionPlugin::~VisualizationWorkstationExtensionPlugin() { if (_foreground) { _foregroundScale = 1.; - emit changeForegroundImage(NULL, _foregroundScale); - _foreground = NULL; + emit changeForegroundImage(std::weak_ptr(), _foregroundScale); + _foreground.reset(); } _dockWidget = NULL; } bool VisualizationWorkstationExtensionPlugin::initialize(PathologyViewer* viewer) { _viewer = viewer; - connect(this, SIGNAL(changeForegroundImage(MultiResolutionImage*, float)), viewer, SLOT(onForegroundImageChanged(MultiResolutionImage*, float))); + connect(this, SIGNAL(changeForegroundImage(std::weak_ptr, float)), viewer, SLOT(onForegroundImageChanged(std::weak_ptr, float))); return true; } @@ -57,7 +57,7 @@ QDockWidget* VisualizationWorkstationExtensionPlugin::getDockWidget() { return _dockWidget; } -void VisualizationWorkstationExtensionPlugin::onNewImageLoaded(MultiResolutionImage* img, std::string fileName) { +void VisualizationWorkstationExtensionPlugin::onNewImageLoaded(std::weak_ptr img, std::string fileName) { if (_dockWidget) { _dockWidget->setEnabled(true); } @@ -69,12 +69,13 @@ void VisualizationWorkstationExtensionPlugin::onNewImageLoaded(MultiResolutionIm MultiResolutionImageReader reader; if (_foreground) { _foregroundScale = 1; - emit changeForegroundImage(NULL, _foregroundScale); - _foreground = NULL; + emit changeForegroundImage(std::weak_ptr(), _foregroundScale); + _foreground.reset(); } - _foreground = reader.open(likImgPth); + _foreground.reset(reader.open(likImgPth)); if (_foreground) { - std::vector dimsBG = img->getDimensions(); + std::shared_ptr local_img = img.lock(); + std::vector dimsBG = local_img->getDimensions(); std::vector dimsFG = _foreground->getDimensions(); if (dimsBG[0] / dimsFG[0] == dimsBG[1] / dimsFG[1]) { _foregroundScale = dimsBG[0] / dimsFG[0]; @@ -82,7 +83,7 @@ void VisualizationWorkstationExtensionPlugin::onNewImageLoaded(MultiResolutionIm emit changeForegroundImage(_foreground, _foregroundScale); } else { - emit changeForegroundImage(NULL, _foregroundScale); + emit changeForegroundImage(std::weak_ptr(), _foregroundScale); } if (_viewer) { _viewer->setForegroundOpacity(_opacity); @@ -106,9 +107,8 @@ void VisualizationWorkstationExtensionPlugin::onImageClosed() { } if (_foreground) { _foregroundScale = 1; - emit changeForegroundImage(NULL, _foregroundScale); - delete _foreground; - _foreground = NULL; + emit changeForegroundImage(std::weak_ptr(), _foregroundScale); + _foreground.reset(); } if (_dockWidget) { _dockWidget->setEnabled(false); @@ -117,7 +117,7 @@ void VisualizationWorkstationExtensionPlugin::onImageClosed() { void VisualizationWorkstationExtensionPlugin::onEnableLikelihoodToggled(bool toggled) { if (!toggled) { - emit changeForegroundImage(NULL, _foregroundScale); + emit changeForegroundImage(std::weak_ptr(), _foregroundScale); } else { emit changeForegroundImage(_foreground, _foregroundScale); diff --git a/workstation/visualization/VisualizationWorkstationExtensionPlugin.h b/workstation/visualization/VisualizationWorkstationExtensionPlugin.h index a4699656..1df9113f 100644 --- a/workstation/visualization/VisualizationWorkstationExtensionPlugin.h +++ b/workstation/visualization/VisualizationWorkstationExtensionPlugin.h @@ -21,7 +21,7 @@ private : void addSegmentationsToViewer(); void removeSegmentationsFromViewer(); - MultiResolutionImage* _foreground; + std::shared_ptr _foreground; QDockWidget* _dockWidget; QCheckBox* _likelihoodCheckBox; QCheckBox* _segmentationCheckBox; @@ -38,14 +38,14 @@ public : QDockWidget* getDockWidget(); public slots: - void onNewImageLoaded(MultiResolutionImage* img, std::string fileName); + void onNewImageLoaded(std::weak_ptr img, std::string fileName); void onImageClosed(); void onEnableLikelihoodToggled(bool toggled); void onOpacityChanged(double opacity); void onEnableSegmentationToggled(bool toggled); signals: - void changeForegroundImage(MultiResolutionImage*, float scale); + void changeForegroundImage(std::weak_ptr, float scale); }; #endif \ No newline at end of file