From 140ce4cc0a7d3cb8fbb91b34ceaf8033dd03fd61 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Thu, 9 Oct 2014 16:14:10 +0200 Subject: [PATCH 01/42] First commit for GWS (applied itksnap-3.0.0_gWS_54.diff) --- CMakeLists.txt | 14 + Common/SNAPCommon.h | 5 +- GUI/Model/CursorInspectionModel.cxx | 1 + GUI/Model/GlobalUIModel.cxx | 50 +- GUI/Model/GlobalUIModel.h | 22 +- GUI/Model/GlobalWSWizardModel.cxx | 59 ++ GUI/Model/GlobalWSWizardModel.h | 40 + GUI/Model/JoinModel.cxx | 169 +++++ GUI/Model/JoinModel.h | 43 ++ GUI/Model/UIState.h | 2 + GUI/Qt/Components/GlobalWSWizardPanel.cxx | 221 ++++++ GUI/Qt/Components/GlobalWSWizardPanel.h | 74 ++ GUI/Qt/Components/GlobalWSWizardPanel.ui | 793 ++++++++++++++++++++ GUI/Qt/Components/JoinDataPanel.cxx | 132 ++++ GUI/Qt/Components/JoinDataPanel.h | 45 ++ GUI/Qt/Components/JoinDataPanel.ui | 282 +++++++ GUI/Qt/Components/SliceViewPanel.cxx | 17 +- GUI/Qt/Components/SliceViewPanel.ui | 9 + GUI/Qt/Components/SnakeToolROIPanel.cxx | 18 +- GUI/Qt/Resources/SNAPResources.qrc | 1 + GUI/Qt/Resources/globalWS.gif | Bin 0 -> 1800 bytes GUI/Qt/View/JoinInteractionMode.cxx | 50 ++ GUI/Qt/View/JoinInteractionMode.h | 34 + GUI/Qt/Windows/LayerInspectorDialog.cxx | 4 +- GUI/Qt/Windows/MainControlPanel.cxx | 8 + GUI/Qt/Windows/MainControlPanel.ui | 13 +- GUI/Qt/Windows/MainImageWindow.cxx | 60 +- GUI/Qt/Windows/MainImageWindow.h | 13 +- GUI/Qt/Windows/MainImageWindow.ui | 31 + Logic/Common/SNAPRegistryIO.cxx | 1 + Logic/Framework/GenericImageData.h | 1 + Logic/Framework/GlobalState.h | 5 +- Logic/Framework/IRISApplication.cxx | 229 +++++- Logic/Framework/IRISApplication.h | 51 ++ Logic/Framework/JOINImageData.cxx | 236 ++++++ Logic/Framework/JOINImageData.h | 102 +++ Logic/Framework/LayerAssociation.txx | 4 +- Logic/ImageWrapper/DisplayMappingPolicy.cxx | 1 + Logic/ImageWrapper/ImageWrapper.cxx | 1 + Logic/ImageWrapper/ImageWrapperTraits.h | 26 + Logic/ImageWrapper/ScalarImageWrapper.cxx | 1 + 41 files changed, 2843 insertions(+), 25 deletions(-) create mode 100644 GUI/Model/GlobalWSWizardModel.cxx create mode 100644 GUI/Model/GlobalWSWizardModel.h create mode 100644 GUI/Model/JoinModel.cxx create mode 100644 GUI/Model/JoinModel.h create mode 100644 GUI/Qt/Components/GlobalWSWizardPanel.cxx create mode 100644 GUI/Qt/Components/GlobalWSWizardPanel.h create mode 100644 GUI/Qt/Components/GlobalWSWizardPanel.ui create mode 100644 GUI/Qt/Components/JoinDataPanel.cxx create mode 100644 GUI/Qt/Components/JoinDataPanel.h create mode 100644 GUI/Qt/Components/JoinDataPanel.ui create mode 100644 GUI/Qt/Resources/globalWS.gif create mode 100644 GUI/Qt/View/JoinInteractionMode.cxx create mode 100644 GUI/Qt/View/JoinInteractionMode.h create mode 100644 Logic/Framework/JOINImageData.cxx create mode 100644 Logic/Framework/JOINImageData.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b417bfe0..07dc3bce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,7 @@ SET(LOGIC_CXX Logic/Framework/IRISImageData.cxx Logic/Framework/LayerIterator.cxx Logic/Framework/SNAPImageData.cxx + Logic/Framework/JOINImageData.cxx Logic/Framework/UndoDataManager_LabelType.cxx Logic/ImageWrapper/CommonRepresentationPolicy.cxx Logic/ImageWrapper/DisplayMappingPolicy.cxx @@ -261,6 +262,7 @@ SET(LOGIC_HEADERS Logic/Framework/LayerAssociation.txx Logic/Framework/LayerIterator.h Logic/Framework/SNAPImageData.h + Logic/Framework/JOINImageData.h Logic/Framework/UndoDataManager.h Logic/Framework/UndoDataManager.txx Logic/ImageWrapper/CommonRepresentationPolicy.h @@ -352,6 +354,8 @@ SET(UI_GENERIC_CXX GUI/Model/SnakeROIModel.cxx GUI/Model/SnakeROIResampleModel.cxx GUI/Model/SnakeWizardModel.cxx + GUI/Model/JoinModel.cxx + GUI/Model/GlobalWSWizardModel.cxx GUI/Model/StateManagement.cxx GUI/Model/SynchronizationModel.cxx GUI/Model/UIAction.cxx @@ -419,6 +423,8 @@ SET(UI_GENERIC_HEADERS GUI/Model/SnakeROIModel.h GUI/Model/SnakeROIResampleModel.h GUI/Model/SnakeWizardModel.h + GUI/Model/JoinModel.h + GUI/Model/GlobalWSWizardModel.h GUI/Model/StateManagement.h GUI/Model/SynchronizationModel.h GUI/Model/UIAction.h @@ -483,6 +489,8 @@ SET(UI_QT_CXX GUI/Qt/Components/RecentHistoryItemsView.cxx GUI/Qt/Components/SnakeToolROIPanel.cxx GUI/Qt/Components/SnakeWizardPanel.cxx + GUI/Qt/Components/JoinDataPanel.cxx + GUI/Qt/Components/GlobalWSWizardPanel.cxx GUI/Qt/Components/SNAPComponent.cxx GUI/Qt/Components/SNAPQtCommon.cxx GUI/Qt/Components/SliceViewPanel.cxx @@ -508,6 +516,7 @@ SET(UI_QT_CXX GUI/Qt/View/PolygonDrawingInteractionMode.cxx GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx GUI/Qt/View/SnakeROIInteractionMode.cxx + GUI/Qt/View/JoinInteractionMode.cxx GUI/Qt/View/ThumbnailInteractionMode.cxx GUI/Qt/Windows/AboutDialog.cxx GUI/Qt/Windows/DropActionDialog.cxx @@ -560,6 +569,8 @@ SET(UI_MOC_HEADERS GUI/Qt/Components/RecentHistoryItemsView.h GUI/Qt/Components/SnakeToolROIPanel.h GUI/Qt/Components/SnakeWizardPanel.h + GUI/Qt/Components/JoinDataPanel.h + GUI/Qt/Components/GlobalWSWizardPanel.h GUI/Qt/Components/SNAPComponent.h GUI/Qt/Components/SliceViewPanel.h GUI/Qt/Components/SynchronizationInspector.h @@ -583,6 +594,7 @@ SET(UI_MOC_HEADERS GUI/Qt/View/PolygonDrawingInteractionMode.h GUI/Qt/View/SliceWindowInteractionDelegateWidget.h GUI/Qt/View/SnakeROIInteractionMode.h + GUI/Qt/View/JoinInteractionMode.h GUI/Qt/View/ThumbnailInteractionMode.h GUI/Qt/Windows/AboutDialog.h GUI/Qt/Windows/DropActionDialog.h @@ -653,6 +665,8 @@ SET(UI_FORMS GUI/Qt/Components/SliceViewPanel.ui GUI/Qt/Components/SnakeToolROIPanel.ui GUI/Qt/Components/SnakeWizardPanel.ui + GUI/Qt/Components/JoinDataPanel.ui + GUI/Qt/Components/GlobalWSWizardPanel.ui GUI/Qt/Components/SynchronizationInspector.ui GUI/Qt/Components/ViewPanel3D.ui GUI/Qt/Components/ZoomInspector.ui diff --git a/Common/SNAPCommon.h b/Common/SNAPCommon.h index f1b65e24..8a4159f5 100644 --- a/Common/SNAPCommon.h +++ b/Common/SNAPCommon.h @@ -92,6 +92,8 @@ extern const char SNAPBuildInfo[]; // UnaryFunctorCache in the GreyImageWrapper type. Greyscale instensities // 0 to MAXGREYVAL are used in a cache table, which would be too big with int typedef unsigned short LabelType; +typedef itk::IdentifierType GWSType; +typedef LabelType JSRType; typedef short GreyType; extern const GreyType MAXGREYVAL; extern const GreyType MINGREYVAL; @@ -116,7 +118,8 @@ enum LayerRole OVERLAY_ROLE = 0x0002, SNAP_ROLE = 0x0004, LABEL_ROLE = 0x0008, - NO_ROLE = 0x0010 + NO_ROLE = 0x0010, + JOIN_ROLE = 0x0020, }; diff --git a/GUI/Model/CursorInspectionModel.cxx b/GUI/Model/CursorInspectionModel.cxx index 59de5ea4..ce129983 100644 --- a/GUI/Model/CursorInspectionModel.cxx +++ b/GUI/Model/CursorInspectionModel.cxx @@ -102,6 +102,7 @@ void CursorInspectionModel::SetParentModel(GlobalUIModel *parent) int role = MAIN_ROLE | OVERLAY_ROLE | + JOIN_ROLE | SNAP_ROLE; CurrentVoxelInfoItemSetDomain dom(app, role); diff --git a/GUI/Model/GlobalUIModel.cxx b/GUI/Model/GlobalUIModel.cxx index 759b9f2e..fb1e136e 100644 --- a/GUI/Model/GlobalUIModel.cxx +++ b/GUI/Model/GlobalUIModel.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +111,9 @@ GlobalUIModel::GlobalUIModel() m_SnakeROIModel[i] = SnakeROIModel::New(); m_SnakeROIModel[i]->SetParent(m_SliceModel[i]); + m_JoinModel[i] = JoinModel::New(); + m_JoinModel[i]->SetParent(m_SliceModel[i]); + m_PaintbrushModel[i] = PaintbrushModel::New(); m_PaintbrushModel[i]->SetParent(m_SliceModel[i]); } @@ -138,7 +143,7 @@ GlobalUIModel::GlobalUIModel() m_LoadedLayersSelectionModel->SetParentModel(this); m_LoadedLayersSelectionModel->SetRoleFilter( MAIN_ROLE | OVERLAY_ROLE | - SNAP_ROLE); + SNAP_ROLE | JOIN_ROLE); // 3D model m_Model3D = Generic3DModel::New(); @@ -164,6 +169,10 @@ GlobalUIModel::GlobalUIModel() m_SnakeROIResampleModel = SnakeROIResampleModel::New(); m_SnakeROIResampleModel->SetParentModel(this); + // GlobalWS model + m_GlobalWSWizardModel = GlobalWSWizardModel::New(); + m_GlobalWSWizardModel->SetParentModel(this); + // Synchronization model m_SynchronizationModel = SynchronizationModel::New(); m_SynchronizationModel->SetParentModel(this); @@ -288,11 +297,12 @@ bool GlobalUIModel::CheckState(UIState state) case UIF_BASEIMG_LOADED: return m_Driver->IsMainImageLoaded(); case UIF_IRIS_WITH_BASEIMG_LOADED: - return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive(); + return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive();// && !m_Driver->IsJoinModeActive(); ///adding this will disable lablel change in Join mode: Bad! case UIF_IRIS_MODE: - return !m_Driver->IsSnakeModeActive(); + return !m_Driver->IsSnakeModeActive() && !m_Driver->IsJoinModeActive();//not sure if Join extension here has any effect case UIF_IRIS_WITH_OVERLAY_LOADED: return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive() + && !m_Driver->IsJoinModeActive() && m_Driver->GetCurrentImageData()->GetNumberOfOverlays() > 0; case UIF_ROI_VALID: break; @@ -310,6 +320,10 @@ bool GlobalUIModel::CheckState(UIState state) return m_Driver->GetCurrentImageData()->IsOverlayLoaded(); case UIF_SNAKE_MODE: return m_Driver->IsSnakeModeActive(); + case UIF_JOIN_MODE: + return m_Driver->IsJoinModeActive(); + case UIF_NOT_SNAKE_OR_JOIN_MODE: + return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive() && !m_Driver->IsJoinModeActive(); case UIF_LEVEL_SET_ACTIVE: return m_Driver->IsSnakeModeLevelSetActive(); } @@ -371,6 +385,30 @@ void GlobalUIModel::ToggleOverlayVisibility() m_LayerGeneralPropertiesModel->SetLayer(curr_layer); } +void GlobalUIModel::ToggleJsrcVisibility() +{ + // Are we in JOIN mode? + if(CheckState(UIF_JOIN_MODE)){ + GenericImageData *id = m_Driver->GetCurrentImageData(); + + // Remember what layer is current in the general properties model + ImageWrapperBase *curr_layer = m_LayerGeneralPropertiesModel->GetLayer(); + + // Apply the toggle for all overlays + for(LayerIterator it = id->GetLayers(JOIN_ROLE); !it.IsAtEnd(); ++it){ + //if(dynamic_cast(it.GetLayer())){//does not work as currently JsrcImageWrapper == JdstImageWrapper == LabelImageWrapper + if(strcmp(it.GetLayer()->GetNickname().c_str(), "Join Source Image") == 0){ + m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer()); + m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->SetValue( + !m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->GetValue()); + } + } + + // Restore the active layer + m_LayerGeneralPropertiesModel->SetLayer(curr_layer); + } +} + void GlobalUIModel::AdjustOverlayOpacity(int delta) { // Are we in tiled mode or in stack mode? @@ -756,6 +794,12 @@ GlobalUIModel::CreateIOWizardModelForSave(ImageWrapperBase *layer, LayerRole rol else if(dynamic_cast(layer)) category = "Level Set Image"; break; + case JOIN_ROLE: + if(dynamic_cast(layer)) + category = "Join Source Image"; + else if(dynamic_cast(layer)) + category = "Join Destination Image"; + break; case LABEL_ROLE: category = "Segmentation Image"; break; diff --git a/GUI/Model/GlobalUIModel.h b/GUI/Model/GlobalUIModel.h index 3e4ebada..ffd59444 100644 --- a/GUI/Model/GlobalUIModel.h +++ b/GUI/Model/GlobalUIModel.h @@ -56,6 +56,8 @@ class CursorInspectionModel; class SnakeROIModel; class SnakeWizardModel; class SnakeROIResampleModel; +class JoinModel; +class GlobalWSWizardModel; class ProgressReporterDelegate; class ReorientImageModel; class DisplayLayoutModel; @@ -154,12 +156,18 @@ class GlobalUIModel : public AbstractModel return m_PolygonDrawingModel[i]; } - /** Get the polygon drawing model for each slice */ + /** Get the snake drawing model for each slice */ SnakeROIModel *GetSnakeROIModel(unsigned int i) const { return m_SnakeROIModel[i]; } + /** Get the join drawing model for each slice */ + JoinModel *GetJoinModel(unsigned int i) const + { + return m_JoinModel[i]; + } + PaintbrushModel *GetPaintbrushModel(unsigned int i) const { return m_PaintbrushModel[i]; @@ -195,6 +203,9 @@ class GlobalUIModel : public AbstractModel /** The model that handles snake wizard interaction */ irisGetMacro(SnakeWizardModel, SnakeWizardModel *) + /** The model that handles GlobalWS wizard interaction */ + irisGetMacro(GlobalWSWizardModel, GlobalWSWizardModel *) + /** The model handling display layout properties */ irisGetMacro(DisplayLayoutModel, DisplayLayoutModel *) @@ -242,6 +253,9 @@ class GlobalUIModel : public AbstractModel /** Method to toggle overlay visibility (all or selected overlays) */ void ToggleOverlayVisibility(); + /** Method to toggle Jsrc visibility */ + void ToggleJsrcVisibility(); + /** Method to adjust overlay opacity (all or selected overlays) */ void AdjustOverlayOpacity(int delta); @@ -322,6 +336,9 @@ class GlobalUIModel : public AbstractModel // Models for snake ROI drawing SmartPtr m_SnakeROIModel[3]; + // Models for Click'n'Join + SmartPtr m_JoinModel[3]; + // Models for paintbrush drawing SmartPtr m_PaintbrushModel[3]; @@ -358,6 +375,9 @@ class GlobalUIModel : public AbstractModel // The snake wizard model SmartPtr m_SnakeWizardModel; + // The GlobalWS wizard model + SmartPtr m_GlobalWSWizardModel; + // Display layout model SmartPtr m_DisplayLayoutModel; diff --git a/GUI/Model/GlobalWSWizardModel.cxx b/GUI/Model/GlobalWSWizardModel.cxx new file mode 100644 index 00000000..c160d9f8 --- /dev/null +++ b/GUI/Model/GlobalWSWizardModel.cxx @@ -0,0 +1,59 @@ +#include "GlobalWSWizardModel.h" +#include "GlobalUIModel.h" +#include "IRISApplication.h" + + + +GlobalWSWizardModel::GlobalWSWizardModel() +{ +} + +void GlobalWSWizardModel::SetParentModel(GlobalUIModel *model) +{ + m_Parent = model; + m_Driver = m_Parent->GetDriver(); + m_GlobalState = m_Driver->GetGlobalState(); + + // Layer changes are rebroadcast as model changes, causing all child + // models to update themselves. + Rebroadcast(m_Driver, LayerChangeEvent(), ModelUpdateEvent()); + } + +void GlobalWSWizardModel::OnGlobalWSModeEnter() +{ + //// Initialize the image data + m_Driver->InitializeJOINImageData( + m_Driver->GetGlobalState()->GetSegmentationROISettings(), + m_Parent->GetProgressCommand()); + + m_Driver->SetCurrentImageDataToJOIN(); + //m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinDataPanel AND JoinInteraction + m_GlobalState->SetToolbarMode(GWSJOIN_MODE); //only disables JoinDataPanel + +} + +void GlobalWSWizardModel::OnCancelSegmentation() +{ + // Return to IRIS mode + m_Driver->SetCurrentImageDataToIRIS(); + m_Driver->ReleaseJOINImageData(); + + m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction +} + +void GlobalWSWizardModel::OnFinishGWS() +{ + // Update IRIS with JOIN images + m_Driver->UpdateIRISWithJOINImageData(NULL); + + // Set an undo point + m_Driver->StoreUndoPoint("Automatic Segmentation"); + + // Return to IRIS mode + m_Driver->SetCurrentImageDataToIRIS(); + m_Driver->ReleaseJOINImageData(); + + m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction +} + + diff --git a/GUI/Model/GlobalWSWizardModel.h b/GUI/Model/GlobalWSWizardModel.h new file mode 100644 index 00000000..2a737baa --- /dev/null +++ b/GUI/Model/GlobalWSWizardModel.h @@ -0,0 +1,40 @@ +#ifndef GLOBALWSWIZARDMODEL_H +#define GLOBALWSWIZARDMODEL_H + +#include "SNAPCommon.h" +#include "AbstractModel.h" +#include "GlobalState.h" + +class GlobalUIModel; +class IRISApplication; + +class GlobalWSWizardModel : public AbstractModel +{ +public: + + irisITKObjectMacro(GlobalWSWizardModel, AbstractModel) + + void SetParentModel(GlobalUIModel *model); + irisGetMacro(Parent, GlobalUIModel *) + + /** Called when first displaying the GWS wizard */ + void OnGlobalWSModeEnter(); + + /** Cancel segmentation and return to IRIS */ + void OnCancelSegmentation(); + + /** Copy segmentation and return to IRIS */ + void OnFinishGWS(); + +protected: + GlobalWSWizardModel(); + virtual ~GlobalWSWizardModel() {} + + // Parent model + GlobalUIModel *m_Parent; + IRISApplication *m_Driver; + GlobalState *m_GlobalState; + +}; + +#endif // GLOBALWSWIZARDMODEL_H diff --git a/GUI/Model/JoinModel.cxx b/GUI/Model/JoinModel.cxx new file mode 100644 index 00000000..61413500 --- /dev/null +++ b/GUI/Model/JoinModel.cxx @@ -0,0 +1,169 @@ +#include "JoinModel.h" +#include "GlobalState.h" +#include "IRISApplication.h" +#include "JOINImageData.h" + +JoinModel::JoinModel(){ + } + +void JoinModel::SetParent(GenericSliceModel *parent){ + // Set up the parent + m_Parent = parent; + } + +void JoinModel::ComputeMousePosition(const Vector3f &xSlice){ + // Only when an image is loaded + if(!m_Parent->GetDriver()->IsMainImageLoaded()) + return; + + // Compute the new cross-hairs position in image space + Vector3f xCross = m_Parent->MapSliceToImage(xSlice); + + // Round the cross-hairs position down to integer + Vector3i xCrossInteger = to_int(xCross); + + // Make sure that the cross-hairs position is within bounds by clamping + // it to image dimensions + Vector3i xSize = + to_int(m_Parent->GetDriver()->GetCurrentImageData()->GetVolumeExtents()); + + Vector3ui newpos = to_unsigned_int( + xCrossInteger.clamp(Vector3i(0),xSize - Vector3i(1))); + + if(newpos != m_MousePosition || m_MouseInside == false) + { + m_MousePosition = newpos; + m_MouseInside = true; + //InvokeEvent(PaintbrushMovedEvent()); + } + } + +bool +JoinModel +::ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode, bool ctrl){ + // Compute the mouse position + ComputeMousePosition(xSlice); + + if(ctrl){ + processPickLabel(reverse_mode); + } + else { + // Check if the right button was pressed + if(processCnJ(reverse_mode)){ + //add undo point (todo: Undo has no effect so far) + m_Parent->GetDriver()->StoreUndoPoint("Click'n'Join"); + //fire SegmentationChangeEvent for e.g. 3D view Update + m_Parent->GetDriver()->InvokeEvent(SegmentationChangeEvent()); + } + } + + ////do not eat event, i.e. do cursor chasing; only works for LMB not for RMB!!! + return false; + } + +void JoinModel::ProcessLeaveEvent(){ + m_MouseInside = false; + } + +void +JoinModel::processPickLabel(bool reverse_mode){ + + // Get the global objects + IRISApplication *driver = m_Parent->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + // Get Join destination image + JdstImageWrapper *jdst = driver->GetJOINImageData()->GetJdst(); + JdstImageWrapper::ImageType::ValueType JdstClickPV= jdst->GetImage()->GetPixel(to_itkIndex(m_MousePosition)); + + if(!reverse_mode){ + // ColorLabelTable::ValidLabelConstIterator pos = + // driver->GetColorLabelTable()->GetValidLabels().find(JdstClickPV); + // gs->SetDrawingColorLabel(pos); + gs->SetDrawingColorLabel(JdstClickPV); + } + else{ + DrawOverFilter dof = gs->GetDrawOverFilter(); + dof.CoverageMode = PAINT_OVER_ONE; + dof.DrawOverLabel = JdstClickPV; + gs->SetDrawOverFilter(dof); + } + } + +bool +JoinModel::processCnJ(bool reverse_mode){ + // Get the global objects + IRISApplication *driver = m_Parent->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + // Get Join source image + JsrcImageWrapper *jsrc = driver->GetJOINImageData()->GetJsrc(); + + // Get Join destination image + JdstImageWrapper *jdst = driver->GetJOINImageData()->GetJdst(); + + // Get the segmentation image + //LabelImageWrapper *imgLabel = driver->GetCurrentImageData()->GetSegmentation(); + + // Get the paint properties + LabelType drawing_color = gs->GetDrawingColorLabel(); + DrawOverFilter drawover = gs->GetDrawOverFilter(); + + // Define a region of interest + //LabelImageWrapper::ImageType::RegionType xTestRegion= jsrc->GetImage()->GetBufferedRegion(); + JsrcImageWrapper::ImageType::RegionType xTestRegion= jsrc->GetImage()->GetLargestPossibleRegion(); + + // Flag to see if anything was changed + bool flagUpdate = false; + + JsrcImageWrapper::ImageType::ValueType JsrcClickPV= jsrc->GetImage()->GetPixel(to_itkIndex(m_MousePosition)); + // JdstImageWrapper::ImageType::ValueType JdstClickPV= jdst->GetImage()->GetPixel(to_itkIndex(m_MousePosition)); + + + // Iterate over the region + JsrcImageWrapper::Iterator sit(jsrc->GetImage(), xTestRegion); + LabelImageWrapper::Iterator dit(jdst->GetImage(), xTestRegion); + for(; !sit.IsAtEnd(); ++sit, ++dit){ + + if(sit.Get() != JsrcClickPV) + continue; + + LabelType pxLabel = dit.Get(); + + // Standard paint mode + if(!reverse_mode) + { + if(drawover.CoverageMode == PAINT_OVER_ALL || + (drawover.CoverageMode == PAINT_OVER_ONE && pxLabel == drawover.DrawOverLabel) || + (drawover.CoverageMode == PAINT_OVER_VISIBLE && pxLabel != 0)) + { + dit.Set(drawing_color); + if(pxLabel != drawing_color) flagUpdate = true; + } + } + // Background paint mode (clear label over current label) + else + { + if(drawing_color != 0 && pxLabel == drawing_color) + { + dit.Set(0); + if(pxLabel != 0) flagUpdate = true; + } + else if(drawing_color == 0 && drawover.CoverageMode == PAINT_OVER_ONE) + { + dit.Set(drawover.DrawOverLabel); + if(pxLabel != drawover.DrawOverLabel) flagUpdate = true; + } + } + } + + // Image has been updated + if(flagUpdate) + { + jdst->GetImage()->Modified(); + //imgLabel->GetImage()->Modified(); + } + + return flagUpdate; + } + diff --git a/GUI/Model/JoinModel.h b/GUI/Model/JoinModel.h new file mode 100644 index 00000000..ff75a100 --- /dev/null +++ b/GUI/Model/JoinModel.h @@ -0,0 +1,43 @@ +#ifndef JOINMODEL_H +#define JOINMODEL_H + +#include +#include "AbstractModel.h" +#include "GenericSliceModel.h" + +class GenericSliceModel; + +class JoinModel : public AbstractModel +{ +public: + irisITKObjectMacro(JoinModel, AbstractModel) + + irisGetMacro(Parent, GenericSliceModel *) + + void SetParent(GenericSliceModel *); + + bool ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode, bool ctrl); + + void ProcessLeaveEvent(); + +protected: + + // Mouse position in voxel coordinates + Vector3ui m_MousePosition; + bool m_MouseInside; + + // Private constructor stuff + JoinModel(); + virtual ~JoinModel() {} + + void ComputeMousePosition(const Vector3f &xSlice); + + void processPickLabel(bool reverse_mode); + bool processCnJ(bool reverse_mode); + + // Parent model + GenericSliceModel *m_Parent; + +}; + +#endif // JOINMODEL_H diff --git a/GUI/Model/UIState.h b/GUI/Model/UIState.h index 3024486d..1cf6f1b6 100644 --- a/GUI/Model/UIState.h +++ b/GUI/Model/UIState.h @@ -16,6 +16,8 @@ enum UIState { UIF_UNSAVED_CHANGES, UIF_MESH_SAVEABLE, UIF_SNAKE_MODE, + UIF_JOIN_MODE, + UIF_NOT_SNAKE_OR_JOIN_MODE, UIF_LEVEL_SET_ACTIVE }; diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx new file mode 100644 index 00000000..4939ab75 --- /dev/null +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -0,0 +1,221 @@ +/* +part of Click'n'Join mode, which was contributed by Roman Grothausmann +*/ + +#include "GlobalWSWizardPanel.h" +#include "ui_GlobalWSWizardPanel.h" +#include "GlobalUIModel.h" +#include "GlobalWSWizardModel.h" +#include "QtCursorOverride.h" +#include "QtDoubleSliderWithEditorCoupling.h" +#include "IRISException.h" +#include +#include "IRISApplication.h" +#include "GenericImageData.h" +#include "JOINImageData.h" + +#include +#include +#include +#include + +// TODO: move this into a separate file!!!! +class WatershedPipeline{ +public: + typedef itk::Image GreyImageType; + typedef itk::Image LabelImageType; + typedef itk::Image FloatImageType; + typedef itk::Image WatershedImageType; + + WatershedPipeline(){ + adf = ADFType::New(); + gmf = GMFType::New(); + gmf->SetInput(adf->GetOutput()); + wf = WFType::New(); + cif = CIFType::New(); + cif->SetInput(wf->GetOutput()); + } + + LabelImageType* PrecomputeWatersheds( + GreyImageType *grey, + double cParam, size_t sIter, + double iThr, double iLevel, + bool direct){ + + //// Initialize the watershed pipeline + adf->SetInput(grey); + adf->SetNumberOfIterations(sIter); + adf->SetConductanceParameter(cParam); + + if(direct) + wf->SetInput(adf->GetOutput()); + else + wf->SetInput(gmf->GetOutput()); + + wf->SetThreshold(iThr); + wf->SetLevel(iLevel); + cif->UpdateLargestPossibleRegion(); //needed because RequestedRegion can be bigger than BufferedRegion in consecutive runs of GWS (http://itk.org/ITKExamples/src/Core/Common/ReRunPipelineWithChangingLargestPossibleRegion/Documentation.html) + + return(cif->GetOutput()); + } + + void RecomputeWatersheds(double level){ + // Reupdate the filter with new level + wf->SetLevel(level); + cif->Update(); + } + +private: + typedef itk::GradientAnisotropicDiffusionImageFilter ADFType; + typedef itk::GradientMagnitudeImageFilter GMFType; + typedef itk::WatershedImageFilter WFType; + typedef itk::CastImageFilter CIFType; + + ADFType::Pointer adf; + GMFType::Pointer gmf; + WFType::Pointer wf; + CIFType::Pointer cif; + + }; + + + +GlobalWSWizardPanel::GlobalWSWizardPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::GlobalWSWizardPanel){ + ui->setupUi(this); + + connect(ui->inWSLevel, SIGNAL(valueChanged(double)), this, SLOT(on_inWSLevel_valueChanged(double))); + m_old_value= 0; + + m_Watershed = new WatershedPipeline(); + + this->addAction(ui->actionIncreaseWSLevel); + this->addAction(ui->actionDecreaseWSLevel); + } + +GlobalWSWizardPanel::~GlobalWSWizardPanel(){ + delete ui; + } + +void GlobalWSWizardPanel::SetModel(GlobalUIModel *model){ + // Store and pass on the models + m_ParentModel = model; + m_Model = model->GetGlobalWSWizardModel(); + } + +void GlobalWSWizardPanel::Initialize(){ + // Initialize the model + m_Model->OnGlobalWSModeEnter(); + + // Go to the right page + ui->stack->setCurrentWidget(ui->pgPreproc); + } + +void GlobalWSWizardPanel::on_stack_currentChanged(int page){ + // The stack at the top follows the stack at the bottom + ui->stackStepInfo->setCurrentIndex(page); + } + +void GlobalWSWizardPanel::on_btnCancel_clicked(){ + // Tell the model to return to initialization state + m_Model->OnCancelSegmentation(); + + // Tell parent to hide this window + emit wizardFinished(); + } + +void GlobalWSWizardPanel::on_btnNextPreproc_clicked(){ + // Call the initialization code + try + { + // Handle cursor + QtCursorOverride curse(Qt::WaitCursor); + + // Move to the range page + ui->stack->setCurrentWidget(ui->pgWSRange); + } + catch(IRISException &exc) + { + QMessageBox::warning(this, "ITK-SNAP", exc.what(), QMessageBox::Ok); + } + } + +void GlobalWSWizardPanel::on_btnWSRangeNext_clicked(){ + + // Get the global objects + IRISApplication *driver = m_ParentModel->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + try + { + // Handle cursor + QtCursorOverride curse(Qt::WaitCursor); + + driver->GetJOINImageData()->GetJsrc()->SetImage( + m_Watershed->PrecomputeWatersheds( + driver->GetCurrentImageData()->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(), + ui->inConductance->value()/100.0, ui->inSmoothingIter->value(), + ui->inWSMin->value()/100.0, ui->inWSMax->value()/100.0, + ui->chkGlobalWSDirect->isChecked() + ) + ); + + std::cerr << "Changing WS to level: " << ui->inWSLevel->value()/100.0 << std::flush; + m_Watershed->RecomputeWatersheds(ui->inWSLevel->value()/100.0); + std::cerr << " Recomputed WS level." << std::flush << std::endl; + driver->InvokeEvent(SegmentationChangeEvent()); + + ui->stack->setCurrentWidget(ui->pgDynWSLevel); + } + catch(IRISException &exc) + { + QMessageBox::warning(this, "ITK-SNAP", exc.what(), QMessageBox::Ok); + } + + } + +void GlobalWSWizardPanel::on_inWSLevel_valueChanged(double value){ + + // Get the global objects + IRISApplication *driver = m_ParentModel->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + GenericImageData *gid = driver->GetCurrentImageData(); + + if(value != m_old_value){ + try + { + std::cerr << "Changing WS to level: " << value/100.0 << std::flush; + m_Watershed->RecomputeWatersheds(value/100.0); + std::cerr << " Recomputed WS level." << std::flush << std::endl; + driver->InvokeEvent(SegmentationChangeEvent()); + } + catch(IRISException &exc) + { + QMessageBox::warning(this, "ITK-SNAP", exc.what(), QMessageBox::Ok); + } + m_old_value= value; + } + + } + +void GlobalWSWizardPanel::on_btnGWSfinish_clicked(){ + // Tell the model to return to initialization state + m_Model->OnFinishGWS(); + + // Tell parent to hide this window + emit wizardFinished(); + } + +void GlobalWSWizardPanel::on_actionIncreaseWSLevel_triggered(){ + double value= ui->inWSLevel->value() + 0.1; + ui->inWSLevel->setValue(value); + emit ui->inWSLevel->spinnerValueChanged(value); //def in GUI/Qt/Components/QDoubleSliderWithEditor.h + } + +void GlobalWSWizardPanel::on_actionDecreaseWSLevel_triggered(){ + double value= ui->inWSLevel->value() - 0.1; + ui->inWSLevel->setValue(value); + emit ui->inWSLevel->spinnerValueChanged(value); + } diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.h b/GUI/Qt/Components/GlobalWSWizardPanel.h new file mode 100644 index 00000000..1c6cf9e7 --- /dev/null +++ b/GUI/Qt/Components/GlobalWSWizardPanel.h @@ -0,0 +1,74 @@ +/* +part of Click'n'Join mode, which was contributed by Roman Grothausmann +*/ + +#ifndef GLOBALWSWIZARDPANEL_H +#define GLOBALWSWIZARDPANEL_H + +#include +#include + +namespace Ui { +class GlobalWSWizardPanel; +} + +class GlobalUIModel; +class GlobalWSWizardModel; +class WatershedPipeline; + + + +class GlobalWSWizardPanel : public QWidget +{ + Q_OBJECT + +public: + explicit GlobalWSWizardPanel(QWidget *parent = 0); + ~GlobalWSWizardPanel(); + + void SetModel(GlobalUIModel *model); + + /** + Put the panel into the initial state, i.e., ready to perform preprocessing. + You must call this method before showing the panel. + */ + void Initialize(); + +signals: + + void wizardFinished(); + +private slots: + + void on_stack_currentChanged(int arg1); + + void on_btnCancel_clicked(); + + void on_btnNextPreproc_clicked(); + + void on_btnWSRangeNext_clicked(); + + void on_inWSLevel_valueChanged(double value); + + void on_btnGWSfinish_clicked(); + + void on_actionIncreaseWSLevel_triggered(); + + void on_actionDecreaseWSLevel_triggered(); + +private: + + GlobalUIModel *m_ParentModel; + GlobalWSWizardModel *m_Model; + + double m_old_value; + + Ui::GlobalWSWizardPanel *ui; + +protected: + + WatershedPipeline *m_Watershed; + +}; + +#endif // GLOBALWSWIZARDPANEL_H diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.ui b/GUI/Qt/Components/GlobalWSWizardPanel.ui new file mode 100644 index 00000000..1a548eee --- /dev/null +++ b/GUI/Qt/Components/GlobalWSWizardPanel.ui @@ -0,0 +1,793 @@ + + + GlobalWSWizardPanel + + + + 0 + 0 + 177 + 680 + + + + + 0 + 0 + + + + + 177 + 16777215 + + + + Form + + + * { +font-size: 12px; +} +QGroupBox { + background-origin: content; + margin-top: 15px; + font-weight: bold; + font-size: 12px; + font-family: helvetica; + color: rgb(30,30,160); + background-color: rgb(237,237,237); + padding: 5px; + border-radius: 4px; + border: 1px solid rgb(130,130,130); +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; +} + + + + + + 8 + + + 5 + + + + + + 0 + 60 + + + + Current Stage + + + + 0 + + + + + + 0 + 0 + + + + 0 + + + + + 0 + + + + + + 16777215 + 16777215 + + + + font-size:10px; + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lucida Grande'; font-size:10px; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px;">Step 1/3</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px; font-weight:600;">Preprocessing</span></p></body></html> + + + true + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + font-size:10px; + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lucida Grande'; font-size:10px; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px;">Step 2/3</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12px; font-weight:600;">Initialization</span></p></body></html> + + + true + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + font-size:10px; + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10px; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:12px;">Step 3/3</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:12px; font-weight:600;">Click 'n' Join</span></p></body></html> + + + true + + + + + + + + + + + + + + + 0 + 0 + + + + Actions: + + + + 0 + + + + + + 0 + 0 + + + + 0 + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Should the current image be used as input for the GWS or another?</p></body></html> + + + true + + + + + + + Load from File + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + + 12 + + + 0 + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:12px; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13px;">Should the image be used directly for the GWS (direct) or a gradient-magnitude image (indirect)?</span></p></body></html> + + + true + + + + + + + + + + direct + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:12px; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:12px;">Adjust the smoothing filter parameters.</span></p></body></html> + + + true + + + + + + + Conductance + + + + + + + 100 + + + 0 + + + 50 + + + Qt::Horizontal + + + + + + + smoothing iterations + + + + + + + 1 + + + 200 + + + 10 + + + Qt::Horizontal + + + + + + + + 4 + + + 0 + + + + + false + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Back + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Next + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + + + <html><head/><body><p>Adjust the initial parameters for the GWS. No watersheds between the &quot;Min. Depth&quot; and the &quot;Max. Depth&quot; will be available (the smaller this range the faster is the computation). Both parameters are a percentage of the height range of the GWS input image.</p></body></html> + + + true + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + Minimum Depth + + + + + + + + 0 + 0 + + + + 100 + + + Qt::Horizontal + + + + + + + Maximum Depth + + + + + + + 100 + + + 100 + + + Qt::Horizontal + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:12px; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13px;">Press 'Next' to start the computation of the hierarchy tree of Watersheds. This might take a while!</span></p></body></html> + + + true + + + + + + + + 4 + + + 0 + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Back + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Next + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + 0 + + + + + + 12 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:12px; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:12px;">Click LMB to add labeled regions to the final segmentation with the current foreground Label, RMB to remove.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13px;">Use the slider or +/- to adjust the actual depth used for merging labels within the watershed hierarchy.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13px;">CTRL+LMB/RMB picks the FG/BG label from the final segmentation.</span></p></body></html> + + + true + + + + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + adjustable Level + + + + + + + 100 + + + 22 + + + Qt::Horizontal + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:12px; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13px;">&quot;Finish&quot; will copy the final segmentation according to the chosen draw-over mode (BG label).</span></p></body></html> + + + true + + + + + + + + 4 + + + 0 + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Back + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Finish + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Cancel Segmentation + + + + + + + Increase WS Level + + + Increase Watershed Level + + + + + + + + + Decrease WS Level + + + Decrease Watershed Level + + + - + + + + + + QDoubleSliderWithEditor + QSlider +
QDoubleSliderWithEditor.h
+
+
+ + +
diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx new file mode 100644 index 00000000..35992262 --- /dev/null +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -0,0 +1,132 @@ +/* +part of Click'n'Join mode, which was contributed by Roman Grothausmann +*/ + +#include "JoinDataPanel.h" +#include "ui_JoinDataPanel.h" + +#include "SNAPQtCommon.h" //findParentWidget +#include "GlobalUIModel.h" //GlobalUIModel +#include "JoinModel.h" +#include "GlobalState.h" //CROSSHAIRS_MODE +#include "IRISApplication.h" +#include "GenericImageData.h" //GetCurrentImageData()->GetImageRegion(); +#include "QtWidgetActivator.h" //activateOnFlag + + +JoinDataPanel::JoinDataPanel(QWidget *parent) : + SNAPComponent(parent), + ui(new Ui::JoinDataPanel){ + ui->setupUi(this); + } + +JoinDataPanel::~JoinDataPanel(){ + delete ui; + } + +void JoinDataPanel::SetModel(GlobalUIModel *model){ + // Store the model + m_Model = model; + + activateOnNotFlag(ui->btnStartCnJ, m_Model, UIF_JOIN_MODE); + activateOnNotFlag(ui->inJoinType, m_Model, UIF_JOIN_MODE); + activateOnFlag(ui->instrText, m_Model, UIF_JOIN_MODE); + activateOnFlag(ui->btnFinishCnJ, m_Model, UIF_JOIN_MODE); + activateOnFlag(ui->btnCancel, m_Model, UIF_JOIN_MODE); + activateOnFlag(ui->btnCopySeg, m_Model, UIF_JOIN_MODE); + activateOnFlag(ui->btnClearSeg, m_Model, UIF_JOIN_MODE); + } + +void JoinDataPanel::on_btnStartCnJ_clicked(){ + + int sel = ui->inJoinType->currentIndex(); + switch(sel){ + case 0:{ + + IRISApplication *driver = m_Model->GetDriver(); + + //reset ROI from the main image + GlobalState::RegionType roi = + driver->GetCurrentImageData()->GetImageRegion(); + + // Can't be empty! + assert(roi.GetNumberOfPixels()); + + // Update + driver->GetGlobalState()->SetSegmentationROI(roi); + + //// Initialize the image data + driver->InitializeJOINImageData( + driver->GetGlobalState()->GetSegmentationROISettings(), + m_Model->GetProgressCommand()); + + driver->CopySegementationToJsrc( + driver->GetGlobalState()->GetSegmentationROISettings(), + m_Model->GetProgressCommand()); + driver->SetCurrentImageDataToJOIN(); + } break; + case 1:{ + ////panel will be hidden in GWSJOIN_MODE + m_Model->GetGlobalState()->SetToolbarMode(GLOBALWS_ROI_MODE); + } break; + default: + ////Switch to crosshairs mode + m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); + std::cerr << "Index not handled (yet)." << std::endl; + break; + }//switch + } + +void JoinDataPanel::on_btnFinishCnJ_clicked(){ + IRISApplication *driver = m_Model->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + // Update IRIS with JOIN images + driver->UpdateIRISWithJOINImageData(NULL); + + // Set an undo point + driver->StoreUndoPoint("Automatic Segmentation"); + + // Return to IRIS mode + driver->SetCurrentImageDataToIRIS(); + driver->ReleaseJOINImageData(); + + ui->btnStartCnJ->setEnabled(true); + ui->btnCancel->setEnabled(false); + ui->btnFinishCnJ->setEnabled(false); + ui->inJoinType->setEnabled(true); + m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction + } + +void JoinDataPanel::on_btnCancel_clicked(){ + IRISApplication *driver = m_Model->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + // Return to IRIS mode + driver->SetCurrentImageDataToIRIS(); + driver->ReleaseJOINImageData(); + + ui->btnStartCnJ->setEnabled(true); + ui->btnCancel->setEnabled(false); + ui->btnFinishCnJ->setEnabled(false); + ui->inJoinType->setEnabled(true); + m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction + } + + +void JoinDataPanel::on_btnCopySeg_clicked(){ + IRISApplication *driver = m_Model->GetDriver(); + driver->CopySegementationToJdst( + driver->GetGlobalState()->GetSegmentationROISettings(), + m_Model->GetProgressCommand()); + + driver->InvokeEvent(SegmentationChangeEvent()); + + } + +void JoinDataPanel::on_btnClearSeg_clicked(){ + IRISApplication *driver = m_Model->GetDriver(); + driver->ClearJdst(); + + driver->InvokeEvent(SegmentationChangeEvent()); + } diff --git a/GUI/Qt/Components/JoinDataPanel.h b/GUI/Qt/Components/JoinDataPanel.h new file mode 100644 index 00000000..ee9a97a6 --- /dev/null +++ b/GUI/Qt/Components/JoinDataPanel.h @@ -0,0 +1,45 @@ +/* +part of Click'n'Join mode, which was contributed by Roman Grothausmann +*/ + +#ifndef JOINDATAPANEL_H +#define JOINDATAPANEL_H + +#include + +class GlobalUIModel; + +namespace Ui { +class JoinDataPanel; +} + +class JoinDataPanel : public SNAPComponent +{ + Q_OBJECT + +public: + explicit JoinDataPanel(QWidget *parent = 0); + ~JoinDataPanel(); + + void SetModel(GlobalUIModel *); + +private slots: + + void on_btnStartCnJ_clicked(); + + void on_btnCancel_clicked(); + + void on_btnFinishCnJ_clicked(); + + void on_btnCopySeg_clicked(); + + void on_btnClearSeg_clicked(); + +private: + Ui::JoinDataPanel *ui; + + GlobalUIModel *m_Model; +}; + + +#endif // JOINDATAPANEL_H diff --git a/GUI/Qt/Components/JoinDataPanel.ui b/GUI/Qt/Components/JoinDataPanel.ui new file mode 100644 index 00000000..ee8ed581 --- /dev/null +++ b/GUI/Qt/Components/JoinDataPanel.ui @@ -0,0 +1,282 @@ + + + JoinDataPanel + + + + 0 + 0 + 200 + 680 + + + + + 0 + 0 + + + + + 200 + 16777215 + + + + Form + + + * { +font-size: 12px; +} +QGroupBox { + background-origin: content; + margin-top: 15px; + font-weight: bold; + font-size: 12px; + font-family: helvetica; + color: rgb(30,30,160); + background-color: rgb(237,237,237); + padding: 5px; + border-radius: 4px; + border: 1px solid rgb(130,130,130); +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; +} + + + + + + 8 + + + 5 + + + + + + 0 + 0 + + + + Dataset: + + + + 0 + + + + + + 0 + 0 + + + + 0 + + + + + 0 + + + + + + 12 + + + 0 + + + + + Please choose the label data for Click 'n' Join: + + + Qt::PlainText + + + true + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + Current Segmentation + + + + + Global Watershed (GWS) + + + + + Load from File + + + + + + + + + 4 + + + 0 + + + + + false + + + + 0 + 0 + + + + + 64 + 16777215 + + + + Cancel + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + OK + + + + + + + + + + + + + + + + + false + + + + 0 + 0 + + + + Click LMB to add labeled regions to the "Join destination" with the current FG label, RMB to remove. +CTRL+LMB/RMB picks the FG/BG label from the "Join destination". +"Finish" will copy the final segmentation according to the chosen draw-over mode (BG label). + + + Qt::PlainText + + + true + + + + + + + + + + false + + + Copy Segmentation + + + + + + + false + + + Clear Segmentation + + + + + + + + + + false + + + Finish Click 'n' Join + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/GUI/Qt/Components/SliceViewPanel.cxx b/GUI/Qt/Components/SliceViewPanel.cxx index af597a29..b2a94a17 100644 --- a/GUI/Qt/Components/SliceViewPanel.cxx +++ b/GUI/Qt/Components/SliceViewPanel.cxx @@ -12,11 +12,13 @@ #include "PaintbrushRenderer.h" #include "SnakeROIRenderer.h" #include "SnakeROIModel.h" +#include "JoinModel.h" #include "SliceWindowCoordinator.h" #include "PolygonDrawingModel.h" #include "QtWidgetActivator.h" #include "SnakeModeRenderer.h" #include "SnakeWizardModel.h" +#include "GlobalWSWizardModel.h" #include "DisplayLayoutModel.h" #include "PaintbrushModel.h" #include "SliceWindowDecorationRenderer.h" @@ -153,6 +155,7 @@ void SliceViewPanel::Initialize(GlobalUIModel *model, unsigned int index) ui->imThumbnail->SetModel(m_GlobalUI->GetCursorNavigationModel(index)); ui->imPolygon->SetModel(m_GlobalUI->GetPolygonDrawingModel(index)); ui->imSnakeROI->SetModel(m_GlobalUI->GetSnakeROIModel(index)); + ui->imJoin->SetModel(m_GlobalUI->GetJoinModel(index)); ui->imPaintbrush->SetModel(m_GlobalUI->GetPaintbrushModel(index)); // Initialize the 'orphan' renderers (without a custom widget) @@ -181,6 +184,10 @@ void SliceViewPanel::Initialize(GlobalUIModel *model, unsigned int index) connectITK(m_GlobalUI->GetSnakeROIModel(index), ModelUpdateEvent()); + // Listen to the join model too + connectITK(m_GlobalUI->GetJoinModel(index), + ModelUpdateEvent()); + // Listen to paintbrush motion connectITK(m_GlobalUI->GetPaintbrushModel(index), PaintbrushModel::PaintbrushMovedEvent()); @@ -188,6 +195,9 @@ void SliceViewPanel::Initialize(GlobalUIModel *model, unsigned int index) // Listen to all (?) events from the snake wizard as well connectITK(m_GlobalUI->GetSnakeWizardModel(), IRISEvent()); + // Listen to all (?) events from the GlobalWS wizard as well + connectITK(m_GlobalUI->GetGlobalWSWizardModel(), IRISEvent()); + // Widget coupling makeCoupling(ui->inSlicePosition, m_SliceModel->GetSliceIndexModel()); @@ -341,7 +351,12 @@ void SliceViewPanel::OnToolbarModeChange() break; case ANNOTATION_MODE: break; - case ROI_MODE: + case JOIN_MODE: + case GWSJOIN_MODE: + ConfigureEventChain(ui->imJoin); + break; + case GLOBALWS_ROI_MODE: + case SNAKE_ROI_MODE: ConfigureEventChain(ui->imSnakeROI); ovTiled.push_back(ui->imSnakeROI->GetRenderer()); break; diff --git a/GUI/Qt/Components/SliceViewPanel.ui b/GUI/Qt/Components/SliceViewPanel.ui index c9bcc4dc..d8ba6df8 100644 --- a/GUI/Qt/Components/SliceViewPanel.ui +++ b/GUI/Qt/Components/SliceViewPanel.ui @@ -582,6 +582,9 @@ p, li { white-space: pre-wrap; } + + + @@ -830,6 +833,12 @@ p, li { white-space: pre-wrap; }
PaintbrushInteractionMode.h
1 + + JoinInteractionMode + QWidget +
JoinInteractionMode.h
+ 1 +
diff --git a/GUI/Qt/Components/SnakeToolROIPanel.cxx b/GUI/Qt/Components/SnakeToolROIPanel.cxx index 1b62b250..f27807de 100644 --- a/GUI/Qt/Components/SnakeToolROIPanel.cxx +++ b/GUI/Qt/Components/SnakeToolROIPanel.cxx @@ -54,7 +54,8 @@ void SnakeToolROIPanel::on_btnAuto_clicked() // TODO: Check that the label configuration is valid // Handle resampling if requested - if(ui->chkResample->isChecked()) + if(ui->chkResample->isChecked() + && m_Model->GetGlobalState()->GetToolbarMode() != GLOBALWS_ROI_MODE) //hack to not resample for GWS (better would be to disable chkResample { if(m_ResampleDialog->exec() != QDialog::Accepted) return; @@ -66,10 +67,19 @@ void SnakeToolROIPanel::on_btnAuto_clicked() m_Model->GetSnakeROIResampleModel()->Accept(); } - // Switch to crosshairs mode - m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); - // Show the snake panel MainImageWindow *main = findParentWidget(this); + + switch(m_Model->GetGlobalState()->GetToolbarMode()){ + case SNAKE_ROI_MODE: main->OpenSnakeWizard(); + break; + case GLOBALWS_ROI_MODE: + main->OpenGlobalWSWizard(); + break; + default: + // Switch to crosshairs mode + m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); + break; + } } diff --git a/GUI/Qt/Resources/SNAPResources.qrc b/GUI/Qt/Resources/SNAPResources.qrc index c808d511..892b57a9 100644 --- a/GUI/Qt/Resources/SNAPResources.qrc +++ b/GUI/Qt/Resources/SNAPResources.qrc @@ -5,6 +5,7 @@ zoom.gif spray.gif snake.gif + globalWS.gif screencapture2.gif screencapture.gif scalpel.gif diff --git a/GUI/Qt/Resources/globalWS.gif b/GUI/Qt/Resources/globalWS.gif new file mode 100644 index 0000000000000000000000000000000000000000..48e95eeb4e6c90fdb649fb5b29c7888cdcd1be9a GIT binary patch literal 1800 zcmV+j2lx0#Nk%w1VIKe=0O$VzFE4d9Gb#i-pFRWjyZ+LT9fnRxfPLgYpsA8*hbd{@Or+{;Rcy@Yyd@*u% zkal==KaEFtbeuztL3wqNT7h?Wc!7U@Gf=zyYprmz-hlV>zmrrC|*pHY#IM30Y3gN}WXkV}k>c#e`qkdI=Ejfz;JRHcW2R-;>xlt-V8Ym}2slaO$# zhlrMxNRE(=mX%MGlxM$zua}ommzP(Xm`swCk(QWVn3_hKnNw({W}28~w~L!ztYe&; zRg#`nnV5dHj+UC8VxXN-oS#dbon4!sQJ$S}p`cl(o@~37k))zkwV8##lcS`gT)LN+ zv7URPrdYF{cBZ9Yt)p_Or&_n4gs7-zy`7h+t5&k6Z>y?fsjObGu4loijjyv~va)f) zuZ+34aLdJuA^s6Va%Ew3Wn>_CX>@2HM@dak04x9i0018V9{>Od{s7^?QFMwHEjWdk zY|*u75wtQ@fV7ZNWXT*)t6q767--e9KZ(@*sRgXow_3`2Ei$7E(~%%Wa)`)LWlo?u zWp2*7m}!w7J)~syVs=bcrZHxsIij&c%MuJCWLOMT##1n=b5Nlog{qfVud)`!`IU^% zkRedsglJKuN={F>q~Y=uNS4rE$C&j(B@5M}XYg!n*zjNj5;QWG_8+3osFr5RNDD4Af;fB}OckGOm)w53s_j;1rJ zQq@Zqvudptk-Fz>MuQh79++TbPTaYB=lTGt0vA`XU|@UxRb#d&)4hLP8c?7S9SOF5 zUXPKBB=zR9V4m!@lJzWXzHUQoV8R9zY%qj9+Jt4s6QlqWgb3WN5=hi2eO0!IGJTZMNEu~Zw2U~# zh$W6aH$3owhYVZ*i$2vX!dG9qjI#+5IN+cHB6$QdiWiH>!cG^^4c5R0ZuBEgP{j## zO%fbHAb|u9bbvw@G+01JD8tO~0(*mnL615l+9gXg)2NU^0t7TlfCL?6vB8WqNbv#% z52$wrJiVCFP?+FE0mA|c7(jpm1PHJ|1}Q|h9-01}ZO{ceo$67ZEZ0l|LIMaZkU#h`!Ure3P{JX`DAQsly@Ydzy979}fCLXV8DVddZ5w@ zD#vgGg8>2&i{tW-kB{H!oS0t6Abpuq}=)DXi6BUnK`n9&#Iv_d?R=|v^v qM+jE1LKt{RLl1P|2T9mL5|9uCBzSR-{X`}*)zF4En4yh;00298=Mkj< literal 0 HcmV?d00001 diff --git a/GUI/Qt/View/JoinInteractionMode.cxx b/GUI/Qt/View/JoinInteractionMode.cxx new file mode 100644 index 00000000..59d6122e --- /dev/null +++ b/GUI/Qt/View/JoinInteractionMode.cxx @@ -0,0 +1,50 @@ +#include "JoinInteractionMode.h" +#include "SliceViewPanel.h" +#include "GlobalUIModel.h" + +JoinInteractionMode::JoinInteractionMode(GenericSliceView *parent) + : SliceWindowInteractionDelegateWidget(parent){ + m_Model = NULL; + } + +JoinInteractionMode::~JoinInteractionMode(){ + } + +void +JoinInteractionMode +::SetModel(JoinModel *model){ + m_Model = model; + SetParentModel(model->GetParent()); + } + +void JoinInteractionMode::mousePressEvent(QMouseEvent *ev){ + + if(m_Model->GetParent()->GetParentUI()->CheckState(UIF_JOIN_MODE)){ + bool isleft = (ev->button() == Qt::LeftButton); + bool isright = (ev->button() == Qt::RightButton); + + Qt::KeyboardModifiers modifiers = ev->modifiers(); + bool ctrl= modifiers.testFlag( Qt::ControlModifier); + + if(isleft || isright) + { + if(m_Model->ProcessPushEvent(to_float(m_XSlice),isright,ctrl))//ProcessPushEvent currently always returns false + ev->accept(); //eat event, i.e. no cursor chasing + } + } + } + +void JoinInteractionMode::enterEvent(QEvent *){ + // TODO: this is hideous! + SliceViewPanel *panel = dynamic_cast(m_ParentView->parent()); + panel->SetMouseMotionTracking(true); + } + +void JoinInteractionMode::leaveEvent(QEvent *){ + SliceViewPanel *panel = dynamic_cast(m_ParentView->parent()); + panel->SetMouseMotionTracking(false); + + // This fixes a crash when you press quit in paintbrush mode + if(panel->isVisible()) + m_Model->ProcessLeaveEvent(); + } diff --git a/GUI/Qt/View/JoinInteractionMode.h b/GUI/Qt/View/JoinInteractionMode.h new file mode 100644 index 00000000..9268cfc9 --- /dev/null +++ b/GUI/Qt/View/JoinInteractionMode.h @@ -0,0 +1,34 @@ +#ifndef JOININTERACTIONMODE_H +#define JOININTERACTIONMODE_H + +#include +#include +#include "GenericSliceView.h" +#include "JoinModel.h" + +class GenericSliceModel; +class GenericSliceView; +class JoinModel; + +class JoinInteractionMode : public SliceWindowInteractionDelegateWidget +{ + Q_OBJECT + +public: + JoinInteractionMode(GenericSliceView *parent = 0); + ~JoinInteractionMode(); + + irisGetMacro(Model, JoinModel *) + void SetModel(JoinModel *m_Model); + + void mousePressEvent(QMouseEvent *ev); + + void enterEvent(QEvent *); + void leaveEvent(QEvent *); + +protected: + + JoinModel *m_Model; +}; + +#endif // JOININTERACTIONMODE_H diff --git a/GUI/Qt/Windows/LayerInspectorDialog.cxx b/GUI/Qt/Windows/LayerInspectorDialog.cxx index faeb8cd6..37233435 100644 --- a/GUI/Qt/Windows/LayerInspectorDialog.cxx +++ b/GUI/Qt/Windows/LayerInspectorDialog.cxx @@ -166,6 +166,7 @@ void LayerInspectorDialog::GenerateModelsForLayers() LayerIterator it = m_Model->GetDriver()->GetCurrentImageData()->GetLayers( MAIN_ROLE | OVERLAY_ROLE | + JOIN_ROLE | SNAP_ROLE); for(; !it.IsAtEnd(); ++it) @@ -194,6 +195,7 @@ void LayerInspectorDialog::BuildLayerWidgetHierarchy() mapRoleNames[MAIN_ROLE] = "Main Image"; mapRoleNames[OVERLAY_ROLE] = "Overlays"; mapRoleNames[SNAP_ROLE] = "Snake Mode Layers"; + mapRoleNames[JOIN_ROLE] = "Join Mode Layers"; } // Get the top-level layout in the pane @@ -229,7 +231,7 @@ void LayerInspectorDialog::BuildLayerWidgetHierarchy() // Iterate over the layers for each class of displayed layers LayerIterator it = m_Model->GetDriver()->GetCurrentImageData()->GetLayers( - MAIN_ROLE | OVERLAY_ROLE | SNAP_ROLE); + MAIN_ROLE | OVERLAY_ROLE | SNAP_ROLE | JOIN_ROLE); // The current role and associated group box LayerRole currentRole = NO_ROLE; diff --git a/GUI/Qt/Windows/MainControlPanel.cxx b/GUI/Qt/Windows/MainControlPanel.cxx index 8985846f..75f6efc8 100644 --- a/GUI/Qt/Windows/MainControlPanel.cxx +++ b/GUI/Qt/Windows/MainControlPanel.cxx @@ -132,6 +132,7 @@ void MainControlPanel::SetModel(GlobalUIModel *model) ui->pageSyncInspector->SetModel(m_Model->GetSynchronizationModel()); ui->pagePaintbrushTool->SetModel(m_Model->GetPaintbrushSettingsModel()); ui->pageSnakeTool->SetModel(m_Model); + ui->pageJoinTool->SetModel(m_Model); m_LabelSelectionButton->SetModel(model); m_LabelSelectionPopup->SetModel(model); @@ -147,12 +148,16 @@ void MainControlPanel::SetModel(GlobalUIModel *model) void MainControlPanel::onModelUpdate(const EventBucket &bucket) { // A static array of widget/mode mappings + //// mode_inspector_btn, mode_tool_pages and ToolbarModeType should have the same amount of entries! static QToolButton *mode_inspector_btn[] = { ui->btnCursorInspector, ui->btnZoomInspector, ui->btnLabelInspector, ui->btnToolInspector, ui->btnToolInspector, + ui->btnToolInspector, + ui->btnToolInspector, + ui->btnCursorInspector, //little hack to get the Cursor inspector panel without SetToolbarMode(CROSSHAIRS_MODE) ui->btnToolInspector }; static QWidget *mode_tool_pages[] = { @@ -161,6 +166,9 @@ void MainControlPanel::onModelUpdate(const EventBucket &bucket) ui->pageBlank, ui->pagePaintbrushTool, ui->pageSnakeTool, + ui->pageJoinTool, + ui->pageSnakeTool, + ui->pageBlank, ui->pageBlank}; // Respond to changes in toolbar mode diff --git a/GUI/Qt/Windows/MainControlPanel.ui b/GUI/Qt/Windows/MainControlPanel.ui index 7db5f429..faab0a10 100644 --- a/GUI/Qt/Windows/MainControlPanel.ui +++ b/GUI/Qt/Windows/MainControlPanel.ui @@ -6,19 +6,19 @@ 0 0 - 184 + 215 588 - 184 + 215 0 - 184 + 215 16777215 @@ -373,6 +373,7 @@ QToolButton:hover, QToolButton:checked { 1 + @@ -468,6 +469,12 @@ QToolBar {
SynchronizationInspector.h
1 + + JoinDataPanel + QWidget +
JoinDataPanel.h
+ 1 +
diff --git a/GUI/Qt/Windows/MainImageWindow.cxx b/GUI/Qt/Windows/MainImageWindow.cxx index 87e6e23d..cf29a00c 100644 --- a/GUI/Qt/Windows/MainImageWindow.cxx +++ b/GUI/Qt/Windows/MainImageWindow.cxx @@ -39,6 +39,7 @@ #include "ColorMapModel.h" #include "ViewPanel3D.h" #include "SnakeWizardPanel.h" +#include "GlobalWSWizardPanel.h" #include "LatentITKEventNotifier.h" #include #include "QtReporterDelegates.h" @@ -101,6 +102,7 @@ MainImageWindow::MainImageWindow(QWidget *parent) : ui->actionPolygon->setActionGroup(grpToolbarMain); ui->actionPaintbrush->setActionGroup(grpToolbarMain); ui->actionSnake->setActionGroup(grpToolbarMain); + ui->actionJoin->setActionGroup(grpToolbarMain); QActionGroup *grpToolbar3D = new QActionGroup(this); ui->action3DTrackball->setActionGroup(grpToolbar3D); @@ -153,6 +155,15 @@ MainImageWindow::MainImageWindow(QWidget *parent) : QDockWidget::DockWidgetMovable); this->addDockWidget(Qt::RightDockWidgetArea, m_DockRight); + m_DockRight2 = new QDockWidget("Global Watershed", this); + m_GlobalWSWizard = new GlobalWSWizardPanel(this); + m_DockRight2->setWidget(m_GlobalWSWizard); + m_DockRight2->setAllowedAreas(Qt::RightDockWidgetArea); + m_DockRight2->setFeatures( + QDockWidget::DockWidgetFloatable | + QDockWidget::DockWidgetMovable); + this->addDockWidget(Qt::RightDockWidgetArea, m_DockRight2); + // Set up the recent items panels connect(ui->panelRecentImages, SIGNAL(RecentItemSelected(QString)), SLOT(LoadMainImage(QString))); @@ -172,11 +183,16 @@ MainImageWindow::MainImageWindow(QWidget *parent) : // Hide the right dock for now m_DockRight->setVisible(false); + m_DockRight2->setVisible(false); // Hide the dock when the wizard finishes connect(m_SnakeWizard, SIGNAL(wizardFinished()), this, SLOT(onSnakeWizardFinished())); + // Hide the dock when the wizard finishes + connect(m_GlobalWSWizard, SIGNAL(wizardFinished()), + this, SLOT(onGlobalWSWizardFinished())); + // Make the margins adjust when the docks are attached connect(m_DockLeft, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(AdjustMarginsForDocks())); @@ -255,6 +271,7 @@ void MainImageWindow::Initialize(GlobalUIModel *model) m_LabelEditor->SetModel(model->GetLabelEditorModel()); m_LayerInspector->SetModel(model); m_SnakeWizard->SetModel(model); + m_GlobalWSWizard->SetModel(model); m_ReorientImageDialog->SetModel(model->GetReorientImageModel()); m_DropDialog->SetModel(model); m_StatisticsDialog->SetModel(model); @@ -354,6 +371,7 @@ void MainImageWindow::Initialize(GlobalUIModel *model) activateOnFlag(ui->actionUnload_Last_Overlay, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); activateOnFlag(ui->actionUnload_All_Overlays, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); activateOnFlag(ui->menuOverlayAppearance, m_Model, UIF_OVERLAY_LOADED); + activateOnFlag(ui->actionToggleJsrcVis, m_Model, UIF_JOIN_MODE); // Workspace menu activateOnFlag(ui->actionOpenWorkspace, m_Model, UIF_IRIS_MODE); @@ -361,11 +379,12 @@ void MainImageWindow::Initialize(GlobalUIModel *model) activateOnFlag(ui->actionSaveWorkspaceAs, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); // Tool action activations - activateOnFlag(ui->actionCrosshair, m_Model, UIF_BASEIMG_LOADED); - activateOnFlag(ui->actionZoomPan, m_Model, UIF_BASEIMG_LOADED); - activateOnFlag(ui->actionPolygon, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionSnake, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionPaintbrush, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionCrosshair, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionZoomPan, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionPolygon, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionSnake, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionPaintbrush, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionJoin, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); activateOnFlag(ui->action3DCrosshair, m_Model, UIF_BASEIMG_LOADED); activateOnFlag(ui->action3DTrackball, m_Model, UIF_BASEIMG_LOADED); @@ -680,6 +699,18 @@ void MainImageWindow::OpenSnakeWizard() m_DockRight->setVisible(true); } +void MainImageWindow::OpenGlobalWSWizard() +{ + // Initialize the GlobalWS wizard + this->m_GlobalWSWizard->Initialize(); + + // Remember the size of the window before the right dock was shown + m_SizeWithoutRightDock = this->size(); + + // Make the dock containing the wizard visible + m_DockRight2->setVisible(true); +} + void MainImageWindow::AdjustMarginsForDocks() { // Get the current margins @@ -861,6 +892,20 @@ void MainImageWindow::onSnakeWizardFinished() resize(m_SizeWithoutRightDock.width(), m_SizeWithoutRightDock.height()); } +void MainImageWindow::onGlobalWSWizardFinished() +{ + // Make the dock containing the wizard visible + m_DockRight2->setVisible(false); + + // TODO: this way of handling the size of the main window after the right + // dock is hidden is rudimentary. I should learn how to use sizePolicy and + // sizeHint fields more effectively. + + // Return to previous size + this->layout()->activate(); + resize(m_SizeWithoutRightDock.width(), m_SizeWithoutRightDock.height()); +} + void MainImageWindow::on_actionUnload_All_triggered() { // Prompt for unsaved changes @@ -1553,3 +1598,8 @@ void MainImageWindow::on_actionNew_ITK_SNAP_Window_triggered() std::list args; m_Model->GetSystemInterface()->LaunchChildSNAPSimple(args); } + +void MainImageWindow::on_actionToggleJsrcVis_triggered() +{ + m_Model->ToggleJsrcVisibility(); +} diff --git a/GUI/Qt/Windows/MainImageWindow.h b/GUI/Qt/Windows/MainImageWindow.h index eaa91b66..7b4bf318 100644 --- a/GUI/Qt/Windows/MainImageWindow.h +++ b/GUI/Qt/Windows/MainImageWindow.h @@ -36,6 +36,7 @@ class SliceViewPanel; class GlobalUIModel; class QDockWidget; class SnakeWizardPanel; +class GlobalWSWizardPanel; class EventBucket; class QModelIndex; class QProgressDialog; @@ -81,6 +82,9 @@ class MainImageWindow : public QMainWindow // Initiate active contour segmentation void OpenSnakeWizard(); + // Initiate watershed segmentation + void OpenGlobalWSWizard(); + // Load a drag-n-dropped file void LoadDroppedFile(QString file); @@ -131,6 +135,8 @@ private slots: void onSnakeWizardFinished(); + void onGlobalWSWizardFinished(); + void on_actionUnload_All_triggered(); void on_actionReorient_Image_triggered(); @@ -260,6 +266,8 @@ private slots: void on_actionNew_ITK_SNAP_Window_triggered(); + void on_actionToggleJsrcVis_triggered(); + protected: // bool eventFilter(QObject *obj, QEvent *event); @@ -289,7 +297,7 @@ private slots: QWidget *m_ViewPanels[4]; // Left and right docks - QDockWidget *m_DockLeft, *m_DockRight; + QDockWidget *m_DockLeft, *m_DockRight, *m_DockRight2; // Size before the right dock is shown QSize m_SizeWithoutRightDock; @@ -305,6 +313,9 @@ private slots: // SNAP wizard panel (in right dock) SnakeWizardPanel *m_SnakeWizard; + // GlobalWS wizard panel (in right dock) + GlobalWSWizardPanel *m_GlobalWSWizard; + Ui::MainImageWindow *ui; GlobalUIModel *m_Model; diff --git a/GUI/Qt/Windows/MainImageWindow.ui b/GUI/Qt/Windows/MainImageWindow.ui index 4ddb25ed..ae14910c 100644 --- a/GUI/Qt/Windows/MainImageWindow.ui +++ b/GUI/Qt/Windows/MainImageWindow.ui @@ -402,6 +402,7 @@ color:rgb(103, 103, 103); +
@@ -423,6 +424,7 @@ color:rgb(103, 103, 103); +
@@ -1296,6 +1298,35 @@ color:rgb(103, 103, 103); New ITK-SNAP Window + + + true + + + + :/root/globalWS.gif:/root/globalWS.gif + + + Click 'n' Join Mode + + + <html><head/><body><p><span style=" font-weight:600;">Click 'n' Join Mode</span></p><p>Join labeled regions by clicking.</p></body></html> + + + 6 + + + + + ToggleJsrcVis + + + Toggle Join source image visibility + + + T + + diff --git a/Logic/Common/SNAPRegistryIO.cxx b/Logic/Common/SNAPRegistryIO.cxx index 7cd725aa..99d8433e 100644 --- a/Logic/Common/SNAPRegistryIO.cxx +++ b/Logic/Common/SNAPRegistryIO.cxx @@ -450,6 +450,7 @@ void SNAPRegistryIO::BuildEnums() m_EnumMapLayerRole.AddPair(LABEL_ROLE, "SegmentationRole"); m_EnumMapLayerRole.AddPair(SNAP_ROLE, "SnakeModeRole"); m_EnumMapLayerRole.AddPair(NO_ROLE, "InvalidRole"); + m_EnumMapLayerRole.AddPair(JOIN_ROLE, "JoinModeRole"); m_EnumMapLayerLayout.AddPair(LAYOUT_STACKED, "Stacked"); m_EnumMapLayerLayout.AddPair(LAYOUT_TILED, "Tiled"); diff --git a/Logic/Framework/GenericImageData.h b/Logic/Framework/GenericImageData.h index 188f29b4..da459c46 100644 --- a/Logic/Framework/GenericImageData.h +++ b/Logic/Framework/GenericImageData.h @@ -313,6 +313,7 @@ class GenericImageData : public itk::Object ImageCoordinateGeometry m_ImageGeometry; friend class SNAPImageData; + friend class JOINImageData; friend class LayerIterator; // Append an image wrapper to a role diff --git a/Logic/Framework/GlobalState.h b/Logic/Framework/GlobalState.h index 29002fa1..24a540c7 100644 --- a/Logic/Framework/GlobalState.h +++ b/Logic/Framework/GlobalState.h @@ -117,7 +117,10 @@ enum ToolbarModeType NAVIGATION_MODE, POLYGON_DRAWING_MODE, PAINTBRUSH_MODE, - ROI_MODE, + SNAKE_ROI_MODE, + JOIN_MODE, + GLOBALWS_ROI_MODE, + GWSJOIN_MODE, ANNOTATION_MODE }; diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index 300406e2..dbcc1df9 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -45,6 +45,7 @@ #include "IRISImageData.h" #include "IRISVectorTypesToITKConversion.h" #include "SNAPImageData.h" +#include "JOINImageData.h" #include "MeshManager.h" #include "MeshExportSettings.h" #include "SegmentationStatistics.h" @@ -108,6 +109,9 @@ ::IRISApplication() m_SNAPImageData = SNAPImageData::New(); m_SNAPImageData->SetParent(this); + m_JOINImageData = JOINImageData::New(); + m_JOINImageData->SetParent(this); + // Set the current IRIS pointer m_CurrentImageData = m_IRISImageData.GetPointer(); @@ -115,6 +119,7 @@ ::IRISApplication() // as our own events. Rebroadcaster::RebroadcastAsSourceEvent(m_IRISImageData, WrapperChangeEvent(), this); Rebroadcaster::RebroadcastAsSourceEvent(m_SNAPImageData, WrapperChangeEvent(), this); + Rebroadcaster::RebroadcastAsSourceEvent(m_JOINImageData, WrapperChangeEvent(), this); // TODO: should this also be a generic Wrapper Image Data change event? Rebroadcaster::RebroadcastAsSourceEvent(m_SNAPImageData, LevelSetImageChangeEvent(), this); @@ -245,6 +250,119 @@ ::InitializeSNAPImageData(const SNAPSegmentationROISettings &roi, InvokeEvent(LayerChangeEvent()); } +void +IRISApplication +::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, + CommandType *progressCommand) +{ + assert(m_IRISImageData->IsMainLoaded()); + + // Create the JOIN image data object + m_JOINImageData->InitializeToROI(m_IRISImageData, roi, progressCommand); + + // Initialize the source and destination images of the JOIN image data + m_JOINImageData->InitializeJsrc(); + m_JOINImageData->InitializeJdst(); + + // Pass the cleaned up segmentation image to SNAP + m_JOINImageData->SetSegmentationImage(m_JOINImageData->GetJdst()->GetImage()); + + // Remember the ROI object + m_GlobalState->SetSegmentationROISettings(roi); + + // The set of layers has changed + InvokeEvent(LayerChangeEvent()); +} + +void +IRISApplication +::CopySegementationToJsrc(const SNAPSegmentationROISettings &roi, + CommandType *progressCommand) +{ + assert(m_JOINImageData->IsJsrcLoaded()); + + ////creating deep copy, should only be used for initialization of CnJ (GWS fills its Jsrc with WS) + + SNAPSegmentationROISettings roiLabel = roi; + roiLabel.SetInterpolationMethod(SNAPSegmentationROISettings::NEAREST_NEIGHBOR); + // Get chunk of the label image + JsrcImageType::Pointer imgNewLabel = + m_IRISImageData->GetSegmentation()->DeepCopyRegion(roiLabel,progressCommand); + + // Pass the cleaned up segmentation image to JOIN + m_JOINImageData->SetJsrc(imgNewLabel); + + InvokeEvent(LayerChangeEvent()); +} + +void +IRISApplication +::CopySegementationToJdst(const SNAPSegmentationROISettings &roi, + CommandType *progressCommand) +{ + assert(m_JOINImageData->IsJdstLoaded()); + + ////creating shallow copy since Jdst already is initialized and points to m_LabelImage set by m_JOINImageData->SetSegmentationImage in InitializeJOINImageData + + typedef LabelImageWrapper::ImageType SourceImageType; + typedef JdstImageWrapper::ImageType TargetImageType; + + SourceImageType::Pointer source = m_IRISImageData->GetSegmentation()->GetImage(); + TargetImageType::Pointer target = m_JOINImageData->GetJdst()->GetImage(); + + // Create iterators for copying from one to the other + typedef itk::ImageRegionConstIterator SourceIteratorType; + typedef itk::ImageRegionIterator TargetIteratorType; + SourceIteratorType itSource(source,source->GetBufferedRegion()); + TargetIteratorType itTarget(target,source->GetBufferedRegion()); + //SourceIteratorType itSource(source,roi.GetROI()); + //TargetIteratorType itTarget(target,roi.GetROI()); + + // Go through both iterators, copy the new over the old + itSource.GoToBegin(); + itTarget.GoToBegin(); + while(!itSource.IsAtEnd()) + { + itTarget.Set(itSource.Get()); + + ++itSource; + ++itTarget; + } + + // The target has been modified + target->Modified(); + + + InvokeEvent(LayerChangeEvent()); +} + +void +IRISApplication +::ClearJdst() +{ + assert(m_JOINImageData->IsJdstLoaded()); + + ////clear Jdst manually + typedef JdstImageWrapper::ImageType TargetImageType; + + TargetImageType::Pointer target = m_JOINImageData->GetJdst()->GetImage(); + + typedef itk::ImageRegionIterator TargetIteratorType; + TargetIteratorType itTarget(target,target->GetLargestPossibleRegion()); + + itTarget.GoToBegin(); + while(!itTarget.IsAtEnd()) + { + itTarget.Set((LabelType) 0); + ++itTarget; + } + + // The target has been modified + target->Modified(); + + InvokeEvent(LayerChangeEvent()); +} + void IRISApplication ::SetDisplayToAnatomyRAI(const char *rai0,const char *rai1,const char *rai2) @@ -670,6 +788,57 @@ ::UpdateIRISWithSnapImageData(CommandType *progressCommand) target->Modified(); } +void +IRISApplication +::UpdateIRISWithJOINImageData(CommandType *progressCommand) +{ + assert(IsJoinModeActive()); + + ////exchanging pointers (only works if UnloadAll does not unload Join layers) + //m_IRISImageData->SetSegmentationImage(m_JOINImageData->GetJdst()->GetImage()); + ////full copy + // Get pointers to the source and destination images + typedef JdstImageWrapper::ImageType SourceImageType; + typedef LabelImageWrapper::ImageType TargetImageType; + + // If the voxel size of the image does not match the voxel size of the + // main image, we need to resample the region + SourceImageType::Pointer source = m_JOINImageData->GetJdst()->GetImage(); + TargetImageType::Pointer target = m_IRISImageData->GetSegmentation()->GetImage(); + + // Construct are region of interest into which the result will be pasted + SNAPSegmentationROISettings roi = m_GlobalState->GetSegmentationROISettings(); + + // Create iterators for copying from one to the other + typedef itk::ImageRegionConstIterator SourceIteratorType; + typedef itk::ImageRegionIterator TargetIteratorType; + SourceIteratorType itSource(source,source->GetLargestPossibleRegion()); + //SourceIteratorType itSource(source,roi.GetROI()); + TargetIteratorType itTarget(target,roi.GetROI()); + //TargetIteratorType itTarget(target,source->GetLargestPossibleRegion()); + + DrawOverFilter drawover = m_GlobalState->GetDrawOverFilter(); + + // Go through both iterators, copy the new over the old + itSource.GoToBegin(); + itTarget.GoToBegin(); + while(!itSource.IsAtEnd()){ + LabelType pxLabel= itTarget.Get(); + if(drawover.CoverageMode == PAINT_OVER_ALL || + (drawover.CoverageMode == PAINT_OVER_ONE && pxLabel == drawover.DrawOverLabel) || + (drawover.CoverageMode == PAINT_OVER_VISIBLE && pxLabel != 0)) + { + itTarget.Set(itSource.Get()); + } + + ++itSource; + ++itTarget; + } + + // The target has been modified + target->Modified(); +} + void IRISApplication ::SetCursorPosition(const Vector3ui cursor, bool force) @@ -978,9 +1147,6 @@ ::Redo() InvokeEvent(SegmentationChangeEvent()); } - - - void IRISApplication ::ReleaseSNAPImageData() @@ -991,6 +1157,16 @@ ::ReleaseSNAPImageData() m_SNAPImageData->UnloadAll(); } +void +IRISApplication +::ReleaseJOINImageData() +{ + assert(m_JOINImageData->IsMainLoaded() && + m_CurrentImageData != m_JOINImageData); + + m_JOINImageData->UnloadAll(); +} + void IRISApplication ::TransferCursor(GenericImageData *source, GenericImageData *target) @@ -1023,8 +1199,14 @@ ::SetCurrentImageDataToIRIS() assert(m_IRISImageData); if(m_CurrentImageData != m_IRISImageData) { + if(m_CurrentImageData == m_JOINImageData){ + m_CurrentImageData = m_IRISImageData; + TransferCursor(m_JOINImageData, m_IRISImageData); + } + else{ m_CurrentImageData = m_IRISImageData; TransferCursor(m_SNAPImageData, m_IRISImageData); + } InvokeEvent(MainImageDimensionsChangeEvent()); } } @@ -1051,6 +1233,28 @@ ::SetCurrentImageDataToSNAP() } } +void IRISApplication +::SetCurrentImageDataToJOIN() +{ + assert(m_JOINImageData->IsMainLoaded()); + if(m_CurrentImageData != m_JOINImageData) + { + // The cursor needs to be modified to point to the same location + // as before, or to the center of the image + TransferCursor(m_IRISImageData, m_JOINImageData); + + // Set the image data + m_CurrentImageData = m_JOINImageData; + + // Fire the event + InvokeEvent(MainImageDimensionsChangeEvent()); + + // Upon entering this mode, we need set the active tools + m_GlobalState->SetToolbarMode(JOIN_MODE); + m_GlobalState->SetToolbarMode3D(TRACKBALL_MODE); + } +} + size_t IRISApplication ::GetImageDirectionForAnatomicalDirection(AnatomicalDirection iAnat) @@ -1909,6 +2113,20 @@ IRISApplication::CreateSaveDelegateForLayer(ImageWrapperBase *layer, LayerRole r category = "Level Set Image"; } } + else if(role == JOIN_ROLE) + { + if(dynamic_cast(layer)) + { + history = "JsrcImage"; + category = "Join Source Image"; + } + + else if(dynamic_cast(layer)) + { + history = "JdstImage"; + category = "Join Destination Image"; + } + } // Create delegate SmartPtr delegate = DefaultSaveImageDelegate::New(); @@ -2224,6 +2442,11 @@ bool IRISApplication::IsSnakeModeActive() const return (m_CurrentImageData == m_SNAPImageData); } +bool IRISApplication::IsJoinModeActive() const +{ + return (m_CurrentImageData == m_JOINImageData); +} + bool IRISApplication::IsSnakeModeLevelSetActive() const { return IsSnakeModeActive() && m_SNAPImageData->IsSnakeLoaded(); diff --git a/Logic/Framework/IRISApplication.h b/Logic/Framework/IRISApplication.h index 82e433c2..9daaff61 100644 --- a/Logic/Framework/IRISApplication.h +++ b/Logic/Framework/IRISApplication.h @@ -53,6 +53,7 @@ class GenericImageData; class IRISException; class IRISImageData; class SNAPImageData; +class JOINImageData; class MeshExportSettings; class GuidedNativeImageIO; class ThresholdSettings; @@ -117,6 +118,8 @@ class IRISApplication : public itk::Object typedef itk::Image LabelImageType; typedef itk::Image SpeedImageType; + typedef itk::Image JsrcImageType;//why not by #include "JOINImageData.h" ??? + typedef itk::Image JdstImageType;//why not by #include "JOINImageData.h" ??? typedef itk::Command CommandType; typedef UndoDataManager UndoManagerType; @@ -146,6 +149,11 @@ class IRISApplication : public itk::Object */ irisGetMacro(SNAPImageData,SNAPImageData *); + /** + * Get image data related to Join operations + */ + irisGetMacro(JOINImageData,JOINImageData *); + /** * Get the image data currently used */ @@ -161,11 +169,21 @@ class IRISApplication : public itk::Object */ void SetCurrentImageDataToSNAP(); + /** + * Enter the JOIN mode + */ + void SetCurrentImageDataToJOIN(); + /** Whether we are currently in active contour mode or not */ bool IsSnakeModeActive() const; + /** + Whether we are currently in Join mode or not + */ + bool IsJoinModeActive() const; + /** * Whether there is currently a valid level set function */ @@ -255,6 +273,29 @@ class IRISApplication : public itk::Object void InitializeSNAPImageData(const SNAPSegmentationROISettings &roi, CommandType *progressCommand = NULL); + /** + * Initialize JOIN Image data using region of interest extents + */ + void InitializeJOINImageData(const SNAPSegmentationROISettings &roi, + CommandType *progressCommand = NULL); + + /** + * Copy Segmentation to Jsrc for JOIN-mode 0 + */ + void CopySegementationToJsrc(const SNAPSegmentationROISettings &roi, + CommandType *progressCommand = NULL); + + /** + * Copy Segmentation to Jsrc for JOIN-mode 0 + */ + void CopySegementationToJdst(const SNAPSegmentationROISettings &roi, + CommandType *progressCommand = NULL); + + /** + * Clear Jdst for JOIN-mode 0 + */ + void ClearJdst(); + /** Enter given preprocessing mode. This activates the pipeline that can be used to provide automatic on-the-fly preview of the preprocessing result @@ -300,6 +341,12 @@ class IRISApplication : public itk::Object */ void UpdateIRISWithSnapImageData(CommandType *progressCommand = NULL); + /** + * Update IRIS image data with the segmentation contained in the JOIN image + * data. + */ + void UpdateIRISWithJOINImageData(CommandType *progressCommand = NULL); + /** * Get the segmentation label data */ @@ -308,6 +355,9 @@ class IRISApplication : public itk::Object /** Release the SNAP Image data */ void ReleaseSNAPImageData(); + /** Release the JOIN Image data */ + void ReleaseJOINImageData(); + /** Update the display-anatomy mapping as an RAI code */ void SetDisplayToAnatomyRAI(const char *rai0,const char *rai1,const char *rai2); @@ -562,6 +612,7 @@ class IRISApplication : public itk::Object GenericImageData *m_CurrentImageData; SmartPtr m_IRISImageData; SmartPtr m_SNAPImageData; + SmartPtr m_JOINImageData; // Color label data SmartPtr m_ColorLabelTable; diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx new file mode 100644 index 00000000..d1fccc22 --- /dev/null +++ b/Logic/Framework/JOINImageData.cxx @@ -0,0 +1,236 @@ +/*========================================================================= + + Program: ITK-SNAP + Module: $RCSfile: SNAPImageData.cxx,v $ + Language: C++ + Date: $Date: 2011/04/18 17:35:30 $ + Version: $Revision: 1.11 $ + Copyright (c) 2007 Paul A. Yushkevich + + This file is part of ITK-SNAP + + ITK-SNAP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ----- + + Copyright (c) 2003 Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "IRISApplication.h" +#include "JOINImageData.h" + +JOINImageData +::JOINImageData(){ + } + + +JOINImageData +::~JOINImageData(){ + } + +void +JOINImageData +::InitializeJsrc(){ + // The Grey image wrapper should be present + assert(m_MainImageWrapper->IsInitialized()); + + // Intialize Jsrc based on the current grey image + if(m_JsrcWrapper.IsNull()) + { + m_JsrcWrapper = JsrcImageWrapper::New(); + m_JsrcWrapper->SetDefaultNickname("Join Source Image"); + PushBackImageWrapper(JOIN_ROLE, m_JsrcWrapper.GetPointer()); + } + + m_JsrcWrapper->GetDisplayMapping()->SetLabelColorTable(m_Parent->GetColorLabelTable()); + m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (JSRType) 0); + m_JsrcWrapper->SetSticky(true); //overlay, ie no separate tile + m_JsrcWrapper->SetAlpha(0.3); + + InvokeEvent(LayerChangeEvent()); + } + +JsrcImageWrapper* +JOINImageData +::GetJsrc(){ + // Make sure it exists + assert(IsJsrcLoaded()); + return m_JsrcWrapper; + } + +void +JOINImageData +::SetJsrc(JsrcImageType *newJsrcImage){ + ////from ./Logic/Framework/GenericImageData.cxx:244:::SetSegmentationImage + // Check that the image matches the size of the grey image + assert(m_MainImageWrapper->IsInitialized()); + + assert(m_MainImageWrapper->GetBufferedRegion() == + newJsrcImage->GetBufferedRegion()); + + // Pass the image to the wrapper + m_JsrcWrapper->SetImage(newJsrcImage); + + // Sync up spacing between the main and label image + newJsrcImage->SetSpacing(m_MainImageWrapper->GetImageBase()->GetSpacing()); + newJsrcImage->SetOrigin(m_MainImageWrapper->GetImageBase()->GetOrigin()); + } + +bool +JOINImageData +::IsJsrcLoaded(){ + return m_JsrcWrapper && m_JsrcWrapper->IsInitialized(); + } + +void +JOINImageData +::InitializeJdst(){ + assert(IsJsrcLoaded()); + + // If a initialization wrapper does not exist, create it + if(!m_JdstWrapper) + { + m_JdstWrapper = JdstImageWrapper::New(); + m_JdstWrapper->SetDefaultNickname("Join Destination Image"); + PushBackImageWrapper(JOIN_ROLE, m_JdstWrapper.GetPointer()); + } + + m_JdstWrapper->GetDisplayMapping()->SetLabelColorTable(m_Parent->GetColorLabelTable()); + m_JdstWrapper->InitializeToWrapper(m_MainImageWrapper, (LabelType) 0); + m_JdstWrapper->SetSticky(false); + m_JdstWrapper->SetAlpha(0.5); + + InvokeEvent(LayerChangeEvent()); + } + +JdstImageWrapper* +JOINImageData +::GetJdst(){ + assert(IsJdstLoaded()); + return m_JdstWrapper; + } + +bool +JOINImageData +::IsJdstLoaded() +{ + return (m_JdstWrapper && m_JdstWrapper->IsInitialized()); +} + +void +JOINImageData +::InitializeToROI(GenericImageData *source, + const SNAPSegmentationROISettings &roi, + itk::Command *progressCommand){ + // Get the source grey wrapper + AnatomicImageWrapper *srcWrapper = source->GetMain(); + + // Get the roi chunk from the grey image + SmartPtr imgNew = + srcWrapper->DeepCopyRegion(roi, progressCommand); //only roi of grey + //source->GetMain()->GetImage(); //full grey, only roi GWS processed + + // Get the size of the region + Vector3ui size = imgNew->GetLargestPossibleRegion().GetSize(); + + // Compute an image coordinate geometry for the region of interest + std::string rai[] = { + this->m_Parent->GetDisplayToAnatomyRAI(0), + this->m_Parent->GetDisplayToAnatomyRAI(1), + this->m_Parent->GetDisplayToAnatomyRAI(2) }; + ImageCoordinateGeometry icg( + source->GetImageGeometry().GetImageDirectionCosineMatrix(), + rai, size); + + // Assign the new wrapper to the target + this->SetMainImage(imgNew, icg, srcWrapper->GetNativeMapping()); + + // Copy metadata + this->CopyLayerMetadata(this->GetMain(), source->GetMain()); + + // Repeat all of this for the overlays + for(LayerIterator lit = source->GetLayers(OVERLAY_ROLE); + !lit.IsAtEnd(); ++lit) + { + // Cast the layer to anatomic image wrapper type + AnatomicImageWrapper *ovlWrapper = + dynamic_cast(lit.GetLayer()); + + assert(ovlWrapper); + + // Create a copy of the layer for the requested ROI + SmartPtr ovlNew = ovlWrapper->DeepCopyRegion(roi, progressCommand); + + // Add the overlay + this->AddOverlay(ovlNew, ovlWrapper->GetNativeMapping()); + + // Copy metadata + this->CopyLayerMetadata(this->GetLastOverlay(), ovlWrapper); + } + } + +void JOINImageData::CopyLayerMetadata( + ImageWrapperBase *target, ImageWrapperBase *source){ + // Nickname + target->SetDefaultNickname(source->GetNickname()); + + // This is a little bit of overhead, but not enough to be a big deal: + // we just save the display mapping to a Registry and then restore it + // in the target wrapper. + Registry folder; + source->GetDisplayMapping()->Save(folder); + target->GetDisplayMapping()->Restore(folder); + + // Threshold settings. These should be copied for each scalar component + if(source->IsScalar()) + { + target->SetUserData("ThresholdSettings", source->GetUserData("ThresholdSettings")); + } + else + { + // Copy threshold settings for all the scalar components + VectorImageWrapperBase *v_source = dynamic_cast(source); + VectorImageWrapperBase *v_target = dynamic_cast(target); + + for(ScalarRepresentationIterator it(v_source); !it.IsAtEnd(); ++it) + { + ImageWrapperBase *c_source = v_source->GetScalarRepresentation(it); + ImageWrapperBase *c_target = v_target->GetScalarRepresentation(it); + c_target->SetUserData("ThresholdSettings", c_source->GetUserData("ThresholdSettings")); + } + } + + // TODO: alpha, stickiness? + } + +void JOINImageData::UnloadAll(){ + // Unload all the data + this->UnloadOverlays(); + this->UnloadMainImage(); //do not unload if Main just points to IRIS-Main!!! + + // We need to unload all the JOIN layers + while(this->m_Wrappers[JOIN_ROLE].size()) + PopBackImageWrapper(JOIN_ROLE); + m_JsrcWrapper = NULL; + m_JdstWrapper = NULL; + + InvokeEvent(LayerChangeEvent()); + } + diff --git a/Logic/Framework/JOINImageData.h b/Logic/Framework/JOINImageData.h new file mode 100644 index 00000000..2bd93ae9 --- /dev/null +++ b/Logic/Framework/JOINImageData.h @@ -0,0 +1,102 @@ +/*========================================================================= + + Program: ITK-SNAP + Module: $RCSfile: SNAPImageData.h,v $ + Language: C++ + Date: $Date: 2009/01/23 20:09:38 $ + Version: $Revision: 1.4 $ + Copyright (c) 2007 Paul A. Yushkevich + + This file is part of ITK-SNAP + + ITK-SNAP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ----- + + Copyright (c) 2003 Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __JOINImageData_h_ +#define __JOINImageData_h_ + +#include "SNAPCommon.h" + +#include "GenericImageData.h" +#include "itkImageAdaptor.h" + +/** + * \class JOINImageData + * \brief Wrapper around the JOIN automatic segmentation pipelines. + * + * This class encapsulates several images used in the JOIN application + */ +class JOINImageData : public GenericImageData +{ +public: + irisITKObjectMacro(JOINImageData, GenericImageData) + + // The type of the internal level set image + typedef Superclass::AnatomicImageType AnatomicImageType; + typedef JsrcImageWrapper::ImageType JsrcImageType; + typedef JdstImageWrapper::ImageType JdstImageType; + + /** Initialize to a ROI from another image data object */ + void InitializeToROI(GenericImageData *source, + const SNAPSegmentationROISettings &roi, + itk::Command *progressCommand); + + /** Copy nickname, settings, and other such junk from IRIS to SNAP during + * initialization */ + void CopyLayerMetadata(ImageWrapperBase *target, ImageWrapperBase *source); + + /** + Unload all images in the JOIN image data, releasing memory and returning + this object to initial state. + */ + void UnloadAll(); + + void InitializeJsrc(); + JsrcImageWrapper* GetJsrc(); + void SetJsrc(JsrcImageType *newJsrcImage); + bool IsJsrcLoaded(); + + + void InitializeJdst(); + JdstImageWrapper* GetJdst(); + bool IsJdstLoaded(); + +protected: + + JOINImageData(); + ~JOINImageData(); + + // Speed image adata + SmartPtr m_JsrcWrapper; + + // Wrapper around the level set image + SmartPtr m_JdstWrapper; +}; + + + + + + + +#endif diff --git a/Logic/Framework/LayerAssociation.txx b/Logic/Framework/LayerAssociation.txx index dbf5f320..ae6d10bd 100644 --- a/Logic/Framework/LayerAssociation.txx +++ b/Logic/Framework/LayerAssociation.txx @@ -6,6 +6,7 @@ #include "GenericImageData.h" #include "IRISImageData.h" #include "SNAPImageData.h" +#include "JOINImageData.h" #include "ImageWrapperBase.h" template @@ -36,9 +37,10 @@ LayerAssociation { // Iterate over all of the image data objects in IRISApplication GenericImageData *id[] = {m_Source->GetIRISImageData(), + m_Source->GetJOINImageData(), m_Source->GetSNAPImageData()}; - for(int k = 0; k < 2; k++) + for(int k = 0; k < 3; k++) { if(id[k]) { diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.cxx b/Logic/ImageWrapper/DisplayMappingPolicy.cxx index 8895050d..4bb4a28d 100644 --- a/Logic/ImageWrapper/DisplayMappingPolicy.cxx +++ b/Logic/ImageWrapper/DisplayMappingPolicy.cxx @@ -948,6 +948,7 @@ ::Restore(Registry &folder) template class ColorLabelTableDisplayMappingPolicy; +template class ColorLabelTableDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; diff --git a/Logic/ImageWrapper/ImageWrapper.cxx b/Logic/ImageWrapper/ImageWrapper.cxx index c4f77bcd..34b24e77 100644 --- a/Logic/ImageWrapper/ImageWrapper.cxx +++ b/Logic/ImageWrapper/ImageWrapper.cxx @@ -1273,6 +1273,7 @@ ::DeepCopyRegion(const SNAPSegmentationROISettings &roi, template class ImageWrapper; template class ImageWrapper; template class ImageWrapper; +template class ImageWrapper; template class ImageWrapper, VectorImageWrapperBase>; template class ImageWrapper, ScalarImageWrapperBase>; diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index 527d0e33..3a9738a3 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -51,6 +51,29 @@ class LabelImageWrapperTraits itkStaticConstMacro(PipelineOutput, bool, false); }; +class JsrcImageWrapperTraits +{ +public: + typedef JsrcImageWrapperTraits Self; + + typedef ScalarImageWrapper WrapperType; + + typedef JSRType ComponentType; + typedef itk::Image ImageType; + + typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping; + typedef ColorLabelTableDisplayMappingPolicy DisplayMapping; + typedef NullScalarImageWrapperCommonRepresentation CommonRepresentationPolicy; + + //itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_GREY); + + // Whether this image is shown on top of all other layers by default + itkStaticConstMacro(StickyByDefault, bool, false); + + // Whether this image is produced from another by a pipeline (e.g., speed image) + itkStaticConstMacro(PipelineOutput, bool, true); +}; + class SpeedImageWrapperTraits { public: @@ -194,6 +217,9 @@ typedef VectorDerivedQuantityImageWrapperTraits typedef AnatomicImageWrapperTraits::WrapperType AnatomicImageWrapper; typedef LabelImageWrapperTraits::WrapperType LabelImageWrapper; typedef SpeedImageWrapperTraits::WrapperType SpeedImageWrapper; +//typedef JsrcImageWrapperTraits::WrapperType JsrcImageWrapper; +typedef LabelImageWrapperTraits::WrapperType JsrcImageWrapper; +typedef LabelImageWrapperTraits::WrapperType JdstImageWrapper; typedef LevelSetImageWrapperTraits::WrapperType LevelSetImageWrapper; diff --git a/Logic/ImageWrapper/ScalarImageWrapper.cxx b/Logic/ImageWrapper/ScalarImageWrapper.cxx index d4c23a6e..7e9dbf36 100644 --- a/Logic/ImageWrapper/ScalarImageWrapper.cxx +++ b/Logic/ImageWrapper/ScalarImageWrapper.cxx @@ -322,6 +322,7 @@ ::GetHistogram(size_t nBins) template class ScalarImageWrapper; template class ScalarImageWrapper; template class ScalarImageWrapper; +template class ScalarImageWrapper; template class ScalarImageWrapper< ComponentImageWrapperTraits >; typedef VectorDerivedQuantityImageWrapperTraits MagTraits; From 6664d248e5134de5d3c70f597ac5e69d6a799996 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Fri, 10 Oct 2014 12:49:57 +0200 Subject: [PATCH 02/42] Added copy+clear segmentation for GWS; debugged IRISApplication::CopySegementationToJdst --- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 19 ++++++++++++++++ GUI/Qt/Components/GlobalWSWizardPanel.h | 4 ++++ GUI/Qt/Components/GlobalWSWizardPanel.ui | 27 ++++++++++++----------- Logic/Framework/IRISApplication.cxx | 6 ++--- todo | 12 ++++++++++ 5 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 todo diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index 4939ab75..84c42abe 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -102,6 +102,9 @@ void GlobalWSWizardPanel::SetModel(GlobalUIModel *model){ // Store and pass on the models m_ParentModel = model; m_Model = model->GetGlobalWSWizardModel(); + + activateOnFlag(ui->btnCopySeg, m_ParentModel, UIF_JOIN_MODE); + activateOnFlag(ui->btnClearSeg, m_ParentModel, UIF_JOIN_MODE); } void GlobalWSWizardPanel::Initialize(){ @@ -219,3 +222,19 @@ void GlobalWSWizardPanel::on_actionDecreaseWSLevel_triggered(){ ui->inWSLevel->setValue(value); emit ui->inWSLevel->spinnerValueChanged(value); } + +void GlobalWSWizardPanel::on_btnCopySeg_clicked(){ + IRISApplication *driver = m_ParentModel->GetDriver(); + driver->CopySegementationToJdst( + driver->GetGlobalState()->GetSegmentationROISettings(), + m_ParentModel->GetProgressCommand()); + + driver->InvokeEvent(SegmentationChangeEvent()); + } + +void GlobalWSWizardPanel::on_btnClearSeg_clicked(){ + IRISApplication *driver = m_ParentModel->GetDriver(); + driver->ClearJdst(); + + driver->InvokeEvent(SegmentationChangeEvent()); + } diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.h b/GUI/Qt/Components/GlobalWSWizardPanel.h index 1c6cf9e7..ef3837d0 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.h +++ b/GUI/Qt/Components/GlobalWSWizardPanel.h @@ -56,6 +56,10 @@ private slots: void on_actionDecreaseWSLevel_triggered(); + void on_btnCopySeg_clicked(); + + void on_btnClearSeg_clicked(); + private: GlobalUIModel *m_ParentModel; diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.ui b/GUI/Qt/Components/GlobalWSWizardPanel.ui index 1a548eee..02894858 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.ui +++ b/GUI/Qt/Components/GlobalWSWizardPanel.ui @@ -396,19 +396,6 @@ p, li { white-space: pre-wrap; }
- - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -737,6 +724,20 @@ p, li { white-space: pre-wrap; } + + + + Copy Segmentation + + + + + + + Clear Segmentation + + + diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index dbcc1df9..0b8c0e76 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -313,9 +313,9 @@ ::CopySegementationToJdst(const SNAPSegmentationROISettings &roi, // Create iterators for copying from one to the other typedef itk::ImageRegionConstIterator SourceIteratorType; typedef itk::ImageRegionIterator TargetIteratorType; - SourceIteratorType itSource(source,source->GetBufferedRegion()); - TargetIteratorType itTarget(target,source->GetBufferedRegion()); - //SourceIteratorType itSource(source,roi.GetROI()); + //SourceIteratorType itSource(source,source->GetBufferedRegion()); + TargetIteratorType itTarget(target,target->GetBufferedRegion()); + SourceIteratorType itSource(source,roi.GetROI()); //TargetIteratorType itTarget(target,roi.GetROI()); // Go through both iterators, copy the new over the old diff --git a/todo b/todo new file mode 100644 index 00000000..6dda1339 --- /dev/null +++ b/todo @@ -0,0 +1,12 @@ +TODOs for GWS: + +- add copy/clear segmentation for GWS +- add image+layer for adf output +- add relabeller if itk::watershed::Relabeler does not relabel consecutively +- add 'n' for next smallest unused label +- make UnDo possible +- impl. connected component relabeling +- make long long for GWS possible +- """ for image from file +- make GUI parts more fool prove +- add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData From 41de5b1aa258e7605c8df1e2b44b3767cfa44f22 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 14 Oct 2014 13:47:50 +0200 Subject: [PATCH 03/42] Added code to set LAYOUT_TILED for CnJ and GWS to ease understanding of the interaction modes --- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 4 ++++ GUI/Qt/Components/JoinDataPanel.cxx | 4 ++++ todo | 9 ++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index 84c42abe..af9b1bee 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -13,6 +13,7 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann #include "IRISApplication.h" #include "GenericImageData.h" #include "JOINImageData.h" +#include "DisplayLayoutModel.h" //access tiled/stacked view mode #include #include @@ -111,6 +112,9 @@ void GlobalWSWizardPanel::Initialize(){ // Initialize the model m_Model->OnGlobalWSModeEnter(); + // set tiled layout to ease understanding the interaction mode + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); + // Go to the right page ui->stack->setCurrentWidget(ui->pgPreproc); } diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index 35992262..6c4d362d 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -12,6 +12,7 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann #include "IRISApplication.h" #include "GenericImageData.h" //GetCurrentImageData()->GetImageRegion(); #include "QtWidgetActivator.h" //activateOnFlag +#include "DisplayLayoutModel.h" //access tiled/stacked view mode JoinDataPanel::JoinDataPanel(QWidget *parent) : @@ -64,6 +65,9 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ driver->GetGlobalState()->GetSegmentationROISettings(), m_Model->GetProgressCommand()); driver->SetCurrentImageDataToJOIN(); + + // set tiled layout to ease understanding the interaction mode + m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); } break; case 1:{ ////panel will be hidden in GWSJOIN_MODE diff --git a/todo b/todo index 6dda1339..c86c2dd0 100644 --- a/todo +++ b/todo @@ -1,12 +1,19 @@ TODOs for GWS: -- add copy/clear segmentation for GWS - add image+layer for adf output - add relabeller if itk::watershed::Relabeler does not relabel consecutively - add 'n' for next smallest unused label - make UnDo possible +- add functionality to all buttons, e.g. back +- destinguish RMB click from RMB drag (zoom) - impl. connected component relabeling - make long long for GWS possible - """ for image from file - make GUI parts more fool prove - add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData + + + +done: + +- add copy/clear segmentation for GWS From b48eabc116408600bc9c30e343b95cafc4e2e2e3 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 4 Nov 2014 11:20:12 +0100 Subject: [PATCH 04/42] First commit for dWS (applied itksnap-3.0.0_dynWS+direct_09.diff) --- GUI/Model/PaintbrushModel.cxx | 137 ++++++++++++++++++---- GUI/Model/PaintbrushModel.h | 10 ++ GUI/Model/PaintbrushSettingsModel.cxx | 6 +- GUI/Model/PaintbrushSettingsModel.h | 3 + GUI/Qt/Components/PaintbrushToolPanel.cxx | 1 + GUI/Qt/Components/PaintbrushToolPanel.ui | 15 ++- GUI/Qt/View/PaintbrushInteractionMode.cxx | 15 +++ GUI/Qt/View/PaintbrushInteractionMode.h | 2 + Logic/Framework/GlobalState.cxx | 1 + Logic/Framework/GlobalState.h | 1 + 10 files changed, 162 insertions(+), 29 deletions(-) diff --git a/GUI/Model/PaintbrushModel.cxx b/GUI/Model/PaintbrushModel.cxx index 9a11a9c8..8f4d84fa 100644 --- a/GUI/Model/PaintbrushModel.cxx +++ b/GUI/Model/PaintbrushModel.cxx @@ -30,7 +30,6 @@ class BrushWatershedPipeline gmf = GMFType::New(); gmf->SetInput(adf->GetOutput()); wf = WFType::New(); - wf->SetInput(gmf->GetOutput()); } void PrecomputeWatersheds( @@ -38,39 +37,55 @@ class BrushWatershedPipeline LabelImageType *label, itk::ImageRegion<3> region, itk::Index<3> vcenter, - size_t smoothing_iter) + size_t smoothing_iter, + bool direct) { - this->region = region; + this->m_region = region; // Get the offset of vcenter in the region - if(region.IsInside(vcenter)) + // if(m_region.IsInside(vcenter)) + // for(size_t d = 0; d < 3; d++) + // this->vcenter[d] = vcenter[d] - m_region.GetIndex()[d]; + // else for(size_t d = 0; d < 3; d++) - this->vcenter[d] = vcenter[d] - region.GetIndex()[d]; - else - for(size_t d = 0; d < 3; d++) - this->vcenter[d] = region.GetSize()[d] / 2; + this->vcenter[d] = m_region.GetSize()[d] / 2; // Create a backup of the label image LROIType::Pointer lroi = LROIType::New(); lroi->SetInput(label); - lroi->SetRegionOfInterest(region); + lroi->SetRegionOfInterest(m_region); lroi->Update(); - lsrc = lroi->GetOutput(); + lsrc= lroi->GetOutput(); lsrc->DisconnectPipeline(); // Initialize the watershed pipeline roi->SetInput(grey); - roi->SetRegionOfInterest(region); + roi->SetRegionOfInterest(m_region); adf->SetNumberOfIterations(smoothing_iter); + if(direct) + wf->SetInput(adf->GetOutput()); + else + wf->SetInput(gmf->GetOutput()); // Set the initial level to lowest possible - to get all watersheds wf->SetLevel(1.0); wf->Update(); } +void RecomputeLabelBackup(LabelImageType *label)//, itk::ImageRegion<3> region) + { + // Create a backup of the label image + LROIType::Pointer lroi = LROIType::New(); + lroi->SetInput(label); + lroi->SetRegionOfInterest(m_region); + lroi->Update(); + lsrc= lroi->GetOutput(); + lsrc->DisconnectPipeline(); + } + void RecomputeWatersheds(double level) { - // Reupdate the filter with new level + // Reupdate the filter with new level if a precomputed input already exists for this view wf->SetLevel(level); wf->Update(); } @@ -100,7 +115,7 @@ class BrushWatershedPipeline typedef itk::ImageRegionIterator LIter; WIter wit(wf->GetOutput(), wf->GetOutput()->GetBufferedRegion()); LIter sit(lsrc, lsrc->GetBufferedRegion()); - LIter tit(ltrg, region); + LIter tit(ltrg, m_region); for(; !wit.IsAtEnd(); ++sit,++tit,++wit) { LabelType pxLabel = sit.Get(); @@ -138,7 +153,7 @@ class BrushWatershedPipeline GMFType::Pointer gmf; WFType::Pointer wf; - itk::ImageRegion<3> region; + itk::ImageRegion<3> m_region; LabelImageType::Pointer lsrc; itk::Index<3> vcenter; }; @@ -152,6 +167,7 @@ PaintbrushModel::PaintbrushModel() { m_ReverseMode = false; m_Watershed = new BrushWatershedPipeline(); + m_PrecomputedWS= false; } PaintbrushModel::~PaintbrushModel() @@ -239,6 +255,49 @@ bool PaintbrushModel::TestInside(const Vector3d &x, const PaintbrushSettings &ps } } +bool //returns false if no voxel changed, this should not be used to accept the wheel event! +PaintbrushModel +::ProcessWheelEvent(int delta) + { + + ////Event is only issued if mouse is inside the view, however each view has its own watershed pipeline! The region is only needed in PrecomputeWatersheds for the WS input. So just keep the input for any reordering and do nothing if there is no precomputed input. + + ////return if there is no precomp WS + if(!m_PrecomputedWS) + return false; + + // Get the paintbrush properties (TODO: should we own them?) + PaintbrushSettings pbs = + m_Parent->GetDriver()->GetGlobalState()->GetPaintbrushSettings(); + + ////inc./dec. level by 1% depending on wheel direction + if(delta > 0){ + m_level+= 0.01; + if(m_level > 1) + m_level= 1.0; + } + else{ + m_level-= 0.01; + if(m_level < 0) + m_level= 0.0; + } + m_Parent->GetDriver()->GetGlobalState()->SetPaintbrushSettings(pbs); + + if(pbs.mode == PAINTBRUSH_WATERSHED) + { + fprintf(stderr, "Regrouping watersheds! (view %d, level %f)\n", m_Parent->GetId(), m_level); + ////Update the brush state + if(UpdateBrush()){ + ////tell the GUI to repaint the segmentation and that the 3D view can be updated + m_Parent->GetDriver()->StoreUndoPoint("Dynamic Granularity change"); + m_Parent->GetDriver()->InvokeEvent(SegmentationChangeEvent()); + return true; + } + } + ////do not use event for cursor chasing, but for GUI hint + return false; + } + bool PaintbrushModel ::ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode) @@ -249,6 +308,7 @@ ::ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode) // Compute the mouse position ComputeMousePosition(xSlice); + m_level= pbs.watershed.level; // Check if the right button was pressed ApplyBrush(reverse_mode, false); @@ -323,6 +383,13 @@ bool PaintbrushModel::ProcessMouseMoveEvent(const Vector3f &xSlice) return true; } +// bool PaintbrushModel::ProcessMouseEnterEvent() +// { +// if(m_PrecomputedWS == false) +// return false; +// m_Watershed->RecomputeLabelBackup(m_Parent->GetDriver()->GetCurrentImageData()->GetSegmentation()->GetImage()); +// return true; +// } bool PaintbrushModel::ProcessMouseLeaveEvent() { @@ -374,6 +441,7 @@ PaintbrushModel::ApplyBrush(bool reverse_mode, bool dragging) // Crop the region by the buffered region xTestRegion.Crop(imgLabel->GetImage()->GetBufferedRegion()); + m_OldxTestRegion= xTestRegion; // Flag to see if anything was changed bool flagUpdate = false; @@ -383,13 +451,17 @@ PaintbrushModel::ApplyBrush(bool reverse_mode, bool dragging) { GenericImageData *gid = driver->GetCurrentImageData(); + fprintf(stderr, "Precomputing watersheds! (view %d, level %f)\n", m_Parent->GetId(), m_level); // Precompute the watersheds m_Watershed->PrecomputeWatersheds( gid->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(), - driver->GetCurrentImageData()->GetSegmentation()->GetImage(), - xTestRegion, to_itkIndex(m_MousePosition), pbs.watershed.smooth_iterations); + imgLabel->GetImage(), + xTestRegion, to_itkIndex(m_MousePosition), pbs.watershed.smooth_iterations, pbs.direct); + + m_Watershed->RecomputeWatersheds(m_level); + m_PrecomputedWS= true; + return m_Watershed->UpdateLabelImage(imgLabel->GetImage(), gs->GetDrawOverFilter().CoverageMode, gs->GetDrawingColorLabel(), gs->GetDrawOverFilter().DrawOverLabel); - m_Watershed->RecomputeWatersheds(pbs.watershed.level); } // Shift vector (different depending on whether the brush has odd/even diameter @@ -414,13 +486,13 @@ PaintbrushModel::ApplyBrush(bool reverse_mode, bool dragging) continue; // Check if the pixel is in the watershed - if(flagWatershed) - { - LabelImageWrapper::ImageType::IndexType idxoff = to_itkIndex( - Vector3l(idx.GetIndex()) - Vector3l(xTestRegion.GetIndex().GetIndex())); - if(!m_Watershed->IsPixelInSegmentation(idxoff)) - continue; - } + // if(flagWatershed) + // { + // LabelImageWrapper::ImageType::IndexType idxoff = to_itkIndex( + // Vector3l(idx.GetIndex()) - Vector3l(xTestRegion.GetIndex().GetIndex())); + // if(!m_Watershed->IsPixelInSegmentation(idxoff)) + // continue; + // } // Paint the pixel LabelType pxLabel = it.Get(); @@ -461,6 +533,23 @@ PaintbrushModel::ApplyBrush(bool reverse_mode, bool dragging) return flagUpdate; } +bool +PaintbrushModel::UpdateBrush() + { + // Get the global objects + IRISApplication *driver = m_Parent->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + + // Get the segmentation image + LabelImageWrapper *imgLabel = driver->GetCurrentImageData()->GetSegmentation(); + + // Get the paintbrush properties + PaintbrushSettings pbs = gs->GetPaintbrushSettings(); + + m_Watershed->RecomputeWatersheds(m_level); + + return m_Watershed->UpdateLabelImage(imgLabel->GetImage(), gs->GetDrawOverFilter().CoverageMode, gs->GetDrawingColorLabel(), gs->GetDrawOverFilter().DrawOverLabel); + } Vector3f PaintbrushModel::GetCenterOfPaintbrushInSliceSpace() { diff --git a/GUI/Model/PaintbrushModel.h b/GUI/Model/PaintbrushModel.h index 6d3c09b1..d5faea47 100644 --- a/GUI/Model/PaintbrushModel.h +++ b/GUI/Model/PaintbrushModel.h @@ -3,6 +3,7 @@ #include "AbstractModel.h" #include "GlobalState.h" +#include "GenericImageData.h" //contains def. of LabelImageWrapper class GenericSliceModel; class BrushWatershedPipeline; @@ -22,11 +23,13 @@ class PaintbrushModel : public AbstractModel FIRES(PaintbrushMovedEvent) + bool ProcessWheelEvent(int delta); bool ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode); bool ProcessDragEvent(const Vector3f &xSlice, const Vector3f &xSliceLast, double pixelsMoved, bool release); bool ProcessMouseMoveEvent(const Vector3f &xSlice); + //bool ProcessMouseEnterEvent(); bool ProcessMouseLeaveEvent(); // Get the location in slice coordinates where the center of the paintbrush @@ -43,6 +46,12 @@ class PaintbrushModel : public AbstractModel Vector3ui m_MousePosition; bool m_MouseInside; + //for WS updates + double m_level; + bool m_PrecomputedWS; + Vector3f m_offset; + LabelImageWrapper::ImageType::RegionType m_OldxTestRegion; + // Mouse position in slice coordinates from which we need to draw the // next segment Vector3f m_LastApplyX; @@ -54,6 +63,7 @@ class PaintbrushModel : public AbstractModel void ComputeMousePosition(const Vector3f &xSlice); bool ApplyBrush(bool reverse_mode, bool dragging); + bool UpdateBrush(); bool TestInside(const Vector2d &x, const PaintbrushSettings &ps); bool TestInside(const Vector3d &x, const PaintbrushSettings &ps); diff --git a/GUI/Model/PaintbrushSettingsModel.cxx b/GUI/Model/PaintbrushSettingsModel.cxx index 6785a21c..606e6e07 100644 --- a/GUI/Model/PaintbrushSettingsModel.cxx +++ b/GUI/Model/PaintbrushSettingsModel.cxx @@ -26,6 +26,10 @@ PaintbrushSettingsModel::PaintbrushSettingsModel() wrapStructMemberAsSimpleProperty( m_PaintbrushSettingsModel, offsetof(PaintbrushSettings, chase)); + m_DirecWSModel = + wrapStructMemberAsSimpleProperty( + m_PaintbrushSettingsModel, offsetof(PaintbrushSettings, direct)); + // The paintbrush size model requires special processing, so it is implemeted // using a getter/setter pair m_BrushSizeModel = wrapGetterSetterPairAsProperty( @@ -70,7 +74,7 @@ ::GetBrushSizeValueAndRange(int &value, NumericValueRange *domain) // Round just in case value = (int) (pbs.radius * 2 + 0.5); if(domain) - domain->Set(1, 40, 1); + domain->Set(1, 1000, 1); return true; } diff --git a/GUI/Model/PaintbrushSettingsModel.h b/GUI/Model/PaintbrushSettingsModel.h index bdb24196..7e02f8d9 100644 --- a/GUI/Model/PaintbrushSettingsModel.h +++ b/GUI/Model/PaintbrushSettingsModel.h @@ -25,6 +25,7 @@ class PaintbrushSettingsModel : public AbstractModel irisGetMacro(ChaseCursorModel, AbstractSimpleBooleanProperty *) irisGetMacro(AdaptiveModeModel, AbstractSimpleBooleanProperty *) + irisGetMacro(DirecWSModel, AbstractSimpleBooleanProperty *) irisGetMacro(ThresholdLevelModel, AbstractRangedDoubleProperty *) irisGetMacro(SmoothingIterationsModel, AbstractRangedIntProperty *) @@ -53,6 +54,8 @@ class PaintbrushSettingsModel : public AbstractModel SmartPtr m_AdaptiveModeModel; bool GetAdaptiveModeValue(bool &value); + SmartPtr m_DirecWSModel; + SmartPtr m_ThresholdLevelModel; bool GetThresholdLevelValueAndRange(double &value, NumericValueRange *domain); void SetThresholdLevelValue(double value); diff --git a/GUI/Qt/Components/PaintbrushToolPanel.cxx b/GUI/Qt/Components/PaintbrushToolPanel.cxx index 5a3f67ce..1d4535c1 100644 --- a/GUI/Qt/Components/PaintbrushToolPanel.cxx +++ b/GUI/Qt/Components/PaintbrushToolPanel.cxx @@ -55,4 +55,5 @@ void PaintbrushToolPanel::SetModel(PaintbrushSettingsModel *model) makeCoupling(ui->inGranularity, model->GetThresholdLevelModel()); makeCoupling(ui->inSmoothness, model->GetSmoothingIterationsModel()); + makeCoupling(ui->chkDirect, model->GetDirecWSModel()); } diff --git a/GUI/Qt/Components/PaintbrushToolPanel.ui b/GUI/Qt/Components/PaintbrushToolPanel.ui index 54e0fc63..20ed8f75 100644 --- a/GUI/Qt/Components/PaintbrushToolPanel.ui +++ b/GUI/Qt/Components/PaintbrushToolPanel.ui @@ -310,7 +310,7 @@ font-size: 11px; 0 - + Granularity: @@ -320,14 +320,14 @@ font-size: 11px; - + <html><head/><body><p>Lower values of this parameter lead to oversegmentation, while higher values lead to undersegmentation. </p></body></html> - + Smoothness: @@ -337,13 +337,20 @@ font-size: 11px; - + <html><head/><body><p>Larger values of this parameter produce smoother segments.</p></body></html> + + + + direct + + + diff --git a/GUI/Qt/View/PaintbrushInteractionMode.cxx b/GUI/Qt/View/PaintbrushInteractionMode.cxx index 44bb2820..98cc133b 100644 --- a/GUI/Qt/View/PaintbrushInteractionMode.cxx +++ b/GUI/Qt/View/PaintbrushInteractionMode.cxx @@ -27,6 +27,20 @@ ::SetModel(PaintbrushModel *model) SetParentModel(model->GetParent()); } +void PaintbrushInteractionMode::wheelEvent(QWheelEvent *ev) + { + ////catch wheel event if CTRL is pressed, otherwise pass it to slice scroll + Qt::KeyboardModifiers modifiers = ev->modifiers(); + if(modifiers.testFlag( Qt::ControlModifier )){ + ///accept event even if no voxel changed (i.e. not every level causes a WS change!) + //if(m_Model->ProcessWheelEvent(ev->delta())){ + m_Model->ProcessWheelEvent(ev->delta()); + ////do not pass event to cursor chasing + ev->accept(); + //} + } + } + void PaintbrushInteractionMode::mousePressEvent(QMouseEvent *ev) { bool isleft = (ev->button() == Qt::LeftButton); @@ -73,6 +87,7 @@ void PaintbrushInteractionMode::enterEvent(QEvent *) // TODO: this is hideous! SliceViewPanel *panel = dynamic_cast(m_ParentView->parent()); panel->SetMouseMotionTracking(true); + //m_Model->ProcessMouseEnterEvent(); } void PaintbrushInteractionMode::leaveEvent(QEvent *) diff --git a/GUI/Qt/View/PaintbrushInteractionMode.h b/GUI/Qt/View/PaintbrushInteractionMode.h index 5bd41bf1..2e8980f0 100644 --- a/GUI/Qt/View/PaintbrushInteractionMode.h +++ b/GUI/Qt/View/PaintbrushInteractionMode.h @@ -3,6 +3,7 @@ #include #include +#include class GenericSliceModel; class GenericSliceView; @@ -23,6 +24,7 @@ class PaintbrushInteractionMode : public SliceWindowInteractionDelegateWidget irisGetMacro(Renderer, PaintbrushRenderer *) + void wheelEvent(QWheelEvent *ev); void mousePressEvent(QMouseEvent *ev); void mouseMoveEvent(QMouseEvent *ev); void mouseReleaseEvent(QMouseEvent *ev); diff --git a/Logic/Framework/GlobalState.cxx b/Logic/Framework/GlobalState.cxx index 97c8a038..3fe2da6f 100644 --- a/Logic/Framework/GlobalState.cxx +++ b/Logic/Framework/GlobalState.cxx @@ -88,6 +88,7 @@ ::GlobalState() m_PaintbrushSettings.volumetric = false; m_PaintbrushSettings.isotropic = false; m_PaintbrushSettings.chase = false; + m_PaintbrushSettings.direct = false; m_PaintbrushSettings.watershed.level = 0.2; m_PaintbrushSettings.watershed.smooth_iterations = 15; diff --git a/Logic/Framework/GlobalState.h b/Logic/Framework/GlobalState.h index 29002fa1..28a0200f 100644 --- a/Logic/Framework/GlobalState.h +++ b/Logic/Framework/GlobalState.h @@ -153,6 +153,7 @@ struct PaintbrushSettings bool volumetric; bool isotropic; bool chase; + bool direct; PaintbrushWatershedSettings watershed; }; From f60ab32221f357f1a7b8311cc8f7c1dbac243666 Mon Sep 17 00:00:00 2001 From: "Dr. Roman Grothausmann" Date: Sun, 30 Nov 2014 21:54:15 +0100 Subject: [PATCH 05/42] modifications for transit for Jsrc from LabelType to GWSType --- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 8 ++--- Logic/Framework/IRISApplication.cxx | 37 ++++++++++++++++++----- Logic/ImageWrapper/ImageWrapperTraits.h | 3 +- todo | 8 ++--- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index af9b1bee..6bb8bf12 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -24,7 +24,7 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann class WatershedPipeline{ public: typedef itk::Image GreyImageType; - typedef itk::Image LabelImageType; + typedef itk::Image JsrcImageType; typedef itk::Image FloatImageType; typedef itk::Image WatershedImageType; @@ -37,7 +37,7 @@ class WatershedPipeline{ cif->SetInput(wf->GetOutput()); } - LabelImageType* PrecomputeWatersheds( + JsrcImageType* PrecomputeWatersheds( GreyImageType *grey, double cParam, size_t sIter, double iThr, double iLevel, @@ -70,7 +70,7 @@ class WatershedPipeline{ typedef itk::GradientAnisotropicDiffusionImageFilter ADFType; typedef itk::GradientMagnitudeImageFilter GMFType; typedef itk::WatershedImageFilter WFType; - typedef itk::CastImageFilter CIFType; + typedef itk::CastImageFilter CIFType; ADFType::Pointer adf; GMFType::Pointer gmf; @@ -159,7 +159,7 @@ void GlobalWSWizardPanel::on_btnWSRangeNext_clicked(){ // Handle cursor QtCursorOverride curse(Qt::WaitCursor); - driver->GetJOINImageData()->GetJsrc()->SetImage( + driver->GetJOINImageData()->SetJsrc( m_Watershed->PrecomputeWatersheds( driver->GetCurrentImageData()->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(), ui->inConductance->value()/100.0, ui->inSmoothingIter->value(), diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index 0b8c0e76..d28aa457 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -281,16 +281,37 @@ ::CopySegementationToJsrc(const SNAPSegmentationROISettings &roi, { assert(m_JOINImageData->IsJsrcLoaded()); - ////creating deep copy, should only be used for initialization of CnJ (GWS fills its Jsrc with WS) + ////creating (shallow) copy, should only be used for initialization of CnJ (GWS fills its Jsrc with WS) + ////avoids m_IRISImageData->GetSegmentation()->DeepCopyRegion in case JSRType != LabelType - SNAPSegmentationROISettings roiLabel = roi; - roiLabel.SetInterpolationMethod(SNAPSegmentationROISettings::NEAREST_NEIGHBOR); - // Get chunk of the label image - JsrcImageType::Pointer imgNewLabel = - m_IRISImageData->GetSegmentation()->DeepCopyRegion(roiLabel,progressCommand); + typedef LabelImageWrapper::ImageType SourceImageType; + typedef JsrcImageWrapper::ImageType TargetImageType; + + SourceImageType::Pointer source = m_IRISImageData->GetSegmentation()->GetImage(); + TargetImageType::Pointer target = m_JOINImageData->GetJsrc()->GetImage(); + + // Create iterators for copying from one to the other + typedef itk::ImageRegionConstIterator SourceIteratorType; + typedef itk::ImageRegionIterator TargetIteratorType; + //SourceIteratorType itSource(source,source->GetBufferedRegion()); + TargetIteratorType itTarget(target,target->GetBufferedRegion()); + SourceIteratorType itSource(source,roi.GetROI()); + //TargetIteratorType itTarget(target,roi.GetROI()); + + // Go through both iterators, copy the new over the old + itSource.GoToBegin(); + itTarget.GoToBegin(); + while(!itSource.IsAtEnd()) + { + itTarget.Set(itSource.Get());//needs no cast as JSRType >= LabelType + + ++itSource; + ++itTarget; + } + + // The target has been modified + target->Modified(); - // Pass the cleaned up segmentation image to JOIN - m_JOINImageData->SetJsrc(imgNewLabel); InvokeEvent(LayerChangeEvent()); } diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index 3a9738a3..371826ce 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -217,8 +217,7 @@ typedef VectorDerivedQuantityImageWrapperTraits typedef AnatomicImageWrapperTraits::WrapperType AnatomicImageWrapper; typedef LabelImageWrapperTraits::WrapperType LabelImageWrapper; typedef SpeedImageWrapperTraits::WrapperType SpeedImageWrapper; -//typedef JsrcImageWrapperTraits::WrapperType JsrcImageWrapper; -typedef LabelImageWrapperTraits::WrapperType JsrcImageWrapper; +typedef JsrcImageWrapperTraits::WrapperType JsrcImageWrapper; typedef LabelImageWrapperTraits::WrapperType JdstImageWrapper; typedef LevelSetImageWrapperTraits::WrapperType LevelSetImageWrapper; diff --git a/todo b/todo index c86c2dd0..d16cd165 100644 --- a/todo +++ b/todo @@ -2,7 +2,7 @@ TODOs for GWS: - add image+layer for adf output - add relabeller if itk::watershed::Relabeler does not relabel consecutively -- add 'n' for next smallest unused label +- add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx - make UnDo possible - add functionality to all buttons, e.g. back - destinguish RMB click from RMB drag (zoom) @@ -12,8 +12,4 @@ TODOs for GWS: - make GUI parts more fool prove - add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData - - -done: - -- add copy/clear segmentation for GWS +- add MorphlogicalWS from all Labels into PB and/or CnJ From a534ec3bdd56ccdd1960c92203cad70c0c709d04 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 4 Mar 2015 16:08:11 +0100 Subject: [PATCH 06/42] added progress-report on stderr to GWS --- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index 6bb8bf12..3d5b2478 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -19,6 +19,19 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann #include #include #include +#include + + +void FilterEventHandlerITK(itk::Object *caller, const itk::EventObject &event, void*){ + + const itk::ProcessObject* filter = static_cast(caller); + + if(itk::ProgressEvent().CheckEvent(&event)) + fprintf(stderr, "\r%s progress: %5.1f%%", filter->GetNameOfClass(), 100.0 * filter->GetProgress());//stderr is flushed directly + else if(itk::EndEvent().CheckEvent(&event)) + std::cerr << std::endl << std::flush; + } + // TODO: move this into a separate file!!!! class WatershedPipeline{ @@ -29,10 +42,21 @@ class WatershedPipeline{ typedef itk::Image WatershedImageType; WatershedPipeline(){ + + itk::CStyleCommand::Pointer eventCallbackITK; + eventCallbackITK = itk::CStyleCommand::New(); + eventCallbackITK->SetCallback(FilterEventHandlerITK); + adf = ADFType::New(); + adf->AddObserver(itk::ProgressEvent(), eventCallbackITK); + adf->AddObserver(itk::EndEvent(), eventCallbackITK); gmf = GMFType::New(); + gmf->AddObserver(itk::ProgressEvent(), eventCallbackITK); + gmf->AddObserver(itk::EndEvent(), eventCallbackITK); gmf->SetInput(adf->GetOutput()); wf = WFType::New(); + wf->AddObserver(itk::ProgressEvent(), eventCallbackITK); + wf->AddObserver(itk::EndEvent(), eventCallbackITK); cif = CIFType::New(); cif->SetInput(wf->GetOutput()); } From aba99b12d12b386636b1e1e8866275f44eb747bd Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Mon, 9 Mar 2015 16:46:09 +0100 Subject: [PATCH 07/42] new GIF for btnSnakeInspector, as this is used for ROI selection not only in SNAKE_ROI_MODE but also in GLOBALWS_ROI_MODE --- GUI/Qt/Resources/SNAPResources.qrc | 1 + GUI/Qt/Resources/roi.gif | Bin 0 -> 422 bytes GUI/Qt/Windows/MainControlPanel.ui | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 GUI/Qt/Resources/roi.gif diff --git a/GUI/Qt/Resources/SNAPResources.qrc b/GUI/Qt/Resources/SNAPResources.qrc index 4587358b..0045a940 100644 --- a/GUI/Qt/Resources/SNAPResources.qrc +++ b/GUI/Qt/Resources/SNAPResources.qrc @@ -6,6 +6,7 @@ spray.gif snake.gif globalWS.gif + roi.gif screencapture2.gif screencapture.gif scalpel.gif diff --git a/GUI/Qt/Resources/roi.gif b/GUI/Qt/Resources/roi.gif new file mode 100644 index 0000000000000000000000000000000000000000..369970e452be2a538145b4cdd9c055da7e28cf85 GIT binary patch literal 422 zcmZ?wbhEHblwpuzSgODP1k9YA+&nz|!XO|bDJdx@r=Y5;psKB=t*v8Zq-SYq?dI+r z5a1mi?h_v$9G@OjP>@nlk<-{%+SOG)d2$^PO_|d+XHM7Br4!e!o4J0+?43K896Ge* z(CMY8PyeSeQ2Zz8T$GwvlA5AWo>`Ki;O^-gz@Ye(g^`Ovfk6l4J&;Ek*w#5rDDcpc z>Oa(Av@%9%extgEmTu6*hE>xl?uPA-+HiIDl&-T+3UvR(5Vq_M{ zmSz)o+QP)fwJlSQYm%fqFN=tL4L^_25gBeysTxr>c2;&7Nj9E&DblR0BJ9iAxMj=b Xc=!}rSa{YvJtiwGe5=ddk--`OemcN_ literal 0 HcmV?d00001 diff --git a/GUI/Qt/Windows/MainControlPanel.ui b/GUI/Qt/Windows/MainControlPanel.ui index 2ebfb03a..69083463 100644 --- a/GUI/Qt/Windows/MainControlPanel.ui +++ b/GUI/Qt/Windows/MainControlPanel.ui @@ -462,7 +462,7 @@ QWidget#widget { - :/root/snake.gif:/root/snake.gif + :/root/roi.gif:/root/roi.gif true From b12681fbcac143114d2c0b4182ac4a256fbf9269 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Mon, 9 Mar 2015 17:05:31 +0100 Subject: [PATCH 08/42] some comments in the code how ToolbarModeType and mode_inspector_btn correlate --- GUI/Qt/Windows/MainControlPanel.cxx | 18 +++++++++--------- Logic/Framework/GlobalState.h | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/GUI/Qt/Windows/MainControlPanel.cxx b/GUI/Qt/Windows/MainControlPanel.cxx index 23f472c6..04bb2b4b 100644 --- a/GUI/Qt/Windows/MainControlPanel.cxx +++ b/GUI/Qt/Windows/MainControlPanel.cxx @@ -160,15 +160,15 @@ void MainControlPanel::onModelUpdate(const EventBucket &bucket) // A static array of widget/mode mappings //// mode_inspector_btn, mode_tool_pages and ToolbarModeType should have the same amount of entries! static QToolButton *mode_inspector_btn[] = { - ui->btnCursorInspector, - ui->btnZoomInspector, - ui->btnPolygonInspector, - ui->btnPaintbrushInspector, - ui->btnSnakeInspector, - ui->btnJoinInspector, - ui->btnSnakeInspector, - ui->btnCursorInspector, - ui->btnSnakeInspector + ui->btnCursorInspector, //0: CROSSHAIRS_MODE + ui->btnZoomInspector, //1: NAVIGATION_MODE + ui->btnPolygonInspector, //2: POLYGON_DRAWING_MODE + ui->btnPaintbrushInspector, //3: PAINTBRUSH_MODE + ui->btnSnakeInspector, //4: SNAKE_ROI_MODE + ui->btnJoinInspector, //5: JOIN_MODE + ui->btnSnakeInspector, //6: GLOBALWS_ROI_MODE + ui->btnCursorInspector, //7: GWSJOIN_MODE + ui->btnSnakeInspector //8: ANNOTATION_MODE }; diff --git a/Logic/Framework/GlobalState.h b/Logic/Framework/GlobalState.h index b7dbb182..f23e32ad 100644 --- a/Logic/Framework/GlobalState.h +++ b/Logic/Framework/GlobalState.h @@ -106,15 +106,15 @@ enum DisplayPanel enum ToolbarModeType { - CROSSHAIRS_MODE = 0, - NAVIGATION_MODE, - POLYGON_DRAWING_MODE, - PAINTBRUSH_MODE, - SNAKE_ROI_MODE, - JOIN_MODE, - GLOBALWS_ROI_MODE, - GWSJOIN_MODE, - ANNOTATION_MODE + CROSSHAIRS_MODE = 0, //0: btnCursorInspector + NAVIGATION_MODE, //1: btnZoomInspector + POLYGON_DRAWING_MODE, //2: btnPolygonInspector + PAINTBRUSH_MODE, //3: btnPaintbrushInspector + SNAKE_ROI_MODE, //4: btnSnakeInspector + JOIN_MODE, //5: btnJoinInspector + GLOBALWS_ROI_MODE, //6: btnSnakeInspector + GWSJOIN_MODE, //7: btnCursorInspector + ANNOTATION_MODE //8: btnSnakeInspector }; enum ToolbarMode3DType From 32fa3652ab439a514c36b4021e563b38f97ba064 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Thu, 12 Mar 2015 14:08:06 +0100 Subject: [PATCH 09/42] using LinearColorMapDisplayMappingPolicy, basically works but bound to fixed intensity range --- Common/SNAPCommon.h | 2 +- Logic/Framework/JOINImageData.cxx | 1 - Logic/ImageWrapper/DisplayMappingPolicy.cxx | 2 +- Logic/ImageWrapper/ImageWrapperTraits.h | 9 ++++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Common/SNAPCommon.h b/Common/SNAPCommon.h index 8a4159f5..ed029b14 100644 --- a/Common/SNAPCommon.h +++ b/Common/SNAPCommon.h @@ -93,7 +93,7 @@ extern const char SNAPBuildInfo[]; // 0 to MAXGREYVAL are used in a cache table, which would be too big with int typedef unsigned short LabelType; typedef itk::IdentifierType GWSType; -typedef LabelType JSRType; +typedef GWSType JSRType; typedef short GreyType; extern const GreyType MAXGREYVAL; extern const GreyType MINGREYVAL; diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index d1fccc22..f612826b 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -59,7 +59,6 @@ ::InitializeJsrc(){ PushBackImageWrapper(JOIN_ROLE, m_JsrcWrapper.GetPointer()); } - m_JsrcWrapper->GetDisplayMapping()->SetLabelColorTable(m_Parent->GetColorLabelTable()); m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (JSRType) 0); m_JsrcWrapper->SetSticky(true); //overlay, ie no separate tile m_JsrcWrapper->SetAlpha(0.3); diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.cxx b/Logic/ImageWrapper/DisplayMappingPolicy.cxx index 4bb4a28d..8b4c4678 100644 --- a/Logic/ImageWrapper/DisplayMappingPolicy.cxx +++ b/Logic/ImageWrapper/DisplayMappingPolicy.cxx @@ -948,7 +948,7 @@ ::Restore(Registry &folder) template class ColorLabelTableDisplayMappingPolicy; -template class ColorLabelTableDisplayMappingPolicy; +template class LinearColorMapDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index 371826ce..d4d9b6de 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -61,11 +61,14 @@ class JsrcImageWrapperTraits typedef JSRType ComponentType; typedef itk::Image ImageType; - typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping; - typedef ColorLabelTableDisplayMappingPolicy DisplayMapping; + //typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping; + typedef LinearInternalToNativeIntensityMapping NativeIntensityMapping; + typedef LinearColorMapDisplayMappingPolicy DisplayMapping; typedef NullScalarImageWrapperCommonRepresentation CommonRepresentationPolicy; + static void GetFixedIntensityRange(float &min, float &max) + { min = 0; max = 65535; } - //itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_GREY); + itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_JET); // Whether this image is shown on top of all other layers by default itkStaticConstMacro(StickyByDefault, bool, false); From 378711a5220a9996aba1b02dbc8eaf9098083bd4 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Fri, 13 Mar 2015 12:22:27 +0100 Subject: [PATCH 10/42] created JsrcDisplayMappingPolicy which can handle 64-bit and uses itkScalarToRGBPixelFunctor --- Logic/Framework/JOINImageData.cxx | 2 +- Logic/ImageWrapper/DisplayMappingPolicy.cxx | 76 ++++++++++++++++++++- Logic/ImageWrapper/DisplayMappingPolicy.h | 70 +++++++++++++++++++ Logic/ImageWrapper/ImageWrapperTraits.h | 2 +- todo | 5 +- 5 files changed, 148 insertions(+), 7 deletions(-) diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index f612826b..d81af634 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -61,7 +61,7 @@ ::InitializeJsrc(){ m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (JSRType) 0); m_JsrcWrapper->SetSticky(true); //overlay, ie no separate tile - m_JsrcWrapper->SetAlpha(0.3); + m_JsrcWrapper->SetAlpha(0.5); InvokeEvent(LayerChangeEvent()); } diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.cxx b/Logic/ImageWrapper/DisplayMappingPolicy.cxx index 8b4c4678..7baaf35c 100644 --- a/Logic/ImageWrapper/DisplayMappingPolicy.cxx +++ b/Logic/ImageWrapper/DisplayMappingPolicy.cxx @@ -15,6 +15,7 @@ #include "itkUnaryFunctorImageFilter.h" #include "InputSelectionImageFilter.h" #include "Rebroadcaster.h" +#include /* =============================================================== @@ -96,6 +97,79 @@ ::GetLabelColorTable() const } +/* =============================================================== + JsrcDisplayMappingPolicy implementation + =============================================================== */ + +template +JsrcDisplayMappingPolicy +::JsrcDisplayMappingPolicy() +{ + m_Wrapper = NULL; + + for(int i = 0; i < 3; i++) + { + m_RGBAFilter[i] = RGBAFilterType::New(); + m_RGBAFilter[i]->SetFunctor(m_Functor); + } +} + +template +JsrcDisplayMappingPolicy +::~JsrcDisplayMappingPolicy() +{ + +} + +template +void +JsrcDisplayMappingPolicy +::Initialize(WrapperType *wrapper) +{ + // Initialize the wrapper + m_Wrapper = wrapper; + + for(int i = 0; i < 3; i++) + { + m_RGBAFilter[i]->SetInput(wrapper->GetSlice(i)); + } +} + +template +void +JsrcDisplayMappingPolicy +::UpdateImagePointer(ImageType *image) +{ + // Nothing to do here, since we are connected to the slices? +} + +template +typename JsrcDisplayMappingPolicy::DisplaySlicePointer +JsrcDisplayMappingPolicy +::GetDisplaySlice(unsigned int slice) +{ + return m_RGBAFilter[slice]->GetOutput(); +} + +template +inline typename JsrcDisplayMappingPolicy::DisplayPixelType +JsrcDisplayMappingPolicy::MappingFunctor +::operator()(PixelType in) +{ + itk::RGBPixel RGBp; + DisplayPixelType RGBAp; + itk::Functor::ScalarToRGBPixelFunctor mFunctor; + + RGBp= mFunctor(in); + RGBAp[0]= RGBp[0]; + RGBAp[1]= RGBp[1]; + RGBAp[2]= RGBp[2]; + RGBAp[3]= itk::NumericTraits::max(); + + return RGBAp; +} + + /* =============================================================== CachingCurveAndColorMapDisplayMappingPolicy implementation =============================================================== */ @@ -948,7 +1022,7 @@ ::Restore(Registry &folder) template class ColorLabelTableDisplayMappingPolicy; -template class LinearColorMapDisplayMappingPolicy; +template class JsrcDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.h b/Logic/ImageWrapper/DisplayMappingPolicy.h index 1bc2de25..57c145ae 100644 --- a/Logic/ImageWrapper/DisplayMappingPolicy.h +++ b/Logic/ImageWrapper/DisplayMappingPolicy.h @@ -105,6 +105,76 @@ class ColorLabelTableDisplayMappingPolicy WrapperType *m_Wrapper; }; + /** + * JsrcDisplayMappingPolicy is based on + * ColorLabelTableDisplayMappingPolicy and LinearColorMapDisplayMappingPolicy + */ +class AbstractJsrcDisplayMappingPolicy : public AbstractDisplayMappingPolicy +{ +public: + + irisITKAbstractObjectMacro(AbstractJsrcDisplayMappingPolicy, + AbstractDisplayMappingPolicy) +}; + +namespace itk { + template + class UnaryFunctorImageFilter; +} + +template +class JsrcDisplayMappingPolicy + : public AbstractJsrcDisplayMappingPolicy +{ +public: + + irisITKObjectMacro(JsrcDisplayMappingPolicy, + AbstractJsrcDisplayMappingPolicy) + + typedef typename TWrapperTraits::WrapperType WrapperType; + typedef typename TWrapperTraits::ImageType ImageType; + typedef typename ImageType::PixelType PixelType; + + typedef itk::Image InputSliceType; + typedef ImageWrapperBase::DisplaySliceType DisplaySliceType; + typedef ImageWrapperBase::DisplaySlicePointer DisplaySlicePointer; + typedef ImageWrapperBase::DisplayPixelType DisplayPixelType; + + void Initialize(WrapperType *wrapper); + void UpdateImagePointer(ImageType *image); + + DisplaySlicePointer GetDisplaySlice(unsigned int slice); + + virtual IntensityCurveInterface *GetIntensityCurve() const { return NULL; } + virtual ColorMap *GetColorMap() const { return NULL; } + + virtual void Save(Registry &folder) {} + virtual void Restore(Registry &folder) {} + +protected: + + JsrcDisplayMappingPolicy(); + ~JsrcDisplayMappingPolicy(); + + class MappingFunctor + { + public: + DisplayPixelType operator()(PixelType in); + bool operator != (const MappingFunctor &f) const {return false;} //needed by UnaryFunctorImageFilter even tough ScalarToRGBPixelFunctor does not have this operator + }; + + // it is not possible to use ScalarToRGBPixelFunctor directly here + // because the expected output of MappingFunctor is RGBA + typedef itk::UnaryFunctorImageFilter + RGBAFilterType; + typedef SmartPtr RGBAFilterPointer; + + RGBAFilterPointer m_RGBAFilter[3]; + MappingFunctor m_Functor; + + WrapperType *m_Wrapper; +}; + /** * @brief The parent class for the policies that involve curve-based mappings, * for both scalar and vector images. diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index d4d9b6de..6c44c52f 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -63,7 +63,7 @@ class JsrcImageWrapperTraits //typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping; typedef LinearInternalToNativeIntensityMapping NativeIntensityMapping; - typedef LinearColorMapDisplayMappingPolicy DisplayMapping; + typedef JsrcDisplayMappingPolicy DisplayMapping; typedef NullScalarImageWrapperCommonRepresentation CommonRepresentationPolicy; static void GetFixedIntensityRange(float &min, float &max) { min = 0; max = 65535; } diff --git a/todo b/todo index d16cd165..410d819d 100644 --- a/todo +++ b/todo @@ -1,14 +1,11 @@ TODOs for GWS: - add image+layer for adf output -- add relabeller if itk::watershed::Relabeler does not relabel consecutively - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx - make UnDo possible - add functionality to all buttons, e.g. back - destinguish RMB click from RMB drag (zoom) -- impl. connected component relabeling -- make long long for GWS possible -- """ for image from file +- would be nice to let user choose which color representation should be used for Jsrc - make GUI parts more fool prove - add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData From b83953090c6575c70a35f9b54b5cc09f3d6b24d3 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Fri, 13 Mar 2015 14:31:07 +0100 Subject: [PATCH 11/42] added basic "load from file" functionality --- GUI/Qt/Components/CursorInspector.cxx | 2 +- GUI/Qt/Components/CursorInspector.ui | 6 ---- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 19 ++++++++++ GUI/Qt/Components/GlobalWSWizardPanel.h | 2 ++ GUI/Qt/Components/JoinDataPanel.cxx | 43 +++++++++++++++++++++++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/GUI/Qt/Components/CursorInspector.cxx b/GUI/Qt/Components/CursorInspector.cxx index 6ef57b56..ebd95067 100644 --- a/GUI/Qt/Components/CursorInspector.cxx +++ b/GUI/Qt/Components/CursorInspector.cxx @@ -83,7 +83,7 @@ CursorInspector::CursorInspector(QWidget *parent) : ui->setupUi(this); ui->tableVoxelUnderCursor->setAlternatingRowColors(true); - ui->tableVoxelUnderCursor->setFixedWidth(160); + //ui->tableVoxelUnderCursor->setFixedWidth(160);//let table expand ui->tableVoxelUnderCursor->setFixedHeight(120); ui->tableVoxelUnderCursor->setContextMenuPolicy(Qt::CustomContextMenu); diff --git a/GUI/Qt/Components/CursorInspector.ui b/GUI/Qt/Components/CursorInspector.ui index 612f1dd4..c6294810 100644 --- a/GUI/Qt/Components/CursorInspector.ui +++ b/GUI/Qt/Components/CursorInspector.ui @@ -173,12 +173,6 @@ font-size: 11px; 0 - - - 185 - 120 - - Qt::CustomContextMenu diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index 3d5b2478..5eb9a967 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -14,6 +14,9 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann #include "GenericImageData.h" #include "JOINImageData.h" #include "DisplayLayoutModel.h" //access tiled/stacked view mode +#include "ImageIODelegates.h" +#include "ImageIOWizard.h" +#include "ImageIOWizardModel.h" #include #include @@ -266,3 +269,19 @@ void GlobalWSWizardPanel::on_btnClearSeg_clicked(){ driver->InvokeEvent(SegmentationChangeEvent()); } + +void GlobalWSWizardPanel::on_btnLoadFromFile_clicked() +{ + // not working yet + // Create a model for IO + SmartPtr delegate = LoadMainImageDelegate::New(); + delegate->Initialize(m_ParentModel->GetDriver()); + SmartPtr model = ImageIOWizardModel::New(); + model->InitializeForLoad(m_ParentModel, delegate, + "GWSImage", "GWS Source Image"); + + // Execute the IO wizard + ImageIOWizard wiz(this); + wiz.SetModel(model); + wiz.exec(); +} diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.h b/GUI/Qt/Components/GlobalWSWizardPanel.h index ef3837d0..f6a2114c 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.h +++ b/GUI/Qt/Components/GlobalWSWizardPanel.h @@ -60,6 +60,8 @@ private slots: void on_btnClearSeg_clicked(); + void on_btnLoadFromFile_clicked(); + private: GlobalUIModel *m_ParentModel; diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index 6c4d362d..34fa0974 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -13,6 +13,9 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann #include "GenericImageData.h" //GetCurrentImageData()->GetImageRegion(); #include "QtWidgetActivator.h" //activateOnFlag #include "DisplayLayoutModel.h" //access tiled/stacked view mode +#include "ImageIODelegates.h" +#include "ImageIOWizard.h" +#include "ImageIOWizardModel.h" JoinDataPanel::JoinDataPanel(QWidget *parent) : @@ -73,6 +76,46 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ ////panel will be hidden in GWSJOIN_MODE m_Model->GetGlobalState()->SetToolbarMode(GLOBALWS_ROI_MODE); } break; + case 2:{ + // Create a model for IO + SmartPtr delegate = LoadSegmentationImageDelegate::New(); + delegate->Initialize(m_Model->GetDriver()); + SmartPtr model = ImageIOWizardModel::New(); + model->InitializeForLoad(m_Model, delegate, + "JsrImage", "Join Source Image"); + + // Execute the IO wizard + ImageIOWizard wiz(this); + wiz.SetModel(model); + wiz.exec(); + + //todo check for cancel in wizard and return from JOIN_MODE + + IRISApplication *driver = m_Model->GetDriver(); + + //reset ROI from the main image + GlobalState::RegionType roi = + driver->GetCurrentImageData()->GetImageRegion(); + + // Can't be empty! + assert(roi.GetNumberOfPixels()); + + // Update + driver->GetGlobalState()->SetSegmentationROI(roi); + + //// Initialize the image data + driver->InitializeJOINImageData( + driver->GetGlobalState()->GetSegmentationROISettings(), + m_Model->GetProgressCommand()); + + driver->CopySegementationToJsrc( + driver->GetGlobalState()->GetSegmentationROISettings(), + m_Model->GetProgressCommand()); + driver->SetCurrentImageDataToJOIN(); + + // set tiled layout to ease understanding the interaction mode + m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); + } break; default: ////Switch to crosshairs mode m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); From 99754724ea9eb7c6c0719645938645b385fa88fe Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Fri, 13 Mar 2015 14:49:20 +0100 Subject: [PATCH 12/42] label 0 now fully transparent when using JsrcDisplayMappingPolicy --- Logic/ImageWrapper/DisplayMappingPolicy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.cxx b/Logic/ImageWrapper/DisplayMappingPolicy.cxx index 7baaf35c..002f1176 100644 --- a/Logic/ImageWrapper/DisplayMappingPolicy.cxx +++ b/Logic/ImageWrapper/DisplayMappingPolicy.cxx @@ -164,7 +164,7 @@ ::operator()(PixelType in) RGBAp[0]= RGBp[0]; RGBAp[1]= RGBp[1]; RGBAp[2]= RGBp[2]; - RGBAp[3]= itk::NumericTraits::max(); + RGBAp[3]= (in == 0) ? 0 : itk::NumericTraits::max(); //make label 0 fully transparent return RGBAp; } From f339f1f766cc6e280d58d4f51111045f44394592 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Fri, 13 Mar 2015 15:07:03 +0100 Subject: [PATCH 13/42] cleaned up ImageWrapperTraits.h --- Logic/ImageWrapper/ImageWrapperTraits.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index 6c44c52f..95f20f70 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -61,14 +61,9 @@ class JsrcImageWrapperTraits typedef JSRType ComponentType; typedef itk::Image ImageType; - //typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping; typedef LinearInternalToNativeIntensityMapping NativeIntensityMapping; typedef JsrcDisplayMappingPolicy DisplayMapping; typedef NullScalarImageWrapperCommonRepresentation CommonRepresentationPolicy; - static void GetFixedIntensityRange(float &min, float &max) - { min = 0; max = 65535; } - - itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_JET); // Whether this image is shown on top of all other layers by default itkStaticConstMacro(StickyByDefault, bool, false); From 52bcb13b42f62e3b5f87a757161ce2d639281615 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 17 Mar 2015 12:55:46 +0100 Subject: [PATCH 14/42] added functionality to some GWS buttons --- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 37 ++++++++++++++++++++--- GUI/Qt/Components/GlobalWSWizardPanel.h | 4 +++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index 5eb9a967..bb8e0d33 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -270,18 +270,47 @@ void GlobalWSWizardPanel::on_btnClearSeg_clicked(){ driver->InvokeEvent(SegmentationChangeEvent()); } -void GlobalWSWizardPanel::on_btnLoadFromFile_clicked() -{ +void GlobalWSWizardPanel::on_btnLoadFromFile_clicked(){ // not working yet // Create a model for IO SmartPtr delegate = LoadMainImageDelegate::New(); delegate->Initialize(m_ParentModel->GetDriver()); SmartPtr model = ImageIOWizardModel::New(); model->InitializeForLoad(m_ParentModel, delegate, - "GWSImage", "GWS Source Image"); + "GWSImage", "GWS Source Image"); // Execute the IO wizard ImageIOWizard wiz(this); wiz.SetModel(model); wiz.exec(); -} + } + +void GlobalWSWizardPanel::on_btnWSRangeBack_clicked(){ + try + { + // Handle cursor + QtCursorOverride curse(Qt::WaitCursor); + + // Move to the range page + ui->stack->setCurrentWidget(ui->pgPreproc); + } + catch(IRISException &exc) + { + QMessageBox::warning(this, "ITK-SNAP", exc.what(), QMessageBox::Ok); + } + } + +void GlobalWSWizardPanel::on_btnJoinBack_clicked(){ + try + { + // Handle cursor + QtCursorOverride curse(Qt::WaitCursor); + + // Move to the range page + ui->stack->setCurrentWidget(ui->pgWSRange); + } + catch(IRISException &exc) + { + QMessageBox::warning(this, "ITK-SNAP", exc.what(), QMessageBox::Ok); + } + } diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.h b/GUI/Qt/Components/GlobalWSWizardPanel.h index f6a2114c..bc2e3de4 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.h +++ b/GUI/Qt/Components/GlobalWSWizardPanel.h @@ -62,6 +62,10 @@ private slots: void on_btnLoadFromFile_clicked(); + void on_btnWSRangeBack_clicked(); + + void on_btnJoinBack_clicked(); + private: GlobalUIModel *m_ParentModel; From 739001a66c284e116d26856635120ebcda4c6763 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Sat, 21 Mar 2015 17:45:07 +0100 Subject: [PATCH 15/42] split up PrecomputeWatersheds to ComputeWSImage on btnNextPreproc_clicked --- Common/SNAPCommon.h | 1 + GUI/Qt/Components/GlobalWSWizardPanel.cxx | 55 ++++++++++++++--------- todo | 6 +-- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/Common/SNAPCommon.h b/Common/SNAPCommon.h index ed029b14..f67544aa 100644 --- a/Common/SNAPCommon.h +++ b/Common/SNAPCommon.h @@ -94,6 +94,7 @@ extern const char SNAPBuildInfo[]; typedef unsigned short LabelType; typedef itk::IdentifierType GWSType; typedef GWSType JSRType; +typedef float WSRType; typedef short GreyType; extern const GreyType MAXGREYVAL; extern const GreyType MINGREYVAL; diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index bb8e0d33..c362e1d9 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -41,7 +41,7 @@ class WatershedPipeline{ public: typedef itk::Image GreyImageType; typedef itk::Image JsrcImageType; - typedef itk::Image FloatImageType; + typedef itk::Image WsrcImageType; typedef itk::Image WatershedImageType; WatershedPipeline(){ @@ -64,10 +64,9 @@ class WatershedPipeline{ cif->SetInput(wf->GetOutput()); } - JsrcImageType* PrecomputeWatersheds( + WsrcImageType* ComputeWSImage( GreyImageType *grey, double cParam, size_t sIter, - double iThr, double iLevel, bool direct){ //// Initialize the watershed pipeline @@ -75,10 +74,22 @@ class WatershedPipeline{ adf->SetNumberOfIterations(sIter); adf->SetConductanceParameter(cParam); - if(direct) - wf->SetInput(adf->GetOutput()); - else - wf->SetInput(gmf->GetOutput()); + WsrcImageType* wsImage; + + if(direct){ + adf->UpdateLargestPossibleRegion(); + wsImage= adf->GetOutput(); + } + else{ + gmf->UpdateLargestPossibleRegion(); + wsImage= gmf->GetOutput(); + } + + wf->SetInput(wsImage); + return(wsImage); + } + + JsrcImageType* PrecomputeWatersheds(double iThr, double iLevel){ wf->SetThreshold(iThr); wf->SetLevel(iLevel); @@ -94,9 +105,9 @@ class WatershedPipeline{ } private: - typedef itk::GradientAnisotropicDiffusionImageFilter ADFType; - typedef itk::GradientMagnitudeImageFilter GMFType; - typedef itk::WatershedImageFilter WFType; + typedef itk::GradientAnisotropicDiffusionImageFilter ADFType; + typedef itk::GradientMagnitudeImageFilter GMFType; + typedef itk::WatershedImageFilter WFType; typedef itk::CastImageFilter CIFType; ADFType::Pointer adf; @@ -160,13 +171,22 @@ void GlobalWSWizardPanel::on_btnCancel_clicked(){ } void GlobalWSWizardPanel::on_btnNextPreproc_clicked(){ - // Call the initialization code + // Get the global objects + IRISApplication *driver = m_ParentModel->GetDriver(); + GlobalState *gs = driver->GetGlobalState(); + try { // Handle cursor QtCursorOverride curse(Qt::WaitCursor); + + m_Watershed->ComputeWSImage( + driver->GetCurrentImageData()->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(), + ui->inConductance->value()/100.0, ui->inSmoothingIter->value(), + ui->chkGlobalWSDirect->isChecked() + ); - // Move to the range page + // Move to the range page ui->stack->setCurrentWidget(ui->pgWSRange); } catch(IRISException &exc) @@ -187,12 +207,7 @@ void GlobalWSWizardPanel::on_btnWSRangeNext_clicked(){ QtCursorOverride curse(Qt::WaitCursor); driver->GetJOINImageData()->SetJsrc( - m_Watershed->PrecomputeWatersheds( - driver->GetCurrentImageData()->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(), - ui->inConductance->value()/100.0, ui->inSmoothingIter->value(), - ui->inWSMin->value()/100.0, ui->inWSMax->value()/100.0, - ui->chkGlobalWSDirect->isChecked() - ) + m_Watershed->PrecomputeWatersheds(ui->inWSMin->value()/100.0, ui->inWSMax->value()/100.0) ); std::cerr << "Changing WS to level: " << ui->inWSLevel->value()/100.0 << std::flush; @@ -270,10 +285,10 @@ void GlobalWSWizardPanel::on_btnClearSeg_clicked(){ driver->InvokeEvent(SegmentationChangeEvent()); } -void GlobalWSWizardPanel::on_btnLoadFromFile_clicked(){ +void GlobalWSWizardPanel::on_btnLoadFromFile_clicked(){///better make it a choose overlay button as ROI cropping has already happend // not working yet // Create a model for IO - SmartPtr delegate = LoadMainImageDelegate::New(); + SmartPtr delegate = LoadOverlayImageDelegate::New(); delegate->Initialize(m_ParentModel->GetDriver()); SmartPtr model = ImageIOWizardModel::New(); model->InitializeForLoad(m_ParentModel, delegate, diff --git a/todo b/todo index 410d819d..3f824cb1 100644 --- a/todo +++ b/todo @@ -1,12 +1,12 @@ TODOs for GWS: -- add image+layer for adf output +- add layer for adf output - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx - make UnDo possible -- add functionality to all buttons, e.g. back - destinguish RMB click from RMB drag (zoom) - would be nice to let user choose which color representation should be used for Jsrc - make GUI parts more fool prove - add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData -- add MorphlogicalWS from all Labels into PB and/or CnJ +- add MorphlogicalWS from all Labels into PB, result as overlay +- change "load from file" to "load from overlay" in CnJ and gWS From 9c49ced1a52618228c5bac6723f3221d3c5ee42c Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Sat, 21 Mar 2015 18:00:43 +0100 Subject: [PATCH 16/42] introduced "GWS source image" (WsrcImage) layer to vis gWS preprocessing results; WsrcImage not visible in Slice-View yet --- GUI/Model/GlobalUIModel.cxx | 2 + GUI/Model/GlobalWSWizardModel.cxx | 2 +- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 2 + GUI/Qt/Components/JoinDataPanel.cxx | 4 +- Logic/Framework/IRISApplication.cxx | 11 ++- Logic/Framework/IRISApplication.h | 4 +- Logic/Framework/JOINImageData.cxx | 73 ++++++++++++++++++- Logic/Framework/JOINImageData.h | 15 +++- .../CommonRepresentationPolicy.cxx | 3 + Logic/ImageWrapper/DisplayMappingPolicy.cxx | 1 + Logic/ImageWrapper/ImageWrapper.cxx | 1 + Logic/ImageWrapper/ImageWrapperTraits.h | 27 +++++++ Logic/ImageWrapper/ScalarImageWrapper.cxx | 1 + todo | 2 +- 14 files changed, 136 insertions(+), 12 deletions(-) diff --git a/GUI/Model/GlobalUIModel.cxx b/GUI/Model/GlobalUIModel.cxx index fb1e136e..99e310c8 100644 --- a/GUI/Model/GlobalUIModel.cxx +++ b/GUI/Model/GlobalUIModel.cxx @@ -799,6 +799,8 @@ GlobalUIModel::CreateIOWizardModelForSave(ImageWrapperBase *layer, LayerRole rol category = "Join Source Image"; else if(dynamic_cast(layer)) category = "Join Destination Image"; + else if(dynamic_cast(layer)) + category = "GWS Source Image"; break; case LABEL_ROLE: category = "Segmentation Image"; diff --git a/GUI/Model/GlobalWSWizardModel.cxx b/GUI/Model/GlobalWSWizardModel.cxx index c160d9f8..f124f66a 100644 --- a/GUI/Model/GlobalWSWizardModel.cxx +++ b/GUI/Model/GlobalWSWizardModel.cxx @@ -23,7 +23,7 @@ void GlobalWSWizardModel::OnGlobalWSModeEnter() { //// Initialize the image data m_Driver->InitializeJOINImageData( - m_Driver->GetGlobalState()->GetSegmentationROISettings(), + m_Driver->GetGlobalState()->GetSegmentationROISettings(), 1, //1: GWS; todo: use enum for selection state of CnJ m_Parent->GetProgressCommand()); m_Driver->SetCurrentImageDataToJOIN(); diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index c362e1d9..b423b2f1 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -180,10 +180,12 @@ void GlobalWSWizardPanel::on_btnNextPreproc_clicked(){ // Handle cursor QtCursorOverride curse(Qt::WaitCursor); + driver->GetJOINImageData()->SetWsrc( m_Watershed->ComputeWSImage( driver->GetCurrentImageData()->GetMain()->GetDefaultScalarRepresentation()->GetCommonFormatImage(), ui->inConductance->value()/100.0, ui->inSmoothingIter->value(), ui->chkGlobalWSDirect->isChecked() + ) ); // Move to the range page diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index 34fa0974..60d3a5f0 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -61,7 +61,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ //// Initialize the image data driver->InitializeJOINImageData( - driver->GetGlobalState()->GetSegmentationROISettings(), + driver->GetGlobalState()->GetSegmentationROISettings(), sel, m_Model->GetProgressCommand()); driver->CopySegementationToJsrc( @@ -105,7 +105,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ //// Initialize the image data driver->InitializeJOINImageData( - driver->GetGlobalState()->GetSegmentationROISettings(), + driver->GetGlobalState()->GetSegmentationROISettings(), sel, m_Model->GetProgressCommand()); driver->CopySegementationToJsrc( diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index d28aa457..b9600dea 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -252,7 +252,7 @@ ::InitializeSNAPImageData(const SNAPSegmentationROISettings &roi, void IRISApplication -::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, +::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, CommandType *progressCommand) { assert(m_IRISImageData->IsMainLoaded()); @@ -260,6 +260,9 @@ ::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, // Create the JOIN image data object m_JOINImageData->InitializeToROI(m_IRISImageData, roi, progressCommand); + if(CnJMode == 1)//GWS + m_JOINImageData->InitializeWsrc(); + // Initialize the source and destination images of the JOIN image data m_JOINImageData->InitializeJsrc(); m_JOINImageData->InitializeJdst(); @@ -2147,6 +2150,12 @@ IRISApplication::CreateSaveDelegateForLayer(ImageWrapperBase *layer, LayerRole r history = "JdstImage"; category = "Join Destination Image"; } + + else if(dynamic_cast(layer)) + { + history = "WsrcImage"; + category = "GWS Source Image"; + } } // Create delegate diff --git a/Logic/Framework/IRISApplication.h b/Logic/Framework/IRISApplication.h index 9daaff61..0c15dbf2 100644 --- a/Logic/Framework/IRISApplication.h +++ b/Logic/Framework/IRISApplication.h @@ -118,8 +118,6 @@ class IRISApplication : public itk::Object typedef itk::Image LabelImageType; typedef itk::Image SpeedImageType; - typedef itk::Image JsrcImageType;//why not by #include "JOINImageData.h" ??? - typedef itk::Image JdstImageType;//why not by #include "JOINImageData.h" ??? typedef itk::Command CommandType; typedef UndoDataManager UndoManagerType; @@ -276,7 +274,7 @@ class IRISApplication : public itk::Object /** * Initialize JOIN Image data using region of interest extents */ - void InitializeJOINImageData(const SNAPSegmentationROISettings &roi, + void InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, CommandType *progressCommand = NULL); /** diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index d81af634..f68caf4c 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -45,6 +45,11 @@ JOINImageData ::~JOINImageData(){ } + +/* ============================= + Join source Image + ============================= */ + void JOINImageData ::InitializeJsrc(){ @@ -56,7 +61,7 @@ ::InitializeJsrc(){ { m_JsrcWrapper = JsrcImageWrapper::New(); m_JsrcWrapper->SetDefaultNickname("Join Source Image"); - PushBackImageWrapper(JOIN_ROLE, m_JsrcWrapper.GetPointer()); + PushBackImageWrapper(JOIN_ROLE, m_JsrcWrapper.GetPointer()); } m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (JSRType) 0); @@ -98,6 +103,11 @@ ::IsJsrcLoaded(){ return m_JsrcWrapper && m_JsrcWrapper->IsInitialized(); } + +/* ============================= + Join destination Image + ============================= */ + void JOINImageData ::InitializeJdst(){ @@ -133,6 +143,66 @@ ::IsJdstLoaded() return (m_JdstWrapper && m_JdstWrapper->IsInitialized()); } + +/* ============================= + GWS source Image + ============================= */ + +void +JOINImageData +::InitializeWsrc(){ + // The Grey image wrapper should be present + assert(m_MainImageWrapper->IsInitialized()); + + // Intialize Wsrc based on the current grey image + if(m_WsrcWrapper.IsNull()) + { + m_WsrcWrapper = WsrcImageWrapper::New(); + m_WsrcWrapper->SetDefaultNickname("GWS Source Image"); + PushBackImageWrapper(JOIN_ROLE, m_WsrcWrapper.GetPointer()); + } + + m_WsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (WSRType) 0); + m_WsrcWrapper->SetSticky(true); //overlay, ie no separate tile + m_WsrcWrapper->SetAlpha(0.5); + + InvokeEvent(LayerChangeEvent()); + } + +WsrcImageWrapper* +JOINImageData +::GetWsrc(){ + // Make sure it exists + assert(IsWsrcLoaded()); + return m_WsrcWrapper; + } + +void +JOINImageData +::SetWsrc(WsrcImageType *newWsrcImage){ + ////from ./Logic/Framework/GenericImageData.cxx:244:::SetSegmentationImage + // Check that the image matches the size of the grey image + assert(m_MainImageWrapper->IsInitialized()); + + assert(m_MainImageWrapper->GetBufferedRegion() == + newWsrcImage->GetBufferedRegion()); + + // Pass the image to the wrapper + m_WsrcWrapper->SetImage(newWsrcImage); + + // Sync up spacing between the main and label image + newWsrcImage->SetSpacing(m_MainImageWrapper->GetImageBase()->GetSpacing()); + newWsrcImage->SetOrigin(m_MainImageWrapper->GetImageBase()->GetOrigin()); + } + +bool +JOINImageData +::IsWsrcLoaded(){ + return m_WsrcWrapper && m_WsrcWrapper->IsInitialized(); + } + +/**********************************/ + void JOINImageData ::InitializeToROI(GenericImageData *source, @@ -229,6 +299,7 @@ void JOINImageData::UnloadAll(){ PopBackImageWrapper(JOIN_ROLE); m_JsrcWrapper = NULL; m_JdstWrapper = NULL; + m_WsrcWrapper = NULL; InvokeEvent(LayerChangeEvent()); } diff --git a/Logic/Framework/JOINImageData.h b/Logic/Framework/JOINImageData.h index 2bd93ae9..9ed0bc75 100644 --- a/Logic/Framework/JOINImageData.h +++ b/Logic/Framework/JOINImageData.h @@ -55,6 +55,7 @@ class JOINImageData : public GenericImageData typedef Superclass::AnatomicImageType AnatomicImageType; typedef JsrcImageWrapper::ImageType JsrcImageType; typedef JdstImageWrapper::ImageType JdstImageType; + typedef WsrcImageWrapper::ImageType WsrcImageType; /** Initialize to a ROI from another image data object */ void InitializeToROI(GenericImageData *source, @@ -76,21 +77,29 @@ class JOINImageData : public GenericImageData void SetJsrc(JsrcImageType *newJsrcImage); bool IsJsrcLoaded(); - void InitializeJdst(); JdstImageWrapper* GetJdst(); bool IsJdstLoaded(); + + void InitializeWsrc(); + WsrcImageWrapper* GetWsrc(); + void SetWsrc(WsrcImageType *newWsrcImage); + bool IsWsrcLoaded(); + protected: JOINImageData(); ~JOINImageData(); - // Speed image adata + // Join source image SmartPtr m_JsrcWrapper; - // Wrapper around the level set image + // Join destination image SmartPtr m_JdstWrapper; + + // GWS source image + SmartPtr m_WsrcWrapper; }; diff --git a/Logic/ImageWrapper/CommonRepresentationPolicy.cxx b/Logic/ImageWrapper/CommonRepresentationPolicy.cxx index e964e30c..524463e8 100644 --- a/Logic/ImageWrapper/CommonRepresentationPolicy.cxx +++ b/Logic/ImageWrapper/CommonRepresentationPolicy.cxx @@ -88,6 +88,9 @@ template class InPlaceScalarImageWrapperCommonRepresentation< template class CastingScalarImageWrapperCommonRepresentation< GreyType, LevelSetImageWrapperTraits >; +template class CastingScalarImageWrapperCommonRepresentation< + GreyType, WsrcImageWrapperTraits >; + diff --git a/Logic/ImageWrapper/DisplayMappingPolicy.cxx b/Logic/ImageWrapper/DisplayMappingPolicy.cxx index 002f1176..31bbc52c 100644 --- a/Logic/ImageWrapper/DisplayMappingPolicy.cxx +++ b/Logic/ImageWrapper/DisplayMappingPolicy.cxx @@ -1023,6 +1023,7 @@ ::Restore(Registry &folder) template class ColorLabelTableDisplayMappingPolicy; template class JsrcDisplayMappingPolicy; +template class LinearColorMapDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; template class LinearColorMapDisplayMappingPolicy; diff --git a/Logic/ImageWrapper/ImageWrapper.cxx b/Logic/ImageWrapper/ImageWrapper.cxx index 34b24e77..0572e906 100644 --- a/Logic/ImageWrapper/ImageWrapper.cxx +++ b/Logic/ImageWrapper/ImageWrapper.cxx @@ -1274,6 +1274,7 @@ template class ImageWrapper; template class ImageWrapper; template class ImageWrapper; template class ImageWrapper; +template class ImageWrapper; template class ImageWrapper, VectorImageWrapperBase>; template class ImageWrapper, ScalarImageWrapperBase>; diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index 95f20f70..a051e01a 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -72,6 +72,32 @@ class JsrcImageWrapperTraits itkStaticConstMacro(PipelineOutput, bool, true); }; +class WsrcImageWrapperTraits +{ +public: + typedef WsrcImageWrapperTraits Self; + + typedef ScalarImageWrapper WrapperType; + + typedef WSRType ComponentType; + typedef itk::Image ImageType; + + typedef IdentityInternalToNativeIntensityMapping NativeIntensityMapping; + typedef LinearColorMapDisplayMappingPolicy DisplayMapping; + typedef NullScalarImageWrapperCommonRepresentation CommonRepresentationPolicy; + + static void GetFixedIntensityRange(float &min, float &max) + { min = -100.0; max = 100.0; } + + itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_JET); + + // Whether this image is shown on top of all other layers by default + itkStaticConstMacro(StickyByDefault, bool, true); + + // Whether this image is produced from another by a pipeline (e.g., speed image) + itkStaticConstMacro(PipelineOutput, bool, true); +}; + class SpeedImageWrapperTraits { public: @@ -217,6 +243,7 @@ typedef LabelImageWrapperTraits::WrapperType LabelImageWrapper; typedef SpeedImageWrapperTraits::WrapperType SpeedImageWrapper; typedef JsrcImageWrapperTraits::WrapperType JsrcImageWrapper; typedef LabelImageWrapperTraits::WrapperType JdstImageWrapper; +typedef WsrcImageWrapperTraits::WrapperType WsrcImageWrapper; typedef LevelSetImageWrapperTraits::WrapperType LevelSetImageWrapper; diff --git a/Logic/ImageWrapper/ScalarImageWrapper.cxx b/Logic/ImageWrapper/ScalarImageWrapper.cxx index 7e9dbf36..2c14e3ba 100644 --- a/Logic/ImageWrapper/ScalarImageWrapper.cxx +++ b/Logic/ImageWrapper/ScalarImageWrapper.cxx @@ -323,6 +323,7 @@ template class ScalarImageWrapper; template class ScalarImageWrapper; template class ScalarImageWrapper; template class ScalarImageWrapper; +template class ScalarImageWrapper; template class ScalarImageWrapper< ComponentImageWrapperTraits >; typedef VectorDerivedQuantityImageWrapperTraits MagTraits; diff --git a/todo b/todo index 3f824cb1..862322de 100644 --- a/todo +++ b/todo @@ -1,6 +1,6 @@ TODOs for GWS: -- add layer for adf output +- make Wsrc-layer visible in Slice-view - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx - make UnDo possible - destinguish RMB click from RMB drag (zoom) From 488dcd34c04013ab10f911976ef106c6a8b7143f Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Sat, 21 Mar 2015 19:50:43 +0100 Subject: [PATCH 17/42] WsrcImage now visible in Slice-View --- Logic/Framework/JOINImageData.cxx | 2 ++ todo | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index f68caf4c..741f6e5f 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -91,6 +91,7 @@ ::SetJsrc(JsrcImageType *newJsrcImage){ // Pass the image to the wrapper m_JsrcWrapper->SetImage(newJsrcImage); + m_JsrcWrapper->GetImage()->Modified();// This makes sure that the IsDrawable() of the wrapper returns true, essential for showing up in the the SliceView (l.284 GenericSliceRenderer.cxx) // Sync up spacing between the main and label image newJsrcImage->SetSpacing(m_MainImageWrapper->GetImageBase()->GetSpacing()); @@ -189,6 +190,7 @@ ::SetWsrc(WsrcImageType *newWsrcImage){ // Pass the image to the wrapper m_WsrcWrapper->SetImage(newWsrcImage); + m_WsrcWrapper->GetImage()->Modified();// This makes sure that the IsDrawable() of the wrapper returns true, essential for showing up in the the SliceView (l.284 GenericSliceRenderer.cxx) // Sync up spacing between the main and label image newWsrcImage->SetSpacing(m_MainImageWrapper->GetImageBase()->GetSpacing()); diff --git a/todo b/todo index 862322de..e90a9f45 100644 --- a/todo +++ b/todo @@ -1,6 +1,5 @@ TODOs for GWS: -- make Wsrc-layer visible in Slice-view - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx - make UnDo possible - destinguish RMB click from RMB drag (zoom) From 7679da5bdf0fc160eb2f11071b02793d38749495 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Sat, 21 Mar 2015 23:35:27 +0100 Subject: [PATCH 18/42] finer graded setting of visibility and stickyness for CnJ and gWS --- GUI/Model/GlobalUIModel.cxx | 71 ++++++++++++++++++++++- GUI/Model/GlobalUIModel.h | 9 +++ GUI/Qt/Components/GlobalWSWizardPanel.cxx | 36 ++++++++++-- GUI/Qt/Components/JoinDataPanel.cxx | 5 ++ Logic/Framework/JOINImageData.cxx | 15 ++++- Logic/Framework/JOINImageData.h | 2 + Logic/ImageWrapper/ImageWrapperTraits.h | 2 +- todo | 10 +++- 8 files changed, 141 insertions(+), 9 deletions(-) diff --git a/GUI/Model/GlobalUIModel.cxx b/GUI/Model/GlobalUIModel.cxx index 99e310c8..751d66be 100644 --- a/GUI/Model/GlobalUIModel.cxx +++ b/GUI/Model/GlobalUIModel.cxx @@ -396,7 +396,7 @@ void GlobalUIModel::ToggleJsrcVisibility() // Apply the toggle for all overlays for(LayerIterator it = id->GetLayers(JOIN_ROLE); !it.IsAtEnd(); ++it){ - //if(dynamic_cast(it.GetLayer())){//does not work as currently JsrcImageWrapper == JdstImageWrapper == LabelImageWrapper + //if(dynamic_cast(it.GetLayer())){//not tested if(strcmp(it.GetLayer()->GetNickname().c_str(), "Join Source Image") == 0){ m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer()); m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->SetValue( @@ -409,6 +409,75 @@ void GlobalUIModel::ToggleJsrcVisibility() } } +void GlobalUIModel::SetJsrcVisibility(bool set) +{ + // Are we in JOIN mode? + if(CheckState(UIF_JOIN_MODE)){ + GenericImageData *id = m_Driver->GetCurrentImageData(); + + // Remember what layer is current in the general properties model + ImageWrapperBase *curr_layer = m_LayerGeneralPropertiesModel->GetLayer(); + + // Apply the toggle for all overlays + for(LayerIterator it = id->GetLayers(JOIN_ROLE); !it.IsAtEnd(); ++it){ + //if(dynamic_cast(it.GetLayer())){//not tested + if(strcmp(it.GetLayer()->GetNickname().c_str(), "Join Source Image") == 0){ + m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer()); + m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->SetValue(set); + } + } + + // Restore the active layer + m_LayerGeneralPropertiesModel->SetLayer(curr_layer); + } +} + +void GlobalUIModel::SetJdstVisibility(bool set) +{ + // Are we in JOIN mode? + if(CheckState(UIF_JOIN_MODE)){ + GenericImageData *id = m_Driver->GetCurrentImageData(); + + // Remember what layer is current in the general properties model + ImageWrapperBase *curr_layer = m_LayerGeneralPropertiesModel->GetLayer(); + + // Apply the toggle for all overlays + for(LayerIterator it = id->GetLayers(JOIN_ROLE); !it.IsAtEnd(); ++it){ + //if(dynamic_cast(it.GetLayer())){//not tested + if(strcmp(it.GetLayer()->GetNickname().c_str(), "Join Destination Image") == 0){ + m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer()); + m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->SetValue(set); + } + } + + // Restore the active layer + m_LayerGeneralPropertiesModel->SetLayer(curr_layer); + } +} + +void GlobalUIModel::SetWsrcVisibility(bool set) +{ + // Are we in JOIN mode? + if(CheckState(UIF_JOIN_MODE)){ + GenericImageData *id = m_Driver->GetCurrentImageData(); + + // Remember what layer is current in the general properties model + ImageWrapperBase *curr_layer = m_LayerGeneralPropertiesModel->GetLayer(); + + // Apply the toggle for all overlays + for(LayerIterator it = id->GetLayers(JOIN_ROLE); !it.IsAtEnd(); ++it){ + //if(dynamic_cast(it.GetLayer())){//not tested + if(strcmp(it.GetLayer()->GetNickname().c_str(), "GWS Source Image") == 0){ + m_LayerGeneralPropertiesModel->SetLayer(it.GetLayer()); + m_LayerGeneralPropertiesModel->GetLayerVisibilityModel()->SetValue(set); + } + } + + // Restore the active layer + m_LayerGeneralPropertiesModel->SetLayer(curr_layer); + } +} + void GlobalUIModel::AdjustOverlayOpacity(int delta) { // Are we in tiled mode or in stack mode? diff --git a/GUI/Model/GlobalUIModel.h b/GUI/Model/GlobalUIModel.h index ffd59444..f566e807 100644 --- a/GUI/Model/GlobalUIModel.h +++ b/GUI/Model/GlobalUIModel.h @@ -256,6 +256,15 @@ class GlobalUIModel : public AbstractModel /** Method to toggle Jsrc visibility */ void ToggleJsrcVisibility(); + /** Method to set Jsrc visibility */ + void SetJsrcVisibility(bool set); + + /** Method to set Jdst visibility */ + void SetJdstVisibility(bool set); + + /** Method to set Wsrc visibility */ + void SetWsrcVisibility(bool set); + /** Method to adjust overlay opacity (all or selected overlays) */ void AdjustOverlayOpacity(int delta); diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index b423b2f1..a55ef6a7 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -85,7 +85,7 @@ class WatershedPipeline{ wsImage= gmf->GetOutput(); } - wf->SetInput(wsImage); + wf->SetInput(wsImage);//causes recomp even when no params were chanaged -> todo: optimize by setting input only if it changed return(wsImage); } @@ -150,9 +150,6 @@ void GlobalWSWizardPanel::Initialize(){ // Initialize the model m_Model->OnGlobalWSModeEnter(); - // set tiled layout to ease understanding the interaction mode - m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); - // Go to the right page ui->stack->setCurrentWidget(ui->pgPreproc); } @@ -187,6 +184,13 @@ void GlobalWSWizardPanel::on_btnNextPreproc_clicked(){ ui->chkGlobalWSDirect->isChecked() ) ); + // set tiled layout to ease understanding the interaction mode + driver->GetJOINImageData()->SetWsrcSticky(false); + m_ParentModel->SetWsrcVisibility(true); + //m_ParentModel->SetJsrcVisibility(false);//let user decide + //m_ParentModel->SetJdstVisibility(false);//let user decide + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);//only when coming from stacked view will the tiled view get reorganized + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); // Move to the range page ui->stack->setCurrentWidget(ui->pgWSRange); @@ -211,6 +215,14 @@ void GlobalWSWizardPanel::on_btnWSRangeNext_clicked(){ driver->GetJOINImageData()->SetJsrc( m_Watershed->PrecomputeWatersheds(ui->inWSMin->value()/100.0, ui->inWSMax->value()/100.0) ); + // set tiled layout to ease understanding the interaction mode + driver->GetJOINImageData()->SetJdstSticky(false); + driver->GetJOINImageData()->SetWsrcSticky(true); + m_ParentModel->SetWsrcVisibility(false); + m_ParentModel->SetJsrcVisibility(true);//make sure Jsrc is visible + m_ParentModel->SetJdstVisibility(true);//make sure Jdst is visible + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);//only when coming from stacked view will the tiled view get reorganized + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); std::cerr << "Changing WS to level: " << ui->inWSLevel->value()/100.0 << std::flush; m_Watershed->RecomputeWatersheds(ui->inWSLevel->value()/100.0); @@ -310,6 +322,13 @@ void GlobalWSWizardPanel::on_btnWSRangeBack_clicked(){ // Move to the range page ui->stack->setCurrentWidget(ui->pgPreproc); + + // reset tiled layout + m_ParentModel->GetDriver()->GetJOINImageData()->SetWsrcSticky(true); + m_ParentModel->SetWsrcVisibility(false); + //m_ParentModel->SetJsrcVisibility(false);//let user decide + //m_ParentModel->SetJdstVisibility(false);//let user decide + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED); } catch(IRISException &exc) { @@ -325,6 +344,15 @@ void GlobalWSWizardPanel::on_btnJoinBack_clicked(){ // Move to the range page ui->stack->setCurrentWidget(ui->pgWSRange); + + // reset tiled layout + m_ParentModel->GetDriver()->GetJOINImageData()->SetJdstSticky(true); + m_ParentModel->GetDriver()->GetJOINImageData()->SetWsrcSticky(false); + m_ParentModel->SetWsrcVisibility(true); + //m_ParentModel->SetJsrcVisibility(false);//let user decide + //m_ParentModel->SetJdstVisibility(false);//let user decide + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);//only when coming from stacked view will the tiled view get reorganized + m_ParentModel->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); } catch(IRISException &exc) { diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index 60d3a5f0..36fb1a01 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -16,6 +16,7 @@ part of Click'n'Join mode, which was contributed by Roman Grothausmann #include "ImageIODelegates.h" #include "ImageIOWizard.h" #include "ImageIOWizardModel.h" +#include "JOINImageData.h" JoinDataPanel::JoinDataPanel(QWidget *parent) : @@ -70,6 +71,10 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ driver->SetCurrentImageDataToJOIN(); // set tiled layout to ease understanding the interaction mode + driver->GetJOINImageData()->SetJdstSticky(false); + //m_Model->SetJsrcVisibility(true);//crashes, seems to be default anyway + //m_Model->SetJdstVisibility(true);//crashes, seems to be default anyway + m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);//only when coming from stacked view will the tiled view get reorganized m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); } break; case 1:{ diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index 741f6e5f..0efd6948 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -124,7 +124,7 @@ ::InitializeJdst(){ m_JdstWrapper->GetDisplayMapping()->SetLabelColorTable(m_Parent->GetColorLabelTable()); m_JdstWrapper->InitializeToWrapper(m_MainImageWrapper, (LabelType) 0); - m_JdstWrapper->SetSticky(false); + m_JdstWrapper->SetSticky(true);//sticky is set with SetJdstSticky m_JdstWrapper->SetAlpha(0.5); InvokeEvent(LayerChangeEvent()); @@ -144,6 +144,11 @@ ::IsJdstLoaded() return (m_JdstWrapper && m_JdstWrapper->IsInitialized()); } +void +JOINImageData +::SetJdstSticky(bool sticky){ + m_JdstWrapper->SetSticky(sticky); + } /* ============================= GWS source Image @@ -164,7 +169,7 @@ ::InitializeWsrc(){ } m_WsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (WSRType) 0); - m_WsrcWrapper->SetSticky(true); //overlay, ie no separate tile + m_WsrcWrapper->SetSticky(true); //sticky is set with SetWsrcSticky m_WsrcWrapper->SetAlpha(0.5); InvokeEvent(LayerChangeEvent()); @@ -203,6 +208,12 @@ ::IsWsrcLoaded(){ return m_WsrcWrapper && m_WsrcWrapper->IsInitialized(); } +void +JOINImageData +::SetWsrcSticky(bool sticky){ + m_WsrcWrapper->SetSticky(sticky); + } + /**********************************/ void diff --git a/Logic/Framework/JOINImageData.h b/Logic/Framework/JOINImageData.h index 9ed0bc75..8715ffa2 100644 --- a/Logic/Framework/JOINImageData.h +++ b/Logic/Framework/JOINImageData.h @@ -80,11 +80,13 @@ class JOINImageData : public GenericImageData void InitializeJdst(); JdstImageWrapper* GetJdst(); bool IsJdstLoaded(); + void SetJdstSticky(bool sticky); void InitializeWsrc(); WsrcImageWrapper* GetWsrc(); void SetWsrc(WsrcImageType *newWsrcImage); bool IsWsrcLoaded(); + void SetWsrcSticky(bool sticky); protected: diff --git a/Logic/ImageWrapper/ImageWrapperTraits.h b/Logic/ImageWrapper/ImageWrapperTraits.h index a051e01a..aa74aa00 100644 --- a/Logic/ImageWrapper/ImageWrapperTraits.h +++ b/Logic/ImageWrapper/ImageWrapperTraits.h @@ -89,7 +89,7 @@ class WsrcImageWrapperTraits static void GetFixedIntensityRange(float &min, float &max) { min = -100.0; max = 100.0; } - itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_JET); + itkStaticConstMacro(DefaultColorMap, ColorMap::SystemPreset, ColorMap::COLORMAP_RWB); // Whether this image is shown on top of all other layers by default itkStaticConstMacro(StickyByDefault, bool, true); diff --git a/todo b/todo index e90a9f45..de8e328d 100644 --- a/todo +++ b/todo @@ -1,11 +1,19 @@ TODOs for GWS: - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx -- make UnDo possible +- adjust GUI: +-- text on gWS range: max available but causes recompute +-- gWS move use file/overlay to bottom +- set gWS input only if it changed on prepro. page +- make UnDo for CnJ/gWS possible +- parallelize iterators in CnJ and gWS, e.g. in CopySegementationToJsrc and on LMB/RMB - destinguish RMB click from RMB drag (zoom) - would be nice to let user choose which color representation should be used for Jsrc - make GUI parts more fool prove +- add a GUI progress for current stderr progress - add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData +- make contrast and LUT adjustment possible for e.g. GWS Source Image +- make it possible to "save" gWS state, e.g. WS regions and hirarchy such that no recomp. is necessary when gWS state is loaded (difficult, possibly not possible) - add MorphlogicalWS from all Labels into PB, result as overlay - change "load from file" to "load from overlay" in CnJ and gWS From 6c5fbf22325bd8640e10167731cf300fd10532d5 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Mon, 23 Mar 2015 14:36:41 +0100 Subject: [PATCH 19/42] make segementation visibile when entering and leaving CnJ and gWS --- GUI/Model/GlobalWSWizardModel.cxx | 5 ++++- GUI/Qt/Components/GlobalWSWizardPanel.cxx | 2 ++ GUI/Qt/Components/JoinDataPanel.cxx | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/GUI/Model/GlobalWSWizardModel.cxx b/GUI/Model/GlobalWSWizardModel.cxx index f124f66a..dcada4a6 100644 --- a/GUI/Model/GlobalWSWizardModel.cxx +++ b/GUI/Model/GlobalWSWizardModel.cxx @@ -29,7 +29,7 @@ void GlobalWSWizardModel::OnGlobalWSModeEnter() m_Driver->SetCurrentImageDataToJOIN(); //m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinDataPanel AND JoinInteraction m_GlobalState->SetToolbarMode(GWSJOIN_MODE); //only disables JoinDataPanel - + m_Parent->SetSegmentationVisibility(true); } void GlobalWSWizardModel::OnCancelSegmentation() @@ -39,6 +39,7 @@ void GlobalWSWizardModel::OnCancelSegmentation() m_Driver->ReleaseJOINImageData(); m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction + m_Parent->SetSegmentationVisibility(true); } void GlobalWSWizardModel::OnFinishGWS() @@ -54,6 +55,8 @@ void GlobalWSWizardModel::OnFinishGWS() m_Driver->ReleaseJOINImageData(); m_GlobalState->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction + m_Parent->SetSegmentationVisibility(true); } + diff --git a/GUI/Qt/Components/GlobalWSWizardPanel.cxx b/GUI/Qt/Components/GlobalWSWizardPanel.cxx index a55ef6a7..c163c344 100644 --- a/GUI/Qt/Components/GlobalWSWizardPanel.cxx +++ b/GUI/Qt/Components/GlobalWSWizardPanel.cxx @@ -290,6 +290,7 @@ void GlobalWSWizardPanel::on_btnCopySeg_clicked(){ m_ParentModel->GetProgressCommand()); driver->InvokeEvent(SegmentationChangeEvent()); + m_ParentModel->SetSegmentationVisibility(true); } void GlobalWSWizardPanel::on_btnClearSeg_clicked(){ @@ -297,6 +298,7 @@ void GlobalWSWizardPanel::on_btnClearSeg_clicked(){ driver->ClearJdst(); driver->InvokeEvent(SegmentationChangeEvent()); + m_ParentModel->SetSegmentationVisibility(true); } void GlobalWSWizardPanel::on_btnLoadFromFile_clicked(){///better make it a choose overlay button as ROI cropping has already happend diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index 36fb1a01..da309513 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -76,6 +76,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ //m_Model->SetJdstVisibility(true);//crashes, seems to be default anyway m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);//only when coming from stacked view will the tiled view get reorganized m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); + m_Model->SetSegmentationVisibility(true); } break; case 1:{ ////panel will be hidden in GWSJOIN_MODE @@ -120,6 +121,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ // set tiled layout to ease understanding the interaction mode m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); + m_Model->SetSegmentationVisibility(true); } break; default: ////Switch to crosshairs mode @@ -148,6 +150,7 @@ void JoinDataPanel::on_btnFinishCnJ_clicked(){ ui->btnFinishCnJ->setEnabled(false); ui->inJoinType->setEnabled(true); m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction + m_Model->SetSegmentationVisibility(true); } void JoinDataPanel::on_btnCancel_clicked(){ @@ -163,6 +166,7 @@ void JoinDataPanel::on_btnCancel_clicked(){ ui->btnFinishCnJ->setEnabled(false); ui->inJoinType->setEnabled(true); m_Model->GetGlobalState()->SetToolbarMode(CROSSHAIRS_MODE); //disables JoinInteraction + m_Model->SetSegmentationVisibility(true); } @@ -173,7 +177,7 @@ void JoinDataPanel::on_btnCopySeg_clicked(){ m_Model->GetProgressCommand()); driver->InvokeEvent(SegmentationChangeEvent()); - + m_Model->SetSegmentationVisibility(true); } void JoinDataPanel::on_btnClearSeg_clicked(){ @@ -181,4 +185,5 @@ void JoinDataPanel::on_btnClearSeg_clicked(){ driver->ClearJdst(); driver->InvokeEvent(SegmentationChangeEvent()); + m_Model->SetSegmentationVisibility(true); } From 30a80e270dc9adbddd3a9938254f3488832c843d Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Mon, 23 Mar 2015 14:41:48 +0100 Subject: [PATCH 20/42] saving images compressed --- Logic/ImageWrapper/ImageWrapper.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Logic/ImageWrapper/ImageWrapper.cxx b/Logic/ImageWrapper/ImageWrapper.cxx index 0572e906..14d8a8c0 100644 --- a/Logic/ImageWrapper/ImageWrapper.cxx +++ b/Logic/ImageWrapper/ImageWrapper.cxx @@ -147,6 +147,8 @@ class ImageWrapperPartialSpecializationTraitsCommon if(base) writer->SetImageIO(base); writer->SetInput(image); + writer->UseCompressionOn(); //would be nice if made dependent on type=="segmentation" in UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx @ 978 + std::cerr << "Saving image compressed! " << fname << std::endl; writer->Update(); } From ca7964dc50d02a7b7ed1561b0aa519345fac45ae Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Thu, 26 Mar 2015 12:03:03 +0100 Subject: [PATCH 21/42] disabled loading of segmentations (and other actions) during gWS (and CnJ) --- GUI/Model/GlobalUIModel.cxx | 2 +- GUI/Qt/Windows/MainImageWindow.cxx | 26 +++++++++++++------------- Logic/Framework/IRISApplication.cxx | 3 +++ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/GUI/Model/GlobalUIModel.cxx b/GUI/Model/GlobalUIModel.cxx index 751d66be..281a2a10 100644 --- a/GUI/Model/GlobalUIModel.cxx +++ b/GUI/Model/GlobalUIModel.cxx @@ -297,7 +297,7 @@ bool GlobalUIModel::CheckState(UIState state) case UIF_BASEIMG_LOADED: return m_Driver->IsMainImageLoaded(); case UIF_IRIS_WITH_BASEIMG_LOADED: - return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive();// && !m_Driver->IsJoinModeActive(); ///adding this will disable lablel change in Join mode: Bad! + return m_Driver->IsMainImageLoaded() && !m_Driver->IsSnakeModeActive();// && !m_Driver->IsJoinModeActive(); ///adding this will disable lablel change in Join mode, use UIF_NOT_SNAKE_OR_JOIN_MODE if needed. case UIF_IRIS_MODE: return !m_Driver->IsSnakeModeActive() && !m_Driver->IsJoinModeActive();//not sure if Join extension here has any effect case UIF_IRIS_WITH_OVERLAY_LOADED: diff --git a/GUI/Qt/Windows/MainImageWindow.cxx b/GUI/Qt/Windows/MainImageWindow.cxx index cf29a00c..19c44263 100644 --- a/GUI/Qt/Windows/MainImageWindow.cxx +++ b/GUI/Qt/Windows/MainImageWindow.cxx @@ -332,12 +332,12 @@ void MainImageWindow::Initialize(GlobalUIModel *model) // Set up activations - File menu activateOnFlag(ui->actionOpenMain, m_Model, UIF_IRIS_MODE); activateOnFlag(ui->menuRecent_Images, m_Model, UIF_IRIS_MODE); - activateOnFlag(ui->actionSaveMain, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionSaveMain, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE);//CnJ: Main(ROI) can be saved with RMB on layer in cursor inspector activateOnFlag(ui->actionSaveSpeed, m_Model, UIF_SNAKE_MODE); activateOnFlag(ui->actionSaveLevelSet, m_Model, UIF_LEVEL_SET_ACTIVE); activateOnFlag(ui->actionSaveMainROI, m_Model, UIF_SNAKE_MODE); activateOnFlag(ui->menuExport, m_Model, UIF_BASEIMG_LOADED); - activateOnFlag(ui->actionUnload_All, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionUnload_All, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); // Set up activations - Edit menu activateOnFlag(ui->actionUndo, m_Model, UIF_UNDO_POSSIBLE); @@ -356,9 +356,9 @@ void MainImageWindow::Initialize(GlobalUIModel *model) // Set up activations - Segmentation menu - activateOnFlag(ui->actionLoad_from_Image, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionClear, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionSaveSegmentation, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionLoad_from_Image, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionClear, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionSaveSegmentation, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); activateOnFlag(ui->actionSaveSegmentationAs, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); activateOnFlag(ui->actionSave_as_Mesh, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); activateOnFlag(ui->actionLoadLabels, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); @@ -367,16 +367,16 @@ void MainImageWindow::Initialize(GlobalUIModel *model) activateOnFlag(ui->menuAppearance, m_Model, UIF_BASEIMG_LOADED); // Overlay action activations - activateOnFlag(ui->actionAdd_Overlay, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionUnload_Last_Overlay, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionUnload_All_Overlays, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionAdd_Overlay, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionUnload_Last_Overlay, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionUnload_All_Overlays, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); activateOnFlag(ui->menuOverlayAppearance, m_Model, UIF_OVERLAY_LOADED); activateOnFlag(ui->actionToggleJsrcVis, m_Model, UIF_JOIN_MODE); // Workspace menu activateOnFlag(ui->actionOpenWorkspace, m_Model, UIF_IRIS_MODE); - activateOnFlag(ui->actionSaveWorkspace, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->actionSaveWorkspaceAs, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionSaveWorkspace, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->actionSaveWorkspaceAs, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); // Tool action activations activateOnFlag(ui->actionCrosshair, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); @@ -388,8 +388,8 @@ void MainImageWindow::Initialize(GlobalUIModel *model) activateOnFlag(ui->action3DCrosshair, m_Model, UIF_BASEIMG_LOADED); activateOnFlag(ui->action3DTrackball, m_Model, UIF_BASEIMG_LOADED); - activateOnFlag(ui->action3DScalpel, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); - activateOnFlag(ui->action3DSpray, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->action3DScalpel, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); + activateOnFlag(ui->action3DSpray, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); activateOnFlag(ui->actionLayerInspector, m_Model, UIF_BASEIMG_LOADED); activateOnFlag(ui->actionImage_Contrast, m_Model, UIF_BASEIMG_LOADED); @@ -400,7 +400,7 @@ void MainImageWindow::Initialize(GlobalUIModel *model) activateOnFlag(ui->actionImage_Information, m_Model, UIF_BASEIMG_LOADED); activateOnFlag(ui->actionLabel_Editor, m_Model, UIF_BASEIMG_LOADED); - activateOnFlag(ui->actionReorient_Image, m_Model, UIF_IRIS_WITH_BASEIMG_LOADED); + activateOnFlag(ui->actionReorient_Image, m_Model, UIF_NOT_SNAKE_OR_JOIN_MODE); // Hook up toolbar actions to the toolbar makeActionGroupCoupling(this->GetMainToolActionGroup(), diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index b9600dea..9306c131 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -832,6 +832,9 @@ ::UpdateIRISWithJOINImageData(CommandType *progressCommand) // Construct are region of interest into which the result will be pasted SNAPSegmentationROISettings roi = m_GlobalState->GetSegmentationROISettings(); + // the roi above can be wrong if a segmentation was loaded while itksnap is in a ROI-mode (e.g. Snake or gWS) + // the mismatch in the ROI-region index then causes the program to crash when the interators are initialized down below + // therefore disabled loading of segmentations during ROI-modes in MainImageWindow.cxx // Create iterators for copying from one to the other typedef itk::ImageRegionConstIterator SourceIteratorType; From e98eb342d2375455fddf77b81f528ffb751632dc Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 15 Apr 2015 12:42:03 +0200 Subject: [PATCH 22/42] basic implementation of loading an external segementation image into Jsrc for CnJ mode --- GUI/Qt/Components/JoinDataPanel.cxx | 16 ++-------------- GUI/Qt/Components/JoinDataPanel.ui | 3 +++ Logic/Framework/IRISApplication.cxx | 24 ++++++++++++++++++++++++ Logic/Framework/IRISApplication.h | 5 +++++ todo | 2 ++ 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index da309513..cb404605 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -83,19 +83,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ m_Model->GetGlobalState()->SetToolbarMode(GLOBALWS_ROI_MODE); } break; case 2:{ - // Create a model for IO - SmartPtr delegate = LoadSegmentationImageDelegate::New(); - delegate->Initialize(m_Model->GetDriver()); - SmartPtr model = ImageIOWizardModel::New(); - model->InitializeForLoad(m_Model, delegate, - "JsrImage", "Join Source Image"); - - // Execute the IO wizard - ImageIOWizard wiz(this); - wiz.SetModel(model); - wiz.exec(); - - //todo check for cancel in wizard and return from JOIN_MODE + ////todo: implement use of ITK-Snap file-chooser for setting file name IRISApplication *driver = m_Model->GetDriver(); @@ -114,7 +102,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ driver->GetGlobalState()->GetSegmentationROISettings(), sel, m_Model->GetProgressCommand()); - driver->CopySegementationToJsrc( + driver->LoadImageToJsrc(ui->JsrcInputFileName->text().toUtf8().constData(), driver->GetGlobalState()->GetSegmentationROISettings(), m_Model->GetProgressCommand()); driver->SetCurrentImageDataToJOIN(); diff --git a/GUI/Qt/Components/JoinDataPanel.ui b/GUI/Qt/Components/JoinDataPanel.ui index ee8ed581..488c63ee 100644 --- a/GUI/Qt/Components/JoinDataPanel.ui +++ b/GUI/Qt/Components/JoinDataPanel.ui @@ -142,6 +142,9 @@ QGroupBox::title { + + + diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index 9306c131..01ba141b 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -60,6 +60,7 @@ #include "itkBSplineInterpolateImageFunction.h" #include "itkLinearInterpolateImageFunction.h" #include "itkWindowedSincInterpolateImageFunction.h" +#include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkFlipImageFilter.h" #include @@ -319,6 +320,29 @@ ::CopySegementationToJsrc(const SNAPSegmentationROISettings &roi, InvokeEvent(LayerChangeEvent()); } +void +IRISApplication +::LoadImageToJsrc(const char* FileName, const SNAPSegmentationROISettings &roi, CommandType *progressCommand) +{ + assert(m_JOINImageData->IsJsrcLoaded()); + + typedef JsrcImageWrapper::ImageType TargetImageType; + TargetImageType::Pointer target = m_JOINImageData->GetJsrc()->GetImage(); + + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(FileName); + reader->Update(); + // target= reader->GetOutput(); + // target->DisconnectPipeline(); + + // // The target has been modified + // target->Modified(); + m_JOINImageData->SetJsrc(reader->GetOutput()); + + InvokeEvent(LayerChangeEvent()); +} + void IRISApplication ::CopySegementationToJdst(const SNAPSegmentationROISettings &roi, diff --git a/Logic/Framework/IRISApplication.h b/Logic/Framework/IRISApplication.h index 0c15dbf2..86b11511 100644 --- a/Logic/Framework/IRISApplication.h +++ b/Logic/Framework/IRISApplication.h @@ -283,6 +283,11 @@ class IRISApplication : public itk::Object void CopySegementationToJsrc(const SNAPSegmentationROISettings &roi, CommandType *progressCommand = NULL); + /** + * Load external Segmentation to Jsrc for JOIN-mode 2 + */ + void LoadImageToJsrc(const char* FileName, const SNAPSegmentationROISettings &roi, CommandType *progressCommand); + /** * Copy Segmentation to Jsrc for JOIN-mode 0 */ diff --git a/todo b/todo index de8e328d..06b7f56c 100644 --- a/todo +++ b/todo @@ -1,5 +1,7 @@ TODOs for GWS: +- combine mode 2 with mode 0 and add extra button for "LoadImageToJsrc" +-- restructure JoinDataPanel to have two main buttons: CnJ from Seg. or File OR CnJ from gWS - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx - adjust GUI: -- text on gWS range: max available but causes recompute From 3186e708e1b44c097e41bf9a66b6b2f575b5b00f Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Mon, 15 Jun 2015 14:26:44 +0200 Subject: [PATCH 23/42] BUG: preventing crash due to overflow for large int vectors by circumventing VNL dot_product --- Logic/Slicing/IRISSlicer.txx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Logic/Slicing/IRISSlicer.txx b/Logic/Slicing/IRISSlicer.txx index da2441d7..a60ecd5b 100644 --- a/Logic/Slicing/IRISSlicer.txx +++ b/Logic/Slicing/IRISSlicer.txx @@ -367,7 +367,10 @@ void IRISSlicer szVol[m_SliceDirectionImageAxis] == 1 ? 0 : m_SliceIndex; // Get the offset of the first voxel - size_t iStart = dot_product(stride_image, xStartVoxel); + //size_t iStart = dot_product(stride_image, xStartVoxel);//overflows if any product is greater than uint32! see: http://itk.org/gitweb?p=ITK.git;a=blob;f=Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sse.h;h=04f930ef05bb49036e1fa69d6fe9ae9a697e2d45;hb=HEAD#l189 + size_t iStart = (size_t)stride_image[0]*(size_t)xStartVoxel[0] + + (size_t)stride_image[1]*(size_t)xStartVoxel[1] + + (size_t)stride_image[2]*(size_t)xStartVoxel[2];//doing it outside VNL, save but slower? // Get the size of the output region (whole slice) typename OutputImageType::RegionType rgn = outputPtr->GetBufferedRegion(); From bc2bfac24bac81ad7dab86f94439f3e0f24bf1ca Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 16 Jun 2015 11:42:19 +0200 Subject: [PATCH 24/42] BUG: preventing crash due to overflow for large int vectors by circumventing VNL dot_product (backport to gdWS) --- Logic/Slicing/IRISSlicer.txx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Logic/Slicing/IRISSlicer.txx b/Logic/Slicing/IRISSlicer.txx index c19dc4ff..71615c9b 100644 --- a/Logic/Slicing/IRISSlicer.txx +++ b/Logic/Slicing/IRISSlicer.txx @@ -366,7 +366,10 @@ void IRISSlicer szVol[m_SliceDirectionImageAxis] == 1 ? 0 : m_SliceIndex; // Get the offset of the first voxel - size_t iStart = dot_product(stride_image, xStartVoxel); + //size_t iStart = dot_product(stride_image, xStartVoxel);//overflows if any product is greater than uint32! see: http://itk.org/gitweb?p=ITK.git;a=blob;f=Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sse.h;h=04f930ef05bb49036e1fa69d6fe9ae9a697e2d45;hb=HEAD#l189 + size_t iStart = (size_t)stride_image[0]*(size_t)xStartVoxel[0] + + (size_t)stride_image[1]*(size_t)xStartVoxel[1] + + (size_t)stride_image[2]*(size_t)xStartVoxel[2];//doing it outside VNL, save but slower? // Get the size of the output region (whole slice) typename OutputImageType::RegionType rgn = outputPtr->GetBufferedRegion(); From b4a75da2e5e129307af1734740868aa86e0018c2 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 16 Jun 2015 11:45:29 +0200 Subject: [PATCH 25/42] ENH: made LoadImageToJsrc use less memory --- GUI/Model/GlobalWSWizardModel.cxx | 1 + GUI/Qt/Components/JoinDataPanel.cxx | 9 ++++++--- Logic/Framework/IRISApplication.cxx | 28 ++++++++++++++++++++++++---- Logic/Framework/IRISApplication.h | 2 +- Logic/Framework/JOINImageData.cxx | 7 +++++-- Logic/Framework/JOINImageData.h | 2 +- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/GUI/Model/GlobalWSWizardModel.cxx b/GUI/Model/GlobalWSWizardModel.cxx index dcada4a6..889703ef 100644 --- a/GUI/Model/GlobalWSWizardModel.cxx +++ b/GUI/Model/GlobalWSWizardModel.cxx @@ -24,6 +24,7 @@ void GlobalWSWizardModel::OnGlobalWSModeEnter() //// Initialize the image data m_Driver->InitializeJOINImageData( m_Driver->GetGlobalState()->GetSegmentationROISettings(), 1, //1: GWS; todo: use enum for selection state of CnJ + NULL, m_Parent->GetProgressCommand()); m_Driver->SetCurrentImageDataToJOIN(); diff --git a/GUI/Qt/Components/JoinDataPanel.cxx b/GUI/Qt/Components/JoinDataPanel.cxx index cb404605..90f483f6 100644 --- a/GUI/Qt/Components/JoinDataPanel.cxx +++ b/GUI/Qt/Components/JoinDataPanel.cxx @@ -63,6 +63,7 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ //// Initialize the image data driver->InitializeJOINImageData( driver->GetGlobalState()->GetSegmentationROISettings(), sel, + NULL, m_Model->GetProgressCommand()); driver->CopySegementationToJsrc( @@ -100,14 +101,16 @@ void JoinDataPanel::on_btnStartCnJ_clicked(){ //// Initialize the image data driver->InitializeJOINImageData( driver->GetGlobalState()->GetSegmentationROISettings(), sel, + ui->JsrcInputFileName->text().toUtf8().constData(), m_Model->GetProgressCommand()); - driver->LoadImageToJsrc(ui->JsrcInputFileName->text().toUtf8().constData(), - driver->GetGlobalState()->GetSegmentationROISettings(), - m_Model->GetProgressCommand()); driver->SetCurrentImageDataToJOIN(); // set tiled layout to ease understanding the interaction mode + driver->GetJOINImageData()->SetJdstSticky(false); + //m_Model->SetJsrcVisibility(true);//crashes, seems to be default anyway + //m_Model->SetJdstVisibility(true);//crashes, seems to be default anyway + m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_STACKED);//only when coming from stacked view will the tiled view get reorganized m_Model->GetDisplayLayoutModel()->GetSliceViewLayerLayoutModel()->SetValue(LAYOUT_TILED); m_Model->SetSegmentationVisibility(true); } break; diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index 01ba141b..8f11f028 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -253,7 +253,7 @@ ::InitializeSNAPImageData(const SNAPSegmentationROISettings &roi, void IRISApplication -::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, +::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, const char* FileName, CommandType *progressCommand) { assert(m_IRISImageData->IsMainLoaded()); @@ -261,11 +261,31 @@ ::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, // Create the JOIN image data object m_JOINImageData->InitializeToROI(m_IRISImageData, roi, progressCommand); - if(CnJMode == 1)//GWS - m_JOINImageData->InitializeWsrc(); + if(CnJMode == 0){//CnJ with "current segementation" + m_JOINImageData->InitializeJsrc();//fills Jsrc with zeros + } + else if(CnJMode == 1){//GWS + m_JOINImageData->InitializeWsrc(); + m_JOINImageData->InitializeJsrc();//fills Jsrc with zeros + } + else if(CnJMode == 2){//CnJ with "load from file" + assert(FileName); + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(FileName); + try{ + reader->Update(); + m_JOINImageData->InitializeJsrc(reader->GetOutput()); + } + catch(itk::ExceptionObject &ex){ + std::cerr << ex << std::endl; + + ////ToDo: return from CnJ if an error occures (e.g. file does not exist) + m_JOINImageData->InitializeJsrc();//fills Jsrc with zeros + } + } // Initialize the source and destination images of the JOIN image data - m_JOINImageData->InitializeJsrc(); m_JOINImageData->InitializeJdst(); // Pass the cleaned up segmentation image to SNAP diff --git a/Logic/Framework/IRISApplication.h b/Logic/Framework/IRISApplication.h index 86b11511..b7fc0a21 100644 --- a/Logic/Framework/IRISApplication.h +++ b/Logic/Framework/IRISApplication.h @@ -274,7 +274,7 @@ class IRISApplication : public itk::Object /** * Initialize JOIN Image data using region of interest extents */ - void InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, + void InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, const char* FileName, CommandType *progressCommand = NULL); /** diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index 0efd6948..ea8467c4 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -52,7 +52,7 @@ JOINImageData void JOINImageData -::InitializeJsrc(){ +::InitializeJsrc(JsrcImageType *newJsrcImage){ // The Grey image wrapper should be present assert(m_MainImageWrapper->IsInitialized()); @@ -64,7 +64,10 @@ ::InitializeJsrc(){ PushBackImageWrapper(JOIN_ROLE, m_JsrcWrapper.GetPointer()); } - m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (JSRType) 0); + if(newJsrcImage) + m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, newJsrcImage); + else + m_JsrcWrapper->InitializeToWrapper(m_MainImageWrapper, (JSRType) 0); m_JsrcWrapper->SetSticky(true); //overlay, ie no separate tile m_JsrcWrapper->SetAlpha(0.5); diff --git a/Logic/Framework/JOINImageData.h b/Logic/Framework/JOINImageData.h index 8715ffa2..cf430a63 100644 --- a/Logic/Framework/JOINImageData.h +++ b/Logic/Framework/JOINImageData.h @@ -72,7 +72,7 @@ class JOINImageData : public GenericImageData */ void UnloadAll(); - void InitializeJsrc(); + void InitializeJsrc(JsrcImageType *newJsrcImage= NULL); JsrcImageWrapper* GetJsrc(); void SetJsrc(JsrcImageType *newJsrcImage); bool IsJsrcLoaded(); From 3176abcf7167bbd3cfa14e5fa9a076d5f3336274 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 16 Jun 2015 13:39:19 +0200 Subject: [PATCH 26/42] added defaults to ImageWrapper.h to make last merge work --- Logic/ImageWrapper/ImageWrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Logic/ImageWrapper/ImageWrapper.h b/Logic/ImageWrapper/ImageWrapper.h index 94e62865..310e23e2 100644 --- a/Logic/ImageWrapper/ImageWrapper.h +++ b/Logic/ImageWrapper/ImageWrapper.h @@ -161,7 +161,7 @@ class ImageWrapper : public TBase * source wrapper, otherwise, it's equivalent to SetImage() */ virtual void InitializeToWrapper( - const ImageWrapperBase *source, ImageType *image, ImageBaseType *refSpace, ITKTransformType *tran); + const ImageWrapperBase *source, ImageType *image, ImageBaseType *refSpace= NULL, ITKTransformType *tran= NULL); /** Get a unique id for this wrapper. All wrappers ever created have From f6172790b96fd19400f328f708daa6a024408524 Mon Sep 17 00:00:00 2001 From: Paul Yushkevich Date: Sat, 17 Oct 2015 05:26:08 -0400 Subject: [PATCH 27/42] Fixed wraparound behavior of drawing tools in slice views --- GUI/Qt/Components/SliceViewPanel.ui | 6 +----- GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx | 8 +++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/GUI/Qt/Components/SliceViewPanel.ui b/GUI/Qt/Components/SliceViewPanel.ui index a62b7a0c..17c338bc 100644 --- a/GUI/Qt/Components/SliceViewPanel.ui +++ b/GUI/Qt/Components/SliceViewPanel.ui @@ -759,11 +759,7 @@ p, li { white-space: pre-wrap; } - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Helvetica'; font-size:11px; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pastes the last polygon that you have accepted in this slice view. You can then move the vertices in the pasted polygon to fit image data. This can be more efficient than drawing a new polygon when performing segmentation across multiple slices.</p></body></html> + <html><head/><body><p><span style=" font-family:'Helvetica'; font-size:11px;">Pastes the last polygon that you have accepted in this slice view. You can then move the vertices in the pasted polygon to fit image data. This can be more efficient than drawing a new polygon when performing segmentation across multiple slices.</span></p></body></html> paste diff --git a/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx b/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx index e87e17cd..d971e34a 100644 --- a/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx +++ b/GUI/Qt/View/SliceWindowInteractionDelegateWidget.cxx @@ -133,8 +133,10 @@ ::GetEventWorldCoordinates(QMouseEvent *ev, bool flipY) modelMatrix,projMatrix,viewport, &xProjection[0], &xProjection[1], &xProjection[2]); - // Get the within-cell coordinates - xProjection[0] = fmod(xProjection[0], (double) m_ParentModel->GetSize()[0]); - xProjection[1] = fmod(xProjection[1], (double) m_ParentModel->GetSize()[1]); + // Get the within-cell coordinates by subtracting the corner of the cell + xProjection[0] -= icol * m_ParentModel->GetSize()[0]; + xProjection[1] -= flipY + ? ((nrows - 1) - irow) * m_ParentModel->GetSize()[1] + : irow * m_ParentModel->GetSize()[1]; return xProjection; } From 35787dee8ca6dfca18f7efbd678000bf1bc42241 Mon Sep 17 00:00:00 2001 From: Paul Yushkevich Date: Sat, 17 Oct 2015 06:10:06 -0400 Subject: [PATCH 28/42] Compile error fix on Qt4 --- .gitignore | 2 +- GUI/Qt/Windows/LabelEditorDialog.cxx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 252540c0..9ada7eba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # VIM swap files .*.sw? -*.un~ +*~ # MACOS files .DS_Store* diff --git a/GUI/Qt/Windows/LabelEditorDialog.cxx b/GUI/Qt/Windows/LabelEditorDialog.cxx index f1418fcf..03777457 100644 --- a/GUI/Qt/Windows/LabelEditorDialog.cxx +++ b/GUI/Qt/Windows/LabelEditorDialog.cxx @@ -109,9 +109,13 @@ void LabelEditorDialog::SetModel(LabelEditorModel *model) LabelEditorModel::UIF_EDITABLE_LABEL_SELECTED); // Set resizing behavior +#if QT_VERSION >= 0x050000 ui->lvLabels->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); ui->lvLabels->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); - +#else + ui->lvLabels->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents); + ui->lvLabels->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch); +#endif } void LabelEditorDialog::on_btnClose_clicked() From 6cf1430fda1cf67e214a5a41a1bb7e85b62a6ef3 Mon Sep 17 00:00:00 2001 From: Paul Yushkevich Date: Mon, 30 Nov 2015 18:38:38 -0500 Subject: [PATCH 29/42] Set version to 3.4.0 --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e23b0e7c..e061b181 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,12 +55,12 @@ endforeach() # These four fields should be modified when versions change SET(SNAP_VERSION_MAJOR 3) SET(SNAP_VERSION_MINOR 4) -SET(SNAP_VERSION_PATCH 1) -SET(SNAP_VERSION_QUALIFIER "-alpha") +SET(SNAP_VERSION_PATCH 0) +SET(SNAP_VERSION_QUALIFIER "") # These fields should also be modified each time -SET(SNAP_VERSION_RELEASE_DATE "20151017") -SET(SNAP_VERSION_RELEASE_DATE_FORMATTED "Oct 17, 2015") +SET(SNAP_VERSION_RELEASE_DATE "20151130") +SET(SNAP_VERSION_RELEASE_DATE_FORMATTED "Nov 30, 2015") # This field should only change when the format of the settings files changes # in a non backwards-compatible way From 145508b24424aeb9e7b26e3dba0ec834f397bf90 Mon Sep 17 00:00:00 2001 From: Paul Yushkevich Date: Thu, 3 Dec 2015 14:35:49 -0500 Subject: [PATCH 30/42] Fixed problem created during merge with CDash drop site --- CTestConfig.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CTestConfig.cmake b/CTestConfig.cmake index 1915c652..2a7898b8 100644 --- a/CTestConfig.cmake +++ b/CTestConfig.cmake @@ -6,10 +6,10 @@ ## ENABLE_TESTING() ## INCLUDE(CTest) -set(CTEST_PROJECT_NAME "ITK-SNAP master") -set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") +set(CTEST_PROJECT_NAME "ITK-SNAP 3.4") +set(CTEST_NIGHTLY_START_TIME "00:00:00 UTC") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "itksnap.org") -set(CTEST_DROP_LOCATION "/cdash/submit.php?project=ITK-SNAP+master") +set(CTEST_DROP_LOCATION "/cdash/submit.php?project=ITK-SNAP+3.4") set(CTEST_DROP_SITE_CDASH TRUE) From 55a738f345e9608f867b52baf03db8c6f46ee269 Mon Sep 17 00:00:00 2001 From: Paul Yushkevich Date: Thu, 3 Dec 2015 16:43:06 -0500 Subject: [PATCH 31/42] Release notes edited for 3.4 --- ReleaseNotes.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index a347e7ad..782e1229 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -59,7 +59,8 @@ on usability. - Command tooltips have been redesigned and now include information on the shortcut key to activate each command. In addion, tooltips for the tools in - the main palette describe the actions of each mouse button. + the main palette describe the actions of each mouse button. Many new shortcuts + have been added. - Cleaned up the behavior of mouse buttons and mouse scrolling to be more consistent between modes. Added Shift-scroll action, which scrolls through @@ -83,6 +84,13 @@ on usability. and a slider for "classifier bias", which allows you to bias the classfier output more toward the foreground class or background classes. + - Added the ability to select more than one class as the foreground class in + the random forest classification mode. This is powerful when the foreground + object has heterogeneous intensity. + + - Training examples drawn in random forest classificaiton mode are now retained + and can be reused to label multiple structures. + 1.1.2. Programmatic Improvements From c41af1d6728178a7bb159578fc6b70fdb1da3ff7 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 30 Jan 2018 14:48:44 +0100 Subject: [PATCH 32/42] btnJoin was not visible (with/out changes from v3.4) --- GUI/Qt/Windows/MainControlPanel.cxx | 1 + GUI/Qt/Windows/MainControlPanel.ui | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/GUI/Qt/Windows/MainControlPanel.cxx b/GUI/Qt/Windows/MainControlPanel.cxx index c4dcd4b0..02fb3dbd 100644 --- a/GUI/Qt/Windows/MainControlPanel.cxx +++ b/GUI/Qt/Windows/MainControlPanel.cxx @@ -93,6 +93,7 @@ MainControlPanel::MainControlPanel(MainImageWindow *parent) : ui->btnZoom->setDefaultAction(FindUpstreamAction(this, "actionZoomPan")); ui->btnPolygon->setDefaultAction(FindUpstreamAction(this, "actionPolygon")); ui->btnPaintbrush->setDefaultAction(FindUpstreamAction(this, "actionPaintbrush")); + ui->btnJoin->setDefaultAction(FindUpstreamAction(this, "actionJoin")); ui->btnAnnotation->setDefaultAction(FindUpstreamAction(this, "actionAnnotation")); ui->btnSnake->setDefaultAction(FindUpstreamAction(this, "actionSnake")); diff --git a/GUI/Qt/Windows/MainControlPanel.ui b/GUI/Qt/Windows/MainControlPanel.ui index 9d7d4b28..31633013 100644 --- a/GUI/Qt/Windows/MainControlPanel.ui +++ b/GUI/Qt/Windows/MainControlPanel.ui @@ -297,6 +297,20 @@ QToolButton:checked { + + + + ... + + + + :/root/globalWS.gif:/root/globalWS.gif + + + true + + + From 32813440b60d87fd3d8d71fcbe3b08c87e44e585 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Tue, 30 Jan 2018 15:48:53 +0100 Subject: [PATCH 33/42] actionToggleJsrcVis was missing (with/out changes from v3.4) --- GUI/Qt/Windows/MainImageWindow.ui | 1 + 1 file changed, 1 insertion(+) diff --git a/GUI/Qt/Windows/MainImageWindow.ui b/GUI/Qt/Windows/MainImageWindow.ui index 887f5153..71b5ba29 100644 --- a/GUI/Qt/Windows/MainImageWindow.ui +++ b/GUI/Qt/Windows/MainImageWindow.ui @@ -437,6 +437,7 @@ color:rgb(103, 103, 103); Appearance + From ef40b5d2d59000322dc816135dcebfa955c54311 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 31 Jan 2018 13:39:57 +0100 Subject: [PATCH 34/42] pass transform to JOIN data (for v>3.0.0, according to SNAPImageData but has no apparent effect) --- Logic/Framework/IRISApplication.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index 4301be55..5cf09dc2 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -445,6 +445,12 @@ ::SetDisplayGeometry(const IRISDisplayGeometry &dispGeom) m_SNAPImageData->SetDisplayGeometry(dispGeom); } + // Create the appropriate transform and pass it to the JOIN data + if(m_JOINImageData->IsMainLoaded()) + { + m_JOINImageData->SetDisplayGeometry(dispGeom); + } + // Invoke the corresponding event InvokeEvent(DisplayToAnatomyCoordinateMappingChangeEvent()); } From 6e31ad8fc88606b4b31fa3bb73fb4b3137d167e5 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Fri, 8 May 2015 13:48:18 +0200 Subject: [PATCH 35/42] basic implementation of JoinCopyFilter and its integration into CnJ --- GUI/Model/JoinModel.cxx | 68 +------------------------- Logic/Common/itkJoinCopyFilter.cxx | 76 +++++++++++++++++++++++++++++ Logic/Common/itkJoinCopyFilter.h | 73 +++++++++++++++++++++++++++ Logic/Framework/IRISApplication.cxx | 24 +++++++++ Logic/Framework/IRISApplication.h | 6 +++ Logic/Framework/JOINImageData.cxx | 22 +++++++++ Logic/Framework/JOINImageData.h | 9 ++++ todo | 7 +++ 8 files changed, 218 insertions(+), 67 deletions(-) create mode 100644 Logic/Common/itkJoinCopyFilter.cxx create mode 100644 Logic/Common/itkJoinCopyFilter.h diff --git a/GUI/Model/JoinModel.cxx b/GUI/Model/JoinModel.cxx index 61413500..0f834fc0 100644 --- a/GUI/Model/JoinModel.cxx +++ b/GUI/Model/JoinModel.cxx @@ -94,75 +94,9 @@ bool JoinModel::processCnJ(bool reverse_mode){ // Get the global objects IRISApplication *driver = m_Parent->GetDriver(); - GlobalState *gs = driver->GetGlobalState(); - - // Get Join source image - JsrcImageWrapper *jsrc = driver->GetJOINImageData()->GetJsrc(); - - // Get Join destination image - JdstImageWrapper *jdst = driver->GetJOINImageData()->GetJdst(); - - // Get the segmentation image - //LabelImageWrapper *imgLabel = driver->GetCurrentImageData()->GetSegmentation(); - - // Get the paint properties - LabelType drawing_color = gs->GetDrawingColorLabel(); - DrawOverFilter drawover = gs->GetDrawOverFilter(); - - // Define a region of interest - //LabelImageWrapper::ImageType::RegionType xTestRegion= jsrc->GetImage()->GetBufferedRegion(); - JsrcImageWrapper::ImageType::RegionType xTestRegion= jsrc->GetImage()->GetLargestPossibleRegion(); // Flag to see if anything was changed - bool flagUpdate = false; - - JsrcImageWrapper::ImageType::ValueType JsrcClickPV= jsrc->GetImage()->GetPixel(to_itkIndex(m_MousePosition)); - // JdstImageWrapper::ImageType::ValueType JdstClickPV= jdst->GetImage()->GetPixel(to_itkIndex(m_MousePosition)); - - - // Iterate over the region - JsrcImageWrapper::Iterator sit(jsrc->GetImage(), xTestRegion); - LabelImageWrapper::Iterator dit(jdst->GetImage(), xTestRegion); - for(; !sit.IsAtEnd(); ++sit, ++dit){ - - if(sit.Get() != JsrcClickPV) - continue; - - LabelType pxLabel = dit.Get(); - - // Standard paint mode - if(!reverse_mode) - { - if(drawover.CoverageMode == PAINT_OVER_ALL || - (drawover.CoverageMode == PAINT_OVER_ONE && pxLabel == drawover.DrawOverLabel) || - (drawover.CoverageMode == PAINT_OVER_VISIBLE && pxLabel != 0)) - { - dit.Set(drawing_color); - if(pxLabel != drawing_color) flagUpdate = true; - } - } - // Background paint mode (clear label over current label) - else - { - if(drawing_color != 0 && pxLabel == drawing_color) - { - dit.Set(0); - if(pxLabel != 0) flagUpdate = true; - } - else if(drawing_color == 0 && drawover.CoverageMode == PAINT_OVER_ONE) - { - dit.Set(drawover.DrawOverLabel); - if(pxLabel != drawover.DrawOverLabel) flagUpdate = true; - } - } - } - - // Image has been updated - if(flagUpdate) - { - jdst->GetImage()->Modified(); - //imgLabel->GetImage()->Modified(); - } + bool flagUpdate= driver->ExecuteCnJCopy(to_itkIndex(m_MousePosition)); return flagUpdate; } diff --git a/Logic/Common/itkJoinCopyFilter.cxx b/Logic/Common/itkJoinCopyFilter.cxx new file mode 100644 index 00000000..20b7daf2 --- /dev/null +++ b/Logic/Common/itkJoinCopyFilter.cxx @@ -0,0 +1,76 @@ +////image filter to set DrawingColor in output image if input pixel equals SeedValue + +#ifndef __itkJoinCopyFilter_cxx +#define __itkJoinCopyFilter_cxx + +#include "itkJoinCopyFilter.h" +#include +#include +#include + +namespace itk{ + + template + JoinCopyFilter + ::JoinCopyFilter(){ + m_SeedActive= false; + m_SeedIndex.Fill(0); + m_SeedValue= NumericTraits::Zero; + } + + template + void JoinCopyFilter + ::SetJsrc(const TInputImage1 *image1){ + this->SetNthInput( 0, const_cast< TInputImage1 * >( image1 ) ); + } + + template + void JoinCopyFilter + ::SetJdst(const TInputImage2 *image2){ + this->SetNthInput( 1, const_cast< TInputImage2 * >( image2 ) ); + } + + + template + void JoinCopyFilter + ::BeforeThreadedGenerateData(){ + + if(m_SeedActive){ + typename TInputImage1::ConstPointer input = dynamic_cast( ProcessObject::GetInput(0) ); + m_SeedValue= input->GetPixel(m_SeedIndex); + } + m_UpdateFlag= false; + } + + + template + void JoinCopyFilter + ::ThreadedGenerateData(const typename Superclass::OutputImageRegionType& outputRegionForThread, ThreadIdType threadId){ + + if(m_SeedActive){ + typename TInputImage1::ConstPointer input = dynamic_cast( ProcessObject::GetInput(0) ); + typename TOutputImage::Pointer output = this->GetOutput(); + + itk::ImageRegionConstIterator iti(input, outputRegionForThread); + itk::ImageRegionIterator ito(output, outputRegionForThread); + + // support progress methods/callbacks with 1000 updates + ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels(), 1000); + + while(!iti.IsAtEnd()){ + if(iti.Get() == m_SeedValue){ + ito.Set(m_DrawingColor); + } + ++iti; + ++ito; + progress.CompletedPixel(); + } + + m_UpdateFlag= true; + m_SeedActive= false; + //output->Modified(); + } + } + }// end namespace + +#endif //__itkJoinCopyFilter_cxx diff --git a/Logic/Common/itkJoinCopyFilter.h b/Logic/Common/itkJoinCopyFilter.h new file mode 100644 index 00000000..5b0a4150 --- /dev/null +++ b/Logic/Common/itkJoinCopyFilter.h @@ -0,0 +1,73 @@ +#ifndef __itkJoinCopyFilter_h +#define __itkJoinCopyFilter_h + +#include + +namespace itk{ + /** \class JoinCopyFilter + * \brief: sets DrawingColor in output image if input pixel equals SeedValue + * + * \ingroup ImageFilters + */ + template + class JoinCopyFilter: + public InPlaceImageFilter{ + public: + /** Standard class typedefs. */ + typedef JoinCopyFilter Self; + typedef InPlaceImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(JoinCopyFilter, InPlaceImageFilter); + + void SetJsrc(const TInputImage1 *image1); + void SetJdst(const TInputImage2 *image2); + + /** Set/Get SeedIndex value */ + itkSetMacro(SeedIndex, typename TInputImage1::IndexType); + itkGetConstMacro(SeedIndex, typename TInputImage1::IndexType); + + /** Set/Get DrawingColor value */ + itkSetMacro(DrawingColor, typename TOutputImage::ValueType); + itkGetConstMacro(DrawingColor, typename TOutputImage::ValueType); + + /** Get UpdateFlag value */ + itkGetConstMacro(UpdateFlag, bool); + + /** Get/Set SeedActive value */ + itkSetMacro(SeedActive, bool); + itkGetConstMacro(SeedActive, bool); + + protected: + JoinCopyFilter(); + ~JoinCopyFilter(){} + + bool m_SeedActive; + typename TInputImage1::IndexType m_SeedIndex; + typename TInputImage1::ValueType m_SeedValue; + typename TOutputImage::ValueType m_DrawingColor; + bool m_UpdateFlag; + + + virtual void BeforeThreadedGenerateData(); + virtual void ThreadedGenerateData(const typename Superclass::OutputImageRegionType& outputRegionForThread, ThreadIdType threadId); + + private: + JoinCopyFilter(const Self &); //purposely not implemented + void operator=(const Self &); //purposely not implemented + + }; + } //namespace ITK + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkJoinCopyFilter.cxx" +#endif + +#endif // __itkJoinCopyFilter_h + diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index 5cf09dc2..ce8f2ce4 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -289,10 +289,34 @@ ::InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, c // Remember the ROI object m_GlobalState->SetSegmentationROISettings(roi); + // Initialize JoinCopyFilter + m_JOINImageData->InitializeJoinCF(); + // The set of layers has changed InvokeEvent(LayerChangeEvent()); } +bool +IRISApplication +::ExecuteCnJCopy(JsrcImageWrapper::ImageType::IndexType SeedIndex) +{ + assert(m_JOINImageData->IsJsrcLoaded()); + + GlobalState *gs = GetGlobalState(); + + // Get the paint properties + LabelType drawing_color = gs->GetDrawingColorLabel(); + DrawOverFilter drawover = gs->GetDrawOverFilter(); + + m_JOINImageData->GetJoinCF()->SetSeedIndex(SeedIndex); + m_JOINImageData->GetJoinCF()->SetDrawingColor(drawing_color); + m_JOINImageData->GetJoinCF()->SetSeedActive(true); + m_JOINImageData->GetJoinCF()->Update(); + + InvokeEvent(LayerChangeEvent()); + return m_JOINImageData->GetJoinCF()->GetUpdateFlag(); +} + void IRISApplication ::CopySegementationToJsrc(const SNAPSegmentationROISettings &roi, diff --git a/Logic/Framework/IRISApplication.h b/Logic/Framework/IRISApplication.h index 1accd45b..3f55fd29 100644 --- a/Logic/Framework/IRISApplication.h +++ b/Logic/Framework/IRISApplication.h @@ -46,6 +46,7 @@ #include "SystemInterface.h" #include "UndoDataManager.h" #include "SNAPEvents.h" +#include "JOINImageData.h" //for JsrcImageWrapper::ImageType::IndexType // #include "itkImage.h" @@ -320,6 +321,11 @@ class IRISApplication : public itk::Object void InitializeJOINImageData(const SNAPSegmentationROISettings &roi, int CnJMode, const char* FileName, CommandType *progressCommand = NULL); + /** + * Execute CnJ CopyFilter + */ + bool ExecuteCnJCopy(JsrcImageWrapper::ImageType::IndexType SeedIndex); + /** * Copy Segmentation to Jsrc for JOIN-mode 0 */ diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index 4da628ac..694958b9 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -301,4 +301,26 @@ void JOINImageData::UnloadAll(){ InvokeEvent(LayerChangeEvent()); } + +void +JOINImageData +::InitializeJoinCF(){ + ////make sure Jsrc and Jdst exist + assert(IsJsrcLoaded()); + assert(IsJdstLoaded()); + + ////Initialize JoinCopyFilter + m_JoinCF= JoinCopyFilterType::New(); + m_JoinCF->SetJsrc(m_JsrcWrapper->GetImage()); + m_JoinCF->SetJdst(m_JdstWrapper->GetImage()); + m_JdstWrapper->SetImage(m_JoinCF->GetOutput()); + m_JdstWrapper->GetImage()->Modified(); + m_JoinCF->InPlaceOn(); //adjust Jdst directly + } + +JOINImageData::JoinCopyFilterPointer +JOINImageData::GetJoinCF(){ + ////todo: introduce check if m_JoinCF was initialized + return m_JoinCF; + } diff --git a/Logic/Framework/JOINImageData.h b/Logic/Framework/JOINImageData.h index cf430a63..5dfbac21 100644 --- a/Logic/Framework/JOINImageData.h +++ b/Logic/Framework/JOINImageData.h @@ -39,6 +39,7 @@ #include "GenericImageData.h" #include "itkImageAdaptor.h" +#include "itkJoinCopyFilter.h" /** * \class JOINImageData @@ -57,6 +58,9 @@ class JOINImageData : public GenericImageData typedef JdstImageWrapper::ImageType JdstImageType; typedef WsrcImageWrapper::ImageType WsrcImageType; + typedef itk::JoinCopyFilter JoinCopyFilterType; + typedef JoinCopyFilterType::Pointer JoinCopyFilterPointer; + /** Initialize to a ROI from another image data object */ void InitializeToROI(GenericImageData *source, const SNAPSegmentationROISettings &roi, @@ -88,6 +92,8 @@ class JOINImageData : public GenericImageData bool IsWsrcLoaded(); void SetWsrcSticky(bool sticky); + void InitializeJoinCF(); + JoinCopyFilterType::Pointer GetJoinCF(); protected: @@ -102,6 +108,9 @@ class JOINImageData : public GenericImageData // GWS source image SmartPtr m_WsrcWrapper; + + JoinCopyFilterPointer m_JoinCF; + }; diff --git a/todo b/todo index 06b7f56c..8516173d 100644 --- a/todo +++ b/todo @@ -1,5 +1,12 @@ TODOs for GWS: +- implement JoinCopyFilter (templated over dimension) +-- multi-threaded ImageRegionIterator +-- multi-threaded ImageScanlineIterator +-- FloodFilledImageFunctionConditionalIterator (Modules/Segmentation/RegionGrowing/include/itkConnectedThresholdImageFilter.hxx) +--- add 2D/3D option to GUI + implementation +- optimize CopySegementationToJdst and CopySegementationToJsrc + - combine mode 2 with mode 0 and add extra button for "LoadImageToJsrc" -- restructure JoinDataPanel to have two main buttons: CnJ from Seg. or File OR CnJ from gWS - add 'n' for next smallest unused label see eg m_Wrapper->GetHistogram(nBins) in ./Logic/ImageWrapper/DisplayMappingPolicy.cxx From 9f0332ca8ff269daa4676b660eb0d22c3e9b5977 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 31 Jan 2018 18:53:15 +0100 Subject: [PATCH 36/42] avoid SetImage (looses coord transf from InitializeToWrapper), no segfault any more, filter executes but has no effect --- Logic/Framework/JOINImageData.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index 694958b9..1b672b38 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -313,9 +313,8 @@ ::InitializeJoinCF(){ m_JoinCF= JoinCopyFilterType::New(); m_JoinCF->SetJsrc(m_JsrcWrapper->GetImage()); m_JoinCF->SetJdst(m_JdstWrapper->GetImage()); - m_JdstWrapper->SetImage(m_JoinCF->GetOutput()); - m_JdstWrapper->GetImage()->Modified(); - m_JoinCF->InPlaceOn(); //adjust Jdst directly + //m_JdstWrapper->SetImage(m_JoinCF->GetOutput()); //causes segfault due to missing transform of uninitialized output + m_JoinCF->InPlaceOn(); //makes 2nd input (SetJdst) be the output } JOINImageData::JoinCopyFilterPointer From 5bcf696791fa559519441c9060b2b2daf8fd9838 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 31 Jan 2018 19:41:26 +0100 Subject: [PATCH 37/42] simplified itkJoinCopyFilter according to InplaceImageFilter example: http://itk.org/Wiki/ITK/Examples/Developer/InplaceImageFilter --- Logic/Common/itkJoinCopyFilter.cxx | 26 +++++++++++++------------- Logic/Common/itkJoinCopyFilter.h | 12 ++++++------ Logic/Framework/JOINImageData.h | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Logic/Common/itkJoinCopyFilter.cxx b/Logic/Common/itkJoinCopyFilter.cxx index 20b7daf2..cf817ba3 100644 --- a/Logic/Common/itkJoinCopyFilter.cxx +++ b/Logic/Common/itkJoinCopyFilter.cxx @@ -10,29 +10,29 @@ namespace itk{ - template - JoinCopyFilter + template + JoinCopyFilter ::JoinCopyFilter(){ m_SeedActive= false; m_SeedIndex.Fill(0); - m_SeedValue= NumericTraits::Zero; + m_SeedValue= NumericTraits::Zero; } - template - void JoinCopyFilter + template + void JoinCopyFilter ::SetJsrc(const TInputImage1 *image1){ this->SetNthInput( 0, const_cast< TInputImage1 * >( image1 ) ); } - template - void JoinCopyFilter + template + void JoinCopyFilter ::SetJdst(const TInputImage2 *image2){ this->SetNthInput( 1, const_cast< TInputImage2 * >( image2 ) ); } - template - void JoinCopyFilter + template + void JoinCopyFilter ::BeforeThreadedGenerateData(){ if(m_SeedActive){ @@ -43,16 +43,16 @@ namespace itk{ } - template - void JoinCopyFilter + template + void JoinCopyFilter ::ThreadedGenerateData(const typename Superclass::OutputImageRegionType& outputRegionForThread, ThreadIdType threadId){ if(m_SeedActive){ typename TInputImage1::ConstPointer input = dynamic_cast( ProcessObject::GetInput(0) ); - typename TOutputImage::Pointer output = this->GetOutput(); + typename TInputImage2::Pointer output = this->GetOutput(); itk::ImageRegionConstIterator iti(input, outputRegionForThread); - itk::ImageRegionIterator ito(output, outputRegionForThread); + itk::ImageRegionIterator ito(output, outputRegionForThread); // support progress methods/callbacks with 1000 updates ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels(), 1000); diff --git a/Logic/Common/itkJoinCopyFilter.h b/Logic/Common/itkJoinCopyFilter.h index 5b0a4150..982897c8 100644 --- a/Logic/Common/itkJoinCopyFilter.h +++ b/Logic/Common/itkJoinCopyFilter.h @@ -9,13 +9,13 @@ namespace itk{ * * \ingroup ImageFilters */ - template + template class JoinCopyFilter: - public InPlaceImageFilter{ + public InPlaceImageFilter{ public: /** Standard class typedefs. */ typedef JoinCopyFilter Self; - typedef InPlaceImageFilter Superclass; + typedef InPlaceImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer< const Self > ConstPointer; @@ -33,8 +33,8 @@ namespace itk{ itkGetConstMacro(SeedIndex, typename TInputImage1::IndexType); /** Set/Get DrawingColor value */ - itkSetMacro(DrawingColor, typename TOutputImage::ValueType); - itkGetConstMacro(DrawingColor, typename TOutputImage::ValueType); + itkSetMacro(DrawingColor, typename TInputImage2::ValueType); + itkGetConstMacro(DrawingColor, typename TInputImage2::ValueType); /** Get UpdateFlag value */ itkGetConstMacro(UpdateFlag, bool); @@ -50,7 +50,7 @@ namespace itk{ bool m_SeedActive; typename TInputImage1::IndexType m_SeedIndex; typename TInputImage1::ValueType m_SeedValue; - typename TOutputImage::ValueType m_DrawingColor; + typename TInputImage2::ValueType m_DrawingColor; bool m_UpdateFlag; diff --git a/Logic/Framework/JOINImageData.h b/Logic/Framework/JOINImageData.h index 5dfbac21..363863f7 100644 --- a/Logic/Framework/JOINImageData.h +++ b/Logic/Framework/JOINImageData.h @@ -58,7 +58,7 @@ class JOINImageData : public GenericImageData typedef JdstImageWrapper::ImageType JdstImageType; typedef WsrcImageWrapper::ImageType WsrcImageType; - typedef itk::JoinCopyFilter JoinCopyFilterType; + typedef itk::JoinCopyFilter JoinCopyFilterType; typedef JoinCopyFilterType::Pointer JoinCopyFilterPointer; /** Initialize to a ROI from another image data object */ From 1b63ff4412c307d7344c7bece5421d472a2e9c61 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 31 Jan 2018 19:54:18 +0100 Subject: [PATCH 38/42] set JoinCF-output as Jdst (filter working now), see comment in example (main): http://itk.org/Wiki/ITK/Examples/Developer/InplaceImageFilter --- Logic/Framework/IRISApplication.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Logic/Framework/IRISApplication.cxx b/Logic/Framework/IRISApplication.cxx index ce8f2ce4..cc66f07e 100644 --- a/Logic/Framework/IRISApplication.cxx +++ b/Logic/Framework/IRISApplication.cxx @@ -312,6 +312,7 @@ ::ExecuteCnJCopy(JsrcImageWrapper::ImageType::IndexType SeedIndex) m_JOINImageData->GetJoinCF()->SetDrawingColor(drawing_color); m_JOINImageData->GetJoinCF()->SetSeedActive(true); m_JOINImageData->GetJoinCF()->Update(); + m_JOINImageData->GetJdst()->SetImage(m_JOINImageData->GetJoinCF()->GetOutput()); //needed because output has stolen the input's buffer and the input has no image buffer. InvokeEvent(LayerChangeEvent()); return m_JOINImageData->GetJoinCF()->GetUpdateFlag(); From a714e119284194c9dea0a6f49b6771c3dffcca7d Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 31 Jan 2018 20:27:15 +0100 Subject: [PATCH 39/42] progress report for itkJoinCopyFilter (from 82f72dc9) --- Logic/Framework/JOINImageData.cxx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Logic/Framework/JOINImageData.cxx b/Logic/Framework/JOINImageData.cxx index 1b672b38..40809ff3 100644 --- a/Logic/Framework/JOINImageData.cxx +++ b/Logic/Framework/JOINImageData.cxx @@ -35,6 +35,20 @@ #include "IRISApplication.h" #include "JOINImageData.h" +//#include "itkJCFilterWatcher.h" +#include + + +void FilterEventHandlerITK2(itk::Object *caller, const itk::EventObject &event, void*){ + + const itk::ProcessObject* filter = static_cast(caller); + + if(itk::ProgressEvent().CheckEvent(&event)) + fprintf(stderr, "\r%s progress: %5.1f%%", filter->GetNameOfClass(), 100.0 * filter->GetProgress());//stderr is flushed directly + else if(itk::EndEvent().CheckEvent(&event)) + std::cerr << std::endl << std::flush; + } + JOINImageData ::JOINImageData(){ @@ -311,10 +325,19 @@ ::InitializeJoinCF(){ ////Initialize JoinCopyFilter m_JoinCF= JoinCopyFilterType::New(); + m_JoinCF->SetJsrc(m_JsrcWrapper->GetImage()); m_JoinCF->SetJdst(m_JdstWrapper->GetImage()); //m_JdstWrapper->SetImage(m_JoinCF->GetOutput()); //causes segfault due to missing transform of uninitialized output m_JoinCF->InPlaceOn(); //makes 2nd input (SetJdst) be the output + + itk::CStyleCommand::Pointer eventCallbackITK; + eventCallbackITK = itk::CStyleCommand::New(); + eventCallbackITK->SetCallback(FilterEventHandlerITK2); + + m_JoinCF->AddObserver(itk::ProgressEvent(), eventCallbackITK); + m_JoinCF->AddObserver(itk::EndEvent(), eventCallbackITK); + } JOINImageData::JoinCopyFilterPointer From f68d5fbba7cbcbeef7e26d10684cfa9facff1af7 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Wed, 31 Jan 2018 21:17:31 +0100 Subject: [PATCH 40/42] Revert "saving images compressed" This reverts commit 30a80e270dc9adbddd3a9938254f3488832c843d. --- Logic/ImageWrapper/ImageWrapper.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/Logic/ImageWrapper/ImageWrapper.cxx b/Logic/ImageWrapper/ImageWrapper.cxx index b72e8acd..b1dd8eb3 100644 --- a/Logic/ImageWrapper/ImageWrapper.cxx +++ b/Logic/ImageWrapper/ImageWrapper.cxx @@ -149,8 +149,6 @@ class ImageWrapperPartialSpecializationTraitsCommon if(base) writer->SetImageIO(base); writer->SetInput(image); - writer->UseCompressionOn(); //would be nice if made dependent on type=="segmentation" in UserInterface/ImageIOWizard/ImageIOWizardLogic.cxx @ 978 - std::cerr << "Saving image compressed! " << fname << std::endl; writer->Update(); } From 14fb16b02df0c5bf54ec59c9c536630b13faded3 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Thu, 1 Feb 2018 13:33:59 +0100 Subject: [PATCH 41/42] disabled StoreUndoPoint (has no effect so far, only takes time) --- GUI/Model/JoinModel.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GUI/Model/JoinModel.cxx b/GUI/Model/JoinModel.cxx index 61413500..229180de 100644 --- a/GUI/Model/JoinModel.cxx +++ b/GUI/Model/JoinModel.cxx @@ -51,7 +51,7 @@ ::ProcessPushEvent(const Vector3f &xSlice, bool reverse_mode, bool ctrl){ // Check if the right button was pressed if(processCnJ(reverse_mode)){ //add undo point (todo: Undo has no effect so far) - m_Parent->GetDriver()->StoreUndoPoint("Click'n'Join"); + // m_Parent->GetDriver()->StoreUndoPoint("Click'n'Join"); // commented as long as it has no effec except for taking single-threaded processing time according to the size of the loaded data //fire SegmentationChangeEvent for e.g. 3D view Update m_Parent->GetDriver()->InvokeEvent(SegmentationChangeEvent()); } From ad75795daba52409889e017e9bf105102a6a2cc7 Mon Sep 17 00:00:00 2001 From: Roman Grothausmann Date: Mon, 10 Sep 2018 19:00:22 +0200 Subject: [PATCH 42/42] ToDo update --- todo | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/todo b/todo index 8516173d..fc68680c 100644 --- a/todo +++ b/todo @@ -1,11 +1,7 @@ -TODOs for GWS: +ToDo: -- implement JoinCopyFilter (templated over dimension) --- multi-threaded ImageRegionIterator --- multi-threaded ImageScanlineIterator --- FloodFilledImageFunctionConditionalIterator (Modules/Segmentation/RegionGrowing/include/itkConnectedThresholdImageFilter.hxx) ---- add 2D/3D option to GUI + implementation - optimize CopySegementationToJdst and CopySegementationToJsrc +-- RMB functionality in JoinCopyFilter - combine mode 2 with mode 0 and add extra button for "LoadImageToJsrc" -- restructure JoinDataPanel to have two main buttons: CnJ from Seg. or File OR CnJ from gWS @@ -15,9 +11,8 @@ TODOs for GWS: -- gWS move use file/overlay to bottom - set gWS input only if it changed on prepro. page - make UnDo for CnJ/gWS possible -- parallelize iterators in CnJ and gWS, e.g. in CopySegementationToJsrc and on LMB/RMB - destinguish RMB click from RMB drag (zoom) -- would be nice to let user choose which color representation should be used for Jsrc +- let user choose which color representation should be used for Jsrc - make GUI parts more fool prove - add a GUI progress for current stderr progress - add an invert option for direct mode, see e.g. InvertFunctor in SNAPImageData @@ -26,3 +21,9 @@ TODOs for GWS: - add MorphlogicalWS from all Labels into PB, result as overlay - change "load from file" to "load from overlay" in CnJ and gWS + + +Done: + +-implement JoinCopyFilter (templated over dimension) +-- multi-threaded ImageRegionIterator