diff --git a/imaging/actions/itkfilters/CMakeLists.txt b/imaging/actions/itkfilters/CMakeLists.txt index 4fd05fff287b2db2f726f9e9d2889fbd07bcd3cd..76f05f05ac41d764fedb80ff6b1e9721f12397f4 100644 --- a/imaging/actions/itkfilters/CMakeLists.txt +++ b/imaging/actions/itkfilters/CMakeLists.txt @@ -27,25 +27,26 @@ camitk_disable_tests(TESTS action-itkfilters-level1-6 action-itkfilters-level1-8 action-itkfilters-level1-14 REASON " Test failure due to ITK exception. - For now disable these tests until this can be taken care of in the save() method - 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...\"" + For now disable these tests until this can be taken care of in the save() method + 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...\"" ) camitk_tests_requirement(TESTS action-itkfilters-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." + 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_tests_requirement(TESTS action-itkfilters-integration-test REQUIRES "${VTK_VERSION} VERSION_EQUAL 6.3" REASON "VTK version is not equals than 6.3 - The default test files are written using the currently supported version of VTK (VTK 6.3). - This test will therefore fail when comparing the input to the output if another version of VTK is used. - E.g., Ubuntu 16.04 LTS comes with VTK 6.2 and Debian buster comes with VTK 7.1 - Although everything should work well on both OS, this test will unconditionnaly fail." + The default test files are written using the currently supported version of VTK (VTK 6.3). + This test will therefore fail when comparing the input to the output if another version of VTK is used. + E.g., Ubuntu 16.04 LTS comes with VTK 6.2 and Debian buster comes with VTK 7.1 + Although everything should work well on both OS, this test will unconditionnaly fail." ) diff --git a/imaging/actions/itkfilters/integration-testdata/asm-input.scxml b/imaging/actions/itkfilters/integration-testdata/asm-input.scxml index 1d586853bc182bb1ae3542269b30a4e4f2e1152e..dec92b940b8e181494224ae5040ec3813aece225 100644 --- a/imaging/actions/itkfilters/integration-testdata/asm-input.scxml +++ b/imaging/actions/itkfilters/integration-testdata/asm-input.scxml @@ -2,7 +2,7 @@ -
  • Open
  • Otsu Threshold Filter
  • Morphological Operators
  • Save As
  • Save As
  • Connected Components Classification
  • Save As
  • Manual Threshold Filter
  • Save As
  • Morphological Operators
  • Save As
  • Morphological Operators
  • Save As
  • Close
  • Close
  • Close
  • Close
  • Close
  • Close
  • Reconstruction
  • Save As
  • Save As
  • Close
  • Reconstruction
  • Save As
  • Close
  • Reconstruction
  • Save As
  • Save As
  • Clean Mesh
  • Save As
  • ]]> +
    • Open
    • Otsu Threshold Filter
    • Morphological Operators
    • Save As
    • Save As
    • Connected Components Classification
    • Save As
    • Manual Threshold Filter
    • Save As
    • Morphological Operators
    • Save As
    • Morphological Operators
    • Save As
    • Close
    • Close
    • Close
    • Close
    • Close
    • Close
    • Reconstruction
    • Save As
    • Save As
    • Close
    • Reconstruction
    • Save As
    • Close
    • Reconstruction
    • Save As
    • Save As
    • Clean Mesh
    • Save As
    ]]>
    diff --git a/imaging/components/itkimage/CMakeLists.txt b/imaging/components/itkimage/CMakeLists.txt index 832f7c7eeca7c6ba10303c895965b97c88dc3fab..e0b433bfc240a1b0f549e7d57628cf8c9566f681 100644 --- a/imaging/components/itkimage/CMakeLists.txt +++ b/imaging/components/itkimage/CMakeLists.txt @@ -18,11 +18,12 @@ camitk_disable_tests(TESTS component-itkimage-level3-3 component-itkimage-level3-19 component-itkimage-level3-20 REASON " Test failure due to ITK exception. - For now disable these tests until this can be dealt with (if possible) - 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...\"" + For now disable these tests until this can be dealt with (if possible) + 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...\"" ) # 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?) @@ -31,7 +32,7 @@ camitk_tests_requirement(TESTS component-itkimage-level3-6 component-itkimage-level3-28 REQUIRES "NOT WIN32" REASON "WIN32 failure (probably) due to double suffix .im.gz or .nii.gz - For input file: BigEndianCompressed.img.gz, LittleEndianCompressed.img.gz and minimal.nii.gz" + For input file: BigEndianCompressed.img.gz, LittleEndianCompressed.img.gz and minimal.nii.gz" ) camitk_tests_requirement(TESTS component-itkimage-level3-1 @@ -45,8 +46,8 @@ camitk_tests_requirement(TESTS component-itkimage-level3-1 component-itkimage-level3-28 REQUIRES "${ITK_VERSION} VERSION_LESS 4.12" REASON " ITK version is greater than 4.11 - The default test files are written using the currently supported version of ITK (ITK 4.11). - This test will therefore fail when comparing the input to the output if another version of ITK is used." + The default test files are written using the currently supported version of ITK (ITK 4.11). + This test will therefore fail when comparing the input to the output if another version of ITK is used." ) # Additional test for SDK actions: this will add auto test for the given actions using the itkimage component diff --git a/sdk/actions/image/imageresampling/ResampleAction.cpp b/sdk/actions/image/imageresampling/ResampleAction.cpp index 3b986b2a1bf036bfcbe9575417a2c46b990b5164..326f89b3288f14c5ff5bcac542d2edd6d0bd367c 100644 --- a/sdk/actions/image/imageresampling/ResampleAction.cpp +++ b/sdk/actions/image/imageresampling/ResampleAction.cpp @@ -27,6 +27,8 @@ #include #include +#include + // Vtk includes #include #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::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::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::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 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(); } diff --git a/sdk/actions/image/imageresampling/ResampleAction.h b/sdk/actions/image/imageresampling/ResampleAction.h index 753c0a8b5eae1b8ba95ba1ed9e2654460e73dabc..8a1d65063cf5efcccfa3768c131ec0e7267db706 100644 --- a/sdk/actions/image/imageresampling/ResampleAction.h +++ b/sdk/actions/image/imageresampling/ResampleAction.h @@ -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) diff --git a/sdk/actions/image/reconstruction/CMakeLists.txt b/sdk/actions/image/reconstruction/CMakeLists.txt index 368098faeefc6e65cf2fa20ab86f325402a355d8..cc3b3725af57317ce5331f1951670b86459079f6 100644 --- a/sdk/actions/image/reconstruction/CMakeLists.txt +++ b/sdk/actions/image/reconstruction/CMakeLists.txt @@ -16,15 +16,15 @@ set(SHIBOKEN_CAMITK_SDK_PATH ${SHIBOKEN_CAMITK_SDK_PATH}:${CMAKE_CURRENT_SOURCE_ camitk_tests_requirement(TESTS action-reconstruction-integration-test REQUIRES "${VTK_VERSION} VERSION_EQUAL 6.3" REASON "VTK version is not equals than 6.3 - The default test files are written using the currently supported version of VTK (VTK 6.3). - This test will therefore fail when comparing the input to the output if another version of VTK is used. - E.g., Ubuntu 16.04 LTS comes with VTK 6.2 and Debian buster comes with VTK 7.1 - Although everything should work well on both OS, this test will unconditionnaly fail." + The default test files are written using the currently supported version of VTK (VTK 6.3). + This test will therefore fail when comparing the input to the output if another version of VTK is used. + E.g., Ubuntu 16.04 LTS comes with VTK 6.2 and Debian buster comes with VTK 7.1 + Although everything should work well on both OS, this test will unconditionnaly fail." ) camitk_tests_requirement(TESTS action-reconstruction-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." + 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." ) diff --git a/sdk/applications/config/testing/config-test.sh b/sdk/applications/config/testing/config-test.sh index 9d05cf73e52bb1f9098e5729c7c1b77f64a93b38..520a06c2add47ed5bb6c8b337c3b6df07921485b 100644 --- a/sdk/applications/config/testing/config-test.sh +++ b/sdk/applications/config/testing/config-test.sh @@ -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" \ diff --git a/sdk/cmake/modules/FindXSD.cmake b/sdk/cmake/modules/FindXSD.cmake index ac02d3ce9c2ee6f50b6a2d2cadd6d238f1fea14d..e0d50c49a0d3220691cd4ed5ee59ee8856a66707 100644 --- a/sdk/cmake/modules/FindXSD.cmake +++ b/sdk/cmake/modules/FindXSD.cmake @@ -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) diff --git a/sdk/cmake/modules/macros/camitk/test/CamiTKDisableTests.cmake b/sdk/cmake/modules/macros/camitk/test/CamiTKDisableTests.cmake index 55836ecc85ca2c5e6745cd2f455704df3b2e1dbe..74ced468b743ddf147b1949f3019816d118cc52f 100644 --- a/sdk/cmake/modules/macros/camitk/test/CamiTKDisableTests.cmake +++ b/sdk/cmake/modules/macros/camitk/test/CamiTKDisableTests.cmake @@ -1,7 +1,7 @@ #! #! @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() diff --git a/sdk/cmake/modules/macros/camitk/test/CamiTKTestsRequirement.cmake b/sdk/cmake/modules/macros/camitk/test/CamiTKTestsRequirement.cmake index f85ad4c190061978543174a4af84def68561c3c8..537d6f8658dbcc26eda2cc81fbafae428e7c0745 100644 --- a/sdk/cmake/modules/macros/camitk/test/CamiTKTestsRequirement.cmake +++ b/sdk/cmake/modules/macros/camitk/test/CamiTKTestsRequirement.cmake @@ -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 ${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 "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}") + 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() diff --git a/sdk/components/vtkmesh/CMakeLists.txt b/sdk/components/vtkmesh/CMakeLists.txt index b44c0ab377bfc704aa324fb0d9953f8205ac0149..7a5bb6a3062f081f315e9f047e4fd9b6618790d6 100644 --- a/sdk/components/vtkmesh/CMakeLists.txt +++ b/sdk/components/vtkmesh/CMakeLists.txt @@ -38,8 +38,8 @@ camitk_tests_requirement(TESTS component-vtkmesh-level3-1 component-vtkmesh-level3-16 REQUIRES "${VTK_VERSION} VERSION_EQUAL 6.3" REASON "VTK version is not equals than 6.3 - The default test files are written using the currently supported version of VTK (VTK 6.3). - This test will therefore fail when comparing the input to the output if another version of VTK is used. - E.g., Ubuntu 16.04 LTS comes with VTK 6.2 and Debian buster comes with VTK 7.1 - Although everything should work well on both OS, this test will unconditionnaly fail." + The default test files are written using the currently supported version of VTK (VTK 6.3). + This test will therefore fail when comparing the input to the output if another version of VTK is used. + E.g., Ubuntu 16.04 LTS comes with VTK 6.2 and Debian buster comes with VTK 7.1 + Although everything should work well on both OS, this test will unconditionnaly fail." ) diff --git a/tutorials/actions/averagevoxelvalues/AverageVoxelValuesExtension.h b/tutorials/actions/averagevoxelvalues/AverageVoxelValuesExtension.h index 20b6491a60cb0ea8b8399192405fa35fadeae151..800b0b19effd84252f0f8beb196cddf2170d525c 100644 --- a/tutorials/actions/averagevoxelvalues/AverageVoxelValuesExtension.h +++ b/tutorials/actions/averagevoxelvalues/AverageVoxelValuesExtension.h @@ -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 diff --git a/tutorials/actions/hardcodedpipeline/CMakeLists.txt b/tutorials/actions/hardcodedpipeline/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b3073a398a3d4f849642fe4b152d1b01b92a6ce --- /dev/null +++ b/tutorials/actions/hardcodedpipeline/CMakeLists.txt @@ -0,0 +1,14 @@ +# 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." +) diff --git a/tutorials/actions/hardcodedpipeline/HardCodedPipelineAction.cpp b/tutorials/actions/hardcodedpipeline/HardCodedPipelineAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07ab5a7b869a2a85bf64ba81bf4733cc288c41ff --- /dev/null +++ b/tutorials/actions/hardcodedpipeline/HardCodedPipelineAction.cpp @@ -0,0 +1,205 @@ +/***************************************************************************** + * $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 . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ +#include "HardCodedPipelineAction.h" + +// CamiTK +#include +#include +#include + +// Qt +#include + +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(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; + } +} + diff --git a/tutorials/actions/hardcodedpipeline/HardCodedPipelineAction.h b/tutorials/actions/hardcodedpipeline/HardCodedPipelineAction.h new file mode 100644 index 0000000000000000000000000000000000000000..4f41f49a5af68dbed302d3d2a61548fe0daf9bb9 --- /dev/null +++ b/tutorials/actions/hardcodedpipeline/HardCodedPipelineAction.h @@ -0,0 +1,96 @@ +/***************************************************************************** + * $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 . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ +#ifndef ACTIONSINACTIONACTION_H +#define ACTIONSINACTIONACTION_H + +#include + +#include + +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 + /// and the user left the instanciated component untouched/unsaved or when the user modified + /// a component manually, outside the pipeline). + /// + /// The best way (for now) to deal with this issue is to simply get the last top-level component + /// in the ouput list. This will be the last instanciated top-level component during the apply() method. + /// Any components that were modified _before_ the apply() will therefore be ignore + /// + /// This is an issue to consider in the Action class. + /// We probably should list in Action::preprocessInPipeline() all the component that were marked modified + /// and ignore them in the output component list (that will not take into account the rare case were a + /// already modified component was modified **as well** during the apply(), but that seems a better + /// behaviour anyway. + /// + camitk::Component *getLastTopLevelOutputComponents(const QString & actionName); + + /// apply the resample action (modifying the parameter) + PipelineActionStatus applyResample(camitk::Component *input); + + /// apply the Otsu action + PipelineActionStatus applyOtsu(camitk::Component *input); +}; + +#endif // ACTIONSINACTIONACTION_H + diff --git a/tutorials/actions/hardcodedpipeline/HardCodedPipelineExtension.cpp b/tutorials/actions/hardcodedpipeline/HardCodedPipelineExtension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d93362d6f1328c17016b5f82058d54006e627c6 --- /dev/null +++ b/tutorials/actions/hardcodedpipeline/HardCodedPipelineExtension.cpp @@ -0,0 +1,35 @@ +/***************************************************************************** + * $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 . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ +#include "HardCodedPipelineExtension.h" + +// include generated actions headers +#include "HardCodedPipelineAction.h" + +// --------------- getActions ------------------- +void HardCodedPipelineExtension::init() { + // Creating and registering the instance of ActionsInActionAction + registerNewAction(HardCodedPipelineAction); +} + diff --git a/tutorials/actions/hardcodedpipeline/HardCodedPipelineExtension.h b/tutorials/actions/hardcodedpipeline/HardCodedPipelineExtension.h new file mode 100644 index 0000000000000000000000000000000000000000..12b38a7b15034f8b93374ffcd3fcfdb94d69b426 --- /dev/null +++ b/tutorials/actions/hardcodedpipeline/HardCodedPipelineExtension.h @@ -0,0 +1,59 @@ +/***************************************************************************** + * $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 . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ +#ifndef ACTIONS_IN_ACTION_EXTENSION_H +#define ACTIONS_IN_ACTION_EXTENSION_H + +#include + +class HardCodedPipelineExtension : public camitk::ActionExtension { + Q_OBJECT + Q_INTERFACES(camitk::ActionExtension); + Q_PLUGIN_METADATA(IID "fr.imag.camitk.tutorials.action.hardcodedpipeline") + +public: + /// Constructor + HardCodedPipelineExtension() : ActionExtension() {}; + + /// Destructor + virtual ~HardCodedPipelineExtension() = default; + + /// Method returning the action extension name + virtual QString getName() { + return "HardCodedPipelineExtension"; + }; + + /// Method returning the action extension descrption + virtual QString getDescription() { + return "Demo that apply two actions from another action"; + }; + + /// initialize all the actions + virtual void init(); + +}; + +#endif // ACTIONS_IN_ACTION_EXTENSION_H + + diff --git a/tutorials/actions/hardcodedpipeline/integration-testdata/asm-input.scxml b/tutorials/actions/hardcodedpipeline/integration-testdata/asm-input.scxml new file mode 100644 index 0000000000000000000000000000000000000000..b021a6585f9979aa53432209cd0baf39e3f043c8 --- /dev/null +++ b/tutorials/actions/hardcodedpipeline/integration-testdata/asm-input.scxml @@ -0,0 +1,122 @@ + + + + + This pipeline therefore just do:
    • Open
    • Hard-Coded Action Pipeline
    • Save As
    ]]>
    +
    +
    + +
    + + + + Open data (component) from a file + + Open File + + + + + + + + + + + + + + + + <p> 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).</p> + + Hard-Coded Action Pipeline + + + + + + + + + + + + + + + + + + + + + + + + + Save the currently selected data under a different filename or format + + Save + + + + + + + + + + + + + + + + + + + + Close the currently selected components + + Close + + + + + + + + + + + + + + Close the currently selected components + + Close + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/tutorials/actions/hardcodedpipeline/integration-testdata/input-1.mha b/tutorials/actions/hardcodedpipeline/integration-testdata/input-1.mha new file mode 100644 index 0000000000000000000000000000000000000000..ddf2f2fa4a94e65dfe01019f2e7426970e8a8fa4 Binary files /dev/null and b/tutorials/actions/hardcodedpipeline/integration-testdata/input-1.mha differ diff --git a/tutorials/actions/hardcodedpipeline/integration-testdata/output-1.mha b/tutorials/actions/hardcodedpipeline/integration-testdata/output-1.mha new file mode 100644 index 0000000000000000000000000000000000000000..fbb75a101b8cd2b3dc2de1fdb7e321f9f3117565 Binary files /dev/null and b/tutorials/actions/hardcodedpipeline/integration-testdata/output-1.mha differ