├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── Image ├── CMakeLists.txt └── include │ └── Image │ ├── Image.hpp │ └── Image_IO_ITK.hpp ├── README.md ├── RORPO_multiscale_Usage ├── CMakeLists.txt ├── RORPO_multiscale_usage.cxx ├── RORPO_multiscale_usage.xml ├── ReadMe.md ├── test_images │ ├── test_image.nii │ └── test_image_RORPO_smin_40_factor_1.32_nbScales_4_window_0_255.nii └── tests │ ├── CMakeLists.txt │ ├── __init__.py │ ├── data │ ├── negative_char.nii │ ├── negative_double.nii │ ├── negative_float.nii │ ├── negative_int.nii │ ├── negative_short.nii │ ├── positive_char.nii │ ├── positive_double.nii │ ├── positive_double_big_num.nii │ ├── positive_float.nii │ ├── positive_float_big_num.nii │ └── positive_int.nii │ ├── generic_test.py │ ├── requirements.txt │ ├── test_double_float.py │ ├── test_negative.py │ ├── test_normalize_option.py │ ├── test_uint8_option.py │ └── test_window_option.py ├── ReadMe.txt ├── docopt ├── CMakeLists.txt ├── LICENSE-Boost-1.0 ├── LICENSE-MIT ├── README.rst ├── docopt.cpp ├── docopt.h ├── docopt.pc.in ├── docopt_private.h ├── docopt_util.h ├── docopt_value.h ├── main.cpp ├── run_testcase.cpp ├── run_tests.py └── testcases.docopt ├── libRORPO ├── CMakeLists.txt ├── include │ └── RORPO │ │ ├── Algo.hpp │ │ ├── Geodilation.hpp │ │ ├── PO.hpp │ │ ├── RORPO.hpp │ │ ├── RORPO_multiscale.hpp │ │ ├── RPO.hpp │ │ ├── pink │ │ ├── generic_macros.h │ │ ├── genfmax.hpp │ │ ├── genfmin.hpp │ │ ├── larith.h │ │ ├── lgeodesic.h │ │ ├── liarp.h │ │ ├── mccodimage.h │ │ ├── mcfifo.h │ │ ├── mcimage.h │ │ ├── mcindic.h │ │ ├── mclifo.h │ │ ├── mcutil.h │ │ └── rect3dmm.hpp │ │ └── sorting.hpp └── src │ ├── larith.c │ ├── lgeodesic.c │ ├── mccodimage.c │ ├── mcfifo.c │ ├── mcimage.c │ ├── mcindic.c │ └── mclifo.c └── pyRORPO ├── CMakeLists.txt ├── README.md ├── bind_RORPO.hpp ├── bind_RORPO_multiscale.hpp ├── bind_RPO.hpp ├── docs ├── Makefile ├── README.md ├── make.bat ├── requirements.txt └── source │ ├── conf.py │ ├── documentation.rst │ ├── index.rst │ └── installation.rst ├── pyRORPO.cpp └── pyRORPO.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt.user 2 | *~ 3 | build 4 | 5 | obj 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pyRORPO/pybind11"] 2 | path = pyRORPO/pybind11 3 | url = https://github.com/pybind/pybind11.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(RORPO VERSION 1.0) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_EXTENSIONS OFF) 7 | 8 | if(UNIX) 9 | SET(LIB_TYPE SHARED) 10 | else() 11 | SET(LIB_TYPE STATIC) 12 | endif() 13 | 14 | # Build Type 15 | if(NOT CMAKE_BUILD_TYPE) 16 | SET(CMAKE_BUILD_TYPE Release 17 | CACHE STRING "Choose the type of build : Debug or Release." 18 | FORCE) 19 | endif() 20 | message("Build Type: " ${CMAKE_BUILD_TYPE}) 21 | 22 | set(PYTHON_BINDING ON CACHE BOOL "enable python binding") 23 | set(3DSLICER_BINDING ON CACHE BOOL "enable 3DSlicer module") 24 | 25 | include_directories( 26 | libRORPO/include 27 | Image/include 28 | docopt) 29 | 30 | if (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release") 31 | enable_testing() 32 | endif() 33 | 34 | add_subdirectory(libRORPO) 35 | 36 | if(NOT 3DSLICER_BINDING) 37 | add_subdirectory(docopt) 38 | endif() 39 | 40 | add_subdirectory(RORPO_multiscale_Usage) 41 | 42 | # retrieving pybind11 43 | if(PYTHON_BINDING) 44 | include_directories(pyRORPO) 45 | add_subdirectory(pyRORPO) 46 | endif() 47 | 48 | -------------------------------------------------------------------------------- /Image/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(Image) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | add_subdirectory(Nifti) 5 | 6 | # ADD FILES 7 | file(GLOB_RECURSE Image_HEADERS include/*.hpp include/*.h) 8 | 9 | install( FILES ${Image_HEADERS} DESTINATION include/Image) 10 | -------------------------------------------------------------------------------- /Image/include/Image/Image_IO_ITK.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | 32 | #ifndef Images_IO_ITK_INCLUDED 33 | #define Images_IO_ITK_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "Image.hpp" 46 | #include 47 | 48 | 49 | // ############################# MHA Image ############################## 50 | 51 | struct Image3DMetadata { 52 | itk::IOComponentEnum pixelType; 53 | std::string pixelTypeString; 54 | uint nbDimensions; 55 | }; 56 | 57 | 58 | std::optional Read_Itk_Metadata(const std::string &image_path) { 59 | itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(image_path.c_str(), 60 | itk::ImageIOFactory::ReadMode); 61 | if (imageIO == nullptr) { 62 | std::cerr << "Error: file not found." << std::endl; 63 | return std::nullopt; 64 | } 65 | imageIO->SetFileName(image_path.c_str()); 66 | imageIO->ReadImageInformation(); 67 | 68 | return std::optional( 69 | {imageIO->GetComponentType(), imageIO->GetComponentTypeAsString(imageIO->GetComponentType()), 70 | imageIO->GetNumberOfDimensions()}); 71 | } 72 | 73 | template 74 | Image3D Read_Itk_Image(const std::string& image_path) 75 | { 76 | typedef itk::Image ITKImageType; 77 | 78 | typedef itk::ImageFileReader ReaderType; 79 | typename ReaderType::Pointer reader = ReaderType::New(); 80 | reader->SetFileName(image_path); 81 | reader->Update(); 82 | 83 | typename ITKImageType::Pointer itkImage = reader->GetOutput(); 84 | 85 | const typename ITKImageType::SizeType& itkSize = itkImage->GetLargestPossibleRegion().GetSize(); 86 | auto spacing = itkImage->GetSpacing(); 87 | auto origin = itkImage->GetOrigin(); 88 | Image3D image(itkSize[0], itkSize[1], itkSize[2],spacing[0],spacing[1],spacing[2],origin[0],origin[1],origin[2]); 89 | image.add_data_from_pointer(itkImage->GetBufferPointer()); 90 | 91 | return image; 92 | } 93 | 94 | template 95 | Image3D Read_Itk_Image_Series(const std::string& image_path) 96 | { 97 | typedef itk::Image ITKImageType; 98 | 99 | // Définition des type de l'image 100 | typedef itk::ImageSeriesReader ReaderType; 101 | typename ReaderType::Pointer reader = ReaderType::New(); 102 | 103 | // Définition du dicom 104 | typedef itk::GDCMImageIO ImageIOType; 105 | ImageIOType::Pointer dicomIO = ImageIOType::New(); 106 | reader->SetImageIO(dicomIO); 107 | 108 | // Mise en place de la lecture en serie 109 | typedef itk::GDCMSeriesFileNames NamesGeneratorType; 110 | NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); 111 | nameGenerator->SetDirectory(image_path); 112 | reader->SetFileNames(nameGenerator->GetInputFileNames()); 113 | 114 | try 115 | { 116 | reader->Update(); 117 | } 118 | catch( itk::ExceptionObject& ex ) 119 | { 120 | std::cout << ex.GetDescription(); 121 | return Image3D(); 122 | } 123 | 124 | const typename ITKImageType::Pointer& itkImage = reader->GetOutput(); 125 | const typename ITKImageType::SizeType& itkSize = itkImage->GetLargestPossibleRegion().GetSize(); 126 | auto spacing = itkImage->GetSpacing(); 127 | auto origin = itkImage->GetOrigin(); 128 | Image3D image(itkSize[0], itkSize[1], itkSize[2],spacing[0],spacing[1],spacing[2],origin[0],origin[1],origin[2]); 129 | 130 | 131 | image.add_data_from_pointer(itkImage->GetBufferPointer()); 132 | 133 | return image; 134 | } 135 | 136 | 137 | template 138 | void Write_Itk_Image( Image3D& image, const std::string& image_path ) 139 | { 140 | typedef itk::Image ITKImageType; 141 | 142 | // Convert image to ITK image 143 | typedef typename itk::ImportImageFilter ImportImageFilterType; 144 | typename ImportImageFilterType::Pointer importFilter = ImportImageFilterType::New(); 145 | 146 | typename ImportImageFilterType::IndexType start; 147 | start.Fill(0); 148 | typename ImportImageFilterType::SizeType size = { image.dimX(), image.dimY(), image.dimZ() }; 149 | typename ImportImageFilterType::RegionType region; 150 | region.SetIndex(start); 151 | region.SetSize(size); 152 | typename ImportImageFilterType::SpacingType origin; 153 | origin[0] = image.originX(); 154 | origin[1] = image.originY(); 155 | origin[2] = image.originZ(); 156 | typename ImportImageFilterType::SpacingType spacing; 157 | spacing[0] = image.spacingX(); 158 | spacing[1] = image.spacingY(); 159 | spacing[2] = image.spacingZ(); 160 | 161 | importFilter->SetRegion(region); 162 | importFilter->SetOrigin(origin); 163 | importFilter->SetSpacing(spacing); 164 | 165 | const bool importImageFilterWillOwnTheBuffer = false; 166 | importFilter->SetImportPointer( image.get_pointer(), image.size(), importImageFilterWillOwnTheBuffer ); 167 | 168 | // Write ITK image 169 | typedef itk::ImageFileWriter< ITKImageType > WriterType; 170 | typename WriterType::Pointer writer = WriterType::New(); 171 | writer->SetFileName( image_path ); 172 | writer->SetInput( importFilter->GetOutput() ); 173 | writer->Update(); 174 | } 175 | 176 | #endif // Images_IO_ITK_INCLUDED 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libRORPO 2 | Welcome to libRORPO, a mathematical morphology library for Path Operators. RORPO 3 | is a morphological vesselness operator, meant to detect vessels and other tubular 4 | structures in medical images. 5 | 6 | This library comes with the following optional bindings : 7 | - A python interface using pybind11. 8 | - A [3DSlicer](https://www.slicer.org/) interface to use RORPO in the interactive 3D environment of Slicer. 9 | 10 | **WARNING : 11 | All images are expected to have an isotropic image resolution (cubic voxels). 12 | The software will produce a result if this not the case but the interpretation 13 | of this result will be questionable.** 14 | 15 | ## File PO.hpp 16 | **PO_3D**: Compute the Path Opening operator in one orientation. The 7 orientations are defined in the function RPO. 17 | ``` 18 | template 19 | void PO_3D(const Image3D &image, int L, std::vector &index_image, std::vector &orientations, Image3D &Output, std::vector b) 20 | ``` 21 | 22 | - image : Input image 23 | - L : Path length 24 | - index_image : sorted index of the image. Result of the sort_image_value function of sorting.hpp 25 | - orientations : defined the orientation used. Choices are [0,0,1] ; [1,0,0] ; [0,1,0] ; [1,1,1] ; [-1,1,1] ; [1,1,-1] ; [-1,1,-1] 26 | - Output : Result of the Path Opening 27 | 28 | ## File RPO.hpp 29 | 30 | **RPO** : Compute the 7 orientations of the Robust Path Opening and return them. 31 | ``` 32 | template 33 | std::array, 7> RPO(const Image3D &image, int L, Image3D &RPO1, Image3D &RPO2, Image3D &RPO3, Image3D &RPO4, 34 | Image3D &RPO5, Image3D &RPO6, Image3D &RPO7, int nb_core, int dilationSize, Image3D &Mask) { 35 | ``` 36 | - image : input image 37 | - L : Path length 38 | - RPO1 : resulting Robust Path Opening in the first orientation. 39 | - RPO2 : resulting Robust Path Opening in the second orientation 40 | - RPO3 : resulting Robust Path Opening in the third orientation 41 | - RPO4 : resulting Robust Path Opening in the fourth orientation 42 | - RPO5 : resulting Robust Path Opening in the fifth orientation 43 | - RPO6 : resulting Robust Path Opening in the sixth orientation 44 | - RPO7 : resulting Robust Path Opening in the seventh orientation 45 | - nb_core : number of cores used to compute the Path Opening (choose between 1 and 7) 46 | 47 | 48 | ## File RORPO.hpp 49 | **RORPO**: Compute the Ranking Orientations Responses of Path Operators 50 | 51 | ``` 52 | template 53 | Image3D RORPO(const Image3D &image, int L, int nbCores, int dilationSize, Image3D &mask) { 54 | ``` 55 | - image: input image 56 | - L: Path length 57 | - nb_core: number of cores used to compute the Path Opening (choose between 1 and 7) 58 | - dilationSize: Size of the dilation for the noise robustness step. 59 | - mask: optional mask image 60 | 61 | ## File RORPO_multiscale.hpp 62 | **RORPO_multiscale**: Compute the multiscale RORPO 63 | ``` 64 | template 65 | Image3D RORPO_multiscale(const Image3D &I, const std::vector& S_list, int nb_core, int dilationSize, int debug_flag, Image3D &Mask) 66 | ``` 67 | - I: input image 68 | - S_list : vector containing the different path length (scales) 69 | - nb_core : number of cores used to compute the Path Opening (choose between 1 and 7) 70 | - debug_flag : 1 (activated) or 0 (desactivated) 71 | - Mask : optional mask image 72 | 73 | 74 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # RORPO_multiscale usage executable 2 | cmake_minimum_required(VERSION 3.2) 3 | project (RORPO_multiscale_usage) 4 | 5 | 6 | # FIND OPENMP 7 | find_package(OpenMP REQUIRED) 8 | if(OPENMP_FOUND) 9 | message("OpenMP FOUND") 10 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 12 | endif() 13 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 14 | 15 | # Find ITK 16 | find_package(ITK REQUIRED) 17 | include(${ITK_USE_FILE}) 18 | 19 | if(3DSLICER_BINDING) 20 | add_definitions(-DSLICER_BINDING) 21 | message("Generating 3D Slicer binding") 22 | # GenerateCLP 23 | find_package(SlicerExecutionModel REQUIRED) 24 | include(${SlicerExecutionModel_USE_FILE}) 25 | # Slicer macro 26 | SEMMacroBuildCLI( 27 | NAME RORPO_multiscale_usage 28 | TARGET_LIBRARIES RORPO ${ITK_LIBRARIES} 29 | INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES} 30 | ) 31 | else() 32 | add_executable( ${PROJECT_NAME} RORPO_multiscale_usage.cxx ) 33 | # LINK REQUIRED LIBS 34 | target_link_libraries( ${PROJECT_NAME} RORPO docopt ${ITK_LIBRARIES} ) 35 | set_target_properties( ${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) 36 | install( TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin/ ) 37 | endif() 38 | 39 | add_subdirectory(tests) 40 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/RORPO_multiscale_usage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Vesselness 4 | RORPO Vesselness Filter 5 | 6 | RORPO Vesselness filter, morphological filter based on path opening. 7 | 8 | 1.0 9 | 10 | 11 | Jonas Lamy 12 | 13 | 14 | 17 | 18 | Scale space is defined by the length of the initial path operator, the number of path elements and the multiplicative length coefficient between two consecutives paths. 19 | 20 | 21 | 22 | scaleMin 23 | scaleMin 24 | minimum path size 25 | 26 | 100 27 | 28 | 0 29 | 800 30 | 1 31 | 32 | 33 | 34 | 35 | factor 36 | factor 37 | multiplicative path factor 38 | 39 | 1.5 40 | 41 | 0 42 | 10 43 | .01 44 | 45 | 46 | 47 | 48 | nbScales 49 | nbScales 50 | Number of scales 51 | 52 | 3 53 | 54 | 2 55 | 30 56 | 1 57 | 58 | 59 | 60 | 61 | dilationSize 62 | dilationSize 63 | Size of the structuring element for dilatation. Useful for noise mitigation 64 | 65 | 0 66 | 67 | 0 68 | 50 69 | 1 70 | 71 | 72 | 73 | 74 | 75 | 76 | 79 | 80 | normalize 81 | 82 | normalize 83 | 1 84 | 85 | 86 | nbCores 87 | 88 | nbCores 89 | 7 90 | 91 | 1 92 | 16 93 | 1 94 | 95 | 96 | 97 | window 98 | 99 | window 100 | 0,255 101 | 102 | -1000 103 | 1000 104 | 1 105 | 106 | 107 | 108 | verbose 109 | 110 | verbose 111 | 0 112 | 113 | 114 | 115 | 116 | 117 | Input/output images 118 | 119 | inputVolume 120 | 121 | input 122 | input 123 | Input volume to be filtered 124 | 125 | 126 | mask image 127 | 128 | maskVolume 129 | 130 | input 131 | mask 132 | mask to be applied on the vesselness 133 | 134 | 135 | outputVolume 136 | 137 | output 138 | o 139 | output 140 | Output filtered 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/ReadMe.md: -------------------------------------------------------------------------------- 1 | # RORPO Multiscale Usage 2 | 3 | Compute the RORPO multiscale for blood vessels from a .nii image. 4 | 5 | **Accepted type**: int8, uint8, int16, uint16, int32, uint32, float 6 | 7 | ***An isotropic image resolution is required (cubic voxels)***. 8 | ```USAGE: 9 | RORPO_multiscale_usage --input=ImagePath --output=OutputPath --scaleMin=MinScale --factor=F --nbScales=NBS [--window=min,max] [--core=nbCores] [--dilationSize=Size] [--mask=maskPath] [--verbose] [--normalize] [--uint8] [--series] 10 | 11 | Parameters: 12 | path to .nii image (string) 13 | path to write the resulting image (string) 14 | Minimum path length (int) 15 | factor for the geometric sequence of scales; scale_(n+1) = factor * scale_(n) (float) 16 | Number of scales (int) 17 | 18 | Options: 19 | --core Number of CPUs used for RPO computation (int) 20 | --dilationSize Size of the dilation for the noise robustness step. 21 | --window Intensity range from the input image (2 int: window_min, window_max) 22 | Convert input image to uint8. Intensities inferior to window_min become 0, 23 | intensities superior to window_max become 255. 24 | Linear transformation between window_min and window_max. 25 | --mask Path to a mask image (0 for the background and 1 for the foreground). 26 | RORPO will only be computed in this mask. The mask image type must be uint8. 27 | --verbose Activation of a verbose mode. 28 | --dicom Specify that is a DICOM image. 29 | --normalize Return a double normalized output image. 30 | --uint8 Convert input image into uint8. 31 | ``` 32 | 33 | Usage Example : 34 | ``` 35 | ./RORPO_multiscale_usage --input input.nii --output output.nii --scaleMin 40 --factor 1.32 --nbScales 4 36 | ``` 37 | 38 | Usage Example : 39 | ``` 40 | ./RORPO_multiscale_usage --input input.nii --output output.nii --scaleMin 40 --factor 1.32 --nbScales 4 --window 0,255 --verbose --core 4 41 | ``` 42 | 43 | ## Test 44 | To build tests, (re-)generate a build system with any CMAKE_BUILD_TYPE flags except release. 45 | ``` 46 | cmake [options] -DCMAKE_BUILD_TYPE=Debug 47 | make tests 48 | ``` 49 | To run tests: 50 | ``` 51 | make test 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/test_images/test_image.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/test_images/test_image.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/test_images/test_image_RORPO_smin_40_factor_1.32_nbScales_4_window_0_255.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/test_images/test_image_RORPO_smin_40_factor_1.32_nbScales_4_window_0_255.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # only generate test when the current build is not release 2 | if (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release") 3 | 4 | find_package(Python3 COMPONENTS Interpreter) 5 | find_program(VIRTUALENV virtualenv) 6 | 7 | # only generate test when python3 and virtualenv is found 8 | if (Python3_Interpreter_FOUND AND VIRTUALENV) 9 | 10 | # create virtual environment 11 | add_custom_command( 12 | OUTPUT venv 13 | COMMAND ${VIRTUALENV} -p python3 venv 14 | ) 15 | 16 | # set variables needed for building tests 17 | set(VENV_BIN ${CMAKE_CURRENT_BINARY_DIR}/venv/bin/) 18 | set(PYTEST ${VENV_BIN}/python ${VENV_BIN}/pytest) 19 | set(ENV_VARS ${CMAKE_COMMAND} -E env BUILD_DIR=${CMAKE_BINARY_DIR} 20 | SRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} 21 | ) 22 | 23 | # install requirements 24 | add_custom_command( 25 | OUTPUT venv.stamp 26 | DEPENDS venv requirements.txt 27 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt requirements.txt 28 | COMMAND ${VENV_BIN}/python -m pip install --upgrade pip 29 | COMMAND ${VENV_BIN}/pip install -r requirements.txt --upgrade 30 | ) 31 | # add these commands to target "tests" 32 | add_custom_target(tests ALL 33 | DEPENDS venv.stamp ${PROJECT_NAME} 34 | SOURCES requirements.txt 35 | ) 36 | 37 | # add all tests 38 | file(GLOB pytest_files "${CMAKE_CURRENT_SOURCE_DIR}/test_*.py") 39 | foreach(filepath ${pytest_files}) 40 | get_filename_component(filename ${filepath} NAME_WE) 41 | add_test(NAME ${filename} COMMAND ${ENV_VARS} ${PYTEST} ${filepath}) 42 | endforeach() 43 | 44 | else () 45 | message("Could not find Python3 or Virtualenv for pytest!") 46 | endif () 47 | 48 | endif() 49 | 50 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/__init__.py -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/negative_char.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/negative_char.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/negative_double.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/negative_double.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/negative_float.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/negative_float.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/negative_int.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/negative_int.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/negative_short.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/negative_short.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/positive_char.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/positive_char.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/positive_double.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/positive_double.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/positive_double_big_num.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/positive_double_big_num.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/positive_float.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/positive_float.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/positive_float_big_num.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/positive_float_big_num.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/data/positive_int.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/RORPO_multiscale_Usage/tests/data/positive_int.nii -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/generic_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | 5 | class TestGeneric(unittest.TestCase): 6 | output = "output" 7 | BUILD_DIR = os.environ.get('BUILD_DIR') 8 | SRC_DIR = os.environ.get('SRC_DIR') 9 | bin = BUILD_DIR + "/bin/RORPO_multiscale_usage" 10 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/requirements.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | nibabel -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/test_double_float.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import glob 3 | import uuid 4 | import os 5 | import re 6 | import numpy as np 7 | from .generic_test import TestGeneric 8 | import nibabel as nib 9 | 10 | 11 | class TestNegative(TestGeneric): 12 | double_pattern = re.compile(r'(?i)(Input image type\s*:*\s* double)') 13 | float_pattern = re.compile(r'(?i)(Input image type\s*:*\s* float)') 14 | conversion_pattern = re.compile(r'(?i)(Convert image to uint8)') 15 | 16 | def run_test_(self, image_type): 17 | if image_type == 0: 18 | paths = glob.glob(self.SRC_DIR + '/data/positive_float*.nii') 19 | pat = self.float_pattern 20 | else: 21 | paths = glob.glob(self.SRC_DIR + '/data/positive_double*.nii') 22 | pat = self.double_pattern 23 | for path in paths: 24 | output_path = os.path.join(self.BUILD_DIR, self.output + str(uuid.uuid4()) + ".nii") 25 | args = [self.bin, "--input=" + path, "--output=" + output_path, "--scaleMin=40", 26 | "--factor=1.32", "--nbScales=1", "--verbose"] 27 | proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 28 | outs, errs = proc.communicate(timeout=20) 29 | 30 | # check return value is 0 31 | assert (proc.returncode == 0) 32 | 33 | # check if file exists 34 | assert(os.path.exists(output_path)) 35 | 36 | # check type of output image is uint8 37 | img = nib.load(output_path) 38 | assert(img.header.get_data_dtype() == np.dtype(np.uint8)) 39 | 40 | # remove generated output image 41 | os.remove(output_path) 42 | 43 | # check if program generate expected messages 44 | outs = str(outs) 45 | assert (pat.search(outs) is not None) 46 | assert (self.conversion_pattern.search(outs) is not None) 47 | assert ("computation" in outs) 48 | 49 | def test_double(self): 50 | self.run_test_(1) 51 | 52 | def test_float(self): 53 | self.run_test_(0) 54 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/test_negative.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import glob 3 | import uuid 4 | import os 5 | import re 6 | from .generic_test import TestGeneric 7 | 8 | 9 | class TestNegative(TestGeneric): 10 | error_pattern = re.compile(r'(?i)(Image contains negative values)') 11 | 12 | def test_positive(self): 13 | for path in glob.glob(self.SRC_DIR + '/data/positive*.nii'): 14 | output_path = os.path.join(self.BUILD_DIR, self.output + str(uuid.uuid4()) + ".nii") 15 | args = [self.bin, "--input=" + path, "--output=" + output_path, "--scaleMin=40", 16 | "--factor=1.32", "--nbScales=1"] 17 | proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 18 | outs, errs = proc.communicate(timeout=15) 19 | 20 | # check return value is 0 21 | assert (proc.returncode == 0) 22 | 23 | # check if file exists 24 | assert(os.path.exists(output_path)) 25 | 26 | # remove generated output image 27 | os.remove(output_path) 28 | 29 | # check if program generate expected messages 30 | outs, errs = str(outs), str(errs) 31 | assert ("computation" in outs) 32 | assert (self.error_pattern.search(errs) is None) 33 | 34 | def test_negative(self): 35 | for path in glob.glob(self.SRC_DIR + '/data/negative*.nii'): 36 | output_path = self.output + str(uuid.uuid4()) + ".nii" 37 | args = [self.bin, "--input=" + path, "--output=" + output_path, "--scaleMin=40", 38 | "--factor=1.32", "--nbScales=1"] 39 | proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 40 | outs, errs = proc.communicate(timeout=15) 41 | 42 | # check return value is 1 43 | assert (proc.returncode == 1) 44 | 45 | # check if file does not exist 46 | assert(not os.path.exists(output_path)) 47 | 48 | # check if program generate expected messages 49 | outs, errs = str(outs), str(errs) 50 | assert ("computation" not in outs) 51 | assert (self.error_pattern.search(errs) is not None) 52 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/test_normalize_option.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import glob 3 | import uuid 4 | import os 5 | import re 6 | import numpy as np 7 | from .generic_test import TestGeneric 8 | import nibabel as nib 9 | 10 | 11 | class TestNormalizeOption(TestGeneric): 12 | pattern = re.compile(r'(?i)(converting output image intensity\s*:\s*([0-9]*\s*-?\s*)*to \[0,1\])') 13 | 14 | def test_normalize(self): 15 | for path in glob.glob(self.SRC_DIR + '/data/positive*.nii'): 16 | output_path = os.path.join(self.BUILD_DIR, self.output + str(uuid.uuid4()) + ".nii") 17 | args = [self.bin, "--input=" + path, "--output=" + output_path, "--scaleMin=40", 18 | "--factor=1.32", "--nbScales=1", "--verbose", '--normalize'] 19 | proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 20 | outs, errs = proc.communicate(timeout=15) 21 | 22 | # check return value is 0 23 | assert (proc.returncode == 0) 24 | 25 | # check if file exists 26 | assert(os.path.exists(output_path)) 27 | 28 | # check type of output image is double 29 | img = nib.load(output_path) 30 | assert(img.header.get_data_dtype() == np.dtype(np.float64)) 31 | 32 | # check that output image is normalized 33 | data = img.get_fdata() 34 | assert(data.min() >= 0) 35 | assert(data.max() <= 1) 36 | 37 | # remove generated output image 38 | os.remove(output_path) 39 | 40 | # check if program generate expected messages 41 | assert (proc.returncode == 0) 42 | assert (self.pattern.search(str(outs)) is not None) 43 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/test_uint8_option.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import glob 3 | import uuid 4 | import os 5 | import re 6 | from .generic_test import TestGeneric 7 | import nibabel as nib 8 | import numpy as np 9 | 10 | 11 | class TestUint8Option(TestGeneric): 12 | uint8_pattern = re.compile(r'(?i)(Convert image to uint8)') 13 | max_val = 300 14 | 15 | def test_window(self): 16 | for path in glob.glob(self.SRC_DIR + '/data/positive*.nii'): 17 | output_path = os.path.join(self.BUILD_DIR, self.output + str(uuid.uuid4()) + ".nii") 18 | args = [self.bin, "--input=" + path, "--output=" + output_path, "--scaleMin=40", 19 | "--factor=1.32", "--nbScales=1", "--verbose", "--uint8"] 20 | 21 | proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 22 | outs, errs = proc.communicate(timeout=15) 23 | 24 | # check return value is 0 25 | assert (proc.returncode == 0) 26 | 27 | # check if file exists 28 | assert(os.path.exists(output_path)) 29 | 30 | # check output type is uint8 31 | img = nib.load(output_path) 32 | assert(img.header.get_data_dtype() == np.dtype(np.uint8)) 33 | 34 | # remove generated output image 35 | os.remove(output_path) 36 | 37 | # check if program generate expected messages 38 | outs = str(outs) 39 | assert (self.uint8_pattern.search(outs) is not None) 40 | -------------------------------------------------------------------------------- /RORPO_multiscale_Usage/tests/test_window_option.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import glob 3 | import uuid 4 | import os 5 | import re 6 | from random import randint 7 | from .generic_test import TestGeneric 8 | import nibabel as nib 9 | import numpy as np 10 | 11 | 12 | class TestWindowOption(TestGeneric): 13 | range_pattern = re.compile(r'(?i)(Convert image intensity range from)') 14 | uint8_pattern = re.compile(r'(?i)(Convert image to uint8)') 15 | max_val = 300 16 | 17 | def test_window(self): 18 | for path in glob.glob(self.SRC_DIR + '/data/positive*.nii'): 19 | output_path = os.path.join(self.BUILD_DIR, self.output + str(uuid.uuid4()) + ".nii") 20 | args = [self.bin, "--input=" + path, "--output=" + output_path, "--scaleMin=40", 21 | "--factor=1.32", "--nbScales=1", "--verbose", 22 | '--window=%d,%d' % (randint(-self.max_val, self.max_val), randint(-self.max_val, self.max_val))] 23 | proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 24 | outs, errs = proc.communicate(timeout=15) 25 | 26 | # check return value is 0 27 | assert (proc.returncode == 0) 28 | 29 | # check if file exists 30 | assert(os.path.exists(output_path)) 31 | 32 | # check output type is uint8 33 | img = nib.load(output_path) 34 | assert(img.header.get_data_dtype() == np.dtype(np.uint8)) 35 | 36 | # remove generated output image 37 | os.remove(output_path) 38 | 39 | # check if program generate expected messages 40 | outs = str(outs) 41 | assert (self.range_pattern.search(outs) is not None) 42 | assert (self.uint8_pattern.search(outs) is not None) 43 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | Welcome to libRORPO, a mathematical morphology library for Path Operators. RORPO 2 | is a morphological vesselness operator, meant to detect vessels and other tubular 3 | structures in medical images. 4 | 5 | To compile this code you will need to also install the pybind11 submodule. This 6 | is achieved with the command: 7 | 8 | git submodule update --init 9 | 10 | 11 | ################ libRORPO ############### 12 | 13 | WARNING : 14 | All images are expected to have an isotropic image resolution (cubic voxels). 15 | The software will produce a result if this not the case but the interpretation 16 | of this result will be questionable. 17 | 18 | ---------- File PO.hpp ---------- 19 | 20 | PO_3D : 21 | Compute the Path Opening operator in one orientation. The 7 orientations are defined in the function createNeighbourhood. 22 | 23 | image : Input image 24 | L : Path length 25 | index_image : sorted index of the image. Result of the sort_image_value function of sorting.hpp 26 | orientations : defined the orientation used. Choices are [0,0,1] ; [1,0,0] ; [0,1,0] ; [1,1,1] ; [-1,1,1] ; [1,1,-1] ; [-1,1,-1] 27 | Output : Result of the Path Opening 28 | 29 | 30 | ---------- File RPO.hpp ---------- 31 | 32 | RPO : 33 | Compute the 7 orientations of the Robust Path Opening and return them. 34 | 35 | image : input image 36 | L : Path length 37 | RPO1 : resulting Robust Path Opening in the first orientation. 38 | RPO2 : resulting Robust Path Opening in the second orientation 39 | RPO3 : resulting Robust Path Opening in the third orientation 40 | RPO4 : resulting Robust Path Opening in the fourth orientation 41 | RPO5 : resulting Robust Path Opening in the fifth orientation 42 | RPO6 : resulting Robust Path Opening in the sixth orientation 43 | RPO7 : resulting Robust Path Opening in the seventh orientation 44 | nb_core : number of cores used to compute the Path Opening (choose between 1 and 7) 45 | 46 | 47 | ---------- File RORPO.hpp ---------- 48 | Compute the Ranking Orientations Responses of Path Operators (RORPO) 49 | 50 | image : input image 51 | L : Path length 52 | nb_core : number of cores used to compute the Path Opening (choose between 1 and 7) 53 | 54 | 55 | ---------- File RORPO_multiscale.hpp ---------- 56 | Compute the multiscale RORPO 57 | 58 | image : input image 59 | S_list : vector containing the different path length (scales) 60 | nb_core : number of cores used to compute the Path Opening (choose between 1 and 7) 61 | debug_flag : 1 (activated) or 0 (desactivated) 62 | Mask : optional mask image 63 | 64 | 65 | -------------------------------------------------------------------------------- /docopt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(docopt.cpp VERSION 0.6.2) 3 | 4 | include(GNUInstallDirs) 5 | 6 | #============================================================================ 7 | # Settable options 8 | #============================================================================ 9 | option(WITH_TESTS "Build tests." OFF) 10 | option(WITH_EXAMPLE "Build example." OFF) 11 | option(USE_BOOST_REGEX "Replace std::regex with Boost.Regex" OFF) 12 | 13 | #============================================================================ 14 | # Internal compiler options 15 | #============================================================================ 16 | # C++ standard 17 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 18 | set(CMAKE_CXX_EXTENSIONS OFF) 19 | if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 11) 20 | set(CMAKE_CXX_STANDARD 11) 21 | endif() 22 | 23 | #============================================================================ 24 | # Sources & headers 25 | #============================================================================ 26 | set(docopt_SOURCES docopt.cpp) 27 | set(docopt_HEADERS 28 | docopt.h 29 | docopt_private.h 30 | docopt_util.h 31 | docopt_value.h 32 | ) 33 | 34 | #============================================================================ 35 | # Compile targets 36 | #============================================================================ 37 | if(MSVC OR XCODE) 38 | # MSVC requires __declspec() attributes, which are achieved via the 39 | # DOCOPT_DLL and DOCOPT_EXPORTS macros below. Since those macros are only 40 | # defined when building a shared library, we must build the shared and 41 | # static libraries completely separately. 42 | # Xcode does not support libraries with only object files as sources. 43 | # See https://cmake.org/cmake/help/v3.0/command/add_library.html?highlight=add_library 44 | add_library(docopt SHARED ${docopt_SOURCES} ${docopt_HEADERS}) 45 | add_library(docopt_s STATIC ${docopt_SOURCES} ${docopt_HEADERS}) 46 | else() 47 | # If not using MSVC or Xcode, we will create an intermediate object target 48 | # to avoid compiling the source code twice. 49 | add_library(docopt_o OBJECT ${docopt_SOURCES} ${docopt_HEADERS}) 50 | set_target_properties(docopt_o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 51 | 52 | add_library(docopt SHARED $) 53 | set_target_properties(docopt PROPERTIES 54 | VERSION ${PROJECT_VERSION} 55 | SOVERSION ${PROJECT_VERSION_MAJOR} 56 | ) 57 | add_library(docopt_s STATIC $) 58 | endif() 59 | 60 | target_include_directories(docopt PUBLIC $ $) 61 | target_include_directories(docopt_s PUBLIC $ $) 62 | 63 | if(MSVC) 64 | # DOCOPT_DLL: Must be specified when building *and* when using the DLL. 65 | # That's what the "PUBLIC" means. 66 | # DOCOPT_EXPORTS: Must use __declspec(dllexport) when building the DLL. 67 | # "PRIVATE" means it's only defined when building the DLL. 68 | target_compile_definitions(docopt PUBLIC DOCOPT_DLL 69 | PRIVATE DOCOPT_EXPORTS) 70 | endif() 71 | 72 | if(NOT MSVC) 73 | set_target_properties(docopt PROPERTIES OUTPUT_NAME docopt) 74 | set_target_properties(docopt_s PROPERTIES OUTPUT_NAME docopt) 75 | endif() 76 | 77 | if(USE_BOOST_REGEX) 78 | add_definitions("-DDOCTOPT_USE_BOOST_REGEX") 79 | # This is needed on Linux, where linking a static library into docopt.so 80 | # fails because boost static libs are not compiled with -fPIC 81 | set(Boost_USE_STATIC_LIBS OFF) 82 | find_package(Boost 1.53 REQUIRED COMPONENTS regex) 83 | include_directories(${Boost_INCLUDE_DIRS}) 84 | target_link_libraries(docopt ${Boost_LIBRARIES}) 85 | if(WITH_STATIC) 86 | target_link_libraries(docopt_s ${Boost_LIBRARIES}) 87 | endif() 88 | endif() 89 | 90 | #============================================================================ 91 | # Examples 92 | #============================================================================ 93 | if(WITH_EXAMPLE) 94 | add_executable(docopt_example examples/naval_fate.cpp) 95 | target_link_libraries(docopt_example docopt) 96 | endif() 97 | 98 | #============================================================================ 99 | # Tests 100 | #============================================================================ 101 | if(WITH_TESTS) 102 | set(TESTPROG "${CMAKE_CURRENT_BINARY_DIR}/run_testcase") 103 | set(TESTCASES "${PROJECT_SOURCE_DIR}/testcases.docopt") 104 | add_executable(run_testcase run_testcase.cpp) 105 | target_link_libraries(run_testcase docopt) 106 | configure_file( 107 | "${PROJECT_SOURCE_DIR}/run_tests.py" 108 | "${CMAKE_CURRENT_BINARY_DIR}/run_tests" 109 | ESCAPE_QUOTES 110 | ) 111 | add_test("Testcases docopt" ${TESTPROG}) 112 | endif() 113 | 114 | #============================================================================ 115 | # Install 116 | #============================================================================ 117 | set(export_name "docopt-targets") 118 | 119 | # Runtime package 120 | install(TARGETS docopt EXPORT ${export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR}) 121 | 122 | # Development package 123 | install(TARGETS docopt_s EXPORT ${export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR}) 124 | install(FILES ${docopt_HEADERS} DESTINATION include/docopt) 125 | 126 | # CMake Package 127 | include(CMakePackageConfigHelpers) 128 | write_basic_package_version_file("${PROJECT_BINARY_DIR}/docopt-config-version.cmake" COMPATIBILITY SameMajorVersion) 129 | install(FILES docopt-config.cmake ${PROJECT_BINARY_DIR}/docopt-config-version.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") 130 | install(EXPORT ${export_name} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") 131 | 132 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docopt.pc.in ${CMAKE_CURRENT_BINARY_DIR}/docopt.pc @ONLY) 133 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/docopt.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) 134 | 135 | #============================================================================ 136 | # CPack 137 | #============================================================================ 138 | set(CPACK_PACKAGE_NAME "docopt") 139 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "") 140 | set(CPACK_RPM_PACKAGE_REQUIRES "") 141 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Beautiful command line interfaces") 142 | set(CPACK_PACKAGE_VENDOR "Jared Grubb") 143 | set(CPACK_PACKAGE_CONTACT ${CPACK_PACKAGE_VENDOR}) 144 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.rst") 145 | set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE-MIT") 146 | set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) 147 | set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) 148 | set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) 149 | set(CPACK_DEBIAN_PACKAGE_SECTION "Development") 150 | set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") 151 | set(CPACK_RPM_PACKAGE_LICENSE "MIT") 152 | set(CPACK_STRIP_FILES TRUE) 153 | include(CPack) 154 | -------------------------------------------------------------------------------- /docopt/LICENSE-Boost-1.0: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /docopt/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Vladimir Keleshev, 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software 6 | without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to 9 | whom the Software is furnished to do so, subject to the 10 | following conditions: 11 | 12 | The above copyright notice and this permission notice shall 13 | be included in all copies or substantial portions of the 14 | Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /docopt/docopt.h: -------------------------------------------------------------------------------- 1 | // 2 | // docopt.h 3 | // docopt 4 | // 5 | // Created by Jared Grubb on 2013-11-03. 6 | // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 | // 8 | 9 | #ifndef docopt__docopt_h_ 10 | #define docopt__docopt_h_ 11 | 12 | #include "docopt_value.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef DOCOPT_HEADER_ONLY 20 | #define DOCOPT_INLINE inline 21 | #define DOCOPT_API 22 | #else 23 | #define DOCOPT_INLINE 24 | 25 | // With Microsoft Visual Studio, export certain symbols so they 26 | // are available to users of docopt.dll (shared library). The DOCOPT_DLL 27 | // macro should be defined if building a DLL (with Visual Studio), 28 | // and by clients using the DLL. The CMakeLists.txt and the 29 | // docopt-config.cmake it generates handle this. 30 | #ifdef DOCOPT_DLL 31 | // Whoever is *building* the DLL should define DOCOPT_EXPORTS. 32 | // The CMakeLists.txt that comes with docopt does this. 33 | // Clients of docopt.dll should NOT define DOCOPT_EXPORTS. 34 | #ifdef DOCOPT_EXPORTS 35 | #define DOCOPT_API __declspec(dllexport) 36 | #else 37 | #define DOCOPT_API __declspec(dllimport) 38 | #endif 39 | #else 40 | #define DOCOPT_API 41 | #endif 42 | #endif 43 | 44 | namespace docopt { 45 | 46 | // Usage string could not be parsed (ie, the developer did something wrong) 47 | struct DocoptLanguageError : std::runtime_error { using runtime_error::runtime_error; }; 48 | 49 | // Arguments passed by user were incorrect (ie, developer was good, user is wrong) 50 | struct DocoptArgumentError : std::runtime_error { using runtime_error::runtime_error; }; 51 | 52 | // Arguments contained '--help' and parsing was aborted early 53 | struct DocoptExitHelp : std::runtime_error { DocoptExitHelp() : std::runtime_error("Docopt --help argument encountered"){} }; 54 | 55 | // Arguments contained '--version' and parsing was aborted early 56 | struct DocoptExitVersion : std::runtime_error { DocoptExitVersion() : std::runtime_error("Docopt --version argument encountered") {} }; 57 | 58 | /// A map of options set by the user 59 | using Options = std::map; 60 | 61 | /// Parse user options from the given option string. 62 | /// 63 | /// @param doc The usage string 64 | /// @param argv The user-supplied arguments 65 | /// @param help Whether to end early if '-h' or '--help' is in the argv 66 | /// @param version Whether to end early if '--version' is in the argv 67 | /// @param options_first Whether options must precede all args (true), or if args and options 68 | /// can be arbitrarily mixed. 69 | /// 70 | /// @throws DocoptLanguageError if the doc usage string had errors itself 71 | /// @throws DocoptExitHelp if 'help' is true and the user has passed the '--help' argument 72 | /// @throws DocoptExitVersion if 'version' is true and the user has passed the '--version' argument 73 | /// @throws DocoptArgumentError if the user's argv did not match the usage patterns 74 | Options DOCOPT_API docopt_parse(std::string const& doc, 75 | std::vector const& argv, 76 | bool help = true, 77 | bool version = true, 78 | bool options_first = false); 79 | 80 | /// Parse user options from the given string, and exit appropriately 81 | /// 82 | /// Calls 'docopt_parse' and will terminate the program if any of the exceptions above occur: 83 | /// * DocoptLanguageError - print error and terminate (with exit code -1) 84 | /// * DocoptExitHelp - print usage string and terminate (with exit code 0) 85 | /// * DocoptExitVersion - print version and terminate (with exit code 0) 86 | /// * DocoptArgumentError - print error and usage string and terminate (with exit code -1) 87 | Options DOCOPT_API docopt(std::string const& doc, 88 | std::vector const& argv, 89 | bool help = true, 90 | std::string const& version = {}, 91 | bool options_first = false) noexcept; 92 | } 93 | 94 | #ifdef DOCOPT_HEADER_ONLY 95 | #include "docopt.cpp" 96 | #endif 97 | 98 | #endif /* defined(docopt__docopt_h_) */ 99 | -------------------------------------------------------------------------------- /docopt/docopt.pc.in: -------------------------------------------------------------------------------- 1 | libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@ 2 | includedir=@CMAKE_INSTALL_PREFIX@/include/docopt 3 | 4 | Name: docopt.cpp 5 | Description: C++11 port of docopt 6 | Version: @PROJECT_VERSION@ 7 | Requires: 8 | Libs: -L${libdir} -ldocopt 9 | Cflags: -I${includedir} 10 | -------------------------------------------------------------------------------- /docopt/docopt_util.h: -------------------------------------------------------------------------------- 1 | // 2 | // docopt_util.h 3 | // docopt 4 | // 5 | // Created by Jared Grubb on 2013-11-04. 6 | // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 | // 8 | 9 | #ifndef docopt_docopt_util_h 10 | #define docopt_docopt_util_h 11 | 12 | #if DOCTOPT_USE_BOOST_REGEX 13 | #include 14 | namespace std { 15 | using boost::regex; 16 | using boost::sregex_token_iterator; 17 | } 18 | #else 19 | #include 20 | #endif 21 | 22 | #if 0 23 | #pragma mark - 24 | #pragma mark General utility 25 | #endif 26 | 27 | namespace { 28 | bool starts_with(std::string const& str, std::string const& prefix) 29 | { 30 | if (str.length() < prefix.length()) 31 | return false; 32 | return std::equal(prefix.begin(), prefix.end(), 33 | str.begin()); 34 | } 35 | 36 | std::string trim(std::string&& str, 37 | const std::string& whitespace = " \t\n") 38 | { 39 | const auto strEnd = str.find_last_not_of(whitespace); 40 | if (strEnd==std::string::npos) 41 | return {}; // no content 42 | str.erase(strEnd+1); 43 | 44 | const auto strBegin = str.find_first_not_of(whitespace); 45 | str.erase(0, strBegin); 46 | 47 | return std::move(str); 48 | } 49 | 50 | std::vector split(std::string const& str, size_t pos = 0) 51 | { 52 | const char* const anySpace = " \t\r\n\v\f"; 53 | 54 | std::vector ret; 55 | while (pos != std::string::npos) { 56 | auto start = str.find_first_not_of(anySpace, pos); 57 | if (start == std::string::npos) break; 58 | 59 | auto end = str.find_first_of(anySpace, start); 60 | auto size = end==std::string::npos ? end : end-start; 61 | ret.emplace_back(str.substr(start, size)); 62 | 63 | pos = end; 64 | } 65 | 66 | return ret; 67 | } 68 | 69 | std::tuple partition(std::string str, std::string const& point) 70 | { 71 | std::tuple ret; 72 | 73 | auto i = str.find(point); 74 | 75 | if (i == std::string::npos) { 76 | // no match: string goes in 0th spot only 77 | } else { 78 | std::get<2>(ret) = str.substr(i + point.size()); 79 | std::get<1>(ret) = point; 80 | str.resize(i); 81 | } 82 | std::get<0>(ret) = std::move(str); 83 | 84 | return ret; 85 | } 86 | 87 | template 88 | std::string join(I iter, I end, std::string const& delim) { 89 | if (iter==end) 90 | return {}; 91 | 92 | std::string ret = *iter; 93 | for(++iter; iter!=end; ++iter) { 94 | ret.append(delim); 95 | ret.append(*iter); 96 | } 97 | return ret; 98 | } 99 | 100 | std::vector regex_split(std::string const& text, std::regex const& re) 101 | { 102 | std::vector ret; 103 | for (auto it = std::sregex_token_iterator(text.begin(), text.end(), re, -1); 104 | it != std::sregex_token_iterator(); 105 | ++it) { 106 | ret.emplace_back(*it); 107 | } 108 | return ret; 109 | } 110 | } 111 | 112 | namespace docopt { 113 | template 114 | inline void hash_combine(std::size_t& seed, T const& v) 115 | { 116 | // stolen from boost::hash_combine 117 | std::hash hasher; 118 | seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); 119 | } 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /docopt/docopt_value.h: -------------------------------------------------------------------------------- 1 | // 2 | // value.h 3 | // docopt 4 | // 5 | // Created by Jared Grubb on 2013-10-14. 6 | // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 | // 8 | 9 | #ifndef docopt__value_h_ 10 | #define docopt__value_h_ 11 | 12 | #include 13 | #include 14 | #include // std::hash 15 | #include 16 | #include 17 | 18 | namespace docopt { 19 | 20 | enum class Kind { 21 | Empty, 22 | Bool, 23 | Long, 24 | String, 25 | StringList 26 | }; 27 | 28 | /// A generic type to hold the various types that can be produced by docopt. 29 | /// 30 | /// This type can be one of: {bool, long, string, vector}, or empty. 31 | struct value { 32 | /// An empty value 33 | value() {} 34 | 35 | value(std::string); 36 | value(std::vector); 37 | 38 | explicit value(bool); 39 | explicit value(long); 40 | explicit value(int v) : value(static_cast(v)) {} 41 | 42 | ~value(); 43 | value(value const&); 44 | value(value&&) noexcept; 45 | value& operator=(value const&); 46 | value& operator=(value&&) noexcept; 47 | 48 | Kind kind() const { return kind_; } 49 | 50 | // Test if this object has any contents at all 51 | explicit operator bool() const { return kind_ != Kind::Empty; } 52 | 53 | // Test the type contained by this value object 54 | bool isBool() const { return kind_==Kind::Bool; } 55 | bool isString() const { return kind_==Kind::String; } 56 | bool isLong() const { return kind_==Kind::Long; } 57 | bool isStringList() const { return kind_==Kind::StringList; } 58 | 59 | // Throws std::invalid_argument if the type does not match 60 | bool asBool() const; 61 | long asLong() const; 62 | std::string const& asString() const; 63 | std::vector const& asStringList() const; 64 | 65 | size_t hash() const noexcept; 66 | 67 | friend bool operator==(value const&, value const&); 68 | friend bool operator!=(value const&, value const&); 69 | 70 | private: 71 | union Variant { 72 | Variant() {} 73 | ~Variant() { /* do nothing; will be destroyed by ~value */ } 74 | 75 | bool boolValue; 76 | long longValue; 77 | std::string strValue; 78 | std::vector strList; 79 | }; 80 | 81 | static const char* kindAsString(Kind kind) { 82 | switch (kind) { 83 | case Kind::Empty: return "empty"; 84 | case Kind::Bool: return "bool"; 85 | case Kind::Long: return "long"; 86 | case Kind::String: return "string"; 87 | case Kind::StringList: return "string-list"; 88 | } 89 | return "unknown"; 90 | } 91 | 92 | void throwIfNotKind(Kind expected) const { 93 | if (kind_ == expected) 94 | return; 95 | 96 | std::string error = "Illegal cast to "; 97 | error += kindAsString(expected); 98 | error += "; type is actually "; 99 | error += kindAsString(kind_); 100 | throw std::runtime_error(std::move(error)); 101 | } 102 | 103 | Kind kind_ = Kind::Empty; 104 | Variant variant_ {}; 105 | }; 106 | 107 | /// Write out the contents to the ostream 108 | std::ostream& operator<<(std::ostream&, value const&); 109 | } 110 | 111 | namespace std { 112 | template <> 113 | struct hash { 114 | size_t operator()(docopt::value const& val) const noexcept { 115 | return val.hash(); 116 | } 117 | }; 118 | } 119 | 120 | namespace docopt { 121 | inline 122 | value::value(bool v) 123 | : kind_(Kind::Bool) 124 | { 125 | variant_.boolValue = v; 126 | } 127 | 128 | inline 129 | value::value(long v) 130 | : kind_(Kind::Long) 131 | { 132 | variant_.longValue = v; 133 | } 134 | 135 | inline 136 | value::value(std::string v) 137 | : kind_(Kind::String) 138 | { 139 | new (&variant_.strValue) std::string(std::move(v)); 140 | } 141 | 142 | inline 143 | value::value(std::vector v) 144 | : kind_(Kind::StringList) 145 | { 146 | new (&variant_.strList) std::vector(std::move(v)); 147 | } 148 | 149 | inline 150 | value::value(value const& other) 151 | : kind_(other.kind_) 152 | { 153 | switch (kind_) { 154 | case Kind::String: 155 | new (&variant_.strValue) std::string(other.variant_.strValue); 156 | break; 157 | 158 | case Kind::StringList: 159 | new (&variant_.strList) std::vector(other.variant_.strList); 160 | break; 161 | 162 | case Kind::Bool: 163 | variant_.boolValue = other.variant_.boolValue; 164 | break; 165 | 166 | case Kind::Long: 167 | variant_.longValue = other.variant_.longValue; 168 | break; 169 | 170 | case Kind::Empty: 171 | default: 172 | break; 173 | } 174 | } 175 | 176 | inline 177 | value::value(value&& other) noexcept 178 | : kind_(other.kind_) 179 | { 180 | switch (kind_) { 181 | case Kind::String: 182 | new (&variant_.strValue) std::string(std::move(other.variant_.strValue)); 183 | break; 184 | 185 | case Kind::StringList: 186 | new (&variant_.strList) std::vector(std::move(other.variant_.strList)); 187 | break; 188 | 189 | case Kind::Bool: 190 | variant_.boolValue = other.variant_.boolValue; 191 | break; 192 | 193 | case Kind::Long: 194 | variant_.longValue = other.variant_.longValue; 195 | break; 196 | 197 | case Kind::Empty: 198 | default: 199 | break; 200 | } 201 | } 202 | 203 | inline 204 | value::~value() 205 | { 206 | switch (kind_) { 207 | case Kind::String: 208 | variant_.strValue.~basic_string(); 209 | break; 210 | 211 | case Kind::StringList: 212 | variant_.strList.~vector(); 213 | break; 214 | 215 | case Kind::Empty: 216 | case Kind::Bool: 217 | case Kind::Long: 218 | default: 219 | // trivial dtor 220 | break; 221 | } 222 | } 223 | 224 | inline 225 | value& value::operator=(value const& other) { 226 | // make a copy and move from it; way easier. 227 | return *this = value{other}; 228 | } 229 | 230 | inline 231 | value& value::operator=(value&& other) noexcept { 232 | // move of all the types involved is noexcept, so we dont have to worry about 233 | // these two statements throwing, which gives us a consistency guarantee. 234 | this->~value(); 235 | new (this) value(std::move(other)); 236 | 237 | return *this; 238 | } 239 | 240 | template 241 | void hash_combine(std::size_t& seed, const T& v); 242 | 243 | inline 244 | size_t value::hash() const noexcept 245 | { 246 | switch (kind_) { 247 | case Kind::String: 248 | return std::hash()(variant_.strValue); 249 | 250 | case Kind::StringList: { 251 | size_t seed = std::hash()(variant_.strList.size()); 252 | for(auto const& str : variant_.strList) { 253 | hash_combine(seed, str); 254 | } 255 | return seed; 256 | } 257 | 258 | case Kind::Bool: 259 | return std::hash()(variant_.boolValue); 260 | 261 | case Kind::Long: 262 | return std::hash()(variant_.longValue); 263 | 264 | case Kind::Empty: 265 | default: 266 | return std::hash()(nullptr); 267 | } 268 | } 269 | 270 | inline 271 | bool value::asBool() const 272 | { 273 | throwIfNotKind(Kind::Bool); 274 | return variant_.boolValue; 275 | } 276 | 277 | inline 278 | long value::asLong() const 279 | { 280 | // Attempt to convert a string to a long 281 | if (kind_ == Kind::String) { 282 | const std::string& str = variant_.strValue; 283 | std::size_t pos; 284 | const long ret = stol(str, &pos); // Throws if it can't convert 285 | if (pos != str.length()) { 286 | // The string ended in non-digits. 287 | throw std::runtime_error( str + " contains non-numeric characters."); 288 | } 289 | return ret; 290 | } 291 | throwIfNotKind(Kind::Long); 292 | return variant_.longValue; 293 | } 294 | 295 | inline 296 | std::string const& value::asString() const 297 | { 298 | throwIfNotKind(Kind::String); 299 | return variant_.strValue; 300 | } 301 | 302 | inline 303 | std::vector const& value::asStringList() const 304 | { 305 | throwIfNotKind(Kind::StringList); 306 | return variant_.strList; 307 | } 308 | 309 | inline 310 | bool operator==(value const& v1, value const& v2) 311 | { 312 | if (v1.kind_ != v2.kind_) 313 | return false; 314 | 315 | switch (v1.kind_) { 316 | case Kind::String: 317 | return v1.variant_.strValue==v2.variant_.strValue; 318 | 319 | case Kind::StringList: 320 | return v1.variant_.strList==v2.variant_.strList; 321 | 322 | case Kind::Bool: 323 | return v1.variant_.boolValue==v2.variant_.boolValue; 324 | 325 | case Kind::Long: 326 | return v1.variant_.longValue==v2.variant_.longValue; 327 | 328 | case Kind::Empty: 329 | default: 330 | return true; 331 | } 332 | } 333 | 334 | inline 335 | bool operator!=(value const& v1, value const& v2) 336 | { 337 | return !(v1 == v2); 338 | } 339 | } 340 | 341 | #endif /* defined(docopt__value_h_) */ 342 | -------------------------------------------------------------------------------- /docopt/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // docopt 4 | // 5 | // Created by Jared Grubb on 2013-10-03. 6 | // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 | // 8 | 9 | #include "docopt.h" 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | 14 | return 0; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /docopt/run_testcase.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // docopt_tests.cpp 3 | // docopt 4 | // 5 | // Created by Jared Grubb on 2013-11-03. 6 | // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 | // 8 | 9 | #include "docopt.h" 10 | 11 | #include 12 | 13 | int main(int argc, const char** argv) 14 | { 15 | if (argc < 2) { 16 | std::cerr << "Usage: docopt_tests USAGE [arg]..." << std::endl; 17 | exit(-5); 18 | } 19 | 20 | std::string usage = argv[1]; 21 | std::vector args {argv+2, argv+argc}; 22 | 23 | auto result = docopt::docopt(usage, args); 24 | 25 | // print it out in JSON form 26 | std::cout << "{ "; 27 | bool first = true; 28 | for(auto const& arg : result) { 29 | if (first) { 30 | first = false; 31 | } else { 32 | std::cout << "," << std::endl; 33 | } 34 | 35 | std::cout << '"' << arg.first << '"' << ": " << arg.second; 36 | } 37 | std::cout << " }" << std::endl; 38 | 39 | return 0; 40 | } -------------------------------------------------------------------------------- /docopt/run_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import re 4 | import sys 5 | import json 6 | import subprocess 7 | 8 | executable = "${TESTPROG}" 9 | 10 | def parse_test(raw): 11 | raw = re.compile('#.*$', re.M).sub('', raw).strip() 12 | if raw.startswith('"""'): 13 | raw = raw[3:] 14 | 15 | for fixture in raw.split('r"""'): 16 | name = '' 17 | doc, _, body = fixture.partition('"""') 18 | cases = [] 19 | for case in body.split('$')[1:]: 20 | argv, _, expect = case.strip().partition('\n') 21 | expect = json.loads(expect) 22 | prog, _, argv = argv.strip().partition(' ') 23 | cases.append((prog, argv, expect)) 24 | 25 | yield name, doc, cases 26 | 27 | failures = 0 28 | passes = 0 29 | 30 | tests = open('${TESTCASES}','r').read() 31 | for _, doc, cases in parse_test(tests): 32 | if not cases: continue 33 | 34 | for prog, argv, expect in cases: 35 | args = [ x for x in argv.split() if x ] 36 | 37 | expect_error = not isinstance(expect, dict) 38 | 39 | error = None 40 | out = None 41 | try: 42 | out = subprocess.check_output([executable, doc]+args, stderr=subprocess.STDOUT) 43 | if expect_error: 44 | error = " ** an error was expected but it appeared to succeed!" 45 | else: 46 | json_out = json.loads(out) 47 | if expect != json_out: 48 | error = " ** JSON does not match expected: %r" % expect 49 | except subprocess.CalledProcessError as e: 50 | if not expect_error: 51 | error = "\n ** this should have succeeded! exit code = %s" % e.returncode 52 | 53 | if not error: 54 | passes += 1 55 | continue 56 | 57 | failures += 1 58 | 59 | print "="*40 60 | print doc 61 | print ':'*20 62 | print prog, argv 63 | print '-'*20 64 | if out: 65 | print out 66 | print error 67 | 68 | if failures: 69 | print "%d failures" % failures 70 | sys.exit(1) 71 | else: 72 | print "PASS (%d)" % passes 73 | -------------------------------------------------------------------------------- /libRORPO/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # RORPO Lib 2 | cmake_minimum_required(VERSION 3.2) 3 | project(libRORPO) 4 | 5 | # FIND OPENMP 6 | find_package( OpenMP REQUIRED) 7 | if(OPENMP_FOUND) 8 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 10 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 11 | endif() 12 | 13 | # ADD FILES 14 | file(GLOB_RECURSE RORPO_HEADERS *.hpp *.h) 15 | file(GLOB_RECURSE RORPO_SOURCES *.c) 16 | 17 | add_library(RORPO ${LIB_TYPE} ${RORPO_SOURCES} ${RORPO_HEADERS}) 18 | 19 | install( FILES ${RORPO_HEADERS} DESTINATION include/libRORPO) 20 | install( TARGETS RORPO DESTINATION lib) 21 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/Algo.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | 32 | #ifndef ALGO_INCLUDED 33 | #define ALGO_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include "Image/Image.hpp" 40 | 41 | 42 | // Return the difference between images image1 and image2 43 | template 44 | const Image3D diff(const Image3D &image1, const Image3D &image2){ 45 | 46 | Image3D result(image1.dimX(), image1.dimY(), image1.dimZ()); 47 | 48 | if (image1.size() != image2.size()){ 49 | std::cout<<"Error Diff : Size of images are not the same."< 65 | int min_crush(Image3D &image1, const Image3D &image2) 66 | { 67 | if (image1.size() != image2.size()){ 68 | std::cout<<"Error in Algo.hpp (min_crush l 55): " 69 | <<"Size of images is not the same."< 83 | int max_crush(Image3D &image1, const Image3D &image2) 84 | { 85 | if (image1.size() != image2.size()){ 86 | std::cout<<"Error in Algo.hpp (max_crush l 76): " 87 | <<"Size of images is not the same."< 100 | void mask_image(Image3D &image, const Image3D &mask){ 101 | if (image.size() != mask.size()){ 102 | std::cout<<"Error in Algo.hpp (mask_image l 96): " 103 | <<"Size of image and mask is not the same."< 115 | float computeSTD(Iterator begin, Iterator end) 116 | { 117 | float mean = 0; 118 | int k = 0; 119 | for (auto i = begin; i != end; i++) { 120 | mean += i->first; 121 | k++; 122 | } 123 | mean /= k + 1; 124 | 125 | float std = 0; 126 | for (auto i = begin; i != end; i++) { 127 | std += pow(i->first - mean, 2); 128 | } 129 | std /= k + 1; 130 | std = sqrt(std); 131 | 132 | return std; 133 | } 134 | 135 | #endif // ALGO_INCLUDED 136 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/Geodilation.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | 32 | #ifndef GEODILATION_INCLUDED 33 | #define GEODILATION_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include "RORPO/pink/mcimage.h" 40 | #include "RORPO/pink/mccodimage.h" 41 | #include "RORPO/pink/lgeodesic.h" 42 | 43 | 44 | 45 | template 46 | Image3D geodilation(Image3D &G, Image3D &R, int connex, int niter) 47 | { 48 | Image3D geodilat(G.dimX(), G.dimY(), G.dimZ()); 49 | 50 | // Pink Images 51 | struct xvimage* imageG; 52 | struct xvimage* imageR; 53 | struct xvimage* temp; 54 | int32_t typepixel; 55 | 56 | if (sizeof(T)==1) 57 | typepixel = VFF_TYP_1_BYTE; 58 | else if (sizeof(T)==2) 59 | typepixel = VFF_TYP_2_BYTE; 60 | else if (sizeof(T)==4) 61 | typepixel = VFF_TYP_4_BYTE; 62 | else 63 | std::cerr<<"Error in Geodilation : ImageType not known"<image_data= G.get_pointer(); 67 | 68 | imageR=allocheader(NULL,G.dimX(),G.dimY(),G.dimZ(),typepixel); 69 | imageR->image_data= R.get_pointer(); 70 | 71 | temp=copyimage(imageG); 72 | 73 | lgeodilat(temp,imageR,connex,niter); 74 | 75 | for (int z = 0; zimage_data))[x 79 | + y * G.dimX() + z * G.dimX() * G.dimY()]; 80 | } 81 | } 82 | } 83 | 84 | free(imageR); 85 | free(imageG); 86 | free(temp); 87 | 88 | return geodilat; 89 | } 90 | 91 | #endif // GEODILATION_INCLUDED 92 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/PO.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | 31 | We used the Luengo Hendriks path opening algorithm presented in Fig2 of this paper: 32 | Luengo Hendriks, C.L., "Constrained and Dimensionality-Independent Path Openings," 33 | in Image Processing, IEEE Transactions on , vol.19, no.6, pp.1587-1595, June 2010 34 | doi: 10.1109/TIP.2010.2044959 35 | */ 36 | 37 | #ifndef PO_INCLUDED 38 | #define PO_INCLUDED 39 | 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #include "RORPO/pink/rect3dmm.hpp" 51 | #include "RORPO/sorting.hpp" 52 | #include "Image/Image.hpp" 53 | #include "RORPO/Algo.hpp" 54 | 55 | typedef long IndexType; 56 | 57 | 58 | void create_neighbourhood(int nb_col, 59 | int dim_frame, 60 | const std::vector & orientation, 61 | std::vector & upList, 62 | std::vector & downList) { 63 | 64 | int col_shift = orientation[0]; 65 | int line_shift = orientation[1]; 66 | int depth_shift = orientation[2]; 67 | 68 | //depth orientation [1 0 0] 69 | if((depth_shift == 1 && line_shift == 0 && col_shift == 0) || 70 | (depth_shift == -1 && line_shift == 0 && col_shift == 0) ) { 71 | upList.push_back( dim_frame - nb_col - 1); 72 | upList.push_back( dim_frame - nb_col + 1); 73 | upList.push_back( dim_frame + nb_col -1 ); 74 | upList.push_back( dim_frame + nb_col + 1); 75 | 76 | upList.push_back( dim_frame - 1); 77 | upList.push_back( dim_frame - nb_col); 78 | upList.push_back( dim_frame + 1); 79 | upList.push_back( dim_frame + nb_col); 80 | upList.push_back( dim_frame ); 81 | 82 | downList.push_back( -dim_frame + nb_col + 1); 83 | downList.push_back( -dim_frame + nb_col - 1); 84 | downList.push_back( -dim_frame - nb_col + 1 ); 85 | downList.push_back( -dim_frame - nb_col - 1); 86 | 87 | downList.push_back( -dim_frame + 1); 88 | downList.push_back( -dim_frame + nb_col); 89 | downList.push_back( -dim_frame - 1); 90 | downList.push_back( -dim_frame - nb_col); 91 | downList.push_back( -dim_frame ); 92 | 93 | } 94 | //from up to down orientation [0 1 0] 95 | if((depth_shift == 0 && line_shift == 1 && col_shift == 0) || 96 | (depth_shift == 0 && line_shift == -1 && col_shift == 0)) { 97 | 98 | upList.push_back(dim_frame + nb_col - 1 ); 99 | upList.push_back(dim_frame + nb_col + 1); 100 | upList.push_back( -dim_frame + nb_col -1 ); 101 | upList.push_back( -dim_frame + nb_col + 1); 102 | 103 | 104 | upList.push_back(nb_col - 1); 105 | upList.push_back(dim_frame + nb_col); 106 | upList.push_back( nb_col + 1); 107 | upList.push_back( -dim_frame + nb_col); 108 | upList.push_back( nb_col ); 109 | 110 | downList.push_back(-dim_frame - nb_col + 1 ); 111 | downList.push_back(-dim_frame - nb_col - 1); 112 | downList.push_back( dim_frame - nb_col + 1 ); 113 | downList.push_back( dim_frame - nb_col - 1); 114 | 115 | downList.push_back(-nb_col + 1); 116 | downList.push_back(-dim_frame - nb_col); 117 | downList.push_back( -nb_col - 1); 118 | downList.push_back( dim_frame - nb_col); 119 | downList.push_back( -nb_col ); 120 | 121 | } 122 | //from left to right orientation [0 0 1] 123 | if((depth_shift == 0 && line_shift == 0 && col_shift == 1) || 124 | (depth_shift == 0 && line_shift == 0 && col_shift == -1)) { 125 | 126 | upList.push_back(-nb_col +1 - dim_frame); 127 | upList.push_back(-nb_col +1 + dim_frame); 128 | upList.push_back(nb_col +1 - dim_frame); 129 | upList.push_back( nb_col +1 + dim_frame); 130 | 131 | upList.push_back(dim_frame + 1); 132 | upList.push_back(-nb_col + 1); 133 | upList.push_back(-dim_frame + 1); 134 | upList.push_back( nb_col + 1); 135 | upList.push_back( 1 ); 136 | 137 | downList.push_back(nb_col -1 + dim_frame); 138 | downList.push_back(nb_col -1 - dim_frame); 139 | downList.push_back(-nb_col -1 + dim_frame); 140 | downList.push_back( -nb_col -1 - dim_frame); 141 | 142 | downList.push_back(-dim_frame - 1); 143 | downList.push_back(nb_col - 1); 144 | downList.push_back(dim_frame - 1); 145 | downList.push_back( -nb_col - 1); 146 | downList.push_back( -1 ); 147 | 148 | } 149 | //1st diagonal [1 1 1] 150 | if((depth_shift == 1 && line_shift == 1 && col_shift == 1) || 151 | (depth_shift == -1 && line_shift == -1 && col_shift == -1)) { 152 | 153 | upList.push_back(1); 154 | upList.push_back(dim_frame); 155 | upList.push_back(nb_col); 156 | 157 | upList.push_back(dim_frame + nb_col); 158 | upList.push_back(nb_col + 1); 159 | upList.push_back(dim_frame + 1 ); 160 | //main direction 161 | upList.push_back(dim_frame + nb_col + 1); 162 | 163 | downList.push_back(-1); 164 | downList.push_back(-dim_frame); 165 | downList.push_back(-nb_col); 166 | 167 | downList.push_back( -dim_frame - nb_col); 168 | downList.push_back( -nb_col - 1); 169 | downList.push_back( -dim_frame - 1 ); 170 | 171 | //main direction 172 | downList.push_back(-dim_frame - nb_col - 1); 173 | 174 | } 175 | //2nd diagonal [1 1 -1] 176 | if((depth_shift == 1 && line_shift == 1 && col_shift == -1) || 177 | (depth_shift == -1 && line_shift == -1 && col_shift == 1)) { 178 | 179 | upList.push_back(-1); 180 | upList.push_back(dim_frame); 181 | upList.push_back(nb_col); 182 | 183 | upList.push_back(dim_frame + nb_col); 184 | upList.push_back(nb_col - 1); 185 | upList.push_back(dim_frame - 1); 186 | 187 | //main direction 188 | upList.push_back( dim_frame + nb_col - 1 ); 189 | 190 | downList.push_back( 1 ); 191 | downList.push_back( -dim_frame ); 192 | downList.push_back(-nb_col); 193 | 194 | downList.push_back(-dim_frame - nb_col); 195 | downList.push_back(-nb_col +1); 196 | downList.push_back(-dim_frame + 1 ); 197 | 198 | //main direction 199 | downList.push_back( -dim_frame - nb_col + 1 ); 200 | 201 | } 202 | //3rd diagonal [-1 1 1] 203 | if((depth_shift == -1 && line_shift == 1 && col_shift == 1) || 204 | (depth_shift == 1 && line_shift == -1 && col_shift == -1)) { 205 | 206 | upList.push_back( 1 ); 207 | upList.push_back( -dim_frame ); 208 | upList.push_back(nb_col); 209 | 210 | upList.push_back(-dim_frame + nb_col); 211 | upList.push_back( nb_col + 1); 212 | upList.push_back( -dim_frame + 1 ); 213 | 214 | //main direction 215 | upList.push_back( -dim_frame + nb_col + 1 ); 216 | 217 | downList.push_back( -1 ); 218 | downList.push_back( dim_frame ); 219 | downList.push_back(-nb_col); 220 | 221 | downList.push_back(dim_frame - nb_col); 222 | downList.push_back( -nb_col -1); 223 | downList.push_back( dim_frame - 1 ); 224 | 225 | //main direction 226 | downList.push_back( dim_frame - nb_col -1 ); 227 | 228 | } 229 | //4th diagonal [-1 1 -1] 230 | if((depth_shift == -1 && line_shift == 1 && col_shift == -1) || 231 | (depth_shift == 1 && line_shift == -1 && col_shift == 1)) { 232 | 233 | upList.push_back( -1 ); 234 | upList.push_back( -dim_frame ); 235 | upList.push_back(nb_col); 236 | 237 | upList.push_back(-dim_frame + nb_col); 238 | upList.push_back( nb_col - 1); 239 | upList.push_back( -dim_frame - 1 ); 240 | 241 | //main direction 242 | upList.push_back( -dim_frame + nb_col - 1 ); 243 | 244 | downList.push_back( 1 ); 245 | downList.push_back( dim_frame ); 246 | downList.push_back(-nb_col); 247 | 248 | downList.push_back(dim_frame - nb_col); 249 | downList.push_back( -nb_col + 1); 250 | downList.push_back( dim_frame + 1 ); 251 | 252 | //main direction 253 | downList.push_back( dim_frame - nb_col + 1 ); 254 | 255 | } 256 | 257 | } 258 | 259 | 260 | template 261 | void propagate(IndexType p, std::vector&lambda, std::vector&nf, 262 | std::vector&nb, std::vector&b, 263 | std::queue &Qc) 264 | 265 | // Propagation from pixel p 266 | { 267 | std::queue Qq; 268 | lambda[p]=0; 269 | 270 | std::vector::iterator it; 271 | for (it=nf.begin(); it!=nf.end();++it) 272 | { 273 | if ((p+*it) 306 | void PO_3D(const Image3D &image, 307 | int L, 308 | std::vector &index_image, 309 | const std::vector &orientations, 310 | Image3D &Output, 311 | std::vector b) 312 | 313 | { 314 | 315 | // Create the offset np and nm 316 | std::vectornp; 317 | std::vectornm; 318 | create_neighbourhood(image.dimX(), image.dimX() * image.dimY(), 319 | orientations, np, nm); 320 | 321 | //Create other temporary images 322 | std::vectorLp(image.size(), L); 323 | std::vectorLm(image.size(), L); 324 | 325 | //Create FIFO queue Qc 326 | std::queue Qc; 327 | 328 | // Propagate 329 | std::vector::iterator it; 330 | int indice; 331 | for (it = index_image.begin(), indice = 0 ; it != index_image.end() ; 332 | ++it , ++indice) 333 | { 334 | if (b[*it]) 335 | { 336 | propagate(*it, Lm, np, nm, b, Qc); 337 | propagate(*it, Lp, nm, np, b, Qc); 338 | 339 | while (! Qc.empty()) 340 | { 341 | IndexType q = Qc.front(); 342 | Qc.pop(); 343 | if (Lp[q] + Lm[q]-1 < L) 344 | { 345 | Output.get_data()[q] = Output.get_data()[*it]; 346 | b[q] = 0; 347 | Lp[q] = 0; 348 | Lm[q] = 0; 349 | } 350 | } 351 | } 352 | } 353 | } 354 | 355 | 356 | #endif // PO_INCLUDED 357 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/RORPO.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | #ifndef RORPO_INCLUDED 32 | #define RORPO_INCLUDED 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "RORPO/sorting.hpp" 46 | #include "RORPO/Algo.hpp" 47 | #include "RORPO/Geodilation.hpp" 48 | #include "RORPO/RPO.hpp" 49 | 50 | 51 | template 52 | Image3D RORPO(const Image3D &image, int L, int nbCores, int dilationSize, Image3D &mask, std::shared_ptr> directions = nullptr) { 53 | 54 | // ############################# RPO ###################################### 55 | 56 | // the 7 RPO images with a 2-pixel border 57 | Image3D RPO1(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 58 | Image3D RPO2(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 59 | Image3D RPO3(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 60 | Image3D RPO4(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 61 | Image3D RPO5(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 62 | Image3D RPO6(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 63 | Image3D RPO7(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 64 | 65 | auto orientationsRPO = RPO(image, L, RPO1, RPO2, RPO3, RPO4, RPO5, RPO6, RPO7, nbCores, dilationSize, mask); 66 | 67 | // ################### Limit Orientations Treatment ####################### 68 | 69 | // ------------------------- Computation of Imin -------------------------- 70 | 71 | // ---- Imin limit case 4 orientations ---- 72 | 73 | Image3D Imin4(image.dimX(), image.dimY(), image.dimZ()); 74 | 75 | //6 combinations for pattern 1 76 | //c1: horizontal + vertical + diag1 + diag4 77 | Image3D Imin4_1 = RPO1.copy_image(); 78 | min_crush(Imin4_1, RPO2); 79 | min_crush(Imin4_1, RPO4); 80 | min_crush(Imin4_1, RPO7); 81 | max_crush(Imin4, Imin4_1); 82 | Imin4_1.clear_image(); 83 | 84 | //c2: horizontal + vertical + diag2 + diag3 85 | Image3D Imin4_2 = RPO1.copy_image(); 86 | min_crush(Imin4_2, RPO2); 87 | min_crush(Imin4_2, RPO5); 88 | min_crush(Imin4_2, RPO6); 89 | max_crush(Imin4, Imin4_2); 90 | Imin4_2.clear_image(); 91 | 92 | //c3: horizontal + profondeur + diag2+ diag4 93 | Image3D Imin4_3 = RPO1.copy_image(); 94 | min_crush(Imin4_3, RPO3); 95 | min_crush(Imin4_3, RPO5); 96 | min_crush(Imin4_3, RPO7); 97 | max_crush(Imin4, Imin4_3); 98 | Imin4_3.clear_image(); 99 | 100 | //c4: horizontal + profondeur + diag1+ diag3 101 | Image3D Imin4_4 = RPO1.copy_image(); 102 | min_crush(Imin4_4, RPO3); 103 | min_crush(Imin4_4, RPO4); 104 | min_crush(Imin4_4, RPO6); 105 | max_crush(Imin4, Imin4_4); 106 | Imin4_4.clear_image(); 107 | 108 | //c5: vertical + profondeur + diag3+ diag4 109 | Image3D Imin4_5 = RPO2.copy_image(); 110 | min_crush(Imin4_5, RPO3); 111 | min_crush(Imin4_5, RPO6); 112 | min_crush(Imin4_5, RPO7); 113 | max_crush(Imin4, Imin4_5); 114 | Imin4_5.clear_image(); 115 | 116 | //c6: vertical + profondeur + diag1+ diag2 117 | Image3D Imin4_6 = RPO2.copy_image(); 118 | min_crush(Imin4_6, RPO3); 119 | min_crush(Imin4_6, RPO4); 120 | min_crush(Imin4_6, RPO5); 121 | max_crush(Imin4, Imin4_6); 122 | Imin4_6.clear_image(); 123 | 124 | //4 combinations for pattern 2 125 | //c7: horizontal + vertical + profondeur + diag1 126 | Image3D Imin4_7 = RPO1.copy_image(); 127 | min_crush(Imin4_7, RPO2); 128 | min_crush(Imin4_7, RPO3); 129 | min_crush(Imin4_7, RPO4); 130 | max_crush(Imin4, Imin4_7); 131 | Imin4_7.clear_image(); 132 | 133 | //c8: horizontal + vertical + profondeur + diag2 134 | Image3D Imin4_8 = RPO1.copy_image(); 135 | min_crush(Imin4_8, RPO2); 136 | min_crush(Imin4_8, RPO3); 137 | min_crush(Imin4_8, RPO5); 138 | max_crush(Imin4, Imin4_8); 139 | Imin4_8.clear_image(); 140 | 141 | //c9: horizontal + vertical + profondeur + diag3 142 | Image3D Imin4_9 = RPO1.copy_image(); 143 | min_crush(Imin4_9, RPO2); 144 | min_crush(Imin4_9, RPO3); 145 | min_crush(Imin4_9, RPO6); 146 | max_crush(Imin4, Imin4_9); 147 | Imin4_9.clear_image(); 148 | 149 | //c10: horizontal + vertical + profondeur + diag4 150 | Image3D Imin4_10 = RPO1.copy_image(); 151 | min_crush(Imin4_10, RPO2); 152 | min_crush(Imin4_10, RPO3); 153 | min_crush(Imin4_10, RPO7); 154 | max_crush(Imin4, Imin4_10); 155 | Imin4_10.clear_image(); 156 | 157 | // ---- Imin limit case 5 orientations ---- 158 | Image3D Imin5 = RPO4.copy_image(); 159 | min_crush(Imin5, RPO5); 160 | min_crush(Imin5, RPO6); 161 | min_crush(Imin5, RPO7); 162 | 163 | 164 | // ############### Sorting RPO orientations ################################ 165 | 166 | Image3D RPOt1 = RPO1.copy_image(); 167 | Image3D RPOt2 = RPO2.copy_image(); 168 | Image3D RPOt3 = RPO3.copy_image(); 169 | Image3D RPOt4 = RPO4.copy_image(); 170 | Image3D RPOt5 = RPO5.copy_image(); 171 | Image3D RPOt6 = RPO6.copy_image(); 172 | Image3D RPOt7 = RPO7.copy_image(); 173 | 174 | // Clear Images which are non useful anymore 175 | RPO1.clear_image(); 176 | RPO2.clear_image(); 177 | RPO3.clear_image(); 178 | RPO4.clear_image(); 179 | RPO5.clear_image(); 180 | RPO6.clear_image(); 181 | RPO7.clear_image(); 182 | 183 | // ######################## Compute directions ############################ 184 | 185 | // ------------------------ Pointwise Rank Filter ------------------------- 186 | 187 | if (directions) { 188 | for (size_t i = 0; i < orientationsRPO[0].size(); i++) { 189 | 190 | // Pointwise Rank Filter -------------------------------- 191 | std::vector> pixel{ 192 | std::make_pair(RPOt1(i), 0), 193 | std::make_pair(RPOt2(i), 1), 194 | std::make_pair(RPOt3(i), 2), 195 | std::make_pair(RPOt4(i), 3), 196 | std::make_pair(RPOt5(i), 4), 197 | std::make_pair(RPOt6(i), 5), 198 | std::make_pair(RPOt7(i), 6) 199 | }; 200 | 201 | std::sort(pixel.begin(), pixel.end(), 202 | [&](const auto& a, const auto& b) { 203 | return a.first > b.first; 204 | }); 205 | 206 | float stdMin = 99999999; 207 | int interestNb = 0; 208 | 209 | // Compute Std and find orientations of interest -------- 210 | for (size_t k = 0; k < 3; k++) { 211 | float stdP = computeSTD(pixel.begin(), pixel.begin() + k + 1); 212 | float stdO = computeSTD(pixel.begin() + k + 1, pixel.end()); 213 | 214 | float stdSum = stdP + stdO; 215 | 216 | if (stdSum < stdMin) { 217 | stdMin = stdSum; 218 | interestNb = k; 219 | } 220 | } 221 | 222 | std::array, 7> orientations = { 223 | std::vector{1, 0, 0},//1 224 | std::vector{0, 1, 0},//2 225 | std::vector{0, 0, 1},//3 226 | std::vector{1, 1, 1},//4 227 | std::vector{1, 1, -1},//5 228 | std::vector{-1, 1, 1},//6 229 | std::vector{-1, 1, -1},//7 230 | }; 231 | 232 | // Combine orientations of interest to find direction --- 233 | std::vector direction = orientations[pixel[0].second]; 234 | for (size_t j = 1; j <= interestNb; j++) { 235 | std::transform(direction.begin(), direction.end(), orientations[pixel[j].second].begin(), 236 | direction.begin(), std::plus()); 237 | } 238 | 239 | std::copy(direction.begin(), direction.end(), directions->begin() + i * 3); 240 | } 241 | } // directions 242 | 243 | // Pointwise rank filter 244 | std::vector> o_indices(RPOt1.size()); //orientation indices 245 | sorting(RPOt1, RPOt2, RPOt3, RPOt4, RPOt5, RPOt6, RPOt7, RPOt1.size(), o_indices); 246 | 247 | // Clear Images which are non useful anymore 248 | RPOt1.clear_image(); 249 | RPOt5.clear_image(); 250 | RPOt6.clear_image(); 251 | 252 | // Compute RORPO without limit orientations 253 | Image3D RORPO_res = diff(RPOt7, RPOt4); 254 | RPOt7.clear_image(); 255 | 256 | 257 | // ----------------------- Computation of Imin2 ---------------------------- 258 | //geodesic reconstruction of RPO6 in RPO4 259 | Image3D RPO6_geo = geodilation(RPOt2, RPOt4, 18, -1); 260 | RPOt2.clear_image(); 261 | 262 | //geodesic reconstruction of RPO5 in RPO4 263 | Image3D RPO5_geo = geodilation(RPOt3, RPOt4, 18, -1);; 264 | RPOt3.clear_image(); 265 | RPOt4.clear_image(); 266 | 267 | // ---- Imin2 limit case 4 orientations ---- 268 | Image3D Imin2_4 = Imin4.copy_image(); 269 | min_crush(Imin2_4, RPO5_geo); 270 | RPO5_geo.clear_image(); 271 | 272 | 273 | // ---- Imin2 limit case 5 orientations ---- 274 | Image3D Imin2_5 = Imin5.copy_image(); 275 | min_crush(Imin2_5, RPO6_geo); 276 | 277 | RPO6_geo.clear_image(); 278 | 279 | 280 | // --------------------------- Final Result -------------------------------- 281 | 282 | Image3D Diff_Imin4 = diff(Imin4, Imin2_4); 283 | Image3D Diff_Imin5 = diff(Imin5, Imin2_5); 284 | 285 | Imin4.clear_image(); 286 | Imin2_4.clear_image(); 287 | Imin5.clear_image(); 288 | Imin2_5.clear_image(); 289 | 290 | max_crush(RORPO_res, Diff_Imin4); 291 | max_crush(RORPO_res, Diff_Imin5); 292 | 293 | return RORPO_res; 294 | 295 | } 296 | 297 | #endif // RORPO_INCLUDED 298 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/RORPO_multiscale.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | 32 | #ifndef RORPO_MULTISCALE_INCLUDED 33 | #define RORPO_MULTISCALE_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "RORPO/pink/rect3dmm.hpp" 41 | #include "RORPO/RORPO.hpp" 42 | #include "RORPO/Algo.hpp" 43 | 44 | 45 | template 46 | Image3D RORPO_multiscale(const Image3D &I, 47 | const std::vector& S_list, 48 | int nb_core, 49 | int dilationSize, 50 | int debug_flag, 51 | Image3D &Mask) 52 | { 53 | 54 | // ################## Computation of RORPO for each scale ################## 55 | 56 | Image3D Multiscale(I.dimX(), I.dimY(), I.dimZ(),I.spacingX(),I.spacingY(),I.spacingZ(),I.originX(),I.originY(),I.originZ()); 57 | 58 | std::vector::const_iterator it; 59 | 60 | for (it=S_list.begin();it!=S_list.end();++it) 61 | { 62 | Image3D One_Scale = 63 | RORPO(I, *it, nb_core,dilationSize, Mask); 64 | 65 | // Max of scales 66 | max_crush(Multiscale, One_Scale); 67 | } 68 | 69 | // ----------------- Dynamic Enhancement --------------- 70 | // Find Max value of output_buffer 71 | int max_value_RORPO = Multiscale.max_value(); 72 | int max_value_I = I.max_value(); 73 | 74 | // Contrast Enhancement 75 | for ( auto& val : Multiscale.get_data() ) 76 | val = (PixelType)((val / (float)max_value_RORPO ) * max_value_I); 77 | 78 | min_crush(Multiscale, I); 79 | 80 | if (!Mask.empty()) // A mask image is given 81 | { 82 | // Application of the non dilated mask to output 83 | mask_image(Multiscale, Mask); 84 | } 85 | return Multiscale; 86 | } 87 | 88 | #endif // RORPO_MULTISCALE_INCLUDED 89 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/RPO.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | 32 | #ifndef RPO_INCLUDED 33 | #define RPO_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include "RORPO/sorting.hpp" 40 | #include "RORPO/pink/rect3dmm.hpp" 41 | 42 | 43 | #include "RORPO/Algo.hpp" 44 | #include "Image/Image.hpp" 45 | #include "RORPO/PO.hpp" 46 | 47 | #define OMP 48 | 49 | 50 | template 51 | void Stuff_PO(Image3D &dilatImageWithBorders, 52 | std::vector &index_image, 53 | int L, 54 | std::vector &b, 55 | Image3D &Mask){ 56 | 57 | 58 | // Sort the grey level intensity in a vector 59 | index_image = sort_image_value(dilatImageWithBorders.get_pointer(), 60 | dilatImageWithBorders.size()); 61 | 62 | 63 | int new_dimz = dilatImageWithBorders.dimZ(); 64 | int new_dimy = dilatImageWithBorders.dimY(); 65 | int new_dimx = dilatImageWithBorders.dimX(); 66 | 67 | // z = 0 68 | for (int y = 0; y < dilatImageWithBorders.dimY() ; ++y){ 69 | for (int x = 0 ; x < dilatImageWithBorders.dimX() ; ++x){ 70 | b[y*new_dimx+x] = 0; 71 | } 72 | } 73 | 74 | //z = dimz-1 75 | for (int y = 0; y < dilatImageWithBorders.dimY() ; ++y){ 76 | for (int x = 0 ; x < dilatImageWithBorders.dimX() ; ++x){ 77 | b[(new_dimz-1)*new_dimx*new_dimy+y*new_dimx+x] = 0; 78 | } 79 | } 80 | 81 | //x = 0 82 | for (int z = 0 ; z < dilatImageWithBorders.dimZ() ; ++z){ 83 | for (int y = 0 ; y < dilatImageWithBorders.dimY() ; ++y){ 84 | b[z*new_dimx*new_dimy+y*new_dimx] = 0; 85 | } 86 | } 87 | 88 | //x = dimx-1 89 | for (int z = 0 ; z < dilatImageWithBorders.dimZ() ; ++z){ 90 | for (int y = 0 ; y < dilatImageWithBorders.dimY() ; ++y){ 91 | b[z*new_dimx*new_dimy+y*new_dimx+new_dimx-1] = 0; 92 | } 93 | } 94 | 95 | // y = 0 96 | for (int z = 0 ; z < dilatImageWithBorders.dimZ(); ++z){ 97 | for (int x = 0 ; x < dilatImageWithBorders.dimX() ; ++x){ 98 | b[z*new_dimy*new_dimx+x] = 0; 99 | } 100 | } 101 | 102 | // y = dimy-1 103 | for (int z = 0 ; z < dilatImageWithBorders.dimZ() ; ++z){ 104 | for (int x = 0 ; x < dilatImageWithBorders.dimX() ; ++x){ 105 | b[z*new_dimy*new_dimx+(new_dimy-1)*new_dimx+x] = 0; 106 | } 107 | } 108 | 109 | 110 | // ############################ Mask treatment ############################# 111 | if (!Mask.empty()) 112 | { 113 | Image3D Mask_dilat = Mask.add_border(2); 114 | 115 | int r_dilat= L/2; 116 | 117 | // Mask dynamic [0 1] ==> [0 255] for the dilation 118 | int ind=0; 119 | for(int z = 0; z < Mask_dilat.dimZ(); ++z) { 120 | for(int y = 0 ; y < Mask_dilat.dimY(); ++y) { 121 | for(int x = 0; x < Mask_dilat.dimX(); ++x) { 122 | if (Mask_dilat(x,y,z) != 0){ 123 | Mask_dilat(x,y,z) = 255; 124 | ind += 1; 125 | } 126 | } 127 | } 128 | } 129 | 130 | // Dilation 131 | rect3dminmax(Mask_dilat.get_pointer(), Mask_dilat.dimX(), 132 | Mask_dilat.dimY(), Mask_dilat.dimZ(), 133 | r_dilat, r_dilat, r_dilat, false); 134 | 135 | ind = 0; 136 | for(int z = 0; z < Mask_dilat.dimZ(); ++z) { 137 | for(int y = 0 ; y < Mask_dilat.dimY(); ++y) { 138 | for(int x = 0; x < Mask_dilat.dimX(); ++x) { 139 | if (Mask_dilat(x,y,z) == 0){ 140 | b[z*new_dimy*new_dimx+y*new_dimx+x] = 0; 141 | ind += 1; 142 | } 143 | } 144 | } 145 | } 146 | } 147 | } 148 | 149 | 150 | template 151 | std::array, 7> RPO(const Image3D &image, int L, Image3D &RPO1, 152 | Image3D &RPO2, Image3D &RPO3, Image3D &RPO4, 153 | Image3D &RPO5, Image3D &RPO6, Image3D &RPO7, 154 | int nb_core, int dilationSize, Image3D &Mask) { 155 | 156 | Image3D *RPOs[7] = {&RPO1, &RPO2, &RPO3, &RPO4, &RPO5, &RPO6, &RPO7}; 157 | 158 | // #################### Definition of the orientations ######################### 159 | // orientation vector 160 | std::array, 7> orientations = { 161 | std::vector{1, 0, 0},//1 162 | std::vector{0, 1, 0},//2 163 | std::vector{0, 0, 1},//3 164 | std::vector{1, 1, 1},//4 165 | std::vector{1, 1, -1},//5 166 | std::vector{-1, 1, 1},//6 167 | std::vector{-1, 1, -1},//7 168 | }; 169 | 170 | // ################### Dilation + Add border on image ###################### 171 | 172 | // Dilatation 173 | Image3D imageDilat=image.copy_image(); 174 | 175 | rect3dminmax(imageDilat.get_pointer(), imageDilat.dimX(), imageDilat.dimY(), 176 | imageDilat.dimZ(), dilationSize, dilationSize, dilationSize, false); 177 | 178 | Image3D dilatImageWithBorders=imageDilat.add_border(2); 179 | imageDilat.clear_image(); 180 | 181 | for (auto rpo: RPOs) 182 | rpo->copy_image(dilatImageWithBorders); 183 | 184 | std::vector index_image; 185 | std::vectorb(dilatImageWithBorders.size(),1); 186 | 187 | Stuff_PO(dilatImageWithBorders, index_image, L, b, Mask); 188 | 189 | 190 | 191 | // ############################ COMPUTE PO ################################# 192 | 193 | 194 | std::cout<<"------- RPO computation with scale " <(dilatImageWithBorders, L, index_image, orientations[i], *RPOs[i], b); 208 | std::cout << "orientation" << i + 1 << " " 209 | << orientations[i][0] << " " 210 | << orientations[i][1] << " " 211 | << orientations[i][2] << " : passed" 212 | << std::endl; 213 | } 214 | } 215 | } 216 | } 217 | #endif 218 | 219 | std::cout<<"RPO computation completed"<remove_border(2); 228 | min_crush(*rpo, image); 229 | } 230 | return orientations; 231 | } 232 | 233 | #endif //RPO_INCLUDED 234 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/generic_macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: generic_macros.h 3 | * 4 | * Written by: Image Analysis Group staff, 5 | * CSIRO Mathematical and Information Sciences. 6 | * 7 | * Date: March 2001 8 | * 9 | * 10 | * CSIRO Mathematical and Information Sciences is the owner of all 11 | * copyright subsisting in the software contained in this file. It may 12 | * not be disclosed to, or used by, anyone without the prior approval 13 | * of the Chief, CSIRO Mathematical and Information Sciences. 14 | * 15 | */ 16 | 17 | #ifndef GENERIC_MACROS_H 18 | #define GENERIC_MACROS_H 19 | /* A macro for concatenating the function name,its suffix and the mask type */ 20 | 21 | #undef XCAT2 22 | #undef CAT2 23 | #define CAT2(A, B) A ## B 24 | #define XCAT2(A, B) CAT2(A, B) 25 | 26 | 27 | #undef XCAT3 28 | #undef CAT3 29 | #define CAT3(A,B,C) A ## B ## C 30 | #define XCAT3(A,B,C) CAT3(A,B,C) 31 | 32 | #undef XCAT4 33 | #undef CAT4 34 | #define CAT4(A,B,C,D) A ## B ## C ## D 35 | #define XCAT4(A,B,C,D) CAT4(A,B,C,D) 36 | 37 | /* A macro for mentioning a concatenated function name in error messages */ 38 | #undef STRINGIFY 39 | #undef XSTRINGIFY 40 | #define XSTRINGIFY(A) #A 41 | #define STRINGIFY(A) XSTRINGIFY(A) 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/genfmax.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: genfmin.c 3 | * 4 | Hugues Talbot 7 Dec 2010 5 | 6 | This software is an image processing library whose purpose is to be 7 | used primarily for research and teaching. 8 | 9 | This software is governed by the CeCILL license under French law and 10 | abiding by the rules of distribution of free software. You can use, 11 | modify and/ or redistribute the software under the terms of the CeCILL 12 | license as circulated by CEA, CNRS and INRIA at the following URL 13 | "http://www.cecill.info". 14 | 15 | As a counterpart to the access to the source code and rights to copy, 16 | modify and redistribute granted by the license, users are provided only 17 | with a limited warranty and the software's author, the holder of the 18 | economic rights, and the successive licensors have only limited 19 | liability. 20 | 21 | In this respect, the user's attention is drawn to the risks associated 22 | with loading, using, modifying and/or developing or reproducing the 23 | software by the user in light of its specific status of free software, 24 | that may mean that it is complicated to manipulate, and that also 25 | therefore means that it is reserved for developers and experienced 26 | professionals having in-depth computer knowledge. Users are therefore 27 | encouraged to load and test the software's suitability as regards their 28 | requirements in conditions enabling the security of their systems and/or 29 | data to be ensured and, more generally, to use and operate it in the 30 | same conditions as regards security. 31 | 32 | The fact that you are presently reading this means that you have had 33 | knowledge of the CeCILL license and that you accept its terms. 34 | * 35 | */ 36 | 37 | /* Ed breen wrote a first version of this 38 | * converted into a stand-alone C file by Hugues Talbot 13 Mar 1995 39 | * converted to pixtype-independent code by Annick Le Hegarat 24 Sep 2002 40 | */ 41 | 42 | #ifndef GENFMAX_HPP 43 | #define GENFMAX_HPP 44 | 45 | #include "liarp.h" 46 | 47 | 48 | template 49 | void genfmax(Type *f, 50 | Type *g, 51 | Type *h, 52 | long *p, 53 | unsigned int nx, unsigned int K) 54 | 55 | { 56 | /* ORIGINAL AUTHOR: Ed Breen 57 | ** DATE: May 4 1993 58 | ** 59 | ** f: input array. Where 1st member is *(f+p[0]) and 60 | 2nd member is = *(f+p[1]) etc. 61 | ** g: forward array 62 | ** h: backward array 63 | ** p: array of offsets 64 | ** nx: the number of elements in each array 65 | ** K: the extent of mask 66 | */ 67 | 68 | unsigned int i,j,k,r,r1; 69 | 70 | if (!(K%2)) /* enforce the odd extent */ 71 | K++; 72 | k = nx/K; 73 | r1 = nx%K; 74 | 75 | /* do forward array */ 76 | for(j=0;j>1)) { 88 | g--; 89 | for(i=0;i>1; 112 | g+=r; 113 | if(nx <= K) { 114 | r1 = nx - r - 1; 115 | for(i=0;i 48 | void genfmin(Type *f, 49 | Type *g, 50 | Type *h, 51 | long *p, 52 | unsigned int nx, unsigned int K) 53 | 54 | { 55 | /* ORIGINAL AUTHOR: Ed Breen 56 | ** DATE: May 4 1993 57 | ** 58 | ** f: input array. Where 1st member is *(f+p[0]) and 59 | 2nd member is = *(f+p[1]) etc. 60 | ** g: forward array 61 | ** h: backward array 62 | ** p: array of offsets 63 | ** nx: the number of elements in each array 64 | ** K: the extent of mask 65 | */ 66 | 67 | unsigned int i,j,k,r,r1; 68 | 69 | if (!(K%2)) /* enforce the odd extent */ 70 | K++; 71 | k = nx/K; 72 | r1 = nx%K; 73 | 74 | /* do forward array */ 75 | for(j=0;j>1)) { 87 | g--; 88 | for(i=0;i>1; 111 | g+=r; 112 | if(nx <= K) { 113 | r1 = nx - r - 1; 114 | for(i=0;i(b)?(b):(a)) 24 | #endif 25 | 26 | 27 | #include "generic_macros.h" 28 | 29 | /* pixel types */ 30 | 31 | #ifndef PIX_TYPE 32 | #define PIX_TYPE unsigned char 33 | #define PIX_TYPE_MAX 0xFF 34 | #define PIX_TYPE_MIN 0 35 | #endif 36 | 37 | #ifndef UINT1_TYPE 38 | #define UINT1_TYPE unsigned char 39 | #define UINT1_TYPE_MAX 0xff 40 | #define UINT1_TYPE_MIN 0 41 | #endif 42 | 43 | #ifndef CHAR_TYPE 44 | #define INT1_TYPE char 45 | #define INT1_TYPE_MAX 127 46 | #define INT1_TYPE_MIN -127 47 | #endif 48 | 49 | #ifndef INT1_TYPE 50 | #define INT1_TYPE char 51 | #define INT1_TYPE_MAX 127 52 | #define INT1_TYPE_MIN -127 53 | #endif 54 | 55 | #ifndef INT2_TYPE 56 | #define INT2_TYPE short 57 | #define INT2_TYPE_MAX 32767 58 | #define INT2_TYPE_MIN -32767 59 | #endif 60 | 61 | #ifndef UINT2_TYPE 62 | #define UINT2_TYPE unsigned short 63 | #define UINT2_TYPE_MAX 65535 64 | #define UINT2_TYPE_MIN 0 65 | #endif 66 | 67 | 68 | #ifndef INT4_TYPE 69 | #define INT4_TYPE int 70 | #define INT4_TYPE_MAX 2147483647 71 | #define INT4_TYPE_MIN -2147483647 72 | #endif 73 | 74 | #ifndef UINT4_TYPE 75 | #define UINT4_TYPE unsigned int 76 | #define UINT4_TYPE_MAX 4294967295 77 | #define UINT4_TYPE_MIN 0 78 | #endif 79 | 80 | #ifndef SEED_TYPE 81 | #define SEED_TYPE int 82 | #define SEED_TYPE_MAX 0x7FFFFFFF 83 | #define SEED_TYPE_MIN -0x80000000 84 | #endif 85 | 86 | #ifndef SHRT_TYPE 87 | #define SHRT_TYPE short int 88 | #define SHRT_TYPE_MAX 32767 89 | #define SHRT_TYPE_MIN -32767 90 | #endif 91 | 92 | #ifndef USHRT_TYPE 93 | #define USHRT_TYPE unsigned short 94 | #define USHRT_TYPE_MAX 65535 95 | #define USHRT_TYPE_MIN 0 96 | #endif 97 | 98 | #ifndef INT_TYPE 99 | #define INT_TYPE int 100 | #define INT_TYPE_MAX 2147483647 101 | #define INT_TYPE_MIN -2147483647 102 | #endif 103 | 104 | #ifndef UINT_TYPE 105 | #define UINT_TYPE unsigned 106 | #define UINT_TYPE_MAX 4294967295U 107 | #define UNINT_TYPE_MIN 0 108 | #endif 109 | 110 | #ifndef LONG_TYPE 111 | #define LONG_TYPE long 112 | #define LONG_TYPE_MAX 2147483647 113 | #define LONG_TYPE_MIN -2147483647 114 | #endif 115 | 116 | #ifndef ULONG_TYPE 117 | #define ULONG_TYPE unsigned long 118 | #define ULONG_TYPE_MAX 4294967295U 119 | #define ULONG_TYPE_MIN 0 120 | #endif 121 | 122 | #ifndef FLT_TYPE 123 | #define FLT_TYPE float 124 | #define FLT_TYPE_MAX 3.40282347e+38 125 | #define FLT_TYPE_MIN 1.17549435e-38 126 | #endif 127 | 128 | #ifndef DBL_TYPE 129 | #define DBL_TYPE double 130 | #define DBL_TYPE_MAX 1.7976931348623157e+308 131 | #define DBL_TYPE_MIN 2.2250738585072014e-308 132 | #endif 133 | 134 | #define BINARY_CODE 10 135 | #define INT1_CODE 30 136 | #define CHAR_CODE 30 /* CHAR is signed */ 137 | #define PIX_CODE 31 /* PIX is unsigned */ 138 | #define UINT1_CODE 31 139 | #define SHORT_CODE 35 140 | #define INT2_CODE 35 141 | #define UINT2_CODE 37 142 | #define INT4_CODE 40 143 | #define INT_CODE 40 144 | #define UINT4_CODE 42 145 | #define UINT_CODE 42 146 | #define INT8_CODE 43 147 | #define UINT8_CODE 44 148 | #define FLOAT_CODE 45 149 | #define DBL_CODE 50 150 | #define DOUBLE_CODE 50 151 | 152 | /* default string length */ 153 | #define DFLTSTRLEN 1024 154 | 155 | /* messages functions */ 156 | #define LIARassert(x) assert(x) 157 | 158 | /* prototypes from liarmsgs.c */ 159 | #define dbgprintf LIARdebug 160 | #define errprintf LIARerror 161 | 162 | 163 | // exact copy of the structure in wmisc.h 164 | // located in the c2liar 165 | // these codes are defined in liarlmts.h 166 | /* typedef enum */ 167 | /* { */ 168 | /* IM_DEFAULT = -1, /\* used in arith function when specifying the output type *\/ */ 169 | /* IM_BADPIXEL = 0, /\* error flag for unknown/illegal pixel types (enum value 0)*\/ */ 170 | 171 | /* /\* 1 byte pixel types *\/ */ 172 | /* IM_BINARY = BINARY_CODE, /\* binary (enum value 10) *\/ */ 173 | /* IM_CHAR = CHAR_CODE, /\* char,int (enum value 30)*\/ */ 174 | /* IM_INT1 = INT1_CODE, /\* char,int (enum value 30)*\/ */ 175 | /* IM_UINT1 = UINT1_CODE, /\* unsigned int (enum value 31)*\/ */ 176 | 177 | /* /\* 2 byte pixel types *\/ */ 178 | /* IM_SHORT = SHORT_CODE, /\* int (enum value 35)*\/ */ 179 | /* IM_INT2 = INT2_CODE, /\* int (enum value 35)*\/ */ 180 | /* IM_UINT2 = UINT2_CODE, /\* unsigned int (enum value 37)*\/ */ 181 | 182 | /* /\* 4 byte pixel types *\/ */ 183 | /* IM_INT = INT_CODE, /\* int (enum value 40)*\/ */ 184 | /* IM_INT4 = INT4_CODE, /\* int (enum value 40)*\/ */ 185 | /* IM_UINT4 = UINT4_CODE, /\* unsigned int (enum value 42)*\/ */ 186 | 187 | /* /\* 8 byte pixel types *\/ */ 188 | /* IM_INT8 = INT8_CODE, /\* int (enum value 43)*\/ */ 189 | /* IM_UINT8 = UINT8_CODE, /\* unsigned int (enum value 44)*\/ */ 190 | 191 | /* /\* real-valued pixel types *\/ */ 192 | /* IM_FLOAT = FLOAT_CODE, /\* float (enum value 45)*\/ */ 193 | /* IM_DOUBLE = DOUBLE_CODE /\* double (enum value 50)*\/ */ 194 | /* } */ 195 | /* liar_pixtype; */ 196 | 197 | // extremely weird Hugues Talbot 21 Dec 2010 198 | typedef enum { 199 | IM_BINARY = 0, 200 | IM_INT1 = 1, 201 | IM_UINT1 = 2, 202 | IM_INT2 = 3, 203 | IM_UINT2 = 4, 204 | IM_INT4 = 5, 205 | IM_UINT4 = 6, 206 | IM_INT8 = 7, 207 | IM_UINT8 = 8, 208 | IM_FLOAT = 9, 209 | IM_DOUBLE = 10 210 | } pixtype; 211 | 212 | // flat series (2D and 3D) 213 | //#include "fseries.h" 214 | //#include "fseries3d.h" 215 | 216 | typedef void (*computerankfunc)(PIX_TYPE *in, 217 | PIX_TYPE *out, 218 | PIX_TYPE *offset, 219 | int nx, 220 | int nk); 221 | // pure C function declarations 222 | #ifdef __cplusplus 223 | extern "C" { 224 | #endif 225 | 226 | int LIARdebug(const char *fmt, ...); 227 | int LIARerror(const char *msg, ...); 228 | long *bresenham3d(int dx, int dy, int dz, 229 | int imwidth, int imheight, int imdepth, 230 | int *ol, int *period); 231 | long *periodic3d(int dx, int dy, int dz, 232 | int imwidth, int imheight, int imdepth, 233 | int *ol, int *period); 234 | long *bresenham(int xin,int yin,int angle,int width,int *period); 235 | long *periodic(int x, int y, int angle, int width, int *period); 236 | 237 | /* from chngeval.c */ 238 | void changePIXval(PIX_TYPE *IN, long size, 239 | PIX_TYPE val1, 240 | PIX_TYPE val2); 241 | 242 | void changeSEEDval(SEED_TYPE *IN, long size, 243 | SEED_TYPE val1, 244 | SEED_TYPE val2); 245 | 246 | INT4_TYPE testINTneighs(SEED_TYPE *v,LONG_TYPE *func,INT4_TYPE n); 247 | 248 | void getsubset_3d(void *in, /* Input buffer */ 249 | void **out, /* Output buffer */ 250 | int size, /* Image pixel size */ 251 | int inx, /* nb of cols (input) */ 252 | int iny, /* nb of rows (input) */ 253 | int inz, /* nb of slices (input) */ 254 | int *outx, /* nb of cols (output) */ 255 | int *outy, /* nb of rows (output) */ 256 | int *outz, /* nb of slices (output) */ 257 | int offsetx, /* offset value in x */ 258 | int offsety, /* offset value in y */ 259 | int offsetz); /* offset value in z */ 260 | 261 | void addborder_3d(void *in, /* Input buffer */ 262 | void **out, /* Output buffer */ 263 | int size, /* Image pixel size */ 264 | int inx, /* nb of cols (input) */ 265 | int iny, /* nb of rows (input) */ 266 | int inz, /* nb of slices (input) */ 267 | int *outx, /* nb of cols (output) */ 268 | int *outy, /* nb of rows (output) */ 269 | int *outz, /* nb of slices (output) */ 270 | int offsetx, /* offset value in x */ 271 | int offsety, /* offset value in y */ 272 | int offsetz); /* offset value in z */ 273 | 274 | 275 | /* from setpxbrd.c */ 276 | void setPIXborder(PIX_TYPE *image, int nx, int ny, int nz, 277 | PIX_TYPE val); 278 | 279 | /* from setneigh.c */ 280 | int setNeighFunc3d(long *Nf, /* pointer to a long vector of size 26 */ 281 | int con, /* */ 282 | int nx, /* */ 283 | int ny, /* */ 284 | int nz); /* */ 285 | 286 | /* from lsrgrow3d.c */ 287 | int lsrgrow3d(void **bufin, /* input buffer */ 288 | SEED_TYPE **bufout, /* output buffer */ 289 | SEED_TYPE *seeds, /* seed image */ 290 | int inimagetype, /* pixel type of input image */ 291 | int inpixsize, /* pixel size of input image */ 292 | int seedpixsize, /* pixel size of seeds image */ 293 | int inx, /* nb of cols in the input */ 294 | int iny, /* nb of rows in the input */ 295 | int inz, /* nb of slices in the input */ 296 | int comps, /* nb of components in the input */ 297 | int metric, /* distance measures */ 298 | int borders, /* to display region borders only */ 299 | int connect, /* connectivity of the image */ 300 | int showgrey); /* output greyscale using pixel avge */ 301 | 302 | 303 | #ifdef __cplusplus 304 | } 305 | #endif 306 | 307 | 308 | #endif /* LIARP_ */ 309 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/mcfifo.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is an image processing library whose purpose is to be 7 | used primarily for research and teaching. 8 | 9 | This software is governed by the CeCILL license under French law and 10 | abiding by the rules of distribution of free software. You can use, 11 | modify and/ or redistribute the software under the terms of the CeCILL 12 | license as circulated by CEA, CNRS and INRIA at the following URL 13 | "http://www.cecill.info". 14 | 15 | As a counterpart to the access to the source code and rights to copy, 16 | modify and redistribute granted by the license, users are provided only 17 | with a limited warranty and the software's author, the holder of the 18 | economic rights, and the successive licensors have only limited 19 | liability. 20 | 21 | In this respect, the user's attention is drawn to the risks associated 22 | with loading, using, modifying and/or developing or reproducing the 23 | software by the user in light of its specific status of free software, 24 | that may mean that it is complicated to manipulate, and that also 25 | therefore means that it is reserved for developers and experienced 26 | professionals having in-depth computer knowledge. Users are therefore 27 | encouraged to load and test the software's suitability as regards their 28 | requirements in conditions enabling the security of their systems and/or 29 | data to be ensured and, more generally, to use and operate it in the 30 | same conditions as regards security. 31 | 32 | The fact that you are presently reading this means that you have had 33 | knowledge of the CeCILL license and that you accept its terms. 34 | */ 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #ifndef _MCIMAGE_H 40 | #include 41 | #endif 42 | 43 | typedef struct { 44 | index_t Max; /* taille max de la fifo */ 45 | index_t In; /* index ou ranger le prochain arrivant */ 46 | index_t Out; /* index d'ou retirer le prochain sortant */ 47 | index_t Pts[1]; 48 | } Fifo; 49 | 50 | /* ============== */ 51 | /* prototypes */ 52 | /* ============== */ 53 | 54 | extern Fifo * CreeFifoVide(index_t taillemax); 55 | extern void FifoFlush(Fifo * L); 56 | extern int32_t FifoVide(Fifo * L); 57 | extern index_t FifoPop(Fifo * L); 58 | extern void FifoPush(Fifo * L, index_t V); 59 | extern void FifoPushFirst(Fifo * L, index_t V); 60 | extern index_t FifoTaille(Fifo * L); 61 | extern void FifoPrint(Fifo * L); 62 | extern void FifoTermine(Fifo * L); 63 | 64 | 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/mcimage.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is an image processing library whose purpose is to be 7 | used primarily for research and teaching. 8 | 9 | This software is governed by the CeCILL license under French law and 10 | abiding by the rules of distribution of free software. You can use, 11 | modify and/ or redistribute the software under the terms of the CeCILL 12 | license as circulated by CEA, CNRS and INRIA at the following URL 13 | "http://www.cecill.info". 14 | 15 | As a counterpart to the access to the source code and rights to copy, 16 | modify and redistribute granted by the license, users are provided only 17 | with a limited warranty and the software's author, the holder of the 18 | economic rights, and the successive licensors have only limited 19 | liability. 20 | 21 | In this respect, the user's attention is drawn to the risks associated 22 | with loading, using, modifying and/or developing or reproducing the 23 | software by the user in light of its specific status of free software, 24 | that may mean that it is complicated to manipulate, and that also 25 | therefore means that it is reserved for developers and experienced 26 | professionals having in-depth computer knowledge. Users are therefore 27 | encouraged to load and test the software's suitability as regards their 28 | requirements in conditions enabling the security of their systems and/or 29 | data to be ensured and, more generally, to use and operate it in the 30 | same conditions as regards security. 31 | 32 | The fact that you are presently reading this means that you have had 33 | knowledge of the CeCILL license and that you accept its terms. 34 | */ 35 | 36 | /** Pink 37 | 38 | \brief This file holds the basic image allocation functions. 39 | 40 | \ingroup development 41 | 42 | \file mcimage.h 43 | 44 | \author Michel Couprie, 2009 45 | 46 | */ 47 | 48 | 49 | #ifndef MCIMAGE__H__ 50 | #define MCIMAGE__H__ 51 | 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | 57 | // ******************************************************************************************************** 58 | // ******************************************************************************************************** 59 | // ******************************************************************************************************** 60 | // PLATFORM DEPENDENT CONFIGURATION 61 | // ******************************************************************************************************** 62 | // ******************************************************************************************************** 63 | // ******************************************************************************************************** 64 | 65 | #ifdef UNIXIO 66 | # define __pink__inline inline 67 | # define __pink__export export 68 | # define __pink__import 69 | # include 70 | #else /* NOT UNIXIO */ 71 | # define __pink__inline 72 | # define __pink__export __declspec(dllexport) 73 | # define __pink__import __declspec(dllimport) 74 | typedef unsigned char u_int8_t; 75 | typedef unsigned int u_int32_t; 76 | typedef unsigned char uint8_t; 77 | typedef int int32_t; 78 | typedef unsigned int uint32_t; 79 | typedef long long int64_t_bis; 80 | typedef unsigned long long uint64_t_bis; 81 | typedef unsigned long long u_int64_t_bis; 82 | #endif /* UNIXIO */ 83 | 84 | 85 | // attention : les index doivent être signés (pour les parcours rétro : for(i = N-1; i >=0; i--)) 86 | #ifdef MC_64_BITS 87 | typedef int64_t_bis index_t; 88 | #else 89 | typedef int32_t index_t; 90 | #endif 91 | #define HUGE_IMAGE_SIZE INT32_MAX 92 | 93 | // ******************************************************************************************************** 94 | // ******************************************************************************************************** 95 | // ******************************************************************************************************** 96 | // end of PLATFORM DEPENDENT CONFIGURATION 97 | // ******************************************************************************************************** 98 | // ******************************************************************************************************** 99 | // ******************************************************************************************************** 100 | 101 | /* ============== */ 102 | /* prototypes for mcimage.c */ 103 | /* ============== */ 104 | 105 | /** 106 | \brief Allocates an image object with the given size and type 107 | 108 | \param name Not used 109 | \param rs x-size 110 | \param cs y-size 111 | \param ds z-size 112 | \param t t-size 113 | \return The pointer to the image. 114 | */ 115 | extern struct xvimage *allocimage(char * name, index_t rs, index_t cs, index_t ds, int32_t t); 116 | 117 | extern struct xvimage *allocmultimage(char * name, index_t rs, index_t cs, index_t ds, index_t ts, index_t nb, int32_t t); 118 | 119 | /** 120 | \brief fills the image with zeros 121 | description Sets every pixel of the image to binary zero. 122 | 123 | \param f the input image 124 | \return no return value 125 | */ 126 | extern void razimage(struct xvimage *f); 127 | extern struct xvimage *allocheader(char * name, index_t rs, index_t cs, index_t d, int32_t t); 128 | extern int32_t showheader(char * name); 129 | 130 | /** 131 | \brief Frees an image object 132 | 133 | \param image The pointer to the image 134 | */ 135 | extern void freeimage(struct xvimage *image); 136 | extern struct xvimage *copyimage(struct xvimage *f); 137 | extern int32_t copy2image(struct xvimage *dest, struct xvimage *source); 138 | extern int32_t equalimages(struct xvimage *im1, struct xvimage *im2); 139 | extern void list2image(struct xvimage * image, double *P, index_t n); 140 | extern double * image2list(struct xvimage * image, index_t *n); 141 | 142 | /** 143 | \brief Writes an image to disk. 144 | 145 | \param image The pointer to the image 146 | \param filename The file to write the image at. 147 | */ 148 | extern void writeimage( 149 | struct xvimage * image, 150 | const char *filename 151 | ); 152 | 153 | extern void writese( 154 | struct xvimage * image, 155 | const char *filename, 156 | index_t x, index_t y, index_t z 157 | ); 158 | 159 | extern void writelongimage( 160 | struct xvimage * image, 161 | const char *filename 162 | ); 163 | 164 | extern void writerawimage( 165 | struct xvimage * image, 166 | const char *filename 167 | ); 168 | 169 | extern void writeascimage( 170 | struct xvimage * image, 171 | const char *filename 172 | ); 173 | 174 | extern void printimage( 175 | struct xvimage * image 176 | ); 177 | 178 | extern void writergbimage( 179 | struct xvimage * redimage, 180 | struct xvimage * greenimage, 181 | struct xvimage * blueimage, 182 | const char *filename 183 | ); 184 | 185 | extern void writergbascimage( 186 | struct xvimage * redimage, 187 | struct xvimage * greenimage, 188 | struct xvimage * blueimage, 189 | const char *filename 190 | ); 191 | 192 | /** 193 | \brief Reads an image from a file 194 | 195 | \param filename The name of the image file. 196 | \return A Pointer to a newly allocated image. 197 | */ 198 | extern struct xvimage * readimage( 199 | const char *filename 200 | ); 201 | 202 | extern struct xvimage * readheader( 203 | const char *filename 204 | ); 205 | 206 | extern struct xvimage * readse(const char *filename, index_t *x, index_t *y, index_t*z); 207 | 208 | extern struct xvimage * readlongimage( 209 | const char *filename 210 | ); 211 | 212 | extern int32_t readrgbimage( 213 | const char *filename, 214 | struct xvimage ** r, 215 | struct xvimage ** g, 216 | struct xvimage ** b 217 | ); 218 | 219 | extern int32_t readbmp( 220 | const char *filename, 221 | struct xvimage ** r, 222 | struct xvimage ** g, 223 | struct xvimage ** b 224 | ); 225 | 226 | extern void writebmp( 227 | struct xvimage * redimage, 228 | struct xvimage * greenimage, 229 | struct xvimage * blueimage, 230 | const char *filename 231 | ); 232 | 233 | extern int32_t readrgb( 234 | const char *filename, 235 | struct xvimage ** r, 236 | struct xvimage ** g, 237 | struct xvimage ** b 238 | ); 239 | 240 | extern int32_t convertgen(struct xvimage **f1, struct xvimage **f2); 241 | extern int32_t convertlong(struct xvimage **f1); 242 | extern int32_t convertfloat(struct xvimage **f1); 243 | 244 | extern void writelist2(const char *filename, int32_t *x, int32_t *y, int32_t npoints); 245 | extern void writelist3(const char *filename, int32_t *x, int32_t *y, int32_t *z, int32_t npoints); 246 | 247 | #ifdef __cplusplus 248 | } /* extern "C" */ 249 | #endif 250 | 251 | #endif /* MCIMAGE__H__ */ 252 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/mcindic.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is an image processing library whose purpose is to be 7 | used primarily for research and teaching. 8 | 9 | This software is governed by the CeCILL license under French law and 10 | abiding by the rules of distribution of free software. You can use, 11 | modify and/ or redistribute the software under the terms of the CeCILL 12 | license as circulated by CEA, CNRS and INRIA at the following URL 13 | "http://www.cecill.info". 14 | 15 | As a counterpart to the access to the source code and rights to copy, 16 | modify and redistribute granted by the license, users are provided only 17 | with a limited warranty and the software's author, the holder of the 18 | economic rights, and the successive licensors have only limited 19 | liability. 20 | 21 | In this respect, the user's attention is drawn to the risks associated 22 | with loading, using, modifying and/or developing or reproducing the 23 | software by the user in light of its specific status of free software, 24 | that may mean that it is complicated to manipulate, and that also 25 | therefore means that it is reserved for developers and experienced 26 | professionals having in-depth computer knowledge. Users are therefore 27 | encouraged to load and test the software's suitability as regards their 28 | requirements in conditions enabling the security of their systems and/or 29 | data to be ensured and, more generally, to use and operate it in the 30 | same conditions as regards security. 31 | 32 | The fact that you are presently reading this means that you have had 33 | knowledge of the CeCILL license and that you accept its terms. 34 | */ 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #ifndef _MCIMAGE_H 40 | #include 41 | #endif 42 | 43 | typedef uint8_t Indicstype; 44 | 45 | extern Indicstype *Indics; /* en global pour etre efficace */ 46 | 47 | #define Set(x,INDIC) Indics[x]|=(1< 45 | #endif 46 | 47 | typedef struct { 48 | index_t Max; /* taille max de la Lifo */ 49 | index_t Sp; /* index de pile (pointe la 1ere case libre) */ 50 | index_t Pts[1]; 51 | } Lifo; 52 | 53 | /* ============== */ 54 | /* prototypes */ 55 | /* ============== */ 56 | extern Lifo * CreeLifoVide(index_t taillemax); 57 | extern void LifoFlush(Lifo * L); 58 | extern index_t LifoVide(Lifo * L); 59 | extern index_t LifoPop(Lifo * L); 60 | extern index_t LifoHead(Lifo * L); 61 | extern void LifoPush(Lifo * L, index_t V); 62 | extern void LifoPrint(Lifo * L); 63 | extern void LifoPrintLine(Lifo * L); 64 | extern void LifoTermine(Lifo * L); 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif /* MCLIFO__H__ */ 70 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/mcutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is an image processing library whose purpose is to be 7 | used primarily for research and teaching. 8 | 9 | This software is governed by the CeCILL license under French law and 10 | abiding by the rules of distribution of free software. You can use, 11 | modify and/ or redistribute the software under the terms of the CeCILL 12 | license as circulated by CEA, CNRS and INRIA at the following URL 13 | "http://www.cecill.info". 14 | 15 | As a counterpart to the access to the source code and rights to copy, 16 | modify and redistribute granted by the license, users are provided only 17 | with a limited warranty and the software's author, the holder of the 18 | economic rights, and the successive licensors have only limited 19 | liability. 20 | 21 | In this respect, the user's attention is drawn to the risks associated 22 | with loading, using, modifying and/or developing or reproducing the 23 | software by the user in light of its specific status of free software, 24 | that may mean that it is complicated to manipulate, and that also 25 | therefore means that it is reserved for developers and experienced 26 | professionals having in-depth computer knowledge. Users are therefore 27 | encouraged to load and test the software's suitability as regards their 28 | requirements in conditions enabling the security of their systems and/or 29 | data to be ensured and, more generally, to use and operate it in the 30 | same conditions as regards security. 31 | 32 | The fact that you are presently reading this means that you have had 33 | knowledge of the CeCILL license and that you accept its terms. 34 | */ 35 | #ifndef MCUTIL__H__ 36 | #define MCUTIL__H__ 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | // #define max(a,b) error_max_function_is_ambigous_use_mcmax_instead 43 | // #define min(a,b) error_min_function_is_ambigous_use_mcmin_instead 44 | // #define abs(b) error_abs_function_is_ambigous_use_mcabs_instead 45 | // #define sign(b) error_sign_function_is_ambigous_use_mcsign_instead 46 | // #define odd(b) error_odd_function_is_ambigous_use_mcodd_instead 47 | // #define even(b) error_even_function_is_ambigous_use_mceven_instead 48 | // #define sqr(b) error_sqr_function_is_ambigous_use_mcsqr_instead 49 | 50 | #define mcabs(X) ((X)>=0?(X):-(X)) 51 | #define mcmax(X,Y) ((X)>=(Y)?(X):(Y)) 52 | #define mcmin(X,Y) ((X)<=(Y)?(X):(Y)) 53 | #define mcodd(X) ((X)&1) 54 | #define mceven(X) (((X)&1)==0) 55 | #define arrondi(z) (((z)-(double)((int32_t)(z)))<=0.5?((int32_t)(z)):((int32_t)(z+1))) 56 | #define signe(z) (((z)>0.0)?1.0:-1.0) 57 | #define mcsqr(x) ((x)*(x)) 58 | 59 | #ifndef M_PI 60 | # define M_E 2.7182818284590452354 /* e */ 61 | # define M_LOG2E 1.4426950408889634074 /* log_2 e */ 62 | # define M_LOG10E 0.43429448190325182765 /* log_10 e */ 63 | # define M_LN2 0.69314718055994530942 /* log_e 2 */ 64 | # define M_LN10 2.30258509299404568402 /* log_e 10 */ 65 | # define M_PI 3.14159265358979323846 /* pi */ 66 | # define M_PI_2 1.57079632679489661923 /* pi/2 */ 67 | # define M_PI_4 0.78539816339744830962 /* pi/4 */ 68 | # define M_1_PI 0.31830988618379067154 /* 1/pi */ 69 | # define M_2_PI 0.63661977236758134308 /* 2/pi */ 70 | # define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ 71 | # define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ 72 | # define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ 73 | #endif 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | #endif /* MCUTIL__H__ */ 79 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/pink/rect3dmm.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: rect3dmm.hpp 3 | * 4 | 5 | Hugues Talbot 7 Dec 2010 6 | 7 | This software is an image processing library whose purpose is to be 8 | used primarily for research and teaching. 9 | 10 | This software is governed by the CeCILL license under French law and 11 | abiding by the rules of distribution of free software. You can use, 12 | modify and/ or redistribute the software under the terms of the CeCILL 13 | license as circulated by CEA, CNRS and INRIA at the following URL 14 | "http://www.cecill.info". 15 | 16 | As a counterpart to the access to the source code and rights to copy, 17 | modify and redistribute granted by the license, users are provided only 18 | with a limited warranty and the software's author, the holder of the 19 | economic rights, and the successive licensors have only limited 20 | liability. 21 | 22 | In this respect, the user's attention is drawn to the risks associated 23 | with loading, using, modifying and/or developing or reproducing the 24 | software by the user in light of its specific status of free software, 25 | that may mean that it is complicated to manipulate, and that also 26 | therefore means that it is reserved for developers and experienced 27 | professionals having in-depth computer knowledge. Users are therefore 28 | encouraged to load and test the software's suitability as regards their 29 | requirements in conditions enabling the security of their systems and/or 30 | data to be ensured and, more generally, to use and operate it in the 31 | same conditions as regards security. 32 | 33 | The fact that you are presently reading this means that you have had 34 | knowledge of the CeCILL license and that you accept its terms. 35 | * 36 | */ 37 | 38 | /* rect3dminmax.cpp */ 39 | 40 | #ifndef RECT3DMM_HPP 41 | #define RECT3DMM_HPP 42 | 43 | #include 44 | #include 45 | 46 | #include "liarp.h" 47 | #include "genfmin.hpp" 48 | #include "genfmax.hpp" 49 | 50 | /** 51 | * \brief function to replace each voxel within a 3d image with 52 | max/min within a given 3d structuring element (rectangular) 53 | 54 | This function performs erosion or dilation using the three dimensional 55 | equivelant of a rectangular structuring element. The original image is 56 | described both by the image itself (*in) and the dimensions (nx, ny and 57 | nz) while the structuring element is described by its width, breadth and 58 | depth (w, b and d). The (*func)() argument is then used to specify 59 | either erosion of dilation (genfmin for erosion and genfmax for dilation). 60 | Note that this function does not create a new image but rather modifies the 61 | image supplied (*in). 62 | 63 | TESTS: Tested on a number of images 64 | 65 | Notes: Terminology needs correcting (ie slice, rect3d etc) 66 | 67 | * \param *in: input image 68 | * \param nx: number of columns in input image 69 | * \param ny: number of rows in input image 70 | * \param nz: number of slices in input image 71 | * \param w: width (x dimension) of SE 72 | * \param b: breadth (y dimension) of SE 73 | * \param d: depth (z dimension) of SE 74 | * \param (*func)(): min or max operation (genfmin/genfmax) 75 | 76 | * \return 77 | * \author Ian Sowden 78 | *
Based on existing rectminmax function. 79 | * \date 18/12/97 80 | */ 81 | 82 | template 83 | void rect3dminmax(Type *in, int nx, int ny, int nz, int w, int b, 84 | int d, bool usemin ) 85 | { 86 | int i, j; /* indexing variables */ 87 | int maxdim; /* maximum dimension */ 88 | Type *row, *col, *slice; /* row/col/slice pointers */ 89 | Type *h, *g; /* fowards and backwards arrays (for func) */ 90 | long *p; /* row/col/slice offset array */ 91 | 92 | /* Calculate max dimension */ 93 | maxdim = nx 1 then perform max/min on each row */ 107 | if (w > 1) { 108 | /* set row element offsets */ 109 | for (p[0]=0, i=1; i1) */ 121 | 122 | /* if y dimension of SE > 1 then perform max/min on each column */ 123 | if (b > 1) { 124 | /* set column element offsets */ 125 | for (p[0]=0, i=1; i1) */ 139 | 140 | /* finally, if depth of SE > 1 then perform max/min on each slice */ 141 | if (d > 1) { 142 | /* set slice element offsets */ 143 | for (p[0]=0, i=1; i1) */ 154 | 155 | /* clean up */ 156 | free(g); 157 | free(h); 158 | free(p); 159 | 160 | } /* end rect3dminmax */ 161 | 162 | #if 0 163 | void rect3dminmax_CHAR(PIX_TYPE *in, int nx, int ny, int nz, int w, int b, 164 | int d, void (*func) () ) 165 | { 166 | int i, j; /* indexing variables */ 167 | int maxdim; /* maximum dimension */ 168 | PIX_TYPE *row, *col, *slice; /* row/col/slice pointers */ 169 | PIX_TYPE *h, *g; /* fowards and backwards arrays (for func) */ 170 | INT4_TYPE *p; /* row/col/slice offset array */ 171 | 172 | /* Calculate max dimension */ 173 | maxdim = nx 1 then perform max/min on each row */ 187 | if (w > 1) { 188 | /* set row element offsets */ 189 | for (p[0]=0, i=1; i1) */ 197 | 198 | /* if y dimension of SE > 1 then perform max/min on each column */ 199 | if (b > 1) { 200 | /* set column element offsets */ 201 | for (p[0]=0, i=1; i1) */ 210 | 211 | /* finally, if depth of SE > 1 then perform max/min on each slice */ 212 | if (d > 1) { 213 | /* set slice element offsets */ 214 | for (p[0]=0, i=1; i1) */ 222 | 223 | /* clean up */ 224 | free(g); 225 | free(h); 226 | free(p); 227 | 228 | } /* end rect3dminmax */ 229 | 230 | #endif 231 | 232 | //void rect3dminmax_int4(INT4_TYPE *in, int nx, int ny, int nz, int w, int b, 233 | // int d, void (*func) () ) 234 | //{ 235 | // int i, j; /* indexing variables */ 236 | // int maxdim; /* maximum dimension */ 237 | // INT4_TYPE *row, *col, *slice; /* row/col/slice pointers */ 238 | // INT4_TYPE *h, *g; /* fowards and backwards arrays (for func) */ 239 | // INT4_TYPE *p; /* row/col/slice offset array */ 240 | // 241 | // /* Calculate max dimension */ 242 | // maxdim = nx 1 then perform max/min on each row */ 256 | // if (w > 1) { 257 | // /* set row element offsets */ 258 | // for (p[0]=0, i=1; i1) */ 266 | // 267 | // /* if y dimension of SE > 1 then perform max/min on each column */ 268 | // if (b > 1) { 269 | // /* set column element offsets */ 270 | // for (p[0]=0, i=1; i1) */ 279 | // 280 | // /* finally, if depth of SE > 1 then perform max/min on each slice */ 281 | // if (d > 1) { 282 | // /* set slice element offsets */ 283 | // for (p[0]=0, i=1; i1) */ 291 | // 292 | // /* clean up */ 293 | // free(g); 294 | // free(h); 295 | // free(p); 296 | // 297 | //} /* end rect3dminmax_int4 */ 298 | 299 | 300 | #endif // RECT3DMM_HPP 301 | -------------------------------------------------------------------------------- /libRORPO/include/RORPO/sorting.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Odyssee Merveille 2 | odyssee.merveille@gmail.com 3 | 4 | This software is a computer program whose purpose is to compute RORPO. 5 | This software is governed by the CeCILL-B license under French law and 6 | abiding by the rules of distribution of free software. You can use, 7 | modify and/ or redistribute the software under the terms of the CeCILL-B 8 | license as circulated by CEA, CNRS and INRIA at the following URL 9 | "http://www.cecill.info". 10 | 11 | As a counterpart to the access to the source code and rights to copy, 12 | modify and redistribute granted by the license, users are provided only 13 | with a limited warranty and the software's author, the holder of the 14 | economic rights, and the successive licensors have only limited 15 | liability. 16 | 17 | In this respect, the user's attention is drawn to the risks associated 18 | with loading, using, modifying and/or developing or reproducing the 19 | software by the user in light of its specific status of free software, 20 | that may mean that it is complicated to manipulate, and that also 21 | therefore means that it is reserved for developers and experienced 22 | professionals having in-depth computer knowledge. Users are therefore 23 | encouraged to load and test the software's suitability as regards their 24 | requirements in conditions enabling the security of their systems and/or 25 | data to be ensured and, more generally, to use and operate it in the 26 | same conditions as regards security. 27 | 28 | The fact that you are presently reading this means that you have had 29 | knowledge of the CeCILL-B license and that you accept its terms. 30 | */ 31 | 32 | #ifndef SORTING_HPP_INCLUDED 33 | #define SORTING_HPP_INCLUDED 34 | 35 | #include 36 | #include "Image/Image.hpp" 37 | 38 | template 39 | static inline void sort7_sorting_network_simple_swap(PixelType **d, std::array& indices) { 40 | 41 | #define SWAP(x, y) { if (*d[y] < *d[x]) { auto maxi = *d[x]; *d[x] = *d[y]; *d[y] = maxi; maxi=indices[x]; indices[x]=indices[y]; indices[y]=maxi;}} 42 | 43 | SWAP(1, 2); 44 | SWAP(3, 4); 45 | SWAP(5, 6); 46 | SWAP(0, 2); 47 | SWAP(4, 6); 48 | SWAP(3, 5); 49 | SWAP(2, 6); 50 | SWAP(1, 5); 51 | SWAP(0, 4); 52 | SWAP(2, 5); 53 | SWAP(0, 3); 54 | SWAP(2, 4); 55 | SWAP(1, 3); 56 | SWAP(0, 1); 57 | SWAP(2, 3); 58 | SWAP(4, 5); 59 | 60 | #undef SWAP 61 | } 62 | 63 | 64 | template 65 | static void sorting(Image3D &image1, Image3D &I2, 66 | Image3D &I3, Image3D &I4, 67 | Image3D &I5, Image3D &I6, 68 | Image3D &I7, int N, 69 | std::vector>& indices) { 70 | PixelType *d[7]; 71 | d[0] = image1.get_pointer(); 72 | d[1] = I2.get_pointer(); 73 | d[2] = I3.get_pointer(); 74 | d[3] = I4.get_pointer(); 75 | d[4] = I5.get_pointer(); 76 | d[5] = I6.get_pointer(); 77 | d[6] = I7.get_pointer(); 78 | 79 | 80 | for (int i = 0; i < N; i++) { 81 | indices[i] = {0, 1, 2, 3, 4, 5, 6}; 82 | sort7_sorting_network_simple_swap(d, indices[i]); 83 | for (int j = 0; j < 7; j++) 84 | d[j]++; 85 | } 86 | } 87 | 88 | #ifdef _TEST_SORT_ 89 | int main(int argc, char **argv) { 90 | for (int i=0; i<10; i++){ 91 | PixelType d[7], *b[7]; 92 | for (int j=0;j<7; j++) {d[j]=rand()%256;b[j]=d+j;} 93 | sort7_sorting_network_simple_swap(b); 94 | for (int j=0; j<7; j++) std::cout<< d[j] << "--" ; 95 | std::cout << std::endl; 96 | } 97 | int i; 98 | std::cin >> i; 99 | } 100 | #endif // _TEST_SORT_ 101 | 102 | template 103 | bool my_sorting_function(const PixelType *i, const PixelType *j) 104 | // Input: i, j : two variables containing memory adress pointing to 105 | // PixelType variables. 106 | 107 | // Return : True if the variable pointed by i is smaller than the 108 | // variabled pointed by j 109 | { 110 | return (*i < *j); 111 | } 112 | 113 | template 114 | std::vector sort_image_value(PixelType *image, int size) 115 | // Return pixels index of image sorted according to intensity 116 | { 117 | std::vector index_image(size); 118 | std::vector index_pointer_adress(size); 119 | IndexType it; 120 | typename std::vector::iterator it1; 121 | typename std::vector::iterator it2; 122 | typename std::vector::iterator it3; 123 | 124 | // Fill index_pointer_adress with memory adress of variables in image 125 | for (it = 0, it2 = index_pointer_adress.begin(); it != size; ++it, ++it2) { 126 | *it2 = &image[it]; 127 | } 128 | 129 | // Sorting adresses according to intensity 130 | std::sort(index_pointer_adress.begin(), index_pointer_adress.end(), 131 | my_sorting_function); 132 | 133 | // Conversion from adresses to index of image I 134 | for (it3 = index_image.begin(), it = 0; it != size; ++it, ++it3) { 135 | *it3 = static_cast(index_pointer_adress[it] - &image[0]); 136 | } 137 | return index_image; 138 | } 139 | 140 | #endif // SORTING_HPP_INCLUDED 141 | -------------------------------------------------------------------------------- /libRORPO/src/lgeodesic.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/libRORPO/src/lgeodesic.c -------------------------------------------------------------------------------- /libRORPO/src/mcfifo.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is a computer program whose purpose is to compute RORPO. 7 | This software is governed by the CeCILL-B license under French law and 8 | abiding by the rules of distribution of free software. You can use, 9 | modify and/ or redistribute the software under the terms of the CeCILL-B 10 | license as circulated by CEA, CNRS and INRIA at the following URL 11 | "http://www.cecill.info". 12 | 13 | As a counterpart to the access to the source code and rights to copy, 14 | modify and redistribute granted by the license, users are provided only 15 | with a limited warranty and the software's author, the holder of the 16 | economic rights, and the successive licensors have only limited 17 | liability. 18 | 19 | In this respect, the user's attention is drawn to the risks associated 20 | with loading, using, modifying and/or developing or reproducing the 21 | software by the user in light of its specific status of free software, 22 | that may mean that it is complicated to manipulate, and that also 23 | therefore means that it is reserved for developers and experienced 24 | professionals having in-depth computer knowledge. Users are therefore 25 | encouraged to load and test the software's suitability as regards their 26 | requirements in conditions enabling the security of their systems and/or 27 | data to be ensured and, more generally, to use and operate it in the 28 | same conditions as regards security. 29 | 30 | The fact that you are presently reading this means that you have had 31 | knowledge of the CeCILL-B license and that you accept its terms. 32 | */ 33 | /* 34 | Librairie mcfifo : 35 | 36 | fonctions pour la gestion d'une liste fifo 37 | 38 | Michel Couprie 1996 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | /* ==================================== */ 49 | Fifo * CreeFifoVide( 50 | index_t taillemax) 51 | /* ==================================== */ 52 | { 53 | Fifo * L = (Fifo *)calloc(1,sizeof(Fifo) + sizeof(index_t) * taillemax); /* sic (+1) */ 54 | if (L == NULL) 55 | { 56 | #ifdef MC_64_BITS 57 | fprintf(stderr, "CreeFifoVide() : malloc failed : %lld bytes\n", sizeof(Fifo) + sizeof(index_t) * taillemax); 58 | #else 59 | fprintf(stderr, "CreeFifoVide() : malloc failed : %ld bytes\n", sizeof(Fifo) + sizeof(index_t) * taillemax); 60 | #endif 61 | return NULL; 62 | } 63 | L->Max = taillemax+1; 64 | L->In = 0; 65 | L->Out = 0; 66 | return L; 67 | } 68 | 69 | /* ==================================== */ 70 | void FifoFlush( 71 | Fifo * L) 72 | /* ==================================== */ 73 | { 74 | L->In = 0; 75 | L->Out = 0; 76 | } 77 | 78 | /* ==================================== */ 79 | int32_t FifoVide( 80 | Fifo * L) 81 | /* ==================================== */ 82 | { 83 | return (L->In == L->Out); 84 | } 85 | 86 | /* ==================================== */ 87 | index_t FifoPop( 88 | Fifo * L) 89 | /* ==================================== */ 90 | { 91 | index_t V; 92 | if (L->In == L->Out) 93 | { 94 | fprintf(stderr, "erreur fifo vide\n"); 95 | exit(1); 96 | } 97 | V = L->Pts[L->Out]; 98 | L->Out = (L->Out + 1) % L->Max; 99 | return V; 100 | } 101 | 102 | /* ==================================== */ 103 | void FifoPushFirst( 104 | Fifo * L, 105 | index_t V) 106 | /* ==================================== */ 107 | { 108 | L->Out = (L->Out - 1) % L->Max; 109 | L->Pts[L->Out] = V; 110 | if (L->In == L->Out) 111 | { 112 | fprintf(stderr, "erreur fifo pleine\n"); 113 | exit(1); 114 | } 115 | } 116 | 117 | /* ==================================== */ 118 | void FifoPush( 119 | Fifo * L, 120 | index_t V) 121 | /* ==================================== */ 122 | { 123 | L->Pts[L->In] = V; 124 | L->In = (L->In + 1) % L->Max; 125 | if (L->In == L->Out) 126 | { 127 | fprintf(stderr, "erreur fifo pleine\n"); 128 | exit(1); 129 | } 130 | } 131 | 132 | /* ==================================== */ 133 | void FifoPrint( 134 | Fifo * L) 135 | /* ==================================== */ 136 | { 137 | index_t i; 138 | if (FifoVide(L)) {printf("[]\n"); return;} 139 | #ifdef MC_64_BITS 140 | printf("Taille Fifo: %lld \n",FifoTaille(L)); 141 | #else 142 | printf("Taille Fifo: %d \n",FifoTaille(L)); 143 | #endif 144 | #ifdef MC_64_BITS 145 | printf("Max = %lld ; Out = %lld ; In = %lld\n", L->Max, L->Out, L->In); 146 | #else 147 | printf("Max = %d ; Out = %d ; In = %d\n", L->Max, L->Out, L->In); 148 | #endif 149 | printf("[ "); 150 | for (i = L->Out; i != L->In; i = (i+1) % L->Max) 151 | #ifdef MC_64_BITS 152 | printf("%lld ", L->Pts[i]); 153 | #else 154 | printf("%d ", L->Pts[i]); 155 | #endif 156 | printf("]\n"); 157 | } 158 | 159 | /* ==================================== */ 160 | void FifoTermine( 161 | Fifo * L) 162 | /* ==================================== */ 163 | { 164 | free(L); 165 | } 166 | 167 | /* ==================================== */ 168 | index_t FifoTaille( 169 | Fifo * L) 170 | /* ==================================== */ 171 | { 172 | if (L->In < L->Out) 173 | return (L->Max - (L->Out-L->In)); 174 | else 175 | return (L->In - L->Out); 176 | } 177 | 178 | #ifdef TESTFIFO 179 | void main() 180 | { 181 | Fifo * L = CreeFifoVide(3); 182 | FifoPrint(L); 183 | if (FifoVide(L)) printf("FifoVide OUI\n"); 184 | FifoPush(L,1); 185 | FifoPrint(L); 186 | if (!FifoVide(L)) printf("FifoVide NON\n"); 187 | FifoPush(L,2); 188 | FifoPrint(L); 189 | FifoPush(L,3); 190 | FifoPrint(L); 191 | printf("FifoPop %d attendu 1\n", FifoPop(L)); 192 | FifoPrint(L); 193 | FifoPushFirst(L,225); 194 | FifoPrint(L); 195 | printf("FifoPop %d attendu par christophe 225\n", FifoPop(L)); 196 | FifoPrint(L); 197 | FifoPush(L,4); 198 | FifoPrint(L); 199 | printf("FifoPop %d attendu 2\n", FifoPop(L)); 200 | FifoPrint(L); 201 | printf("FifoPop %d attendu 3\n", FifoPop(L)); 202 | FifoPrint(L); 203 | printf("FifoPop %d attendu 4\n", FifoPop(L)); 204 | FifoPrint(L); 205 | if (FifoVide(L)) printf("FifoVide OUI\n"); 206 | } 207 | #endif 208 | -------------------------------------------------------------------------------- /libRORPO/src/mcimage.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/path-openings/RORPO/f127de5825d01f11bc166946cd210bd68f77041c/libRORPO/src/mcimage.c -------------------------------------------------------------------------------- /libRORPO/src/mcindic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is a computer program whose purpose is to compute RORPO. 7 | This software is governed by the CeCILL-B license under French law and 8 | abiding by the rules of distribution of free software. You can use, 9 | modify and/ or redistribute the software under the terms of the CeCILL-B 10 | license as circulated by CEA, CNRS and INRIA at the following URL 11 | "http://www.cecill.info". 12 | 13 | As a counterpart to the access to the source code and rights to copy, 14 | modify and redistribute granted by the license, users are provided only 15 | with a limited warranty and the software's author, the holder of the 16 | economic rights, and the successive licensors have only limited 17 | liability. 18 | 19 | In this respect, the user's attention is drawn to the risks associated 20 | with loading, using, modifying and/or developing or reproducing the 21 | software by the user in light of its specific status of free software, 22 | that may mean that it is complicated to manipulate, and that also 23 | therefore means that it is reserved for developers and experienced 24 | professionals having in-depth computer knowledge. Users are therefore 25 | encouraged to load and test the software's suitability as regards their 26 | requirements in conditions enabling the security of their systems and/or 27 | data to be ensured and, more generally, to use and operate it in the 28 | same conditions as regards security. 29 | 30 | The fact that you are presently reading this means that you have had 31 | knowledge of the CeCILL-B license and that you accept its terms. 32 | */ 33 | /* gestion d'indicateurs binaires (jusqu'a 8) */ 34 | /* les indicateurs sont numerotes de 0 a 7 */ 35 | /* M. Couprie juillet 1996 */ 36 | 37 | /* gestion d'un indicateur binaire compact */ 38 | /* M. Couprie novembre 1999 */ 39 | 40 | /* 41 | #define TESTINDIC 42 | */ 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | Indicstype *Indics = NULL; /* en global pour etre efficace */ 52 | 53 | /* ==================================== */ 54 | void IndicsInit(index_t Size) 55 | /* ==================================== */ 56 | { 57 | Indics = (Indicstype *)calloc(Size, sizeof(Indicstype)); 58 | if (Indics == NULL) 59 | { 60 | fprintf(stderr, "erreur allocation Indics\n"); 61 | exit(1); 62 | } 63 | } 64 | 65 | /* ==================================== */ 66 | void IndicsReInit(index_t Size) 67 | /* ==================================== */ 68 | { 69 | memset(Indics, 0, Size * sizeof(Indicstype)); 70 | } 71 | 72 | /* ==================================== */ 73 | void Indics1bitInit(index_t Size) 74 | /* ==================================== */ 75 | { 76 | Indics = (Indicstype *)calloc((Size-1)/8 + 1, sizeof(Indicstype)); 77 | if (Indics == NULL) 78 | { 79 | fprintf(stderr, "erreur allocation Indics\n"); 80 | exit(1); 81 | } 82 | } 83 | 84 | /* ==================================== */ 85 | void Indics1bitReInit(index_t Size) 86 | /* ==================================== */ 87 | { 88 | memset(Indics, 0, ((Size-1)/8 + 1) * sizeof(Indicstype)); 89 | } 90 | 91 | /* ==================================== */ 92 | void IndicsTermine() 93 | /* ==================================== */ 94 | { 95 | free(Indics); 96 | } 97 | 98 | #ifdef TESTINDIC 99 | void main() 100 | { 101 | IndicsInit(3); 102 | Set(0, 0); if (IsSet(0, 0)) printf("test1 ok\n"); 103 | printf("->%d\n", Indics[0]); 104 | Set(0, 1); if (IsSet(0, 1)) printf("test2 ok\n"); 105 | printf("->%d\n", Indics[0]); 106 | UnSet(0, 1); if (!IsSet(0, 1)) printf("test3 ok\n"); 107 | printf("->%d\n", Indics[0]); 108 | if (IsSet(0, 0)) printf("test4 ok\n"); 109 | UnSetAll(0); if (!IsSet(0, 0)) printf("test5 ok\n"); 110 | printf("->%d\n", Indics[0]); 111 | 112 | IndicsTermine(); 113 | } 114 | #endif 115 | -------------------------------------------------------------------------------- /libRORPO/src/mclifo.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright ESIEE (2009) 3 | 4 | m.couprie@esiee.fr 5 | 6 | This software is a computer program whose purpose is to compute RORPO. 7 | This software is governed by the CeCILL-B license under French law and 8 | abiding by the rules of distribution of free software. You can use, 9 | modify and/ or redistribute the software under the terms of the CeCILL-B 10 | license as circulated by CEA, CNRS and INRIA at the following URL 11 | "http://www.cecill.info". 12 | 13 | As a counterpart to the access to the source code and rights to copy, 14 | modify and redistribute granted by the license, users are provided only 15 | with a limited warranty and the software's author, the holder of the 16 | economic rights, and the successive licensors have only limited 17 | liability. 18 | 19 | In this respect, the user's attention is drawn to the risks associated 20 | with loading, using, modifying and/or developing or reproducing the 21 | software by the user in light of its specific status of free software, 22 | that may mean that it is complicated to manipulate, and that also 23 | therefore means that it is reserved for developers and experienced 24 | professionals having in-depth computer knowledge. Users are therefore 25 | encouraged to load and test the software's suitability as regards their 26 | requirements in conditions enabling the security of their systems and/or 27 | data to be ensured and, more generally, to use and operate it in the 28 | same conditions as regards security. 29 | 30 | The fact that you are presently reading this means that you have had 31 | knowledge of the CeCILL-B license and that you accept its terms. 32 | */ 33 | /* 34 | Librairie mclifo : 35 | 36 | fonctions pour la gestion d'une liste lifo 37 | 38 | Michel Couprie 1996 39 | */ 40 | 41 | /* #define TESTLifo */ 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | /* ==================================== */ 49 | Lifo * CreeLifoVide(index_t taillemax) 50 | /* ==================================== */ 51 | #undef F_NAME 52 | #define F_NAME "CreeLifoVide" 53 | { 54 | Lifo * L = (Lifo *)calloc(1,sizeof(Lifo) + sizeof(index_t) * (taillemax-1)); 55 | if (L == NULL) 56 | { 57 | fprintf(stderr, "%s: calloc failed\n", F_NAME); 58 | return NULL; 59 | } 60 | L->Max = taillemax; 61 | L->Sp = 0; 62 | return L; 63 | } 64 | 65 | /* ==================================== */ 66 | void LifoFlush(Lifo * L) 67 | /* ==================================== */ 68 | { 69 | L->Sp = 0; 70 | } 71 | 72 | /* ==================================== */ 73 | index_t LifoVide(Lifo * L) 74 | /* ==================================== */ 75 | { 76 | return (L->Sp == 0); 77 | } 78 | 79 | /* ==================================== */ 80 | index_t LifoPop(Lifo * L) 81 | /* ==================================== */ 82 | #undef F_NAME 83 | #define F_NAME "LifoPop" 84 | { 85 | if (L->Sp == 0) 86 | { 87 | fprintf(stderr, "%s: empty Lifo\n", F_NAME); 88 | exit(1); 89 | } 90 | L->Sp -= 1; 91 | return L->Pts[L->Sp]; 92 | } 93 | 94 | /* ==================================== */ 95 | index_t LifoHead(Lifo * L) 96 | /* ==================================== */ 97 | #undef F_NAME 98 | #define F_NAME "LifoHead" 99 | { 100 | if (L->Sp == 0) 101 | { 102 | fprintf(stderr, "%s: empty Lifo\n", F_NAME); 103 | exit(1); 104 | } 105 | return L->Pts[L->Sp-1]; 106 | } 107 | 108 | /* ==================================== */ 109 | void LifoPush(Lifo * L, index_t V) 110 | /* ==================================== */ 111 | #undef F_NAME 112 | #define F_NAME "LifoPush" 113 | { 114 | if (L->Sp > L->Max - 1) 115 | { 116 | fprintf(stderr, "%s: full Lifo\n", F_NAME); 117 | exit(1); 118 | } 119 | L->Pts[L->Sp] = V; 120 | L->Sp += 1; 121 | } 122 | 123 | /* ==================================== */ 124 | void LifoPrint(Lifo * L) 125 | /* ==================================== */ 126 | { 127 | index_t i; 128 | if (LifoVide(L)) {printf("[]"); return;} 129 | printf("[ "); 130 | for (i = 0; i < L->Sp; i++) 131 | #ifdef MC_64_BITS 132 | printf("%lld ", L->Pts[i]); 133 | #else 134 | printf("%d ", L->Pts[i]); 135 | #endif 136 | printf("]"); 137 | } 138 | 139 | /* ==================================== */ 140 | void LifoPrintLine(Lifo * L) 141 | /* ==================================== */ 142 | { 143 | index_t i; 144 | if (LifoVide(L)) {printf("[]\n"); return;} 145 | printf("[ "); 146 | for (i = 0; i < L->Sp; i++) 147 | #ifdef MC_64_BITS 148 | printf("%lld ", L->Pts[i]); 149 | #else 150 | printf("%d ", L->Pts[i]); 151 | #endif 152 | printf("]\n"); 153 | } 154 | 155 | /* ==================================== */ 156 | void LifoTermine(Lifo * L) 157 | /* ==================================== */ 158 | { 159 | free(L); 160 | } 161 | 162 | #ifdef TESTLifo 163 | void main() 164 | { 165 | Lifo * L = CreeLifoVide(3); 166 | LifoPrint(L); 167 | if (LifoVide(L)) printf("LifoVide OUI\n"); 168 | LifoPush(L,1); 169 | LifoPrint(L); 170 | if (!LifoVide(L)) printf("LifoVide NON\n"); 171 | LifoPush(L,2); 172 | LifoPrint(L); 173 | LifoPush(L,3); 174 | LifoPrint(L); 175 | printf("LifoPop %d attendu 3\n", LifoPop(L)); 176 | LifoPrint(L); 177 | LifoPush(L,4); 178 | LifoPrint(L); 179 | printf("LifoPop %d attendu 4\n", LifoPop(L)); 180 | LifoPrint(L); 181 | printf("LifoPop %d attendu 2\n", LifoPop(L)); 182 | LifoPrint(L); 183 | printf("LifoPop %d attendu 1\n", LifoPop(L)); 184 | LifoPrint(L); 185 | if (LifoVide(L)) printf("LifoVide OUI\n"); 186 | printf("maintenant sortie attendue sur lifo pleine :\n"); 187 | LifoPush(L,3); 188 | LifoPush(L,3); 189 | LifoPush(L,3); 190 | LifoPush(L,3); 191 | } 192 | #endif 193 | 194 | -------------------------------------------------------------------------------- /pyRORPO/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | project(pyRORPO) 4 | 5 | # FIND OPENMP 6 | find_package(OpenMP REQUIRED) 7 | if(OPENMP_FOUND) 8 | message("OpenMP FOUND") 9 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 11 | endif() 12 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 13 | 14 | # Find ITK 15 | find_package(ITK REQUIRED) 16 | include(${ITK_USE_FILE}) 17 | 18 | message("Fetching pybind11") 19 | include(FetchContent) 20 | FetchContent_Declare( 21 | pybind11 22 | GIT_REPOSITORY https://github.com/pybind/pybind11.git 23 | ) 24 | FetchContent_MakeAvailable(pybind11) 25 | 26 | 27 | # add_subdirectory("${PROJECT_SOURCE_DIR}/pybind11") 28 | 29 | pybind11_add_module(${PROJECT_NAME} 30 | pyRORPO.cpp 31 | ) 32 | 33 | # LINK REQUIRED LIBS 34 | target_link_libraries( ${PROJECT_NAME} PRIVATE RORPO ${ITK_LIBRARIES} ) 35 | -------------------------------------------------------------------------------- /pyRORPO/README.md: -------------------------------------------------------------------------------- 1 | # Python bindings with Pybind11 2 | 3 | - [Pybind11 Repo](https://github.com/pybind/pybind11) 4 | - [Pybind11 Documentation](https://pybind11.readthedocs.io/en/stable/) 5 | 6 | All resources required to generete the python module are inside the directory `/pyRORPO`. 7 | 8 | ## Usage 9 | 10 | Building target `pyRORPO` will generate a dynamic library. This library can be imported as a python module : 11 | 12 | ``` python 13 | >>> import pyRORPO 14 | >>> print(pyRORPO.__doc__) 15 | FIXME: insert real documentation 16 | ``` 17 | 18 | ## Guide 19 | 20 | PyRORPO documentation: https://rorpo.readthedocs.io/en/latest/ 21 | 22 | All bindings are defined using the following c++ files : 23 | 24 | - `pyRORPO/pyRORPO.cpp` : The python module is defined inside `pyRORPO/pyRORPO.cpp`. 25 | 26 | To add methods to the module from templated functions, pybind11 requires to specify the type. To cover all kind of input types two levels of macros are used: 27 | - `BINDING_(type)` : Creates the python binding for a given method. It is defined with a specific type. 28 | - `BINDINGS_OF_TYPE(type)` : For a given type, adds all bindings using that type. 29 | 30 | - `pyRORPO/bind_*.cpp` : Defines the c++ functions that are binded using `BINDING_(type)` macros as well as the macros themselves. 31 | 32 | - `pyRORPO/bindingUtils.hpp` : Usefull functions to create bindings (e.g. processing of pybind11 types). 33 | -------------------------------------------------------------------------------- /pyRORPO/bind_RORPO.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Image/Image.hpp" 4 | #include "Image/Image_IO_ITK.hpp" 5 | 6 | #include "pyRORPO.hpp" 7 | 8 | #include "RORPO/RORPO.hpp" 9 | 10 | #include 11 | #include 12 | 13 | #define RORPO_BINDING(x) \ 14 | m.def("RORPO", &RORPO_binding, "rorpo usage", \ 15 | py::arg("image"), \ 16 | py::arg("scale"), \ 17 | py::arg("spacing") = py::none(), \ 18 | py::arg("origin") = py::none(), \ 19 | py::arg("nbCores") = 1, \ 20 | py::arg("dilationSize") = 2, \ 21 | py::arg("verbose") = false, \ 22 | py::arg("mask") = py::none(), \ 23 | py::arg("directions") = false \ 24 | ); \ 25 | 26 | namespace pyRORPO 27 | { 28 | template 29 | py::array_t RORPO_binding(py::array_t imageArray, 30 | int scale, 31 | std::optional> spacingOpt, 32 | std::optional> originOpt, 33 | int nbCores = 1, 34 | int dilationSize = 2, 35 | int verbose = false, 36 | std::optional> maskArray = py::none(), 37 | bool directions = false) 38 | { 39 | std::vector window(3); 40 | window[2] = 0; 41 | 42 | std::vector spacing = spacingOpt ? *spacingOpt : std::vector{1.0, 1.0, 1.0}; 43 | std::vector origin = originOpt ? *originOpt : std::vector{1.0, 1.0, 1.0}; 44 | 45 | // ---------------------------- Load image data ---------------------------- 46 | 47 | Image3D image = pyarrayToImage3D(imageArray, spacing, origin); 48 | std::cout << "after arr2img: " << image.get_data()[0] << " : " << image.get_data()[1] << " : " < mask; 53 | 54 | if (maskArray) 55 | mask = pyarrayToImage3D(*maskArray, spacing, origin); 56 | 57 | // ------ Directions setup ---------- 58 | 59 | std::shared_ptr> directionsResult = nullptr; 60 | 61 | if (directions) { 62 | directionsResult = std::make_shared>(std::vector(image.size() * 3, 0)); 63 | } 64 | 65 | // ---------------------------- Run RORPO ---------------------------------- 66 | 67 | Image3D output = RORPO( 68 | image, 69 | scale, 70 | nbCores, 71 | dilationSize, 72 | //verbose, 73 | mask, 74 | directionsResult 75 | ); 76 | 77 | // ---------------------------- Return results ------------------------------ 78 | 79 | if (directions) { 80 | std::vector directionsImgType(directionsResult->begin(), directionsResult->end()); 81 | 82 | auto nbDim = output.dimY(); 83 | nbDim = 3; 84 | 85 | py::array_t result = py::array_t({output.dimZ(), output.dimY(), output.dimX(), nbDim}); 86 | 87 | py::buffer_info buf3 = result.request(); 88 | PixelType* ptr = (PixelType*) buf3.ptr; 89 | 90 | memcpy(ptr, directionsImgType.data(), directionsImgType.size() * sizeof(PixelType)); 91 | 92 | result.resize({output.dimZ(), output.dimY(), output.dimX(), nbDim}); 93 | 94 | return result; 95 | } 96 | 97 | return image3DToPyarray(output); 98 | } 99 | 100 | } // namespace pyRORPO -------------------------------------------------------------------------------- /pyRORPO/bind_RORPO_multiscale.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Image/Image.hpp" 3 | #include "Image/Image_IO_ITK.hpp" 4 | 5 | #include "pyRORPO.hpp" 6 | 7 | #include "RORPO/RORPO_multiscale.hpp" 8 | 9 | #include 10 | 11 | #define RORPO_MULTISCALE_BINDING(x) \ 12 | m.def("RORPO_multiscale", &RORPO_multiscale_binding, "RORPO multiscale", \ 13 | py::arg("image") , \ 14 | py::arg("scaleMin"), \ 15 | py::arg("factor"), \ 16 | py::arg("nbScale"), \ 17 | py::arg("spacing") = py::none(), \ 18 | py::arg("origin") = py::none(), \ 19 | py::arg("nbCores") = 1, \ 20 | py::arg("dilationSize") = 2 , \ 21 | py::arg("verbose") = false, \ 22 | py::arg("mask") = py::none() \ 23 | ); \ 24 | 25 | namespace pyRORPO 26 | { 27 | 28 | template 29 | py::array_t RORPO_multiscale_binding(py::array_t imageArray, 30 | float scaleMin, 31 | float factor, 32 | int nbScales, 33 | std::optional> spacingOpt, 34 | std::optional> originOpt, 35 | int nbCores = 1, 36 | int dilationSize = 2, 37 | int verbose = false, 38 | std::optional> maskArray = py::none()) 39 | { 40 | std::vector window(3); 41 | window[2] = 0; 42 | 43 | std::vector spacing = spacingOpt ? *spacingOpt : std::vector{1.0, 1.0, 1.0}; 44 | std::vector origin = originOpt ? *originOpt : std::vector{1.0, 1.0, 1.0}; 45 | 46 | // -------------------------- Scales computation --------------------------- 47 | 48 | std::vector scaleList(nbScales); 49 | scaleList[0] = scaleMin; 50 | 51 | for (int i = 1; i < nbScales; ++i) 52 | scaleList[i] = int(scaleMin * pow(factor, i)); 53 | 54 | if (verbose){ 55 | std::cout<<"Scales : "; 56 | std::cout< image = pyarrayToImage3D(imageArray, spacing, origin); 64 | 65 | if (verbose){ 66 | std::cout << "dimensions: [" << image.dimX() << ", " << image.dimY() << ", " << image.dimZ() << "]" << std::endl; 67 | std::cout << "spacing: [" << image.spacingX() << ", " << image.spacingY() << ", " << image.spacingZ() << "]" << std::endl; 68 | } 69 | 70 | // ------------------ Compute input image intensity range ------------------ 71 | 72 | std::pair minmax = image.min_max_value(); 73 | 74 | if (verbose){ 75 | std::cout<< "Image intensity range: "<< (int)minmax.first << ", " 76 | << (int)minmax.second << std::endl; 77 | std::cout< mask; 83 | 84 | if (maskArray) 85 | mask = pyarrayToImage3D(*maskArray, spacing, origin); 86 | 87 | // ---------------------- Run RORPO_multiscale ----------------------------- 88 | 89 | Image3D output = RORPO_multiscale(image, scaleList, nbCores, dilationSize, verbose, mask); 90 | 91 | return image3DToPyarray(output); 92 | } 93 | 94 | } // namespace pyRORPO -------------------------------------------------------------------------------- /pyRORPO/bind_RPO.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Image/Image.hpp" 4 | #include "Image/Image_IO_ITK.hpp" 5 | 6 | #include "pyRORPO.hpp" 7 | 8 | #include "RORPO/RPO.hpp" 9 | 10 | #include 11 | 12 | #define RPO_BINDING(x) \ 13 | m.def("RPO", &RPO_binding, "rpo usage", \ 14 | py::arg("image"), \ 15 | py::arg("scale"), \ 16 | py::arg("spacing") = py::none(), \ 17 | py::arg("origin") = py::none(), \ 18 | py::arg("nbCores") = 1, \ 19 | py::arg("dilationSize") = 3, \ 20 | py::arg("verbose") = false, \ 21 | py::arg("mask") = py::none() \ 22 | ); \ 23 | 24 | namespace pyRORPO 25 | { 26 | template 27 | py::array_t RPO_binding(py::array_t imageArray, 28 | int scale, 29 | std::optional> spacingOpt, 30 | std::optional> originOpt, 31 | int nbCores = 1, 32 | int dilationSize = 2, 33 | int verbose = false, 34 | std::optional> maskArray = py::none()) 35 | { 36 | std::vector window(3); 37 | window[2] = 0; 38 | 39 | std::vector spacing = spacingOpt ? *spacingOpt : std::vector{1.0, 1.0, 1.0}; 40 | std::vector origin = originOpt ? *originOpt : std::vector{1.0, 1.0, 1.0}; 41 | 42 | // ---------------------------- Load image data ---------------------------- 43 | 44 | Image3D image = pyarrayToImage3D(imageArray, spacing, origin); 45 | 46 | // -------------------------- mask Image ----------------------------------- 47 | 48 | Image3D mask; 49 | 50 | if (maskArray) 51 | mask = pyarrayToImage3D(*maskArray, spacing, origin); 52 | 53 | // ############################# RPO ###################################### 54 | 55 | // the 7 RPO images with a 2-pixel border 56 | Image3D RPO1(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 57 | Image3D RPO2(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 58 | Image3D RPO3(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 59 | Image3D RPO4(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 60 | Image3D RPO5(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 61 | Image3D RPO6(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 62 | Image3D RPO7(image.dimX() + 4, image.dimY() + 4, image.dimZ() + 4, 2); 63 | 64 | RPO(image, scale, RPO1, RPO2, RPO3, RPO4, RPO5,RPO6, RPO7, nbCores, dilationSize, mask); 65 | 66 | // ----------------------- Image3D to pyarray ------------------------------ 67 | 68 | auto nbDirections = RPO1.dimY(); 69 | nbDirections = 7; 70 | 71 | py::array_t result = py::array_t({nbDirections, RPO1.dimZ(), RPO1.dimY(), RPO1.dimX()}); 72 | 73 | py::buffer_info buf3 = result.request(); 74 | 75 | PixelType* ptr = (PixelType*) buf3.ptr; 76 | 77 | size_t offset = 0; 78 | memcpy(ptr + offset, RPO1.get_pointer(), RPO1.size() * sizeof(PixelType)); 79 | offset += RPO1.size(); 80 | memcpy(ptr + offset, RPO2.get_pointer(), RPO2.size() * sizeof(PixelType)); 81 | offset += RPO2.size(); 82 | memcpy(ptr + offset, RPO3.get_pointer(), RPO3.size() * sizeof(PixelType)); 83 | offset += RPO3.size(); 84 | memcpy(ptr + offset, RPO4.get_pointer(), RPO4.size() * sizeof(PixelType)); 85 | offset += RPO4.size(); 86 | memcpy(ptr + offset, RPO5.get_pointer(), RPO5.size() * sizeof(PixelType)); 87 | offset += RPO5.size(); 88 | memcpy(ptr + offset, RPO6.get_pointer(), RPO6.size() * sizeof(PixelType)); 89 | offset += RPO6.size(); 90 | memcpy(ptr + offset, RPO7.get_pointer(), RPO7.size() * sizeof(PixelType)); 91 | offset += RPO7.size(); 92 | 93 | result.resize({nbDirections, RPO1.dimZ(), RPO1.dimY(), RPO1.dimX()}); 94 | 95 | return result; 96 | } 97 | 98 | } // namespace pyRORPO -------------------------------------------------------------------------------- /pyRORPO/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /pyRORPO/docs/README.md: -------------------------------------------------------------------------------- 1 | # pyRORPO Documentation 2 | 3 | ## References: 4 | - [Read the Docs](https://readthedocs.org/) 5 | - [Sphinx](https://www.sphinx-doc.org/en/master/usage/quickstart.html) 6 | -------------------------------------------------------------------------------- /pyRORPO/docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /pyRORPO/docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx 2 | sphinx_rtd_theme 3 | -------------------------------------------------------------------------------- /pyRORPO/docs/source/conf.py: -------------------------------------------------------------------------------- 1 | project = 'RORPO Pybind' 2 | copyright = '2020, Odyssée Merveille, Hugues Talbot, Laurent Najman, Nicolas Passat' 3 | author = 'Odyssée Merveille, Hugues Talbot, Laurent Najman, Nicolas Passat' 4 | 5 | extensions = [ 6 | 'sphinx_rtd_theme', 7 | ] 8 | 9 | # templates_path = ['_templates'] 10 | exclude_patterns = [] 11 | 12 | html_theme = "sphinx_rtd_theme" 13 | # html_theme_path = ["_themes"] 14 | # html_static_path = ['_static'] 15 | -------------------------------------------------------------------------------- /pyRORPO/docs/source/documentation.rst: -------------------------------------------------------------------------------- 1 | ************* 2 | Documentation 3 | ************* 4 | 5 | RPO 6 | === 7 | 8 | .. py:function:: pyRORPO.RPO(image, scale, spacing=None, origin=None, nbCores=1, dilationSize=3, verbose=False, mask=None) 9 | 10 | Compute the 7 orientations of the Robust Path Opening. 11 | 12 | :param numpy.ndarray image: Input image 13 | :param int scale: Path length smaller than the real curvilinear structure length 14 | :param List[float] spacing: The size of a pixel in physical space along each dimension 15 | :param List[float] origin: The origin of the image - the geometric coordinates of the index (0,0,0) 16 | :param int nbCores: Number of CPUs used for RPO computation 17 | :param int dilationSize: Size of the dilation for the noise robustness step. 18 | :param bool verbose: Activation of a verbose mode 19 | :param numpy.ndarray mask: Path to a mask image (0 for the background and 1 for the foreground) 20 | 21 | :return: 7 Robust Path Opening responses of 7 orientations . 22 | :rtype: numpy.ndarray 23 | 24 | 25 | Example: 26 | 27 | Open image with SimpleITK 28 | 29 | .. code:: python 30 | 31 | import SimpleITK as sitk 32 | 33 | reader = sitk.ImageFileReader() 34 | reader.SetFileName(PATH_TO_IMAGE) 35 | itk_image = reader.Execute() 36 | 37 | 38 | Prepare variables 39 | 40 | .. code:: python 41 | 42 | import numpy as np 43 | 44 | im_arr = sitk.GetArrayFromImage(itk_image) 45 | scale = 80 46 | spacing = itk_image.GetSpacing() 47 | origin = itk_image.GetOrigin() 48 | mask = np.zeros(im_arr.shape, dtype="uint8") 49 | mask[50:-50, 50:-50, 50:-50] = 1 50 | 51 | run RPO 52 | 53 | .. code:: python 54 | 55 | import pyRORPO 56 | responses = pyRORPO.RPO(im_arr, scale, spacing, origin, nbCores=8, dilationSize=2) 57 | 58 | 59 | 60 | RORPO 61 | ===== 62 | 63 | .. py:function:: pyRORPO.RORPO(image, scale, spacing=None, origin=None, nbCores=1, dilationSize=2, verbose=False, mask=None) 64 | 65 | Compute the Ranking Orientations Response of Path Operators 66 | 67 | :param numpy.ndarray image: Input image 68 | :param int scale: Path length smaller than the real curvilinear structure length 69 | :param List[float] spacing: The size of a pixel in physical space along each dimension 70 | :param List[float] origin: The origin of the image - the geometric coordinates of the index (0,0,0) 71 | :param int nbCores: Number of CPUs used for RPO computation 72 | :param int dilationSize: Size of the dilation for the noise robustness step. 73 | :param bool verbose: Activation of a verbose mode 74 | :param numpy.ndarray mask: Path to a mask image (0 for the background and 1 for the foreground) 75 | 76 | :return: Ranking Orientations Response of Path Operators. 77 | :rtype: numpy.ndarray 78 | 79 | .. code:: python 80 | 81 | import pyRORPO 82 | response = pyRORPO.RORPO(im_arr, scale, spacing, origin, nbCores=8, dilationSize=2) 83 | 84 | 85 | 86 | RORPO_multiscale 87 | ================ 88 | 89 | .. py:function:: pyRORPO.RORPO_multiscale(image, scaleMin, factor, nbScale, spacing=None, origin=None, nbCores=1, dilationSize=2, verbose=False, mask=None) 90 | 91 | Compute the multiscale RORPO 92 | 93 | :param numpy.ndarray image: Input image 94 | :param float scaleMin: Path length smaller than the real curvilinear structure length 95 | :param float factor: Factor for the geometric sequence of scales; scale_(n+1) = factor * scale_(n) 96 | :param int nbScale: Number of scales 97 | :param List[float] spacing: The size of a pixel in physical space along each dimension 98 | :param List[float] origin: The origin of the image - the geometric coordinates of the index (0,0,0) 99 | :param int nbCores: Number of CPUs used for RPO computation 100 | :param int dilationSize: Size of the dilation for the noise robustness step. 101 | :param bool verbose: Activation of a verbose mode 102 | :param numpy.ndarray mask: Path to a mask image (0 for the background and 1 for the foreground) 103 | 104 | :return: the multiscale RORPO 105 | :rtype: numpy.ndarray 106 | 107 | .. code:: python 108 | 109 | import pyRORPO 110 | response = pyRORPO.RORPO_multiscale(im_arr, scaleMin=80, factor=1.5, nbScale=4, spacing=spacing, origin=origin, nbCores=8, dilationSize=2) 111 | -------------------------------------------------------------------------------- /pyRORPO/docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. RORPO Pybind documentation master file, created by 2 | sphinx-quickstart on Sun Nov 8 22:38:21 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to RORPO Pybind's documentation! 7 | ======================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | installation 14 | documentation 15 | 16 | 17 | -------------------------------------------------------------------------------- /pyRORPO/docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | Installation 3 | ************ 4 | 5 | Python package (to-be-available) 6 | ================================ 7 | Install the package (or add it to your 8 | ``requirements.txt`` file): 9 | 10 | .. code:: console 11 | 12 | $ pip install rorpo 13 | 14 | 15 | Via a shared library 16 | ==================== 17 | Build the project with cmake, then run the command 18 | ``make pyRORPO`` to generate ``pyRORPO.*.so`` file. 19 | 20 | .. code:: console 21 | 22 | $ mkdir build 23 | $ cd build 24 | $ cmake .. 25 | $ make pyRORPO 26 | 27 | The generated shared library is in pyRORPO directory. 28 | 29 | .. code:: console 30 | 31 | $ ls pyRORPO/pyRORPO.*.so 32 | 33 | 34 | .. note:: 35 | Move ``pyRORPO.*.so`` to working directory of your 36 | project or insert the path of the directory 37 | containing this library to ``sys.path`` to import 38 | the module 39 | 40 | .. code:: python 41 | 42 | import sys 43 | PATH_TO_SHARED_LIBRARY_DIR = "RORPO/build/pyRORPO/" 44 | sys.path.append(PATH_TO_SHARED_LIBRARY_DIR) 45 | 46 | Then import the module 47 | 48 | .. code:: python 49 | 50 | import pyRORPO -------------------------------------------------------------------------------- /pyRORPO/pyRORPO.cpp: -------------------------------------------------------------------------------- 1 | #include "pyRORPO.hpp" 2 | 3 | #include "bind_RORPO.hpp" 4 | #include "bind_RORPO_multiscale.hpp" 5 | #include "bind_RPO.hpp" 6 | 7 | using namespace pyRORPO; 8 | 9 | #define BINDINGS_OF_TYPE(type) \ 10 | RORPO_MULTISCALE_BINDING(type); \ 11 | RORPO_BINDING(type); \ 12 | RPO_BINDING(type); \ 13 | 14 | PYBIND11_MODULE(pyRORPO, m) { 15 | m.doc() = "pybind11 RORPO plugin"; // optional module docstring 16 | 17 | BINDINGS_OF_TYPE(int8_t); 18 | BINDINGS_OF_TYPE(int16_t); 19 | BINDINGS_OF_TYPE(int32_t); 20 | BINDINGS_OF_TYPE(int64_t); 21 | 22 | BINDINGS_OF_TYPE(uint8_t); 23 | BINDINGS_OF_TYPE(uint16_t); 24 | BINDINGS_OF_TYPE(uint32_t); 25 | BINDINGS_OF_TYPE(uint64_t); 26 | 27 | BINDINGS_OF_TYPE(float); 28 | BINDINGS_OF_TYPE(double ); 29 | BINDINGS_OF_TYPE(long double); 30 | } -------------------------------------------------------------------------------- /pyRORPO/pyRORPO.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace py = pybind11; 8 | 9 | #include "Image/Image.hpp" 10 | 11 | namespace pyRORPO 12 | { 13 | template 14 | inline Image3D pyarrayToImage3D(py::array_t& imageInput, std::vector& spacing, 15 | std::vector& origin) 16 | { 17 | auto bufImage = imageInput.request(); 18 | 19 | auto image = Image3D( 20 | bufImage.shape[2], 21 | bufImage.shape[1], 22 | bufImage.shape[0], 23 | spacing[0], 24 | spacing[1], 25 | spacing[2], 26 | origin[0], 27 | origin[1], 28 | origin[2] 29 | ); 30 | 31 | image.add_data_from_pointer((PixelType*) bufImage.ptr); 32 | 33 | return image; 34 | } 35 | 36 | template 37 | inline py::array_t image3DToPyarray(Image3D& image) 38 | { 39 | py::array_t result = py::array_t({image.dimZ(), image.dimY(), image.dimX()}); 40 | 41 | py::buffer_info buf3 = result.request(); 42 | 43 | PixelType* ptr = (PixelType*) buf3.ptr; 44 | 45 | memcpy(ptr, image.get_pointer(), image.size() * sizeof(PixelType)); 46 | 47 | result.resize({image.dimZ(), image.dimY(), image.dimX()}); 48 | 49 | return result; 50 | } 51 | } --------------------------------------------------------------------------------