Commit d46cbc8e authored by Emmanuel Promayon's avatar Emmanuel Promayon
Browse files

Merge branch 'feature/call-actions-in-action' into 'develop'

Feature/call actions in action

See merge request !117
parents 7a06f9cb 64a6f44b
......@@ -31,7 +31,8 @@ camitk_disable_tests(TESTS action-itkfilters-level1-6
For input file: biorad.pic, cthead1.lsm, mini-complex-slow1.nrrd
When applying action Gradient Magnitude With Smoothing, the following exception is raised:
\"camitk-testcomponents aborted by std exception: /usr/include/ITK-4.10/itkRecursiveSeparableImageFilter.hxx:245:
itk::ERROR: RecursiveGaussianImageFilter(0x55b3b21bc700): The number of pixels along direction 2 is less than 4. This filter requires a minimum of four pixels along the dimension to be processed...\""
itk::ERROR: RecursiveGaussianImageFilter(0x55b3b21bc700): The number of pixels along direction 2 is less than 4.
This filter requires a minimum of four pixels along the dimension to be processed...\""
)
camitk_tests_requirement(TESTS action-itkfilters-integration-test
......
......@@ -2,7 +2,7 @@
<state id="Initialize">
<onentry>
<camitk:onState>
<camitk:description><![CDATA[This pipeline will process several actions on the input component(s): <br /> <ul><li>Open</li><li>Otsu Threshold Filter</li><li>Morphological Operators</li><li>Save As</li><li>Save As</li><li>Connected Components Classification</li><li>Save As</li><li>Manual Threshold Filter</li><li>Save As</li><li>Morphological Operators</li><li>Save As</li><li>Morphological Operators</li><li>Save As</li><li>Close</li><li>Close</li><li>Close</li><li>Close</li><li>Close</li><li>Close</li><li>Reconstruction</li><li>Save As</li><li>Save As</li><li>Close</li><li>Reconstruction</li><li>Save As</li><li>Close</li><li>Reconstruction</li><li>Save As</li><li>Save As</li><li>Clean Mesh</li><li>Save As</li>]]></camitk:description>
<camitk:description><![CDATA[This pipeline will process several actions on the input component(s): <br /> <ul><li>Open</li><li>Otsu Threshold Filter</li><li>Morphological Operators</li><li>Save As</li><li>Save As</li><li>Connected Components Classification</li><li>Save As</li><li>Manual Threshold Filter</li><li>Save As</li><li>Morphological Operators</li><li>Save As</li><li>Morphological Operators</li><li>Save As</li><li>Close</li><li>Close</li><li>Close</li><li>Close</li><li>Close</li><li>Close</li><li>Reconstruction</li><li>Save As</li><li>Save As</li><li>Close</li><li>Reconstruction</li><li>Save As</li><li>Close</li><li>Reconstruction</li><li>Save As</li><li>Save As</li><li>Clean Mesh</li><li>Save As</li></ul>]]></camitk:description>
</camitk:onState>
</onentry>
<transition target="Open Input Image" event="Next"/>
......
......@@ -22,7 +22,8 @@ camitk_disable_tests(TESTS component-itkimage-level3-3
For input file: biorad.pic, cthead1.lsm, BigEndian.spr, LittleEndianZ.hdr and LittleEndianZ.img.gz
When applying action Gradient Magnitude With Smoothing, the following exception is raised:
\"camitk-testcomponents aborted by std exception: /usr/include/ITK-4.10/itkRecursiveSeparableImageFilter.hxx:245:
itk::ERROR: RecursiveGaussianImageFilter(0x55b3b21bc700): The number of pixels along direction 2 is less than 4. This filter requires a minimum of four pixels along the dimension to be processed...\""
itk::ERROR: RecursiveGaussianImageFilter(0x55b3b21bc700): The number of pixels along direction 2 is less than 4.
This filter requires a minimum of four pixels along the dimension to be processed...\""
)
# TODO confirm diagnostic: check why BigEndianCompressed.img.gz, LittleEndianCompressed.img.gz and minimal.nii.gz does not work on Windows (maybe because of double suffix .im.gz?)
......
......@@ -27,6 +27,8 @@
#include <Application.h>
#include <Property.h>
#include <Log.h>
// Vtk includes
#include <vtkCallbackCommand.h>
#include "vtkImageShiftScale.h"
......@@ -51,22 +53,25 @@ ResampleAction::ResampleAction(ActionExtension* extension) : Action(extension) {
// You can add tags here with the method addTag("tagName");
// Setting the actions parameters
Property* newImageDimensionPropertyX = new Property(tr("New image X dimension"), 256, tr("The new image width (in voxels)."), "");
Property* newImageDimensionPropertyX = new Property(tr("New Image X Dimension"), 256, tr("The new image width (in voxels)."), "");
newImageDimensionPropertyX->setAttribute("minimum", 1);
newImageDimensionPropertyX->setAttribute("maximum", std::numeric_limits<int>::max());
newImageDimensionPropertyX->setAttribute("singleStep", 1);
addParameter(newImageDimensionPropertyX);
Property* newImageDimensionPropertyY = new Property(tr("New image Y dimension"), 256, tr("The new image height (in voxels)."), "");
Property* newImageDimensionPropertyY = new Property(tr("New Image Y Dimension"), 256, tr("The new image height (in voxels)."), "");
newImageDimensionPropertyY->setAttribute("minimum", 1);
newImageDimensionPropertyY->setAttribute("maximum", std::numeric_limits<int>::max());
newImageDimensionPropertyY->setAttribute("singleStep", 1);
addParameter(newImageDimensionPropertyY);
Property* newImageDimensionPropertyZ = new Property(tr("New image Z dimension"), 256, tr("The new image depth (in voxels)."), "");
Property* newImageDimensionPropertyZ = new Property(tr("New Image Z Dimension"), 256, tr("The new image depth (in voxels)."), "");
newImageDimensionPropertyZ->setAttribute("minimum", 1);
newImageDimensionPropertyZ->setAttribute("maximum", std::numeric_limits<int>::max());
newImageDimensionPropertyZ->setAttribute("singleStep", 1);
addParameter(newImageDimensionPropertyZ);
Property* scalarTypeProperty = new Property(tr("New image scalar type"), SAME_AS_INPUT, tr("The new image voxels scalar type"), "");
Property* scalarTypeProperty = new Property(tr("New Image Scalar Type"), SAME_AS_INPUT, tr("The new image voxels scalar type"), "");
scalarTypeProperty->setEnumTypeName("ScalarType", this);
addParameter(scalarTypeProperty);
}
......@@ -76,6 +81,32 @@ ResampleAction::~ResampleAction() {
}
// --------------- getWidget -------------------
QWidget* ResampleAction::getWidget() {
// set min/max for the dimensions using the last selected target dimensions
int * dims = getTargets().last()->getImageData()->GetDimensions();
camitk::Property *dimProperty = getProperty("New Image X Dimension");
dimProperty->setAttribute("minimum", 1);
dimProperty->setAttribute("maximum", dims[0]);
setProperty("New Image X Dimension", dims[0]);
dimProperty = getProperty("New Image Y Dimension");
dimProperty->setAttribute("minimum", 1);
dimProperty->setAttribute("maximum", dims[1]);
setProperty("New Image Y Dimension", dims[1]);
dimProperty = getProperty("New Image Z Dimension");
dimProperty->setAttribute("minimum", 1);
dimProperty->setAttribute("maximum", dims[2]);
setProperty("New Image Z Dimension", dims[2]);
dimProperty->setReadOnly(dims[2] == 1);
// return the default widget
return Action::getWidget();
}
// --------------- apply -------------------
Action::ApplyStatus ResampleAction::apply() {
......@@ -87,6 +118,7 @@ Action::ApplyStatus ResampleAction::apply() {
return SUCCESS;
}
// --------------- process -------------------
void ResampleAction::process(ImageComponent* comp) {
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Application::showStatusBarMessage(tr("Compute resample..."));
......@@ -95,9 +127,9 @@ void ResampleAction::process(ImageComponent* comp) {
progressCallback->SetCallback(&Application::vtkProgressFunction);
// Get the parameters
double xSize = property("New image X dimension").toDouble();
double ySize = property("New image Y dimension").toDouble();
double zSize = property("New image Z dimension").toDouble();
double xSize = property("New Image X Dimension").toDouble();
double ySize = property("New Image Y Dimension").toDouble();
double zSize = property("New Image Z Dimension").toDouble();
// Getting the input image
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
......@@ -210,7 +242,7 @@ void ResampleAction::process(ImageComponent* comp) {
resampleFilter->Update();
// Create the output component
ImageComponent* outputComp = new ImageComponent(resampleFilter->GetOutput(), comp->getName() + nameScalarType + "_" + property("Size X (nb of Voxels)").toInt() + "*" + property("Size Y (nb of Voxels)").toInt() + "*" + property("Size Z (nb of Voxels)").toInt());
ImageComponent* outputComp = new ImageComponent(resampleFilter->GetOutput(), comp->getName() + nameScalarType + "_" + property("New Image X Dimension").toString() + "x" + property("New Image Y Dimension").toString() + "x" + property("New Image Z Dimension").toString());
// consider frame policy on new image created
Action::applyTargetPosition(comp, outputComp);
......@@ -223,7 +255,8 @@ void ResampleAction::process(ImageComponent* comp) {
}
// --------------- getScalarType -------------------
ResampleAction::ScalarType ResampleAction::getScalarType() {
return (ScalarType) property("New image scalar type").toInt();
return (ScalarType) property("New Image Scalar Type").toInt();
}
......@@ -63,20 +63,24 @@ public:
/// Default Destructor
virtual ~ResampleAction();
/// Retrieve the scalar type
ScalarType getScalarType();
/// Required to update the resize values to half of the currently selected image size
virtual QWidget* getWidget();
public slots:
/// method called when the action is applied
virtual ApplyStatus apply();
private:
///Scalar type of the output
ScalarType Scalar_Type;
/// Scalar type of the output
ScalarType scalarType;
/// helper method to simplify the target component processing
virtual void process(camitk::ImageComponent*);
/// Retrieve the scalar type
ScalarType getScalarType();
};
Q_DECLARE_METATYPE(ResampleAction::ScalarType)
......
......@@ -22,11 +22,11 @@ set -e
# values to check
initTestData() {
# fill test data
extensionCount=( [4.2]=41 [4.1]=41 [4.0]=31 )
extensionCount=( [4.2]=42 [4.1]=41 [4.0]=31 )
componentExtensionCount=( [4.2]=14 [4.1]=14 [4.0]=14 )
actionExtensionCount=( [4.2]=27 [4.1]=27 [4.0]=27 )
actionExtensionCount=( [4.2]=28 [4.1]=27 [4.0]=27 )
fileExtensionCount=( [4.2]=37 [4.1]=37 [4.0]=37 )
actionCount=( [4.2]=105 [4.1]=105 [4.0]=105 )
actionCount=( [4.2]=106 [4.1]=105 [4.0]=105 )
# fill release date
releaseDate=( [4.2]="not yet released, current development version" \
......
......@@ -59,7 +59,8 @@ if(XSD_FOUND)
endif()
if(NOT XSD_FIND_QUIETLY)
message(STATUS "Found XSD executable: ${XSD_EXECUTABLE} version ${XSD_VERSION}")
string(REGEX REPLACE "\n$" "" XSD_VERSION_WITHOUT_TRAILING_NEWLINE "${XSD_VERSION}")
message(STATUS "Found XSD executable: ${XSD_EXECUTABLE} version ${XSD_VERSION_WITHOUT_TRAILING_NEWLINE}")
endif()
else()
if(XSD_FIND_REQUIRED)
......
#!
#! @ingroup group_sdk_cmake_camitk_test
#!
#! camitk_disable_tests is a macro to disable one or more tests unconditionally.
#! camitk_disable_tests is a macro to unconditionally disable one or more tests.
#!
#! It encapsulates CMake set_tests_properties in order to manage version older that CMake 3.9
#! and to force the developper to give a (good) reason for bypassing tests.
......@@ -47,18 +47,22 @@ macro(camitk_disable_tests)
set(multiValueArgs TESTS)
cmake_parse_arguments(CAMITK_DISABLE_TESTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(DISABLE_MESSAGE "")
# CMake < 3.9 did not have the DISABLED test property. Use WILL_FAIL instead
foreach(TEST_NAME ${CAMITK_DISABLE_TESTS_TESTS})
# CMake < 3.9 did not have the DISABLED test property. Use WILL_FAIL instead
if(${CMAKE_VERSION} VERSION_LESS "3.9")
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Unconditionally disabling test ${TEST_NAME} (using WILL_FAIL property)\n")
set_tests_properties(${TEST_NAME} PROPERTIES WILL_FAIL true)
else()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Unconditionally disabling test ${TEST_NAME}\n")
set_tests_properties(${TEST_NAME} PROPERTIES DISABLED true)
endif()
endforeach()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Reason: ${CAMITK_DISABLE_TESTS_REASON}\n")
message(AUTHOR_WARNING ${DISABLE_MESSAGE})
# message to the developper
string(REPLACE ";" " " CAMITK_DISABLE_TESTS_TESTS_STRING "${CAMITK_DISABLE_TESTS_TESTS}")
set(DISABLE_MESSAGE "Unconditionally disabling tests:\n Disabled tests: ${CAMITK_DISABLE_TESTS_TESTS_STRING}\n")
if(${CMAKE_VERSION} VERSION_LESS "3.9")
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " (using WILL_FAIL property because CMake < 3.9)\n")
endif()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Reason: ${CAMITK_DISABLE_TESTS_REASON}")
message(STATUS ${DISABLE_MESSAGE})
endmacro()
......@@ -168,24 +168,24 @@ macro(camitk_tests_requirement)
endif()
# -- disable tests if the requirement is not met
set(DISABLE_MESSAGE "")
string(REPLACE ";" " " CAMITK_TESTS_REQUIREMENT_TESTS_STRING "${CAMITK_TESTS_REQUIREMENT_TESTS}")
if(NOT ${REQUIRES_EVAL})
foreach(TEST_NAME ${CAMITK_TESTS_REQUIREMENT_TESTS})
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Disabling test ${TEST_NAME}")
# CMake < 3.9 did not have the DISABLED test property. Use WILL_FAIL instead
if(${CMAKE_VERSION} VERSION_LESS "3.9")
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " (using WILL_FAIL property)")
set_tests_properties(${TEST_NAME} PROPERTIES WILL_FAIL true)
else()
set_tests_properties(${TEST_NAME} PROPERTIES DISABLED true)
endif()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} "\n")
endforeach()
set(DISABLE_MESSAGE "Test requirement \"${CAMITK_TESTS_REQUIREMENT_REQUIRES}\": Failed\n Disabled tests: ${CAMITK_TESTS_REQUIREMENT_TESTS_STRING}\n")
if(${CMAKE_VERSION} VERSION_LESS "3.9")
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " (using WILL_FAIL property because CMake < 3.9)\n")
endif()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Reason: ${CAMITK_TESTS_REQUIREMENT_REASON}\n")
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Requirement statement unmet: ${CAMITK_TESTS_REQUIREMENT_REQUIRES}.\n")
message(AUTHOR_WARNING ${DISABLE_MESSAGE})
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Requirement statement unmet: ${CAMITK_TESTS_REQUIREMENT_REQUIRES}")
message(STATUS ${DISABLE_MESSAGE})
else()
string(REPLACE ";" " " CAMITK_TESTS_REQUIREMENT_TESTS_STRING "${CAMITK_TESTS_REQUIREMENT_TESTS}")
message(STATUS "Test requirement \"${CAMITK_TESTS_REQUIREMENT_REQUIRES}\": Passed\n Enabled tests: ${CAMITK_TESTS_REQUIREMENT_TESTS_STRING}")
endif()
endmacro()
......@@ -46,7 +46,7 @@ public:
/// Method returning the action extension descrption
virtual QString getDescription() {
return "Extensions for Biopolis developers";
return "Compute the average voxels value in the neiborhoods of the selected voxel";
};
/// initialize all the actions
......
# Call CamiTK CMake Macro to define the action
camitk_extension(ACTION_EXTENSION
# Auto test will not work as this action needs two other action
# and auto test are isolating the action it takes.
# But integration test will perform all the required tests.
ENABLE_INTEGRATION_TEST
)
camitk_tests_requirement(TESTS action-hardcodedpipeline-integration-test
REQUIRES "NOT WIN32"
REASON "WIN32 OpenGL failure on a VM
This test will always fail when run inside a VM due to OpenGL crash.
This test will pass when run directly from a physical windows machine."
)
/*****************************************************************************
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
* (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
*
* Visit http://camitk.imag.fr for more information
*
* This file is part of CamiTK.
*
* CamiTK is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* CamiTK 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 Lesser General Public License version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with CamiTK. If not, see <http://www.gnu.org/licenses/>.
*
* $CAMITK_LICENCE_END$
****************************************************************************/
#include "HardCodedPipelineAction.h"
// CamiTK
#include <Application.h>
#include <Property.h>
#include <Log.h>
// Qt
#include <QVector3D>
using namespace camitk;
// --------------- Constructor -------------------
HardCodedPipelineAction::HardCodedPipelineAction(ActionExtension* extension) : Action(extension) {
// Setting name, description and input component
setName(tr("Hard-Coded Action Pipeline"));
setDescription("Demonstrate how to call one or more actions from another action (that is, implement a hard-coded action pipeline without modifying anything of the called actions).");
setComponent("ImageComponent");
// Setting classification family and tags
setFamily(tr("Tutorial"));
addTag(tr("Pipeline"));
// Setting the action's parameters
addParameter(new Property(tr("Resample Factor"), QVariant(0.5), tr("The resample factor to use when applying the Resample action"), tr("factor")));
}
// --------------- destructor -------------------
HardCodedPipelineAction::~HardCodedPipelineAction() {
// Do not do anything yet.
// Delete stuff if you create stuff
// (except if you use smart pointers of course !!)
}
// --------------- apply -------------------
Action::ApplyStatus HardCodedPipelineAction::apply() {
PipelineActionStatus pipelineStatus = PipelineActionStatus::OK;
//
// Hard-coded Pipeline starts here
// 1. apply Resample action, and check that everything is ok
// 2. apply Otsu threshold
// if everything is alright, remove the intermediate results and force the application refresh
// 1. apply the resample action (first action in the pipeline) on the last selected component
pipelineStatus = applyResample(getTargets().last());
// If the image has been saved, then it is not modified any more...
if (pipelineStatus == OK) {
// You can most of the time safely ignore the safeguard bits below and simply use:
// Component* resampled = resampleAction->getOutputComponent()
// But in some rare case, the second action of this pipeline is not going to use the correct
// input. For these cases, you need to use:
Component* resampled = getLastTopLevelOutputComponents("Resample");
// 2. apply the Otsu action (second action in the pipeline)
pipelineStatus = applyOtsu(resampled);
if (pipelineStatus == OK) {
// if all goes well, don't show the intermediate result
delete resampled;
}
}
switch (pipelineStatus) {
case OTSU_APPLY_ERROR:
CAMITK_ERROR("\"Otsu Threshold Filter\" apply error");
break;
case OTSU_NOT_FOUND:
CAMITK_ERROR("\"Otsu Threshold Filter\" action not found");
break;
case RESAMPLE_APPLY_ERROR:
CAMITK_ERROR("\"Resample Factor\" apply error.");
break;
case RESAMPLE_NOT_FOUND:
CAMITK_ERROR("\"Resample Factor\" action not found");
break;
case OK:
CAMITK_TRACE("Pipeline successful");
break;
}
Application::refresh();
return ((pipelineStatus == OK) ? SUCCESS : ERROR);
}
// --------------- getLastTopLevelOutputComponents -------------------
Component* HardCodedPipelineAction::getLastTopLevelOutputComponents(const QString& actionName) {
Component* lastOutputComponent = nullptr;
Action* currentAction = Application::getAction(actionName);
if (currentAction != nullptr) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
// it Qt >= 5.6 crbegin() exist and we can use a lambda expression to find the first
// top level component, looking from the end to the beginning of the component list.
auto it = find_if(currentAction->getOutputComponents().crbegin(),
currentAction->getOutputComponents().crend(),
[](const Component * c) {
return c->isTopLevel();
});
// This is the equivalent of:
// ComponentList::reverse_iterator it = currentAction->getOutputComponents().rbegin();
// while (it != currentAction->getOutputComponents().rend() && !(*it)->isTopLevel()) {
// it++;
// }
lastOutputComponent = (*it);
#else
// In Qt < 5.6, too bad: crbegin(), crend(), rbegin() and rend() do not exist
unsigned int i = currentAction->getOutputComponents().size() - 1;
while (i > 0 && !currentAction->getOutputComponents().at(i)->isTopLevel()) {
i--;
}
if (i >= 0) {
lastOutputComponent = currentAction->getOutputComponents().at(i);
}
#endif
}
return lastOutputComponent;
}
// --------------- applyResample -------------------
HardCodedPipelineAction::PipelineActionStatus HardCodedPipelineAction::applyResample(Component* input) {
Action* resampleAction = Application::getAction("Resample");
if (resampleAction == nullptr) {
return RESAMPLE_NOT_FOUND;
}
else {
// set the input
resampleAction->setInputComponent(input);
// set the parameter
ImageComponent* inputImage = dynamic_cast<ImageComponent*>(input);
// Note: as ActionsInActionAction takes ImageComponent as inputs, the dynamic_cast is
// guaranty to work perfectly well.
int* dims = inputImage->getImageData()->GetDimensions();
double factor = property("Resample Factor").toDouble();
resampleAction->setProperty("New Image X Dimension", int(dims[0]*factor));
resampleAction->setProperty("New Image Y Dimension", int(dims[1]*factor));
resampleAction->setProperty("New Image Z Dimension", std::max(1, int(dims[2]*factor)));
// apply the action
Action::ApplyStatus status = resampleAction->applyInPipeline();
// reset the flag (just in case)
input->setModified(false);
return (status == Action::SUCCESS) ? OK : RESAMPLE_APPLY_ERROR;
}
}
// --------------- applyOtsu -------------------
HardCodedPipelineAction::PipelineActionStatus HardCodedPipelineAction::applyOtsu(Component* input) {
Action* otsuThreshold = Application::getAction("Otsu Threshold Filter");
if (otsuThreshold == nullptr) {
return OTSU_NOT_FOUND;
}
else {
// set the input
otsuThreshold->setInputComponent(input);
// nothing special to do on the action parameters
// apply the action
Action::ApplyStatus status = otsuThreshold->applyInPipeline();
return (status == Action::SUCCESS) ? OK : OTSU_APPLY_ERROR;
}
}
/*****************************************************************************
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
* (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
*
* Visit http://camitk.imag.fr for more information
*
* This file is part of CamiTK.
*
* CamiTK is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* CamiTK 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 Lesser General Public License version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with CamiTK. If not, see <http://www.gnu.org/licenses/>.
*
* $CAMITK_LICENCE_END$
****************************************************************************/
#ifndef ACTIONSINACTIONACTION_H
#define ACTIONSINACTIONACTION_H
#include <Action.h>
#include <ImageComponent.h>
class HardCodedPipelineAction : public camitk::Action {
Q_OBJECT
public:
/// Default Constructor
HardCodedPipelineAction(camitk::ActionExtension*);
/// Default Destructor
virtual ~HardCodedPipelineAction();
public slots:
/** this method is automatically called when the action is triggered.
* Call getTargets() method to get the list of components to use.
* \note getTargets() is automatically filtered so that it only contains compatible components,
* i.e., instances of ComputeNeighborValueAction (or a subclass).
*/
virtual ApplyStatus apply();
private:
/// many things can happen during the execution of this action
enum PipelineActionStatus {
RESAMPLE_NOT_FOUND,
OTSU_NOT_FOUND,
RESAMPLE_APPLY_ERROR,
OTSU_APPLY_ERROR,
OK,
};
/// Get the last toplevel output component of a given action
/// This is required in some rare specific pipeline execution environment
///
/// Knowing that:
/// - Action::getOutputComponents() method returns all instanciated components during the apply() method
/// **as well** as all the unmodified components (unaware of if this modified components were modified
/// prior to the apply() method).
/// Note that the last instanciated component is at the end of the list.
/// - Action::getOutputComponent() method returns the first instanciated or modified component during the
/// apply().
///
/// There is a specific issue that arise when there are existing components marked as modified
/// **before** the start of the pipeline (e.g., when the action pipeline was run previously