diff --git a/MantidQt/CustomInterfaces/CMakeLists.txt b/MantidQt/CustomInterfaces/CMakeLists.txt
index ada8021d700646e914d4bbe412a8e155037d3058..be571e64c996a33e8e2b1b6535783bbb32c3a6e6 100644
--- a/MantidQt/CustomInterfaces/CMakeLists.txt
+++ b/MantidQt/CustomInterfaces/CMakeLists.txt
@@ -90,7 +90,11 @@ set ( SRC_FILES
   src/SANSPlotSpecial.cpp
   src/SANSRunWindow.cpp
   src/StepScan.cpp
+  src/Tomography/ImageROIPresenter.cpp
+  src/Tomography/ImageROIViewQtWidget.cpp
+  src/Tomography/ImageStackPreParams.cpp
   src/Tomography/SavuConfigDialog.cpp
+  src/Tomography/StackOfImagesDirs.cpp
   src/Tomography/TomographyIfaceModel.cpp
   src/Tomography/TomographyIfacePresenter.cpp
   src/Tomography/TomographyIfaceViewQtGUI.cpp
@@ -205,8 +209,14 @@ set ( INC_FILES
   inc/MantidQtCustomInterfaces/SANSPlotSpecial.h
   inc/MantidQtCustomInterfaces/SANSRunWindow.h
   inc/MantidQtCustomInterfaces/StepScan.h
+  inc/MantidQtCustomInterfaces/Tomography/IImageROIPresenter.h
+  inc/MantidQtCustomInterfaces/Tomography/IImageROIView.h
+  inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h
+  inc/MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h
+  inc/MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h
   inc/MantidQtCustomInterfaces/Tomography/ITomographyIfacePresenter.h
   inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
+  inc/MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h
   inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
   inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
   inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
@@ -308,6 +318,7 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h
                 inc/MantidQtCustomInterfaces/SANSEventSlicing.h
                 inc/MantidQtCustomInterfaces/SANSDiagnostics.h
                 inc/MantidQtCustomInterfaces/StepScan.h
+                inc/MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h
                 inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
                 inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
                 inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
@@ -370,6 +381,7 @@ set ( UI_FILES inc/MantidQtCustomInterfaces/DataComparison.ui
                inc/MantidQtCustomInterfaces/SANSRunWindow.ui
                inc/MantidQtCustomInterfaces/SANSEventSlicing.ui
                inc/MantidQtCustomInterfaces/StepScan.ui
+               inc/MantidQtCustomInterfaces/Tomography/ImageSelectCoRAndRegions.ui
                inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtGUI.ui
                inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabSetup.ui
                inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
@@ -386,12 +398,14 @@ set ( TEST_FILES
   ALCPeakFittingModelTest.h
   ALCPeakFittingPresenterTest.h
   EnggDiffractionPresenterTest.h
+  ImageROIPresenterTest.h
   IO_MuonGroupingTest.h
   MuonAnalysisHelperTest.h
   ParseKeyValueStringTest.h
   ReflGenerateNotebookTest.h
   ReflLegacyTransferStrategyTest.h
   ReflMainViewPresenterTest.h
+  StackOfImagesDirsTest.h
   TomographyIfacePresenterTest.h
   UserInputValidatorTest.h
 )
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/IImageROIPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/IImageROIPresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..581accf1509477c8aa554e2bd2d128822391906e
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/IImageROIPresenter.h
@@ -0,0 +1,77 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IIMAGEROIPRESENTER_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IIMAGEROIPRESENTER_H_
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+Presenter for the widget that handles the selection of the center of
+rotation, region of interest, region for normalization, etc. from an
+image or stack of images. This is the abstract base class / interface
+for the presenter (in the sense of the MVP pattern).  The name
+ImageROI refers to the Center-of-Rotation, which is the most basic
+parameter that users can select via this widget. This class is
+QtGUI-free as it uses the interface of the view. The model is simply
+the ImageStackPreParams class which holds coordinates selected by the
+user.
+
+Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid 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.
+
+Mantid 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 <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class IImageROIPresenter {
+
+public:
+  IImageROIPresenter(){};
+  virtual ~IImageROIPresenter(){};
+
+  /// These are user actions, triggered from the (passive) view, that need
+  /// handling by the presenter
+  enum Notification {
+    Init,                 ///< interface is initing (set, defaults, etc.)
+    BrowseImgOrStack,     ///< User browses for an image file or stack
+    NewImgOrStack,        ///< A new image or stack needs to be loaded
+    UpdateImgIndex,       ///< Sliding/scrolling through the stack
+    SelectCoR,            ///< Start picking of the center of rotation
+    SelectROI,            ///< Start selection of the region of interest
+    SelectNormalization,  ///< Start selection of the normalization region
+    FinishedCoR,          ///< A CoR has been picked
+    FinishedROI,          ///< The ROI is selected
+    FinishedNormalization,///< The normalization region is selected
+    ResetCoR,             ///< Reset CoR to default/none/middle
+    ResetROI,             ///< Reset ROI to default/empty
+    ResetNormalization,   ///< Reet the normalization region to default/empty
+    ShutDown              ///< The widget is being closed/destroyed
+  };
+
+  /**
+   * Notifications sent through the presenter when something changes
+   * in the view. This plays the role of signals emitted by the view
+   * to this presenter.
+   *
+   * @param notif Type of notification to process.
+   */
+  virtual void notify(IImageROIPresenter::Notification notif) = 0;
+};
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IIMAGEROIPRESENTER_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/IImageROIView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/IImageROIView.h
new file mode 100644
index 0000000000000000000000000000000000000000..592dc79a3a1d4e828bf35f1c7c6311257c7d4bb7
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/IImageROIView.h
@@ -0,0 +1,216 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IIMAGEROIVIEW_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IIMAGEROIVIEW_H_
+
+#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+Widget to handle the selection of the center of rotation, region of
+interest, region for normalization, etc. from an image or stack of
+images. This is the abstract base class / interface for the view of
+this widget (in the sense of the MVP pattern).  The name ImageROI
+refers to the Center-of-Rotation, which is the most basic parameter
+that users can select via this widget. This class is Qt-free. Qt
+specific functionality and dependencies are added in a class derived
+from this.
+
+Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid 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.
+
+Mantid 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 <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class IImageROIView {
+
+public:
+  IImageROIView(){};
+  virtual ~IImageROIView(){};
+
+  // Selection states
+  enum SelectionState {
+    SelectNone,          ///< Init, or after any reset
+    SelectCoR,
+    SelectROIFirst,
+    SelectROISecond,
+    SelectNormAreaFirst,
+    SelectNormAreaSecond
+  };
+
+  /**
+   * Sets the user selection. This should guarantee that all widgets
+   * are updated (including spin boxes, image, slider through the
+   * image stack, etc.
+   *
+   * @param params all user-modifyable parameters (coordinates for the
+   * CoR, ROI and area for normalization).
+   *
+   */
+  virtual void setParams(ImageStackPreParams &params) = 0;
+
+  /**
+   * Provides the current user selection.
+   *
+   * @return parameters as set/edited by the user.
+   */
+  virtual ImageStackPreParams userSelection() const = 0;
+
+  /**
+   * The current selection state. For example: nothin/initialized,
+   * selecting CoR, selecting second corner of the normalization area,
+   * selecting first corner of the ROI.
+   *
+   * @return current state
+   */
+  virtual SelectionState selectionState() const = 0;
+
+  /**
+   * Update to a new state (for example select CoR).
+   *
+   * @param state new state we're transitioning into.
+   */
+  virtual void changeSelectionState(const SelectionState& state) = 0;
+
+  /**
+   * Display a special case of stack of images: individual image, from
+   * a path to a recognized directory structure (sample/dark/white) or
+   * image format. Here recognized format means something that is
+   * supported natively by the widgets library, in practice
+   * Qt. Normally you can expect that .tiff and .png images are
+   * supported.
+   *
+   * @param path path to the stack (directory) or individual image file.
+   */
+  virtual void showStack(const std::string &path) = 0;
+
+  /**
+   * Display a stack of images (or individual image as a particular
+   * case), from a workspace group containing matrix workspaces. It
+   * assumes that the workspace contains an image in the form in which
+   * LoadFITS loads FITS images (or spectrum per row, all of them with
+   * the same number of data points (columns)).
+   *
+   * @param ws Workspace group where every workspace is a FITS or
+   * similar image that has been loaded with LoadFITS or similar
+   * algorithm.
+   */
+  virtual void showStack(Mantid::API::WorkspaceGroup_sptr &ws) = 0;
+
+  /**
+   * Get the stack of images currently being displayed (it has been
+   * shown using showStack()), as a workspace group.
+   *
+   * @return workspace group containing the individual images, which
+   * can be empty if no stack has been loaded.
+   */
+  virtual const Mantid::API::WorkspaceGroup_sptr stack() const = 0;
+
+  /**
+   * Normally one image (projection for tomography stacks) will be
+   * shown on a 2D display. Show there a particular projection from a
+   * stack contained in a workspace group.
+   *
+   * @param wsg workspace holding a stack of images
+   *
+   * @param idx index (in the group) of the image to show
+   *
+   */
+  virtual void showProjection(const Mantid::API::WorkspaceGroup_sptr &wsg,
+                              size_t idx) = 0;
+
+  /**
+   * Display a warning to the user (for example as a pop-up window).
+   *
+   * @param warn warning title, should be short and would normally be
+   * shown as the title of the window or a big banner.
+   *
+   * @param description longer, free form description of the issue.
+   */
+  virtual void userWarning(const std::string &warn,
+                           const std::string &description) = 0;
+
+  /**
+   * Display an error message (for example as a pop-up window).
+   *
+   * @param err Error title, should be short and would normally be
+   * shown as the title of the window or a big banner.
+   *
+   * @param description longer, free form description of the issue.
+   */
+  virtual void userError(const std::string &err,
+                         const std::string &description) = 0;
+
+  /**
+   * The index of the image currently shown (from the current stack if there's
+   * any).
+   *
+   * @return index from 0 to the total number of images in the
+   * stack-1, as used for example when indexing workspaces in
+   * workspacegroups
+   */
+  virtual size_t currentImgIndex() const = 0;
+
+  /**
+   * Display now this image (idx) from the stack.
+   *
+   * @param idx index of the image to display.
+   */
+  virtual void updateImgWithIndex(size_t idx) = 0;
+
+  /**
+   * Get the path/location of a stack of images (or single image as a
+   * particular case) that the user is requesting to display.  The
+   * path would be expected to point to a recognized directory
+   * structure (sample/dark/white) or image file (as a particular
+   * case).
+   *
+   * @return location (can be a directory, file, etc.) that needs to
+   * be figured out elsewhere.
+   */
+  virtual std::string askImgOrStackPath() = 0;
+
+  /**
+   * Save settings (normally when closing this widget).
+   */
+  virtual void saveSettings() const = 0;
+
+  /**
+   * Forget the current center-of-rotation selection and set to
+   * default.
+   */
+  virtual void resetCoR() = 0;
+
+  /**
+   * Forget the current region-of-interest selection and set to
+   * default (all).
+   */
+  virtual void resetROI() = 0;
+
+  /**
+   * Forget the current selection of region-for-normalization and set
+   * to default (none).
+   */
+  virtual void resetNormArea() = 0;
+};
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IIMAGEROIVIEW_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfacePresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfacePresenter.h
index 77f46747a077d353afc005a2a3bbe7461230e8e3..be9585bc25ee1d01ede65b98fdd416566c7aa4d4 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfacePresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfacePresenter.h
@@ -9,7 +9,7 @@ Interface for what the presenter of the tomography GUI needs to
 implement. Here the term presenter is used as in the MVP
 (Model-View-Presenter) pattern. The (passive) view will use this.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
index 3802a4b2b8cece79b1dc96f4b9dc12c18349e24c..0130f027370db9e29626b780bc78c2029c46b804 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
@@ -15,7 +15,7 @@ Tomography GUI. Base class / interface for the view of the tomo GUI
 specific functionality/dependencies are added in a class derived from
 this.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..7aaeac9147ec95b82725d83a6b0bef36ccac27ae
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h
@@ -0,0 +1,95 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGEROIPRESENTER_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGEROIPRESENTER_H_
+
+#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidQtCustomInterfaces/Tomography/IImageROIPresenter.h"
+#include "MantidQtCustomInterfaces/Tomography/IImageROIView.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h"
+#include "MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h"
+
+#include <boost/scoped_ptr.hpp>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+Presenter for the image center of rotation (and other parameters)
+selection widget. In principle, in a strict MVP setup, signals from
+the model should always be handled through this presenter and never go
+directly to the view, and viceversa.
+
+Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid 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.
+
+Mantid 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 <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class DLLExport ImageROIPresenter : public IImageROIPresenter {
+
+public:
+  /// Default constructor - normally used from the concrete view
+  ImageROIPresenter(IImageROIView *view);
+  virtual ~ImageROIPresenter();
+
+  void notify(IImageROIPresenter::Notification notif);
+
+protected:
+  void initialize();
+
+  /// clean shut down of model, view, etc.
+  void cleanup();
+
+  void processInit();
+  void processBrowseImg();
+  void processNewStack();
+  void processUpdateImgIndex();
+  void processSelectCoR();
+  void processSelectROI();
+  void processSelectNormalization();
+  void processFinishedCoR();
+  void processFinishedROI();
+  void processFinishedNormalization();
+  void processResetCoR();
+  void processResetROI();
+  void processResetNormalization();
+  void processShutDown();
+
+private:
+  StackOfImagesDirs checkInputStack(const std::string &path);
+
+  /// loads a list of images from a stack, from their individual paths
+  Mantid::API::WorkspaceGroup_sptr
+  loadFITSStack(const std::vector<std::string> &imgs);
+
+  void loadFITSImage(const std::string &path, const std::string &wsName);
+
+  /// path to the image stack being visualized
+  std::string m_stackPath;
+
+  /// Associated view for this presenter (MVP pattern)
+  IImageROIView *const m_view;
+
+  /// Associated model for this presenter (MVP pattern). This is just
+  /// a set of coordinates
+  const boost::scoped_ptr<ImageStackPreParams> m_model;
+};
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGEROIPRESENTER_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..739374aed282d5b19cf3fb1d097b4a95bc583d3e
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h
@@ -0,0 +1,186 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGEROIVIEWQTWIDGET_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGEROIVIEWQTWIDGET_H_
+
+#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidKernel/System.h"
+#include "MantidQtCustomInterfaces/Tomography/IImageROIPresenter.h"
+#include "MantidQtCustomInterfaces/Tomography/IImageROIView.h"
+
+#include "ui_ImageSelectCoRAndRegions.h"
+
+#include <boost/scoped_ptr.hpp>
+
+// forward declarations for Qt
+class QWidget;
+class QPixmap;
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+Qt-based view of the widget to handle the selection of the center of
+rotation, region of interest, region for normalization, etc. from an
+image or stack of images. Provides a concrete view for the graphical
+interface for tomography functionality in Mantid. This view is
+Qt-based and it is probably the only one that will be implemented in a
+foreseeable horizon. The interface of this class is given by
+IImageROIView so that it fits in the MVP (Model-View-Presenter) design
+of the ImageROI widget.
+
+Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid 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.
+
+Mantid 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 <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class DLLExport ImageROIViewQtWidget : public QWidget, public IImageROIView {
+  Q_OBJECT
+
+public:
+  ImageROIViewQtWidget(QWidget *parent = 0);
+  virtual ~ImageROIViewQtWidget(){};
+
+  void setParams(ImageStackPreParams &params);
+
+  ImageStackPreParams userSelection() const;
+
+  SelectionState selectionState() const { return m_selectionState; }
+
+  void changeSelectionState(const SelectionState& state);
+
+  /// show a stack of images given the path to the files
+  void showStack(const std::string &path);
+
+  /// show a stack of images that have been loaded into a group of workspaces
+  void showStack(Mantid::API::WorkspaceGroup_sptr &ws);
+
+  const Mantid::API::WorkspaceGroup_sptr stack() const { return m_stack; }
+
+  void showProjection(const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx);
+
+  void userWarning(const std::string &warn, const std::string &description);
+
+  void userError(const std::string &err, const std::string &description);
+
+  size_t currentImgIndex() const;
+
+  void updateImgWithIndex(size_t idx);
+
+  std::string askImgOrStackPath();
+
+  void saveSettings() const;
+
+  void resetCoR();
+  void resetROI();
+  void resetNormArea();
+
+protected:
+  void initLayout();
+  void showImg();
+
+  /// update coordinates from mouse event
+  void mouseUpdateCoR(int x, int y);
+  void mouseUpdateROICorners12(int x, int y);
+  void mouseUpdateROICorner2(int x, int y);
+  void mouseFinishROI(int x, int y);
+  void mouseUpdateNormAreaCorners12(int x, int y);
+  void mouseUpdateNormAreaCorner2(int x, int y);
+  void mouseFinishNormArea(int x, int y);
+
+private slots:
+  void browseImgClicked();
+
+  void corClicked();
+  void corResetClicked();
+  void roiClicked();
+  void roiResetClicked();
+  void normAreaClicked();
+  void normAreaResetClicked();
+
+  void updateFromImagesSlider(int current);
+
+  void valueUpdatedCoR(int v);
+  void valueUpdatedROI(int v);
+  void valueUpdatedNormArea(int v);
+
+private:
+  void grabCoRFromWidgets();
+  void grabROIFromWidgets();
+  void grabNormAreaFromWidgets();
+
+  void grabCoRFromMousePoint(int x, int y);
+  void grabROICorner1FromMousePoint(int x, int y);
+  void grabROICorner2FromMousePoint(int x, int y);
+  void grabNormAreaCorner1FromMousePoint(int x, int y);
+  void grabNormAreaCorner2FromMousePoint(int x, int y);
+
+  void setupConnections();
+
+  void readSettings();
+
+  // widget closing
+  virtual void closeEvent(QCloseEvent *ev);
+
+  /// enable/disable the groups with spin boxes for the center and corners
+  void enableParamWidgets(bool enable);
+  /// initialize values to defaults and set max/min for the spin boxes
+  void initParamWidgets(size_t maxWidth, size_t maxHeight);
+
+  /// Set coordinates in the widgets from a params object
+  void setParamWidgets(ImageStackPreParams &params);
+
+  // shows the image in a widget
+  void showProjectionImage(const Mantid::API::WorkspaceGroup_sptr &wsg,
+                           size_t idx);
+
+  /// repaint the image with new positions of points and rectangles
+  void refreshROIetAl();
+  void refreshCoR();
+  void refreshROI();
+  void refreshNormArea();
+
+  bool eventFilter(QObject *obj, QEvent *event);
+
+  Ui::ImageSelectCoRAndRegions m_ui;
+
+  Mantid::API::WorkspaceGroup_sptr m_stack;
+
+  /// this holds the base image on top of which rectangles and other
+  /// objects are drawn
+  boost::scoped_ptr<QPixmap> m_basePixmap;
+
+  /// persistent settings
+  static const std::string m_settingsGroup;
+
+  /// parameters currently set by the user
+  ImageStackPreParams m_params;
+
+  /// max image size for the current stack
+  int m_imgWidth, m_imgHeight;
+
+  /// are we picking the CoR, or the first point of the ROI, etc.
+  SelectionState m_selectionState;
+
+  // presenter as in the model-view-presenter
+  boost::scoped_ptr<IImageROIPresenter> m_presenter;
+};
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGEROIVIEWQTWIDGET_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageSelectCoRAndRegions.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageSelectCoRAndRegions.ui
new file mode 100644
index 0000000000000000000000000000000000000000..c71dbfed6a89027b1f6ea39a849f4df738db4671
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageSelectCoRAndRegions.ui
@@ -0,0 +1,669 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ImageSelectCoRAndRegions</class>
+ <widget class="QWidget" name="ImageSelectCoRAndRegions">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>800</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_8">
+   <item row="0" column="0">
+    <widget class="QSplitter" name="splitter_main_horiz">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>1</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QSplitter" name="splitter_img_vertical">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+        <horstretch>2</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="orientation">
+       <enum>Qt::Vertical</enum>
+      </property>
+      <widget class="QWidget" name="layoutWidget">
+       <layout class="QGridLayout" name="gridLayout_5">
+        <property name="sizeConstraint">
+         <enum>QLayout::SetMinimumSize</enum>
+        </property>
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_img_seq">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>0</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>16777215</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>Image:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLineEdit" name="lineEdit_img_seq">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>100</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>0/0</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="2">
+         <widget class="QLabel" name="label_img_name">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>1</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>0</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>16777215</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>none</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="3">
+         <widget class="QPushButton" name="pushButton_browse_img">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>0</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>16777215</width>
+            <height>28</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>Browse</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="layoutWidget">
+       <layout class="QGridLayout" name="gridLayout_7" rowstretch="0,1">
+        <property name="sizeConstraint">
+         <enum>QLayout::SetMaximumSize</enum>
+        </property>
+        <property name="spacing">
+         <number>3</number>
+        </property>
+        <item row="0" column="0">
+         <widget class="QScrollArea" name="scrollArea">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+            <horstretch>2</horstretch>
+            <verstretch>2</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="widgetResizable">
+           <bool>true</bool>
+          </property>
+          <widget class="QWidget" name="scrollAreaWidgetContents">
+           <property name="geometry">
+            <rect>
+             <x>0</x>
+             <y>0</y>
+             <width>510</width>
+             <height>402</height>
+            </rect>
+           </property>
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+             <horstretch>2</horstretch>
+             <verstretch>2</verstretch>
+            </sizepolicy>
+           </property>
+           <layout class="QGridLayout" name="gridLayout" rowstretch="0" columnstretch="0">
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <property name="spacing">
+             <number>1</number>
+            </property>
+            <item row="0" column="0">
+             <widget class="QLabel" name="label_img">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>2</horstretch>
+                <verstretch>2</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string/>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QScrollBar" name="horizontalScrollBar_img_stack">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+            <horstretch>2</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="invertedControls">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+     <widget class="QWidget" name="layoutWidget_2">
+      <layout class="QGridLayout" name="gridLayout_6" columnminimumwidth="0">
+       <property name="sizeConstraint">
+        <enum>QLayout::SetDefaultConstraint</enum>
+       </property>
+       <property name="spacing">
+        <number>4</number>
+       </property>
+       <item row="0" column="0">
+        <widget class="QGroupBox" name="groupBox_cor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>260</width>
+           <height>16777215</height>
+          </size>
+         </property>
+         <property name="title">
+          <string>Center of rotation</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_2">
+          <property name="margin">
+           <number>3</number>
+          </property>
+          <property name="spacing">
+           <number>4</number>
+          </property>
+          <item row="1" column="0">
+           <layout class="QHBoxLayout" name="horizontalLayout">
+            <item>
+             <widget class="QLabel" name="label_3">
+              <property name="text">
+               <string>Column:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QSpinBox" name="spinBox_cor_x">
+              <property name="maximum">
+               <number>9999</number>
+              </property>
+              <property name="value">
+               <number>9999</number>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="label_2">
+              <property name="text">
+               <string>Row:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QSpinBox" name="spinBox_cor_y">
+              <property name="maximum">
+               <number>9999</number>
+              </property>
+              <property name="value">
+               <number>9999</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item row="2" column="0">
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <widget class="QPushButton" name="pushButton_cor">
+              <property name="toolTip">
+               <string>After pushing this button, click on the image to select</string>
+              </property>
+              <property name="text">
+               <string>Select</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_3">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>108</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButton_cor_reset">
+              <property name="text">
+               <string>Reset</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item row="0" column="0">
+           <layout class="QHBoxLayout" name="horizontalLayout_5">
+            <item>
+             <spacer name="horizontalSpacer_4">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>78</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButton">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="text">
+               <string>Auto-find</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QComboBox" name="comboBox">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <item>
+               <property name="text">
+                <string>Method:</string>
+               </property>
+              </item>
+             </widget>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <spacer name="verticalSpacer_2">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Minimum</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="2" column="0">
+        <widget class="QGroupBox" name="groupBox_roi">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>260</width>
+           <height>16777215</height>
+          </size>
+         </property>
+         <property name="title">
+          <string>Region of interest:</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_3">
+          <property name="margin">
+           <number>3</number>
+          </property>
+          <property name="spacing">
+           <number>2</number>
+          </property>
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_4">
+            <property name="text">
+             <string>Corner 1</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QSpinBox" name="spinBox_roi_top_x">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="2">
+           <widget class="QSpinBox" name="spinBox_roi_top_y">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_5">
+            <property name="text">
+             <string>Corner 2</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QSpinBox" name="spinBox_roi_bottom_x">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="2">
+           <widget class="QSpinBox" name="spinBox_roi_bottom_y">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="0" colspan="3">
+           <layout class="QHBoxLayout" name="horizontalLayout_3">
+            <item>
+             <widget class="QPushButton" name="pushButton_roi">
+              <property name="toolTip">
+               <string>After pushing this button, click and drag on the image to select</string>
+              </property>
+              <property name="text">
+               <string>Select</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_2">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>155</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButton_roi_reset">
+              <property name="toolTip">
+               <string>Reset to the whole field of view</string>
+              </property>
+              <property name="text">
+               <string>Reset</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="3" column="0">
+        <spacer name="verticalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Minimum</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="4" column="0">
+        <widget class="QGroupBox" name="groupBox_norm">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>260</width>
+           <height>16777215</height>
+          </size>
+         </property>
+         <property name="title">
+          <string>Area for normalization:</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_4">
+          <property name="margin">
+           <number>3</number>
+          </property>
+          <property name="spacing">
+           <number>2</number>
+          </property>
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_6">
+            <property name="text">
+             <string>Corner 1</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QSpinBox" name="spinBox_norm_top_x">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="2">
+           <widget class="QSpinBox" name="spinBox_norm_top_y">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_7">
+            <property name="text">
+             <string>Corner 2</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QSpinBox" name="spinBox_norm_bottom_x">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="2">
+           <widget class="QSpinBox" name="spinBox_norm_bottom_y">
+            <property name="maximum">
+             <number>9999</number>
+            </property>
+            <property name="value">
+             <number>9999</number>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="0" colspan="3">
+           <layout class="QHBoxLayout" name="horizontalLayout_8">
+            <item>
+             <widget class="QPushButton" name="pushButton_norm_area">
+              <property name="toolTip">
+               <string>After pushing this button, click and drag on the image to select</string>
+              </property>
+              <property name="text">
+               <string>Select</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>98</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButton_norm_area_reset">
+              <property name="toolTip">
+               <string>Reset to empty/none</string>
+              </property>
+              <property name="text">
+               <string>Reset</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="5" column="0">
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>68</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h
new file mode 100644
index 0000000000000000000000000000000000000000..164a3a475f7229f2b91fe6e9a82e15f102cb7065
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h
@@ -0,0 +1,63 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGESTACKPREPARAMS_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGESTACKPREPARAMS_H_
+
+#include "MantidKernel/System.h"
+#include "MantidKernel/V2D.h"
+
+#include <utility>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+This holds parameters for pre-processing images or stacks of images
+for tomographic reconstruction. These parameters are used in different
+pre-processing steps in the tomographic reconstruction pipeline, and
+also for the reconstruction algorithms (iternative methods, FBP,
+etc.).
+
+The parameters include:
+- center of rotation
+- region of interest (clip from original or raw images)
+- region for normalization (where the beam is not blocked by any sample 
+  object throughout the stack of images) other parameters describing
+  the stack of images: 
+
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid 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.
+
+Mantid 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 <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class ImageStackPreParams {
+public:
+
+  ImageStackPreParams();
+
+  typedef std::pair<Mantid::Kernel::V2D, Mantid::Kernel::V2D> Box2D;
+
+  Mantid::Kernel::V2D cor;
+  Box2D roi;
+  Box2D normalizationRegion;  //< also known as 'air' region
+  bool medianFilter;
+};
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_IMAGESTACKPREPARAMS_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ef122016ea93de03b22395c15ab647d62ea9324
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h
@@ -0,0 +1,86 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_STACKOFIMAGESDIR_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_STACKOFIMAGESDIR_H_
+
+#include "MantidKernel/System.h"
+
+#include <string>
+#include <vector>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+Represents the structure of directories where a stack of images is
+stored on disk: data/flat/dark + processed + pre_filtered, etc.
+
+Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid 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.
+
+Mantid 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 <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class DLLExport StackOfImagesDirs {
+public:
+  /// constructor from a path (to a directory)
+  StackOfImagesDirs(const std::string &path);
+
+  /// The current (simple) concept of valid is: there at least a
+  /// sample/data directory with at least one file in it.
+  bool isValid() const { return m_valid; }
+
+  // human readable description of the expected structure of directories
+  std::string description() const;
+
+  // string that describes the status/error message about this directory
+  std::string status() const;
+
+  std::string sampleImagesDir() const { return m_sampleDir; };
+  std::string flatImagesDir() const { return m_flatDir; };
+  std::string darkImagesDir() const { return m_darkDir; };
+
+  std::vector<std::string> sampleFiles() const;
+  std::vector<std::string> flatFiles() const;
+  std::vector<std::string> darkFiles() const;
+
+private:
+  /// tries to find the expected data_/dark_/flat_ directories
+  void findStackDirs(const std::string &path);
+  /// finds images in a directory
+  std::vector<std::string> findImgFiles(const std::string &path) const;
+
+  /// passes basic validity checks
+  bool m_valid;
+  /// string with informative messages specially when not valid
+  std::string m_statusDescStr;
+
+  std::string m_sampleDir;
+  std::string m_flatDir;
+  std::string m_darkDir;
+
+  static const std::string g_descr;
+  static const std::string g_sampleNamePrefix;
+  static const std::string g_flatNamePrefix;
+  static const std::string g_darkNamePrefix;
+  static const std::string g_processedNamePrefix;
+  static const std::string g_prefilteredNamePrefix;
+};
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_STACKOFIMAGESDIR_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h
index 92400342f4a0363d6d52588065ae557fc58994c3..ee3becb0206f8910ae585ab1f4cedae98c201d29 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h
@@ -18,7 +18,7 @@ that define where the data for a particular dataset can be found, and
 that are normally required to run reconstruction tools but also pre-
 and post- processing steps.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoRecToolConfig.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoRecToolConfig.h
index 1ff91bd3933bcec2ee31c120f04e8e814e78bc12..256518618dcb17ac301ae2871bf615424cfb1f02 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoRecToolConfig.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoRecToolConfig.h
@@ -12,7 +12,7 @@ is under development, and as it is not necessarily related to custom
 interfaces this class and some derived ones might be moved out of
 here.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h
index 25857af9e1a9827251c4b52c3453429c8837cb7a..a6047a19de1292643bf844af8fa30a6357b406a6 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h
@@ -13,7 +13,7 @@ namespace CustomInterfaces {
 /**
 Settings for a set of tomographic reconstruction tools supported.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
index 64cfc7a36aed82bdc7e6a1585e4b6895eb15ca0b..5196ca49bef979e5268b8dc9cbd68a5e1c20aca8 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
@@ -15,7 +15,7 @@ namespace CustomInterfaces {
 Third party tool configuration dialog(s) for the tomographic reconstruction
 GUI.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
index a915f0c9ed1f7e54df8fa5b8249154eaef3410f8..4bd8001060f092397a3dec2d71d888c863d8f279 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
@@ -20,7 +20,7 @@ Tomography GUI. Model for the interface (as in the MVP
 signals from this model should always be handled through the presenter
 and never go directly to the view.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
index f37b5569d582d5b09be32ecb775cd754c73d6b22..ec29c07091b112cb2ab2b5de01325dacdce081f0 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
@@ -23,7 +23,7 @@ Tomography GUI. Presenter for the GUI (as in the MVP
 signals from the model should always be handled through this presenter
 and never go directly to the view, and viceversa.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
index ecfc5ff939ec2a361cae319847285f9d52c70162..ea670ee8a7158f0eb58a5f606461f3633d73f3a1 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
@@ -9,8 +9,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>462</width>
-    <height>460</height>
+    <width>671</width>
+    <height>451</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
@@ -74,7 +74,7 @@
         <item row="1" column="0">
          <widget class="QFrame" name="frame_image">
           <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
             <horstretch>2</horstretch>
             <verstretch>2</verstretch>
            </sizepolicy>
@@ -105,10 +105,16 @@
                <rect>
                 <x>0</x>
                 <y>0</y>
-                <width>151</width>
-                <height>180</height>
+                <width>231</width>
+                <height>175</height>
                </rect>
               </property>
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
               <layout class="QGridLayout" name="gridLayout_5">
                <property name="margin">
                 <number>0</number>
@@ -118,6 +124,12 @@
                </property>
                <item row="0" column="0">
                 <widget class="QLabel" name="label_image">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
                  <property name="text">
                   <string/>
                  </property>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
index 010abf23fbeaea0ce1a7fe1b47d4a7fe60bbecf7..3f78f8feafe18f03d52db0af5d4eab26556e76b1 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
@@ -9,6 +9,8 @@
 #include "MantidQtCustomInterfaces/Tomography/ITomographyIfacePresenter.h"
 #include "MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h"
+
+#include "ui_ImageSelectCoRAndRegions.h"
 #include "ui_TomographyIfaceQtGUI.h"
 #include "ui_TomographyIfaceQtTabSetup.h"
 #include "ui_TomographyIfaceQtTabRun.h"
@@ -30,7 +32,7 @@ in a foreseeable horizon. The interface of this class is given by
 ITomographyIfaceView so that it fits in the MVP (Model-View-Presenter)
 design of the tomography GUI.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
@@ -176,8 +178,9 @@ private:
   void processPathBrowseClick(QLineEdit *le, std::string &data);
 
   // Begin of Savu related functionality. This will grow and will need
-  // separation
-
+  // separation. They should find a better place to live.
+  ///@name Savu related methods
+  ///@{
   /// to load plugins (savu classification / API)
   void loadAvailablePlugins();
 
@@ -201,6 +204,7 @@ private:
                                       const std::string &name);
   std::string pluginParamValString(const Json::Value &jsonVal,
                                    const std::string &name);
+  ///@}
 
   static size_t g_nameSeqNo;
 
@@ -213,6 +217,7 @@ private:
   // but they could be separate dialogs, widgets, etc.
   Ui::TomographyIfaceQtTabSetup m_uiTabSetup;
   Ui::TomographyIfaceQtTabRun m_uiTabRun;
+  Ui::ImageSelectCoRAndRegions m_uiTabCoR;
 
   /// Tool specific setup dialogs
   Ui::TomoToolConfigAstra m_uiAstra;
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h
index 80d2b62a64138bcac14062a62289bb451a62e20e..8e4b19d2f7cdac14401455f43f7fbcf0e8c5bc86 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h
@@ -15,7 +15,7 @@ Configuration of a third party tomographic reconstruction tool
 specialized for the Astra Toolbox tomographic reconstruction tool
 (C++, CUDA): Astra Toolbox <http://sourceforge.net/p/astra-toolbox/wiki/Home/
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
@@ -38,7 +38,7 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 class DLLExport ToolConfigAstraToolbox : public TomoRecToolConfig {
 public:
-  ToolConfigAstraToolbox() { }
+  ToolConfigAstraToolbox();
 
   ToolConfigAstraToolbox(const std::string &runnable, double centerRot,
                          double angleMin, double angleMax,
@@ -47,7 +47,7 @@ public:
                          const std::string &pathOpen,
                          const std::string &pathSample);
 
-  ~ToolConfigAstraToolbox() { }
+  ~ToolConfigAstraToolbox() {}
 
 protected:
   virtual std::string makeCmdLineOptions() const;
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h
index fe02d914dc2a9d2db490682fa9daf8e9fdaa845d..98c947dc793a6e7fed3e9f3297e0fe1da67ea057 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h
@@ -18,7 +18,7 @@ custom interfaces might be moved out of here. Tools of other type
 might be added, and then this should not be a sublcass of
 TomoRecToolConfig but of a more general ToolConfig class.
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
index 56eec90cbd50d02bc126f34a091192f029621a78..b3e9054938af5d0c8ecdf4a94751f6ab2628d65e 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
@@ -14,7 +14,7 @@ Third party tomographic reconstruction tool configuration class
 specialized for TomoPy (Python + C++):
 https://www1.aps.anl.gov/Science/Scientific-Software/TomoPy
 
-Copyright &copy; 2014,205 ISIS Rutherford Appleton Laboratory, NScD
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 Oak Ridge National Laboratory & European Spallation Source
 
 This file is part of Mantid.
@@ -37,14 +37,14 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 class DLLExport ToolConfigTomoPy : public TomoRecToolConfig {
 public:
-  ToolConfigTomoPy() { }
+  ToolConfigTomoPy();
 
   ToolConfigTomoPy(const std::string &runnable, const std::string &pathOut,
                    const std::string &pathDark, const std::string &pathOpen,
                    const std::string &pathSample, double centerRot,
                    double angleMin, double angleMax);
 
-  ~ToolConfigTomoPy() { }
+  ~ToolConfigTomoPy() {}
 
 protected:
   virtual std::string makeCmdLineOptions() const;
diff --git a/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp b/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f411515c231575349bb8e05fc40899892918a63
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp
@@ -0,0 +1,305 @@
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h"
+#include "MantidQtCustomInterfaces/Tomography/IImageROIView.h"
+
+using namespace MantidQt::CustomInterfaces;
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+ImageROIPresenter::ImageROIPresenter(IImageROIView *view)
+    : m_view(view), m_model(new ImageStackPreParams()) {
+  if (!m_view) {
+    throw std::runtime_error("Severe inconsistency found. Presenter created "
+                             "with an empty/null view (tomography interface). "
+                             "Cannot continue.");
+  }
+}
+
+ImageROIPresenter::~ImageROIPresenter() { cleanup(); }
+
+void ImageROIPresenter::cleanup() {}
+
+void ImageROIPresenter::notify(Notification notif) {
+
+  switch (notif) {
+
+  case IImageROIPresenter::Init:
+    processInit();
+    break;
+
+  case IImageROIPresenter::BrowseImgOrStack:
+    processBrowseImg();
+    break;
+
+  case IImageROIPresenter::NewImgOrStack:
+    processNewStack();
+    break;
+
+  case IImageROIPresenter::UpdateImgIndex:
+    processUpdateImgIndex();
+    break;
+
+  case IImageROIPresenter::SelectCoR:
+    processSelectCoR();
+    break;
+
+  case IImageROIPresenter::SelectROI:
+    processSelectROI();
+    break;
+
+  case IImageROIPresenter::SelectNormalization:
+    processSelectNormalization();
+    break;
+
+  case IImageROIPresenter::FinishedCoR:
+    processFinishedCoR();
+    break;
+
+  case IImageROIPresenter::FinishedROI:
+    processFinishedROI();
+    break;
+
+  case IImageROIPresenter::FinishedNormalization:
+    processFinishedNormalization();
+    break;
+
+  case IImageROIPresenter::ResetCoR:
+    processResetCoR();
+    break;
+
+  case IImageROIPresenter::ResetROI:
+    processResetROI();
+    break;
+
+  case IImageROIPresenter::ResetNormalization:
+    processResetNormalization();
+    break;
+
+  case IImageROIPresenter::ShutDown:
+    processShutDown();
+    break;
+  }
+}
+
+void ImageROIPresenter::processInit() {
+  ImageStackPreParams p;
+  m_view->setParams(p);
+}
+
+void ImageROIPresenter::processBrowseImg() {
+  const std::string path = m_view->askImgOrStackPath();
+
+  if (path.empty())
+    return;
+
+  m_stackPath = path;
+  processNewStack();
+}
+
+/**
+ * Validates the input stack of images (directories and files), and
+ * shows warning/error messages as needed. The outocome of the
+ * validation can be checkec via isValid() on the returned stack of
+ * images object.
+ *
+ * @param path user provided path to the stack of images
+ *
+ * @return a stack of images built from the path passed, not
+ * necessarily correct (check with isValid())
+ */
+StackOfImagesDirs ImageROIPresenter::checkInputStack(const std::string &path) {
+  StackOfImagesDirs soid(path);
+
+  const std::string soiPath = soid.sampleImagesDir();
+  if (soiPath.empty()) {
+    m_view->userWarning("Error trying to find a stack of images",
+                        "Could not find the sample images directory. The stack "
+                        "of images is expected as: \n\n" +
+                            soid.description());
+  } else if (!soid.isValid()) {
+    m_view->userWarning("Error while checking/validating the stack of images",
+                        "The stack of images could not be loaded correctly. " +
+                            soid.status());
+  }
+
+  return soid;
+}
+
+void ImageROIPresenter::processNewStack() {
+
+  StackOfImagesDirs soid("");
+  try {
+    soid = checkInputStack(m_stackPath);
+  } catch (std::exception &e) {
+    // Poco::FileNotFoundException: this should never happen, unless
+    // the open dir dialog misbehaves unexpectedly, or in tests
+    m_view->userWarning("Error trying to open directories/files",
+                        "The path selected via the dialog cannot be openend or "
+                        "there was a problem while trying to access it. This "
+                        "is an unexpected inconsistency. Error details: " +
+                            std::string(e.what()));
+  }
+
+  if (!soid.isValid())
+    return;
+
+  std::vector<std::string> imgs = soid.sampleFiles();
+  if (0 >= imgs.size()) {
+    m_view->userWarning(
+        "Error trying to find image/projection files in the stack directories",
+        "Could not find any image file in the samples subdirectory: " +
+            soid.sampleImagesDir());
+    return;
+  }
+
+  Mantid::API::WorkspaceGroup_sptr wsg = loadFITSStack(imgs);
+  if (!wsg)
+    return;
+
+  size_t imgCount = wsg->size();
+  if (0 == imgCount) {
+    m_view->userWarning(
+        "Failed to load any FITS images - directory structure issue",
+        "Even though a directory apparently holding a stack of images was "
+        "found, "
+        "it was not possible to load any image file correctly from: " +
+            m_stackPath);
+    return;
+  }
+
+  m_view->showStack(wsg);
+
+  // clean-up container group workspace? Not for now
+  if (false && wsg)
+    Mantid::API::AnalysisDataService::Instance().remove(wsg->getName());
+}
+
+void ImageROIPresenter::processUpdateImgIndex() {
+  m_view->updateImgWithIndex(m_view->currentImgIndex());
+}
+
+void ImageROIPresenter::processSelectCoR() {
+  m_view->changeSelectionState(IImageROIView::SelectCoR);
+}
+
+void ImageROIPresenter::processSelectROI() {
+  m_view->changeSelectionState(IImageROIView::SelectROIFirst);
+}
+
+void ImageROIPresenter::processSelectNormalization() {
+  m_view->changeSelectionState(IImageROIView::SelectNormAreaFirst);
+}
+
+void ImageROIPresenter::processFinishedCoR() {
+  m_view->changeSelectionState(IImageROIView::SelectNone);
+}
+
+void ImageROIPresenter::processFinishedROI() {
+  m_view->changeSelectionState(IImageROIView::SelectNone);
+}
+
+void ImageROIPresenter::processFinishedNormalization() {
+  m_view->changeSelectionState(IImageROIView::SelectNone);
+}
+
+void ImageROIPresenter::processResetCoR() {
+  m_view->resetCoR();
+  m_view->changeSelectionState(IImageROIView::SelectNone);
+}
+
+void ImageROIPresenter::processResetROI() {
+  m_view->resetROI();
+  m_view->changeSelectionState(IImageROIView::SelectNone);
+}
+
+void ImageROIPresenter::processResetNormalization() {
+  m_view->resetNormArea();
+  m_view->changeSelectionState(IImageROIView::SelectNone);
+}
+
+void ImageROIPresenter::processShutDown() { m_view->saveSettings(); }
+
+Mantid::API::WorkspaceGroup_sptr
+ImageROIPresenter::loadFITSStack(const std::vector<std::string> &imgs) {
+  const std::string wsName = "__stack_fits_viewer_tomography_gui";
+  auto &ads = Mantid::API::AnalysisDataService::Instance();
+  if (ads.doesExist(wsName)) {
+    ads.remove(wsName);
+  }
+  for (size_t i = 0; i < imgs.size(); ++i) {
+    loadFITSImage(imgs[i], wsName);
+  }
+
+  Mantid::API::WorkspaceGroup_sptr wsg;
+  try {
+    wsg = ads.retrieveWS<Mantid::API::WorkspaceGroup>(wsName);
+  } catch (std::exception &e) {
+    throw std::runtime_error(
+        "Could not produce a workspace group for the stack images. Cannot "
+        "display it. Error details: " +
+        std::string(e.what()));
+  }
+
+  if (wsg &&
+      Mantid::API::AnalysisDataService::Instance().doesExist(wsg->name()) &&
+      imgs.size() == wsg->size()) {
+    return wsg;
+  } else {
+    return Mantid::API::WorkspaceGroup_sptr();
+  }
+}
+
+void ImageROIPresenter::loadFITSImage(const std::string &path,
+                                      const std::string &wsName) {
+  // get fits file into workspace and retrieve it from the ADS
+  auto alg = Mantid::API::AlgorithmManager::Instance().create("LoadFITS");
+  try {
+    alg->initialize();
+    alg->setPropertyValue("Filename", path);
+    alg->setProperty("OutputWorkspace", wsName);
+    // this is way faster when loading into a MatrixWorkspace
+    alg->setProperty("LoadAsRectImg", true);
+  } catch (std::exception &e) {
+    throw std::runtime_error("Failed to initialize the mantid algorithm to "
+                             "load images. Error description: " +
+                             std::string(e.what()));
+  }
+
+  try {
+    alg->execute();
+  } catch (std::exception &e) {
+    throw std::runtime_error(
+        "Failed to load image. Could not load this file as a "
+        "FITS image: " +
+        std::string(e.what()));
+  }
+
+  if (!alg->isExecuted()) {
+    throw std::runtime_error(
+        "Failed to load image correctly. Note that even though "
+        "the image file has been loaded it seems to contain errors.");
+  }
+
+  try {
+    Mantid::API::WorkspaceGroup_sptr wsg;
+    Mantid::API::MatrixWorkspace_sptr ws;
+    const auto &ads = Mantid::API::AnalysisDataService::Instance();
+    wsg = ads.retrieveWS<Mantid::API::WorkspaceGroup>(wsName);
+    ws = ads.retrieveWS<Mantid::API::MatrixWorkspace>(wsg->getNames()[0]);
+  } catch (std::exception &e) {
+    throw std::runtime_error(
+        "Could not load image contents for file '" + path +
+        "'. An unrecoverable error "
+        "happened when trying to load the image contents. Cannot "
+        "display it. Error details: " +
+        std::string(e.what()));
+  }
+}
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp b/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51d23189b5cc869314dadd5affa48158f7b373b0
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp
@@ -0,0 +1,830 @@
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidQtAPI/AlgorithmInputHistory.h"
+#include "MantidQtAPI/AlgorithmRunner.h"
+
+#include "MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h"
+
+using namespace Mantid::API;
+using namespace MantidQt::CustomInterfaces;
+
+#include <QCloseEvent>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QPainter>
+#include <QSettings>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+// this would be more like a CustomWidget if it's eventually moved there
+const std::string ImageROIViewQtWidget::m_settingsGroup =
+    "CustomInterfaces/ImageROIView";
+
+ImageROIViewQtWidget::ImageROIViewQtWidget(QWidget *parent)
+    : QWidget(parent), IImageROIView(), m_imgWidth(0), m_imgHeight(0),
+      m_selectionState(SelectNone), m_presenter(NULL) {
+  initLayout();
+
+  // using an event filter. might be worth refactoring into a specific
+  // QLabel + selection of ROI+NormArea+CoR class
+  // not using Qwt Pickers to avoid Qwt version issues..
+  m_ui.label_img->installEventFilter(this);
+}
+
+void ImageROIViewQtWidget::setParams(ImageStackPreParams &params) {
+  m_params = params;
+  setParamWidgets(m_params);
+}
+
+ImageStackPreParams ImageROIViewQtWidget::userSelection() const {
+  return m_params;
+}
+
+void ImageROIViewQtWidget::changeSelectionState(
+    const IImageROIView::SelectionState &state) {
+  m_selectionState = state;
+}
+
+void ImageROIViewQtWidget::showStack(const std::string & /*path*/) {
+  // TODO:
+  // a) load as proper stack of images workspace - this can only be done when
+  //    we have a firt working version of the "lean MD workspace". This method
+  //    would then load into one workspace of such type.
+  // b) load as workspace group - this is done in the overloaded method below
+
+  // enableParamWidgets(true);
+}
+
+void ImageROIViewQtWidget::showStack(Mantid::API::WorkspaceGroup_sptr &wsg) {
+  if (0 == wsg->size())
+    return;
+
+  m_stack = wsg;
+
+  m_ui.horizontalScrollBar_img_stack->setEnabled(true);
+  m_ui.horizontalScrollBar_img_stack->setMinimum(0);
+  m_ui.horizontalScrollBar_img_stack->setMaximum(
+      static_cast<int>(m_stack->size() - 1));
+
+  size_t width = 0, height = 0;
+  try {
+    MatrixWorkspace_sptr ws =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(wsg->getItem(0));
+    if (!ws)
+      return;
+    width = ws->blocksize();
+    height = ws->getNumberHistograms();
+  } catch (std::exception &e) {
+    QMessageBox::warning(this, "Cannot load image information",
+                         "There was a problem while "
+                         " trying to find the size of the image: " +
+                             QString::fromStdString(e.what()));
+  }
+
+  showProjection(m_stack, 0);
+  initParamWidgets(width, height);
+  refreshROIetAl();
+  enableParamWidgets(true);
+}
+
+void ImageROIViewQtWidget::showProjection(
+    const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx) {
+
+  showProjectionImage(wsg, idx);
+  refreshROIetAl();
+
+  // give name, set up scroll/slider
+  std::string name;
+  try {
+    MatrixWorkspace_sptr ws =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(wsg->getItem(idx));
+    if (!ws)
+      return;
+    name = ws->run().getLogData("run_title")->value();
+  } catch (std::exception &e) {
+    QMessageBox::warning(this, "Cannot load image information",
+                         "There was a problem while "
+                         " trying to find the name of the image: " +
+                             QString::fromStdString(e.what()));
+  }
+  m_ui.label_img_name->setText(QString::fromStdString(name));
+
+  const size_t numPics = wsg->size();
+  m_ui.lineEdit_img_seq->setText(
+      QString::fromStdString("1/" + boost::lexical_cast<std::string>(numPics)));
+  m_ui.horizontalScrollBar_img_stack->setValue(static_cast<int>(idx));
+}
+
+void ImageROIViewQtWidget::userWarning(const std::string &err,
+                                       const std::string &description) {
+  QMessageBox::warning(this, QString::fromStdString(err),
+                       QString::fromStdString(description), QMessageBox::Ok,
+                       QMessageBox::Ok);
+}
+
+void ImageROIViewQtWidget::userError(const std::string &err,
+                                     const std::string &description) {
+  QMessageBox::critical(this, QString::fromStdString(err),
+                        QString::fromStdString(description), QMessageBox::Ok,
+                        QMessageBox::Ok);
+}
+
+std::string ImageROIViewQtWidget::askImgOrStackPath() {
+  // get path
+  QString fitsStr = QString("Supported formats: FITS, TIFF and PNG "
+                            "(*.fits *.fit *.tiff *.tif *.png);;"
+                            "FITS, Flexible Image Transport System images "
+                            "(*.fits *.fit);;"
+                            "TIFF, Tagged Image File Format "
+                            "(*.tif *.tiff);;"
+                            "PNG, Portable Network Graphics "
+                            "(*.png);;"
+                            "Other extensions/all files (*.*)");
+  QString prevPath =
+      MantidQt::API::AlgorithmInputHistory::Instance().getPreviousDirectory();
+  QString path(QFileDialog::getExistingDirectory(
+      this, tr("Open stack of images"), prevPath, QFileDialog::ShowDirsOnly));
+  if (!path.isEmpty()) {
+    MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(path);
+  }
+
+  return path.toStdString();
+}
+
+void ImageROIViewQtWidget::saveSettings() const {
+  QSettings qs;
+  qs.beginGroup(QString::fromStdString(m_settingsGroup));
+
+  qs.setValue("interface-win-geometry", saveGeometry());
+  qs.endGroup();
+}
+
+void ImageROIViewQtWidget::resetCoR() {
+  int midx =
+      (m_ui.spinBox_cor_x->minimum() + m_ui.spinBox_cor_x->maximum()) / 2;
+  m_ui.spinBox_cor_x->setValue(midx);
+  int midy =
+      (m_ui.spinBox_cor_y->minimum() + m_ui.spinBox_cor_y->maximum()) / 2;
+  m_ui.spinBox_cor_y->setValue(midy);
+}
+
+void ImageROIViewQtWidget::resetROI() {
+  m_ui.spinBox_roi_top_x->setValue(0);
+  m_ui.spinBox_roi_top_y->setValue(0);
+  m_ui.spinBox_roi_bottom_x->setValue(m_ui.spinBox_roi_bottom_x->maximum());
+  m_ui.spinBox_roi_bottom_y->setValue(m_ui.spinBox_roi_bottom_y->maximum());
+}
+
+void ImageROIViewQtWidget::resetNormArea() {
+  m_ui.spinBox_norm_top_x->setValue(0);
+  m_ui.spinBox_norm_top_y->setValue(0);
+  m_ui.spinBox_norm_bottom_x->setValue(0);
+  m_ui.spinBox_norm_bottom_y->setValue(0);
+}
+
+void ImageROIViewQtWidget::initLayout() {
+  // setup container ui
+  m_ui.setupUi(this);
+
+  QList<int> sizes;
+  sizes.push_back(1000);
+  sizes.push_back(100);
+  m_ui.splitter_main_horiz->setSizes(sizes);
+
+  sizes.clear();
+  sizes.push_back(10);
+  sizes.push_back(1000);
+  m_ui.splitter_img_vertical->setSizes(sizes);
+  m_ui.horizontalScrollBar_img_stack->setEnabled(false);
+  m_ui.lineEdit_img_seq->setText("---");
+
+  enableParamWidgets(false);
+
+  setupConnections();
+
+  initParamWidgets(1, 1);
+  grabCoRFromWidgets();
+  grabROIFromWidgets();
+  grabNormAreaFromWidgets();
+
+  // presenter that knows how to handle a IImageROIView should take care
+  // of all the logic. Note the view needs to now the concrete presenter here
+  m_presenter.reset(new ImageROIPresenter(this));
+
+  // it will know what compute resources and tools we have available:
+  // This view doesn't even know the names of compute resources, etc.
+  m_presenter->notify(ImageROIPresenter::Init);
+}
+
+void ImageROIViewQtWidget::setupConnections() {
+
+  // 'browse' buttons
+  connect(m_ui.pushButton_browse_img, SIGNAL(released()), this,
+          SLOT(browseImgClicked()));
+
+  connect(m_ui.pushButton_cor, SIGNAL(released()), this, SLOT(corClicked()));
+  connect(m_ui.pushButton_cor_reset, SIGNAL(released()), this,
+          SLOT(corResetClicked()));
+
+  connect(m_ui.pushButton_roi, SIGNAL(released()), this, SLOT(roiClicked()));
+  connect(m_ui.pushButton_roi_reset, SIGNAL(released()), this,
+          SLOT(roiResetClicked()));
+
+  connect(m_ui.pushButton_norm_area, SIGNAL(released()), this,
+          SLOT(normAreaClicked()));
+  connect(m_ui.pushButton_norm_area_reset, SIGNAL(released()), this,
+          SLOT(normAreaResetClicked()));
+
+  // image sequence scroll/slide:
+  connect(m_ui.horizontalScrollBar_img_stack, SIGNAL(valueChanged(int)), this,
+          SLOT(updateFromImagesSlider(int)));
+
+  // parameter (points) widgets
+  connect(m_ui.spinBox_cor_x, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedCoR(int)));
+  connect(m_ui.spinBox_cor_y, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedCoR(int)));
+
+  connect(m_ui.spinBox_roi_top_x, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedROI(int)));
+  connect(m_ui.spinBox_roi_top_y, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedROI(int)));
+  connect(m_ui.spinBox_roi_bottom_x, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedROI(int)));
+  connect(m_ui.spinBox_roi_bottom_y, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedROI(int)));
+
+  connect(m_ui.spinBox_norm_top_x, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedNormArea(int)));
+  connect(m_ui.spinBox_norm_top_y, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedNormArea(int)));
+  connect(m_ui.spinBox_norm_bottom_x, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedNormArea(int)));
+  connect(m_ui.spinBox_norm_bottom_y, SIGNAL(valueChanged(int)), this,
+          SLOT(valueUpdatedNormArea(int)));
+}
+
+void ImageROIViewQtWidget::valueUpdatedCoR(int) {
+  grabCoRFromWidgets();
+  refreshROIetAl();
+}
+
+void ImageROIViewQtWidget::valueUpdatedROI(int) {
+  grabROIFromWidgets();
+  refreshROIetAl();
+}
+
+void ImageROIViewQtWidget::valueUpdatedNormArea(int) {
+  grabNormAreaFromWidgets();
+  refreshROIetAl();
+}
+
+/**
+ * Parameter values from spin box widgets => coordinate parameters
+ * data member
+ */
+void ImageROIViewQtWidget::grabCoRFromWidgets() {
+  m_params.cor = Mantid::Kernel::V2D(m_ui.spinBox_cor_x->value(),
+                                     m_ui.spinBox_cor_y->value());
+}
+
+void ImageROIViewQtWidget::grabROIFromWidgets() {
+  m_params.roi =
+      std::make_pair(Mantid::Kernel::V2D(m_ui.spinBox_roi_top_x->value(),
+                                         m_ui.spinBox_roi_top_y->value()),
+                     Mantid::Kernel::V2D(m_ui.spinBox_roi_bottom_x->value(),
+                                         m_ui.spinBox_roi_bottom_y->value()));
+}
+
+void ImageROIViewQtWidget::grabNormAreaFromWidgets() {
+  m_params.normalizationRegion =
+      std::make_pair(Mantid::Kernel::V2D(m_ui.spinBox_norm_top_x->value(),
+                                         m_ui.spinBox_norm_top_y->value()),
+                     Mantid::Kernel::V2D(m_ui.spinBox_norm_bottom_x->value(),
+                                         m_ui.spinBox_norm_bottom_y->value()));
+}
+
+/**
+ * Updates the image view with the current image index and selection
+ * of parameters (ROI, normalization area, CoR). This needs to be used
+ * for every event that modifies the current image and/or selection of
+ * parameters.
+ */
+void ImageROIViewQtWidget::refreshROIetAl() {
+
+  const QPixmap *pp = m_ui.label_img->pixmap();
+  if (!pp)
+    return;
+
+  QPixmap toDisplay(*m_basePixmap.get());
+  QPainter painter(&toDisplay);
+
+  // TODO: display settings / nicer symbol?
+
+  QPen penCoR(Qt::red);
+  painter.setPen(penCoR);
+  painter.drawLine(static_cast<int>(m_params.cor.X() - 5),
+                   static_cast<int>(m_params.cor.Y()),
+                   static_cast<int>(m_params.cor.X() + 5),
+                   static_cast<int>(m_params.cor.Y()));
+  painter.drawLine(static_cast<int>(m_params.cor.X()),
+                   static_cast<int>(m_params.cor.Y() - 5),
+                   static_cast<int>(m_params.cor.X()),
+                   static_cast<int>(m_params.cor.Y() + 5));
+
+  QPen penROI(Qt::green);
+  painter.setPen(penROI);
+  painter.drawRect(
+      static_cast<int>(m_params.roi.first.X()),
+      static_cast<int>(m_params.roi.first.Y()),
+      static_cast<int>(m_params.roi.second.X() - m_params.roi.first.X()),
+      static_cast<int>(m_params.roi.second.Y() - m_params.roi.first.Y()));
+
+  QPen penNA(Qt::yellow);
+  painter.setPen(penNA);
+  painter.drawRect(static_cast<int>(m_params.normalizationRegion.first.X()),
+                   static_cast<int>(m_params.normalizationRegion.first.Y()),
+                   static_cast<int>(m_params.normalizationRegion.second.X() -
+                                    m_params.normalizationRegion.first.X()),
+                   static_cast<int>(m_params.normalizationRegion.second.Y() -
+                                    m_params.normalizationRegion.first.Y()));
+
+  m_ui.label_img->setPixmap(toDisplay);
+}
+
+void ImageROIViewQtWidget::refreshCoR() {
+  const QPixmap *pp = m_ui.label_img->pixmap();
+  if (!pp)
+    return;
+
+  grabCoRFromWidgets();
+
+  QPixmap toDisplay(*m_basePixmap.get());
+  QPainter painter(&toDisplay);
+  QPen pen(Qt::red);
+  painter.setPen(pen);
+  painter.drawLine(static_cast<int>(m_params.cor.X() - 5),
+                   static_cast<int>(m_params.cor.Y()),
+                   static_cast<int>(m_params.cor.X() + 5),
+                   static_cast<int>(m_params.cor.Y()));
+  painter.drawLine(static_cast<int>(m_params.cor.X()),
+                   static_cast<int>(m_params.cor.Y() - 5),
+                   static_cast<int>(m_params.cor.X()),
+                   static_cast<int>(m_params.cor.Y() + 5));
+  m_ui.label_img->setPixmap(toDisplay);
+}
+
+void ImageROIViewQtWidget::refreshROI() {
+  const QPixmap *pp = m_ui.label_img->pixmap();
+  if (!pp)
+    return;
+
+  grabROIFromWidgets();
+  // TODO: display proper symbol
+
+  // QPixmap const *pm = m_ui.label_img->pixmap();
+  QPixmap toDisplay(*m_basePixmap.get());
+  QPainter painter(&toDisplay);
+  QPen pen(Qt::green);
+  painter.setPen(pen);
+  painter.drawRect(
+      static_cast<int>(m_params.roi.first.X()),
+      static_cast<int>(m_params.roi.first.Y()),
+      static_cast<int>(m_params.roi.second.X() - m_params.roi.first.X()),
+      static_cast<int>(m_params.roi.second.Y() - m_params.roi.first.Y()));
+  m_ui.label_img->setPixmap(toDisplay);
+}
+
+void ImageROIViewQtWidget::refreshNormArea() {
+  // TODO: display proper symbol
+  const QPixmap *pp = m_ui.label_img->pixmap();
+  if (!pp)
+    return;
+
+  grabNormAreaFromWidgets();
+
+  // QPixmap const *pm = m_ui.label_img->pixmap();
+  QPixmap toDisplay(*m_basePixmap.get());
+  QPainter painter(&toDisplay);
+  QPen pen(Qt::yellow);
+  painter.setPen(pen);
+  painter.drawRect(static_cast<int>(m_params.normalizationRegion.first.X()),
+                   static_cast<int>(m_params.normalizationRegion.first.Y()),
+                   static_cast<int>(m_params.normalizationRegion.second.X() -
+                                    m_params.normalizationRegion.first.X()),
+                   static_cast<int>(m_params.normalizationRegion.second.Y() -
+                                    m_params.normalizationRegion.first.Y()));
+  m_ui.label_img->setPixmap(toDisplay);
+}
+
+void ImageROIViewQtWidget::enableParamWidgets(bool enable) {
+  m_ui.groupBox_cor->setEnabled(enable);
+  m_ui.groupBox_roi->setEnabled(enable);
+  m_ui.groupBox_norm->setEnabled(enable);
+}
+
+void ImageROIViewQtWidget::initParamWidgets(size_t maxWidth, size_t maxHeight) {
+  m_imgWidth = static_cast<int>(maxWidth);
+  m_imgHeight = static_cast<int>(maxHeight);
+
+  m_ui.spinBox_cor_x->setMinimum(0);
+  m_ui.spinBox_cor_x->setMaximum(m_imgWidth - 1);
+  m_ui.spinBox_cor_y->setMinimum(0);
+  m_ui.spinBox_cor_y->setMaximum(m_imgHeight - 1);
+  resetCoR();
+
+  m_ui.spinBox_roi_top_x->setMinimum(0);
+  m_ui.spinBox_roi_top_x->setMaximum(m_imgWidth - 1);
+  m_ui.spinBox_roi_top_y->setMinimum(0);
+  m_ui.spinBox_roi_top_y->setMaximum(m_imgHeight - 1);
+
+  m_ui.spinBox_roi_bottom_x->setMinimum(0);
+  m_ui.spinBox_roi_bottom_x->setMaximum(m_imgWidth - 1);
+  m_ui.spinBox_roi_bottom_y->setMinimum(0);
+  m_ui.spinBox_roi_bottom_y->setMaximum(m_imgHeight - 1);
+
+  resetROI();
+
+  m_ui.spinBox_norm_top_x->setMinimum(0);
+  m_ui.spinBox_norm_top_x->setMaximum(m_imgWidth - 1);
+  m_ui.spinBox_norm_top_y->setMinimum(0);
+  m_ui.spinBox_norm_top_y->setMaximum(m_imgHeight - 1);
+
+  m_ui.spinBox_norm_bottom_x->setMinimum(0);
+  m_ui.spinBox_norm_bottom_x->setMaximum(m_imgWidth - 1);
+  m_ui.spinBox_norm_bottom_y->setMinimum(0);
+  m_ui.spinBox_norm_bottom_y->setMaximum(m_imgHeight - 1);
+
+  resetNormArea();
+}
+
+void ImageROIViewQtWidget::setParamWidgets(ImageStackPreParams &params) {
+  m_ui.spinBox_cor_x->setValue(static_cast<int>(params.cor.X()));
+  m_ui.spinBox_cor_y->setValue(static_cast<int>(params.cor.Y()));
+
+  m_ui.spinBox_roi_top_x->setValue(static_cast<int>(params.roi.first.X()));
+  m_ui.spinBox_roi_top_y->setValue(static_cast<int>(params.roi.first.Y()));
+
+  m_ui.spinBox_roi_bottom_x->setValue(static_cast<int>(params.roi.second.X()));
+  m_ui.spinBox_roi_bottom_y->setValue(static_cast<int>(params.roi.second.Y()));
+
+  m_ui.spinBox_norm_top_x->setValue(
+      static_cast<int>(params.normalizationRegion.first.X()));
+  m_ui.spinBox_norm_top_y->setValue(
+      static_cast<int>(params.normalizationRegion.first.Y()));
+
+  m_ui.spinBox_norm_bottom_x->setValue(
+      static_cast<int>(params.normalizationRegion.second.X()));
+  m_ui.spinBox_norm_bottom_y->setValue(
+      static_cast<int>(params.normalizationRegion.second.Y()));
+}
+
+void ImageROIViewQtWidget::corClicked() {
+  m_presenter->notify(IImageROIPresenter::SelectCoR);
+}
+
+void ImageROIViewQtWidget::corResetClicked() {
+  m_presenter->notify(IImageROIPresenter::ResetCoR);
+  refreshROIetAl();
+}
+
+void ImageROIViewQtWidget::roiClicked() {
+  m_presenter->notify(IImageROIPresenter::SelectROI);
+}
+
+void ImageROIViewQtWidget::roiResetClicked() {
+  m_presenter->notify(IImageROIPresenter::ResetROI);
+  refreshROIetAl();
+}
+
+void ImageROIViewQtWidget::normAreaClicked() {
+  m_presenter->notify(IImageROIPresenter::SelectNormalization);
+}
+
+void ImageROIViewQtWidget::normAreaResetClicked() {
+  m_presenter->notify(IImageROIPresenter::ResetNormalization);
+  refreshROIetAl();
+}
+
+void ImageROIViewQtWidget::browseImgClicked() {
+  m_presenter->notify(IImageROIPresenter::BrowseImgOrStack);
+}
+
+void ImageROIViewQtWidget::updateFromImagesSlider(int /* current */) {
+  m_presenter->notify(IImageROIPresenter::UpdateImgIndex);
+}
+
+size_t ImageROIViewQtWidget::currentImgIndex() const {
+  return m_ui.horizontalScrollBar_img_stack->value();
+}
+
+void ImageROIViewQtWidget::updateImgWithIndex(size_t idx) {
+  int max = m_ui.horizontalScrollBar_img_stack->maximum();
+  int current = m_ui.horizontalScrollBar_img_stack->value();
+
+  showProjection(m_stack, idx);
+  m_ui.lineEdit_img_seq->setText(
+      QString::fromStdString(boost::lexical_cast<std::string>(current + 1) +
+                             "/" + boost::lexical_cast<std::string>(max + 1)));
+}
+
+void ImageROIViewQtWidget::showProjectionImage(
+    const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx) {
+
+  MatrixWorkspace_sptr ws;
+  try {
+    ws = boost::dynamic_pointer_cast<MatrixWorkspace>(wsg->getItem(idx));
+    if (!ws)
+      return;
+  } catch (std::exception &e) {
+    QMessageBox::warning(
+        this, "Cannot load image",
+        "There was a problem while trying to find the image data: " +
+            QString::fromStdString(e.what()));
+  }
+
+  const size_t MAXDIM = 2048 * 16;
+  size_t width;
+  try {
+    width = boost::lexical_cast<size_t>(ws->run().getLogData("Axis1")->value());
+    // TODO: add a settings option for this (like max mem allocation for
+    // images)?
+    if (width >= MAXDIM)
+      width = MAXDIM;
+  } catch (std::exception &e) {
+    QMessageBox::critical(this, "Cannot load image",
+                          "There was a problem while trying to "
+                          "find the width of the image: " +
+                              QString::fromStdString(e.what()));
+    return;
+  }
+
+  size_t height;
+  try {
+    height =
+        boost::lexical_cast<size_t>(ws->run().getLogData("Axis2")->value());
+    if (height >= MAXDIM)
+      height = MAXDIM;
+  } catch (std::exception &e) {
+    QMessageBox::critical(this, "Cannot load image",
+                          "There was a problem while trying to "
+                          "find the height of the image: " +
+                              QString::fromStdString(e.what()));
+    return;
+  }
+
+  // images are loaded as 1 histogram == 1 pixel (1 bin per histogram):
+  if (height != ws->getNumberHistograms() || width != ws->blocksize()) {
+    QMessageBox::critical(
+        this, "Image dimensions do not match in the input image workspace",
+        "Could not load the expected "
+        "number of rows and columns.");
+    return;
+  }
+  // find min and max to scale pixel values
+  double min = std::numeric_limits<double>::max(),
+         max = std::numeric_limits<double>::min();
+  for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
+    for (size_t j = 0; j < ws->blocksize(); ++j) {
+      const double &v = ws->readY(i)[j];
+      if (v < min)
+        min = v;
+      if (v > max)
+        max = v;
+    }
+  }
+  if (min >= max) {
+    QMessageBox::warning(
+        this, "Empty image!",
+        "The image could be loaded but it contains "
+        "effectively no information, all pixels have the same value.");
+    // black picture
+    QPixmap pix(static_cast<int>(width), static_cast<int>(height));
+    pix.fill(QColor(0, 0, 0));
+    m_ui.label_img->setPixmap(pix);
+    m_ui.label_img->show();
+    m_basePixmap.reset(new QPixmap(pix));
+    return;
+  }
+
+  // load / transfer image into a QImage
+  QImage rawImg(QSize(static_cast<int>(width), static_cast<int>(height)),
+                QImage::Format_RGB32);
+  const double max_min = max - min;
+  const double scaleFactor = 255.0 / max_min;
+  for (size_t yi = 0; yi < width; ++yi) {
+    for (size_t xi = 0; xi < width; ++xi) {
+      const double &v = ws->readY(yi)[xi];
+      // color the range min-max in gray scale. To apply different color
+      // maps you'd need to use rawImg.setColorTable() or similar.
+      const int scaled = static_cast<int>(scaleFactor * (v - min));
+      QRgb vRgb = qRgb(scaled, scaled, scaled);
+      rawImg.setPixel(static_cast<int>(xi), static_cast<int>(yi), vRgb);
+    }
+  }
+
+  // paint and show image
+  // direct from image
+  QPixmap pix = QPixmap::fromImage(rawImg);
+  m_ui.label_img->setPixmap(pix);
+  m_ui.label_img->show();
+  m_basePixmap.reset(new QPixmap(pix));
+  // Alternative, drawing with a painter:
+  // QPixmap pix(static_cast<int>(width), static_cast<int>(height));
+  // QPainter painter;
+  // painter.begin(&pix);
+  // painter.drawImage(0, 0, rawImg);
+  // painter.end();
+  // m_ui.label_img->setPixmap(pix);
+  // m_ui.label_img->show();
+  // m_basePixmap.reset(new QPixmap(pix));
+}
+
+/**
+ * Qt events filter for the mouse click and click&drag events that are
+ * used to select points and rectangles. Part of the logic of the
+ * selection is handled here. The test on the presenter can only test
+ * the begin and end of the selection. For full testability (including
+ * the mouse interaction), this method should be implemented fully in
+ * terms of notifications to the presenter. This would require a bunch
+ * of new notifications in IImageROIPresenter, and making at least all
+ * the mouseUpdateCoR, mouseUpdateROICorners12, mouseXXX methods
+ * public in this view interface. This can be considered at a later
+ * stage.
+ *
+ * @param obj object concerned by the event
+ * @param event event received (mouse click, release, move, etc.)
+ **/
+bool ImageROIViewQtWidget::eventFilter(QObject *obj, QEvent *event) {
+  // quick ignore
+  if (IImageROIView::SelectNone == m_selectionState)
+    return false;
+
+  if (m_ui.label_img == obj) {
+
+    QPoint p = m_ui.label_img->mapFromGlobal(QCursor::pos());
+    int x = p.x();
+    int y = p.y();
+    // ignore potential clicks outside of the image
+    if (x >= m_imgWidth || y >= m_imgHeight || x < 0 || y < 0)
+      return false;
+
+    auto type = event->type();
+    if (type == QEvent::MouseButtonPress) {
+
+      if (IImageROIView::SelectCoR == m_selectionState) {
+        mouseUpdateCoR(x, y);
+      } else if (IImageROIView::SelectROIFirst == m_selectionState) {
+        mouseUpdateROICorners12(x, y);
+      } else if (IImageROIView::SelectNormAreaFirst == m_selectionState) {
+        mouseUpdateNormAreaCorners12(x, y);
+      }
+    } else if (type == QEvent::MouseMove) {
+
+      if (IImageROIView::SelectROISecond == m_selectionState) {
+        mouseUpdateROICorner2(x, y);
+      } else if (IImageROIView::SelectNormAreaSecond == m_selectionState) {
+        mouseUpdateNormAreaCorner2(x, y);
+      }
+    } else if (type == QEvent::MouseButtonRelease) {
+
+      if (IImageROIView::SelectROISecond == m_selectionState) {
+        mouseFinishROI(x, y);
+      } else if (IImageROIView::SelectNormAreaSecond == m_selectionState) {
+        mouseFinishNormArea(x, y);
+      }
+    }
+  }
+  // pass on the event up to the parent class
+  return false;
+}
+
+/**
+ * Parameter values from mouse position (at a relevant event like
+ * first click, or last release) => spin box widgets, AND coordinate
+ * parameters data member. This grabs the Center of Rotation (CoR)
+ *
+ * @param x position on x axis (local to the image)
+ * @param y position on y axis (local to the image)
+ */
+void ImageROIViewQtWidget::grabCoRFromMousePoint(int x, int y) {
+  m_params.cor = Mantid::Kernel::V2D(x, y);
+  m_ui.spinBox_cor_x->setValue(x);
+  m_ui.spinBox_cor_y->setValue(y);
+}
+
+void ImageROIViewQtWidget::grabROICorner1FromMousePoint(int x, int y) {
+  m_params.roi.first = Mantid::Kernel::V2D(x, y);
+  m_ui.spinBox_roi_top_x->setValue(x);
+  m_ui.spinBox_roi_top_y->setValue(y);
+}
+
+void ImageROIViewQtWidget::grabROICorner2FromMousePoint(int x, int y) {
+  m_params.roi.second = Mantid::Kernel::V2D(x, y);
+  m_ui.spinBox_roi_bottom_x->setValue(x);
+  m_ui.spinBox_roi_bottom_y->setValue(y);
+}
+
+void ImageROIViewQtWidget::grabNormAreaCorner1FromMousePoint(int x, int y) {
+  m_params.normalizationRegion.first = Mantid::Kernel::V2D(x, y);
+  m_ui.spinBox_norm_top_x->setValue(x);
+  m_ui.spinBox_norm_top_y->setValue(y);
+}
+
+void ImageROIViewQtWidget::grabNormAreaCorner2FromMousePoint(int x, int y) {
+  m_params.normalizationRegion.second = Mantid::Kernel::V2D(x, y);
+  m_ui.spinBox_norm_bottom_x->setValue(x);
+  m_ui.spinBox_norm_bottom_y->setValue(y);
+}
+
+/**
+ * This is an update and implicity a finish, as there's only one
+ * update for the CoR (single point-click). The coordinates count as
+ * usual in Qt widgets. Top-left is (0,0).
+ *
+ * @param x position on x axis (local to the image)
+ * @param y position on y axis (local to the image)
+ */
+void ImageROIViewQtWidget::mouseUpdateCoR(int x, int y) {
+  grabCoRFromMousePoint(x, y);
+  refreshROIetAl();
+
+  m_presenter->notify(IImageROIPresenter::FinishedCoR);
+}
+
+/**
+ * Start of ROI selection (or first click after pushing "select
+ * ROI". The rectangle starts as a point from the mouse click.
+ *
+ * @param x position on x axis (local to the image)
+ * @param y position on y axis (local to the image)
+ */
+void ImageROIViewQtWidget::mouseUpdateROICorners12(int x, int y) {
+  grabROICorner1FromMousePoint(x, y);
+  grabROICorner2FromMousePoint(x, y);
+  refreshROIetAl();
+  m_selectionState = IImageROIView::SelectROISecond;
+}
+
+/**
+ * Change the rectangle while pressing the mouse button. The first
+ * corner stays at the first click, now only the second corner changes
+ * to the new mouse position. On release of the mouse button we'll get
+ * to mouseFinishROICorner2() and end the selection of the ROI.
+ *
+ * @param x position on x axis (local to the image)
+ * @param y position on y axis (local to the image)
+ */
+void ImageROIViewQtWidget::mouseUpdateROICorner2(int x, int y) {
+  grabROICorner2FromMousePoint(x, y);
+  refreshROIetAl();
+}
+
+/**
+ * End of ROI selection (or mouse button release after clicking once
+ * and move, all after pushing "select ROI". The second corner of the
+ * rectangle is set at the current position.
+ *
+ * @param x position on x axis (local to the image)
+ * @param y position on y axis (local to the image)
+ */
+void ImageROIViewQtWidget::mouseFinishROI(int x, int y) {
+  grabROICorner2FromMousePoint(x, y);
+  refreshROIetAl();
+  m_presenter->notify(IImageROIPresenter::FinishedROI);
+}
+
+void ImageROIViewQtWidget::mouseUpdateNormAreaCorners12(int x, int y) {
+  grabNormAreaCorner1FromMousePoint(x, y);
+  grabNormAreaCorner2FromMousePoint(x, y);
+  refreshROIetAl();
+  m_selectionState = IImageROIView::SelectNormAreaSecond;
+}
+
+void ImageROIViewQtWidget::mouseUpdateNormAreaCorner2(int x, int y) {
+  grabNormAreaCorner2FromMousePoint(x, y);
+  refreshROIetAl();
+}
+
+void ImageROIViewQtWidget::mouseFinishNormArea(int x, int y) {
+  grabNormAreaCorner2FromMousePoint(x, y);
+  refreshROIetAl();
+  m_presenter->notify(IImageROIPresenter::FinishedNormalization);
+}
+
+void ImageROIViewQtWidget::readSettings() {
+  QSettings qs;
+  qs.beginGroup(QString::fromStdString(m_settingsGroup));
+  restoreGeometry(qs.value("interface-win-geometry").toByteArray());
+  qs.endGroup();
+}
+
+void ImageROIViewQtWidget::closeEvent(QCloseEvent *event) {
+  m_presenter->notify(IImageROIPresenter::ShutDown);
+  event->accept();
+}
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/ImageStackPreParams.cpp b/MantidQt/CustomInterfaces/src/Tomography/ImageStackPreParams.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..60d8a1e2bd0dbc8a26e01cb9dcae0898e0a27395
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/ImageStackPreParams.cpp
@@ -0,0 +1,13 @@
+#include "MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h"
+
+using namespace MantidQt::CustomInterfaces;
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+ImageStackPreParams::ImageStackPreParams()
+{
+
+}
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/StackOfImagesDirs.cpp b/MantidQt/CustomInterfaces/src/Tomography/StackOfImagesDirs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d8be84c4a5db207fb1285d9888532c6e30c86fe3
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/StackOfImagesDirs.cpp
@@ -0,0 +1,129 @@
+#include "MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h"
+
+#include <boost/algorithm/string.hpp>
+
+#include <Poco/DirectoryIterator.h>
+#include <Poco/Path.h>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+const std::string StackOfImagesDirs::g_descr =
+    "A directory (folder) that contains subdirectories with names "
+    "starting with:\n- 'Data' (for sample images),\n- 'Flat' (for white "
+    "bean images),\n- 'Dark' (for dark images)\nThe first one is "
+    "mandatory whereas the other two are optional.";
+
+const std::string StackOfImagesDirs::g_sampleNamePrefix = "data";
+const std::string StackOfImagesDirs::g_flatNamePrefix = "flat";
+const std::string StackOfImagesDirs::g_darkNamePrefix = "dark";
+const std::string StackOfImagesDirs::g_processedNamePrefix = "processed";
+const std::string StackOfImagesDirs::g_prefilteredNamePrefix = "pre_filtered";
+
+StackOfImagesDirs::StackOfImagesDirs(const std::string &path)
+    : m_valid(false), m_statusDescStr("Constructed, no checks done yet.") {
+  findStackDirs(path);
+}
+
+std::string StackOfImagesDirs::description() const { return g_descr; }
+
+std::string StackOfImagesDirs::status() const {
+  if (m_valid)
+    return "Stack of images is correct";
+  else
+    return "There are errors in the directories and/or files. " +
+           m_statusDescStr;
+}
+
+std::vector<std::string> StackOfImagesDirs::sampleFiles() const {
+  return findImgFiles(m_sampleDir);
+}
+std::vector<std::string> StackOfImagesDirs::flatFiles() const {
+  return findImgFiles(m_flatDir);
+}
+std::vector<std::string> StackOfImagesDirs::darkFiles() const {
+  return findImgFiles(m_darkDir);
+}
+
+void StackOfImagesDirs::findStackDirs(const std::string &path) {
+  if (path.empty())
+    return;
+
+  Poco::File dir(path);
+  if (!dir.isDirectory() || !dir.exists())
+    return;
+
+  Poco::DirectoryIterator end;
+  for (Poco::DirectoryIterator it(dir); it != end; ++it) {
+    if (!it->isDirectory()) {
+      continue;
+    }
+
+    const std::string name = it.name();
+
+    // case insensitive comparison against expected pattersn: data_*, flat_*,
+    // dark_*, etc.
+    if (boost::iequals(name.substr(0, g_sampleNamePrefix.length()),
+                       g_sampleNamePrefix)) {
+      m_sampleDir = it.path().toString();
+    } else if (boost::iequals(name.substr(0, g_flatNamePrefix.length()),
+                              g_flatNamePrefix)) {
+      m_flatDir = name;
+    } else if (boost::iequals(name.substr(0, g_darkNamePrefix.length()),
+                              g_darkNamePrefix)) {
+      m_darkDir = name;
+    }
+  }
+
+  if (m_sampleDir.empty()) {
+    m_statusDescStr = "The the sample images directory (" + g_sampleNamePrefix +
+                      "...) has not been found.";
+    return;
+  }
+
+  // can be valid only if we get here. There must be at least one entry that is
+  // a file
+  Poco::Path samplesPath(m_sampleDir);
+  for (Poco::DirectoryIterator it(samplesPath); it != end; ++it) {
+    if (it->isFile()) {
+      m_valid = true;
+      break;
+    }
+  }
+
+  if (m_valid) {
+    m_statusDescStr = "all checks passed";
+  } else {
+    m_statusDescStr = "No files were found in the sample images directory (" +
+                      g_sampleNamePrefix + "...).";
+  }
+}
+
+std::vector<std::string>
+StackOfImagesDirs::findImgFiles(const std::string &path) const {
+  std::vector<std::string> fnames;
+  Poco::File dir(path);
+  if (!dir.isDirectory() || !dir.exists())
+    return fnames;
+
+  // as an alternative could also use Poco::Glob to find the files
+  Poco::DirectoryIterator it(dir);
+  Poco::DirectoryIterator end;
+  while (it != end) {
+    // TODO: filter names by extension?
+    // const std::string name = it.name();
+    if (it->isFile()) {
+      fnames.push_back(it.path().toString());
+    }
+
+    ++it;
+  }
+
+  // this assumes the usual sorting of images of a stack (directory): a prefix,
+  // and a sequence number (with a fixed number of digits).
+  std::sort(fnames.begin(), fnames.end());
+  return fnames;
+}
+
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp
index 59ae96f3caed1ffa8f76c7fbb143fcdb94a95c34..ef2cad5f09bddc06fd38dd9c798e60f91e150e41 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp
@@ -310,7 +310,6 @@ void TomographyIfacePresenter::processLogMsg() {
   std::vector<std::string> msgs = m_view->logMsgs();
   for (size_t i = 0; i < msgs.size(); i++) {
     m_model->logMsg(msgs[i]);
-    break;
   }
 }
 
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp
index c280ce58fce36a8d851ee1ad68804b38bf4fdd47..48fef5a235172ab657810b05bc0b1f4314753bc7 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp
@@ -3,6 +3,7 @@
 #include "MantidQtAPI/AlgorithmInputHistory.h"
 #include "MantidQtAPI/AlgorithmRunner.h"
 #include "MantidQtAPI/HelpWindow.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h"
 #include "MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h"
