Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

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 ...@@ -31,7 +31,8 @@ camitk_disable_tests(TESTS action-itkfilters-level1-6
For input file: biorad.pic, cthead1.lsm, mini-complex-slow1.nrrd For input file: biorad.pic, cthead1.lsm, mini-complex-slow1.nrrd
When applying action Gradient Magnitude With Smoothing, the following exception is raised: 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: \"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 camitk_tests_requirement(TESTS action-itkfilters-integration-test
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<state id="Initialize"> <state id="Initialize">
<onentry> <onentry>
<camitk:onState> <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> </camitk:onState>
</onentry> </onentry>
<transition target="Open Input Image" event="Next"/> <transition target="Open Input Image" event="Next"/>
......
...@@ -22,7 +22,8 @@ camitk_disable_tests(TESTS component-itkimage-level3-3 ...@@ -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 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: 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: \"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?) # 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 @@ ...@@ -27,6 +27,8 @@
#include <Application.h> #include <Application.h>
#include <Property.h> #include <Property.h>
#include <Log.h>
// Vtk includes // Vtk includes
#include <vtkCallbackCommand.h> #include <vtkCallbackCommand.h>
#include "vtkImageShiftScale.h" #include "vtkImageShiftScale.h"
...@@ -51,22 +53,25 @@ ResampleAction::ResampleAction(ActionExtension* extension) : Action(extension) { ...@@ -51,22 +53,25 @@ ResampleAction::ResampleAction(ActionExtension* extension) : Action(extension) {
// You can add tags here with the method addTag("tagName"); // You can add tags here with the method addTag("tagName");
// Setting the actions parameters // 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("minimum", 1);
newImageDimensionPropertyX->setAttribute("maximum", std::numeric_limits<int>::max());
newImageDimensionPropertyX->setAttribute("singleStep", 1); newImageDimensionPropertyX->setAttribute("singleStep", 1);
addParameter(newImageDimensionPropertyX); 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("minimum", 1);
newImageDimensionPropertyY->setAttribute("maximum", std::numeric_limits<int>::max());
newImageDimensionPropertyY->setAttribute("singleStep", 1); newImageDimensionPropertyY->setAttribute("singleStep", 1);
addParameter(newImageDimensionPropertyY); 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("minimum", 1);
newImageDimensionPropertyZ->setAttribute("maximum", std::numeric_limits<int>::max());
newImageDimensionPropertyZ->setAttribute("singleStep", 1); newImageDimensionPropertyZ->setAttribute("singleStep", 1);
addParameter(newImageDimensionPropertyZ); 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); scalarTypeProperty->setEnumTypeName("ScalarType", this);
addParameter(scalarTypeProperty); addParameter(scalarTypeProperty);
} }
...@@ -76,6 +81,32 @@ ResampleAction::~ResampleAction() { ...@@ -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 ------------------- // --------------- apply -------------------
Action::ApplyStatus ResampleAction::apply() { Action::ApplyStatus ResampleAction::apply() {
...@@ -87,6 +118,7 @@ Action::ApplyStatus ResampleAction::apply() { ...@@ -87,6 +118,7 @@ Action::ApplyStatus ResampleAction::apply() {
return SUCCESS; return SUCCESS;
} }
// --------------- process -------------------
void ResampleAction::process(ImageComponent* comp) { void ResampleAction::process(ImageComponent* comp) {
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Application::showStatusBarMessage(tr("Compute resample...")); Application::showStatusBarMessage(tr("Compute resample..."));
...@@ -95,9 +127,9 @@ void ResampleAction::process(ImageComponent* comp) { ...@@ -95,9 +127,9 @@ void ResampleAction::process(ImageComponent* comp) {
progressCallback->SetCallback(&Application::vtkProgressFunction); progressCallback->SetCallback(&Application::vtkProgressFunction);
// Get the parameters // Get the parameters
double xSize = property("New image X dimension").toDouble(); double xSize = property("New Image X Dimension").toDouble();
double ySize = property("New image Y dimension").toDouble(); double ySize = property("New Image Y Dimension").toDouble();
double zSize = property("New image Z dimension").toDouble(); double zSize = property("New Image Z Dimension").toDouble();
// Getting the input image // Getting the input image
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData(); vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
...@@ -210,7 +242,7 @@ void ResampleAction::process(ImageComponent* comp) { ...@@ -210,7 +242,7 @@ void ResampleAction::process(ImageComponent* comp) {
resampleFilter->Update(); resampleFilter->Update();
// Create the output component // 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 // consider frame policy on new image created
Action::applyTargetPosition(comp, outputComp); Action::applyTargetPosition(comp, outputComp);
...@@ -223,7 +255,8 @@ void ResampleAction::process(ImageComponent* comp) { ...@@ -223,7 +255,8 @@ void ResampleAction::process(ImageComponent* comp) {
} }
// --------------- getScalarType -------------------
ResampleAction::ScalarType ResampleAction::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: ...@@ -63,20 +63,24 @@ public:
/// Default Destructor /// Default Destructor
virtual ~ResampleAction(); virtual ~ResampleAction();
/// Retrieve the scalar type /// Required to update the resize values to half of the currently selected image size
ScalarType getScalarType(); virtual QWidget* getWidget();
public slots: public slots:
/// method called when the action is applied /// method called when the action is applied
virtual ApplyStatus apply(); virtual ApplyStatus apply();
private: private:
///Scalar type of the output /// Scalar type of the output
ScalarType Scalar_Type; ScalarType scalarType;
/// helper method to simplify the target component processing /// helper method to simplify the target component processing
virtual void process(camitk::ImageComponent*); virtual void process(camitk::ImageComponent*);
/// Retrieve the scalar type
ScalarType getScalarType();
}; };
Q_DECLARE_METATYPE(ResampleAction::ScalarType) Q_DECLARE_METATYPE(ResampleAction::ScalarType)
......
...@@ -22,11 +22,11 @@ set -e ...@@ -22,11 +22,11 @@ set -e
# values to check # values to check
initTestData() { initTestData() {
# fill test data # 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 ) 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 ) 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 # fill release date
releaseDate=( [4.2]="not yet released, current development version" \ releaseDate=( [4.2]="not yet released, current development version" \
......
...@@ -59,7 +59,8 @@ if(XSD_FOUND) ...@@ -59,7 +59,8 @@ if(XSD_FOUND)
endif() endif()
if(NOT XSD_FIND_QUIETLY) 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() endif()
else() else()
if(XSD_FIND_REQUIRED) if(XSD_FIND_REQUIRED)
......
#! #!
#! @ingroup group_sdk_cmake_camitk_test #! @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 #! 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. #! and to force the developper to give a (good) reason for bypassing tests.
...@@ -47,18 +47,22 @@ macro(camitk_disable_tests) ...@@ -47,18 +47,22 @@ macro(camitk_disable_tests)
set(multiValueArgs TESTS) set(multiValueArgs TESTS)
cmake_parse_arguments(CAMITK_DISABLE_TESTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 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}) 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") 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) set_tests_properties(${TEST_NAME} PROPERTIES WILL_FAIL true)
else() else()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Unconditionally disabling test ${TEST_NAME}\n")
set_tests_properties(${TEST_NAME} PROPERTIES DISABLED true) set_tests_properties(${TEST_NAME} PROPERTIES DISABLED true)
endif() endif()
endforeach() 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() endmacro()
...@@ -168,24 +168,24 @@ macro(camitk_tests_requirement) ...@@ -168,24 +168,24 @@ macro(camitk_tests_requirement)
endif() endif()
# -- disable tests if the requirement is not met # -- 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}) if(NOT ${REQUIRES_EVAL})
foreach(TEST_NAME ${CAMITK_TESTS_REQUIREMENT_TESTS}) 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 # CMake < 3.9 did not have the DISABLED test property. Use WILL_FAIL instead
if(${CMAKE_VERSION} VERSION_LESS "3.9") 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) set_tests_properties(${TEST_NAME} PROPERTIES WILL_FAIL true)
else() else()
set_tests_properties(${TEST_NAME} PROPERTIES DISABLED true) set_tests_properties(${TEST_NAME} PROPERTIES DISABLED true)
endif() endif()
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} "\n")
endforeach() 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} " Reason: ${CAMITK_TESTS_REQUIREMENT_REASON}\n")
set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Requirement statement unmet: ${CAMITK_TESTS_REQUIREMENT_REQUIRES}.\n") set(DISABLE_MESSAGE ${DISABLE_MESSAGE} " Requirement statement unmet: ${CAMITK_TESTS_REQUIREMENT_REQUIRES}")
message(AUTHOR_WARNING ${DISABLE_MESSAGE}) message(STATUS ${DISABLE_MESSAGE})
else() 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}") message(STATUS "Test requirement \"${CAMITK_TESTS_REQUIREMENT_REQUIRES}\": Passed\n Enabled tests: ${CAMITK_TESTS_REQUIREMENT_TESTS_STRING}")
endif() endif()
endmacro() endmacro()
...@@ -46,7 +46,7 @@ public: ...@@ -46,7 +46,7 @@ public:
/// Method returning the action extension descrption /// Method returning the action extension descrption
virtual QString getDescription() { 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 /// 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)));