@@ -65,12 +66,27 @@ void TomographyIfaceViewQtGUI::initLayout() {
   // setup container ui
   m_ui.setupUi(this);
   // add tab contents and set up their ui's
-  QWidget *tab1w = new QWidget(m_ui.tabMain);
-  m_uiTabRun.setupUi(tab1w);
-  m_ui.tabMain->addTab(tab1w, QString("Run"));
-  QWidget *tab2w = new QWidget(m_ui.tabMain);
-  m_uiTabSetup.setupUi(tab2w);
-  m_ui.tabMain->addTab(tab2w, QString("Setup"));
+  QWidget *tabRunW = new QWidget(m_ui.tabMain);
+  m_uiTabRun.setupUi(tabRunW);
+  m_ui.tabMain->addTab(tabRunW, QString("Run"));
+  QWidget *tabSetupW = new QWidget(m_ui.tabMain);
+  m_uiTabSetup.setupUi(tabSetupW);
+  m_ui.tabMain->addTab(tabSetupW, QString("Setup"));
+
+  ImageROIViewQtWidget *tabROIW = new ImageROIViewQtWidget(m_ui.tabMain);
+  m_ui.tabMain->addTab(tabROIW, QString("ROI etc."));
+
+  QWidget *tabFiltersW = new QWidget();
+  m_ui.tabMain->addTab(tabFiltersW, QString("Filters"));
+
+  QWidget *tabVizW = new QWidget();
+  m_ui.tabMain->addTab(tabVizW, QString("Visualize"));
+
+  QWidget *tabConvertW = new QWidget();
+  m_ui.tabMain->addTab(tabConvertW, QString("Convert"));
+
+  QWidget *tabEBandsW = new QWidget();
+  m_ui.tabMain->addTab(tabEBandsW, QString("Energy bands"));
 
   readSettings();
 
diff --git a/MantidQt/CustomInterfaces/src/Tomography/ToolConfig.cpp b/MantidQt/CustomInterfaces/src/Tomography/ToolConfig.cpp
index 08391894c2eca282554ed2106c4db5f3a7f05a86..feb959472f6907482fb64850c5e862ecd2cb79cb 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/ToolConfig.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/ToolConfig.cpp
@@ -2,12 +2,15 @@
 #include "MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h"
 #include "MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h"
 
-
 #include <boost/lexical_cast.hpp>
 
 namespace MantidQt {
 namespace CustomInterfaces {
 
+ToolConfigTomoPy::ToolConfigTomoPy()
+    : TomoRecToolConfig(""), m_pathOut(""), m_pathDark(""), m_pathOpen(""),
+      m_pathSample(""), m_centerRot(.0), m_angleMin(.0), m_angleMax(180.0) {}
+
 ToolConfigTomoPy::ToolConfigTomoPy(const std::string &runnable,
                                    const std::string &pathOut,
                                    const std::string &pathDark,
@@ -28,6 +31,10 @@ std::string ToolConfigTomoPy::makeCmdLineOptions() const {
          boost::lexical_cast<std::string>(m_centerRot);
 }
 
+ToolConfigAstraToolbox::ToolConfigAstraToolbox()
+    : TomoRecToolConfig(""), m_centerRot(.0), m_angleMin(.0), m_angleMax(180.0),
+      m_pathOut(""), m_pathDark(""), m_pathOpen(""), m_pathSample("") {}
+
 ToolConfigAstraToolbox::ToolConfigAstraToolbox(
     const std::string &runnable, double centerRot, double angleMin,
     double angleMax, const std::string &pathOut, const std::string &pathDark,
diff --git a/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h b/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..56cb937e2c3046ab444d0fe1540a5c5601d4600d
--- /dev/null
+++ b/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h
@@ -0,0 +1,320 @@
+#ifndef MANTID_CUSTOMINTERFACES_IMAGEROIPRESENTERTEST_H
+#define MANTID_CUSTOMINTERFACES_IMAGEROIPRESENTERTEST_H
+
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h"
+
+#include <cxxtest/TestSuite.h>
+
+#include <Poco/File.h>
+
+#include "ImageROIViewMock.h"
+
+using namespace MantidQt::CustomInterfaces;
+using testing::TypedEq;
+using testing::Return;
+
+class ImageROIPresenterTest : public CxxTest::TestSuite {
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ImageROIPresenterTest *createSuite() {
+    return new ImageROIPresenterTest();
+  }
+
+  static void destroySuite(ImageROIPresenterTest *suite) { delete suite; }
+
+  ImageROIPresenterTest() {
+    Mantid::API::FrameworkManager::Instance(); // make sure the framework is
+                                               // initialized
+  }
+
+  void setUp() {
+    m_view.reset(new testing::NiceMock<MockImageROIView>());
+    m_presenter.reset(
+        new MantidQt::CustomInterfaces::ImageROIPresenter(m_view.get()));
+  }
+
+  void tearDown() {
+    TS_ASSERT(testing::Mock::VerifyAndClearExpectations(m_view.get()));
+  }
+
+  void test_initOK() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, setParams(testing::_)).Times(1);
+
+    // No errors/warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(ImageROIPresenter::Init);
+  }
+
+  void test_initWithWrongParams() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, setParams(testing::_)).Times(1);
+
+    // One error, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(ImageROIPresenter::Init);
+  }
+
+  void xxtest_browseImg_EmptyPath() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, askImgOrStackPath()).Times(1).WillOnce(Return(""));
+
+    // No error, no warnings, just ignored
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    // should not get there:
+    EXPECT_CALL(mockView, showStack(testing::An<const std::string &>()))
+        .Times(0);
+    EXPECT_CALL(mockView,
+                showStack(testing::An<Mantid::API::WorkspaceGroup_sptr &>()))
+        .Times(0);
+    EXPECT_CALL(mockView, updateImgWithIndex(testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::BrowseImgOrStack);
+  }
+
+  void xxtest_newImg_EmptyPath() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, askImgOrStackPath()).Times(0);
+
+    // No error, one warning pop-up because a stack is not found
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1);
+
+    // should not get there because there's no stack/img - it's just ignored:
+    EXPECT_CALL(mockView, showStack(testing::An<const std::string &>()))
+        .Times(0);
+    EXPECT_CALL(mockView,
+                showStack(testing::An<Mantid::API::WorkspaceGroup_sptr &>()))
+        .Times(0);
+    EXPECT_CALL(mockView, updateImgWithIndex(testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::NewImgOrStack);
+  }
+
+  void test_browseImg_WrongPath() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, askImgOrStackPath())
+        .Times(1)
+        .WillOnce(Return("dont_look_for_me_i_dont_exist"));
+
+    // A warning
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1);
+
+    // should not get there because there's no stack/img
+    EXPECT_CALL(mockView, showStack(testing::An<const std::string &>()))
+        .Times(0);
+    EXPECT_CALL(mockView,
+                showStack(testing::An<Mantid::API::WorkspaceGroup_sptr &>()))
+        .Times(0);
+    EXPECT_CALL(mockView, updateImgWithIndex(testing::_)).Times(0);
+
+    // this exception is currently handled, and a warning given
+    //TSM_ASSERT_THROWS("There should be an exception if there is an unexpected "
+    //                  "error with the images path",
+    //                  pres.notify(IImageROIPresenter::BrowseImgOrStack),
+    //                  Poco::FileNotFoundException);
+    pres.notify(IImageROIPresenter::BrowseImgOrStack);
+  }
+
+  void test_updateImgIndex() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    int idx = 0;
+    EXPECT_CALL(mockView, currentImgIndex()).Times(1).WillOnce(Return(idx));
+
+    EXPECT_CALL(mockView, updateImgWithIndex(idx)).Times(1);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::UpdateImgIndex);
+  }
+
+  void test_selectCoR() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectCoR))
+        .Times(1);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::SelectCoR);
+  }
+
+  void test_resetCoR() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, resetCoR()).Times(1);
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectNone))
+        .Times(1);
+
+    // just a few calls that should not happen
+    EXPECT_CALL(mockView, resetROI()).Times(0);
+    EXPECT_CALL(mockView, showStack(testing::An<const std::string &>()))
+        .Times(0);
+    EXPECT_CALL(mockView,
+                showStack(testing::An<Mantid::API::WorkspaceGroup_sptr &>()))
+        .Times(0);
+    EXPECT_CALL(mockView, updateImgWithIndex(testing::_)).Times(0);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::ResetCoR);
+  }
+
+  void test_selectROI() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectROIFirst))
+        .Times(1);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::SelectROI);
+  }
+
+  void test_finishROI() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectNone))
+        .Times(1);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::FinishedROI);
+  }
+
+  void test_resetROI() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, resetROI()).Times(1);
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectNone))
+        .Times(1);
+
+    // just a few calls that should not happen
+    EXPECT_CALL(mockView, resetCoR()).Times(0);
+    EXPECT_CALL(mockView, showStack(testing::An<const std::string &>()))
+        .Times(0);
+    EXPECT_CALL(mockView,
+                showStack(testing::An<Mantid::API::WorkspaceGroup_sptr &>()))
+        .Times(0);
+    EXPECT_CALL(mockView, updateImgWithIndex(testing::_)).Times(0);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::ResetROI);
+  }
+
+  void test_selectNormalization() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, changeSelectionState(
+                              IImageROIView::SelectNormAreaFirst)).Times(1);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::SelectNormalization);
+  }
+
+  void test_finishNormalization() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectNone))
+        .Times(1);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::FinishedNormalization);
+  }
+
+  void test_resetNormalization() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, resetNormArea()).Times(1);
+    EXPECT_CALL(mockView, changeSelectionState(IImageROIView::SelectNone))
+        .Times(1);
+
+    // just a few calls that should not happen
+    EXPECT_CALL(mockView, resetCoR()).Times(0);
+    EXPECT_CALL(mockView, resetROI()).Times(0);
+    EXPECT_CALL(mockView, showStack(testing::An<const std::string &>()))
+        .Times(0);
+    EXPECT_CALL(mockView,
+                showStack(testing::An<Mantid::API::WorkspaceGroup_sptr &>()))
+        .Times(0);
+    EXPECT_CALL(mockView, updateImgWithIndex(testing::_)).Times(0);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(IImageROIPresenter::ResetNormalization);
+  }
+
+  void test_shutDown() {
+    testing::NiceMock<MockImageROIView> mockView;
+    MantidQt::CustomInterfaces::ImageROIPresenter pres(&mockView);
+
+    EXPECT_CALL(mockView, saveSettings()).Times(1);
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(ImageROIPresenter::ShutDown);
+  }
+
+private:
+  // boost::shared_ptr
+  boost::scoped_ptr<testing::NiceMock<MockImageROIView>> m_view;
+  boost::scoped_ptr<MantidQt::CustomInterfaces::ImageROIPresenter> m_presenter;
+
+  // To have one FITS, etc.
+  Mantid::API::MatrixWorkspace_sptr m_ws;
+};
+
+#endif // MANTID_CUSTOMINTERFACES_IMAGEROIPRESENTERTEST_H
diff --git a/MantidQt/CustomInterfaces/test/ImageROIViewMock.h b/MantidQt/CustomInterfaces/test/ImageROIViewMock.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ba7ebca13e036ac6569eb64b51857e61ae79e44
--- /dev/null
+++ b/MantidQt/CustomInterfaces/test/ImageROIViewMock.h
@@ -0,0 +1,66 @@
+#ifndef MANTID_CUSTOMINTERFACES_IMAGEROIVIEWMOCK_H
+#define MANTID_CUSTOMINTERFACES_IMAGEROIVIEWMOCK_H
+
+#include "MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h"
+
+#include <gmock/gmock.h>
+
+class MockImageROIView : public MantidQt::CustomInterfaces::IImageROIView {
+public:
+  // void initParams(ImageStackPreParams &params)
+  MOCK_METHOD1(setParams,
+               void(MantidQt::CustomInterfaces::ImageStackPreParams &));
+
+  // ImageStackPreParams userSelection() const;
+  MOCK_CONST_METHOD0(userSelection,
+                     MantidQt::CustomInterfaces::ImageStackPreParams());
+
+  // SelectionState selectionState() const;
+  MOCK_CONST_METHOD0(selectionState, SelectionState());
+
+  // void changeSelectionState(const SelectionState state);
+  MOCK_METHOD1(changeSelectionState, void(const IImageROIView::SelectionState&));
+
+  // void showStack(const std::string &path);
+  MOCK_METHOD1(showStack, void(const std::string &));
+
+  // void showStack(const Mantid::API::WorkspaceGroup_sptr &ws);
+  MOCK_METHOD1(showStack, void(Mantid::API::WorkspaceGroup_sptr &));
+
+  // const Mantid::API::WorkspaceGroup_sptr stack() const;
+  MOCK_CONST_METHOD0(stack, const Mantid::API::WorkspaceGroup_sptr());
+
+  // void showProjection(const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx);
+  MOCK_METHOD2(showProjection, void(const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx));
+
+  // void userWarning(const std::string &warn, const std::string &description)
+  MOCK_METHOD2(userWarning,
+               void(const std::string &warn, const std::string &description));
+
+  // void userError(const std::string &err, const std::string &description)
+  MOCK_METHOD2(userError,
+               void(const std::string &err, const std::string &description));
+
+  // size_t currentImgIndex() const;
+  MOCK_CONST_METHOD0(currentImgIndex, size_t());
+
+  // void updateImgWithIndex(size_t idx)
+  MOCK_METHOD1(updateImgWithIndex, void(size_t));
+
+  // std::string askImgOrStackPath();
+  MOCK_METHOD0(askImgOrStackPath, std::string());
+
+  // void saveSettings() const {}
+  MOCK_CONST_METHOD0(saveSettings, void());
+
+  // void resetCoR()
+  MOCK_METHOD0(resetCoR, void());
+
+  // void resetROI()
+  MOCK_METHOD0(resetROI, void());
+
+  // void resetNormArea()
+  MOCK_METHOD0(resetNormArea, void());
+};
+
+#endif // MANTID_CUSTOMINTERFACES_IMAGEROIVIEWMOCK_H
diff --git a/MantidQt/CustomInterfaces/test/StackOfImagesDirsTest.h b/MantidQt/CustomInterfaces/test/StackOfImagesDirsTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..641dd70eb5d6e709690c04aa1560be5b0d8a9eb6
--- /dev/null
+++ b/MantidQt/CustomInterfaces/test/StackOfImagesDirsTest.h
@@ -0,0 +1,111 @@
+#ifndef MANTID_CUSTOMINTERFACES_STACKOFIMAGESDIRSTEST_H
+#define MANTID_CUSTOMINTERFACES_STACKOFIMAGESDIRSTEST_H
+
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidQtCustomInterfaces/Tomography/StackOfImagesDirs.h"
+
+#include <boost/scoped_ptr.hpp>
+
+#include <cxxtest/TestSuite.h>
+
+using namespace MantidQt::CustomInterfaces;
+
+class StackOfImagesDirsTest : public CxxTest::TestSuite {
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static StackOfImagesDirsTest *createSuite() {
+    return new StackOfImagesDirsTest();
+  }
+
+  static void destroySuite(StackOfImagesDirsTest *suite) { delete suite; }
+
+  StackOfImagesDirsTest() {
+    Mantid::API::FrameworkManager::Instance(); // make sure the framework is
+                                               // initialized
+  }
+
+  void setUp() {
+    // just to test more dynamic allocation
+    m_soid.reset(new StackOfImagesDirs(""));
+  }
+
+  void tearDown() {}
+
+  void test_construct() {
+    StackOfImagesDirs obj("");
+
+    TSM_ASSERT("A stack just constructed with an empty path string should not "
+               "be valid",
+               !obj.isValid());
+  }
+
+  void test_description() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("A description string should be produced",
+               "" != obj.description());
+  }
+
+  void test_status() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("A status string should be produced", "" != obj.status());
+  }
+
+  void test_sampleImagesDir() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("The sample images directory of an empty stack should be empty",
+               "" == obj.sampleImagesDir());
+  }
+
+  void test_flatImagesDir() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("The flat images directory of an empty stack should be empty",
+               "" == obj.flatImagesDir());
+  }
+
+  void test_darkImagesDir() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("The dark images directory of an empty stack should be empty",
+               "" == obj.flatImagesDir());
+  }
+
+  void test_sampleFiles() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("There should not be any sample files in an empty stack",
+               0 == obj.sampleImagesDir().size());
+  }
+
+  void test_flatFiles() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("There should not be any flat image files in an empty stack",
+               0 == obj.flatImagesDir().size());
+  }
+
+  void test_darkFiles() {
+    StackOfImagesDirs obj("");
+
+    TS_ASSERT_THROWS_NOTHING(obj.description());
+    TSM_ASSERT("There should not be any dark image files in an empty stack",
+               0 == obj.darkImagesDir().size());
+  }
+
+private:
+  boost::scoped_ptr<StackOfImagesDirs> m_soid;
+};
+
+#endif /*  MANTID_CUSTOMINTERFACES_STACKOFIMAGESDIRSTEST_H */
diff --git a/docs/source/interfaces/Tomographic_Reconstruction.rst b/docs/source/interfaces/Tomographic_Reconstruction.rst
index d31f16f6ad90f25f598f33de0f037bcb527bc861..10218297b0180cf65a005cfe5af11202a362303f 100644
--- a/docs/source/interfaces/Tomographic_Reconstruction.rst
+++ b/docs/source/interfaces/Tomographic_Reconstruction.rst
@@ -140,6 +140,43 @@ To be able to run jobs on a remote compute resource (cluster, supercomputer, etc
 You can monitor the status of the jobs currently running (and recently
 run) on remote compute resources in the same tab.
 
+Setting common parameters for the reconstruction jobs
+-----------------------------------------------------
+
+Several parameters can be set in the "ROI etc." section or tab. These
+parameters will be used for all the reconstruction jobs, regardless of
+the tool and/or reconstruction method used.
+
+* Region of interest (ROI) for the analysis
+* Area for normalization (open beam, not blocked by sample)
+* Center of rotation, for tomographic reconstruction
+
+At any stage during the process of selecting the regions it is also
+possible to see how the selections fit different images by sliding
+through the images of the stack (using the slider or scroll bar).
+
+The center of rotation can be selected interactively by clicking on
+the select button and then clicking on an image pixel. To select the
+regions of interest or the area of normalization, just click on the
+respective "select" button and then click and drag with the mouse to
+select a rectangle. The precise coordinates of the center and regions
+can be set via the boxes of the right panel as well.
+
+Once you have selected or set one of the regions, or the center, they
+can be selected again by pushing the respective "Select" buttons
+and/or editing their coordinates manually.
+
+The default values, set in principle when a new stack of images is
+loaded, is as follows. The region of intererest is set to cover all
+the images. The regions of normalization is not set (empty), and the
+center of rotation is set to the center of the image. The option to
+find the center of rotation automatically is disabled at present.
+
+If when selection a region the mouse is moved outside of the images,
+it is possible to continue the selection of the region (second corner)
+by clicking again inside the image. Alternatively, any selection can
+be reset at any point by using the "reset" buttons.
+
 Running jobs locally
 --------------------