diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 08e4d6df..5b1435b7 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -4,8 +4,8 @@ on: [push, pull_request]
env:
BUILD_TYPE: "Release"
- OPENCV_VERSION: "3.4.13"
- EDDL_VERSION: "v0.8.3a"
+ OPENCV_VERSION: "3.4.14"
+ EDDL_VERSION: "v0.9.2b"
PROC: 2
jobs:
@@ -14,8 +14,8 @@ jobs:
strategy:
matrix:
cfg:
- - { os: ubuntu-18.04, c-version: gcc-6, cxx-version: g++-6, generator: "Unix Makefiles" }
- - { os: ubuntu-18.04, c-version: gcc-10, cxx-version: g++-10, generator: "Unix Makefiles" }
+ - { os: ubuntu-18.04, c-version: gcc-7, cxx-version: g++-7, generator: "Unix Makefiles" }
+ - { os: ubuntu-18.04, c-version: gcc-11, cxx-version: g++-11, generator: "Unix Makefiles" }
- { os: ubuntu-18.04, c-version: clang-5.0, cxx-version: clang++-5.0, generator: "Unix Makefiles" }
- { os: ubuntu-18.04, c-version: clang-10, cxx-version: clang++-10, generator: "Unix Makefiles" }
steps:
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index f912bf29..2a509013 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -4,8 +4,8 @@ on: [push, pull_request]
env:
BUILD_TYPE: "Release"
- OPENCV_VERSION: "3.4.13"
- EDDL_VERSION: "v0.8.3a"
+ OPENCV_VERSION: "3.4.14"
+ EDDL_VERSION: "v0.9.2b"
PROC: 2
jobs:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 11b124a5..aa3cfcc3 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -4,8 +4,8 @@ on: [push, pull_request]
env:
BUILD_TYPE: "Release"
- OPENCV_VERSION: "3.4.13"
- EDDL_VERSION: "v0.8.3a"
+ OPENCV_VERSION: "3.4.14"
+ EDDL_VERSION: "v0.9.2b"
PROC: 2
jobs:
diff --git a/3rdparty/dcmtk/CMakeLists.txt b/3rdparty/dcmtk/CMakeLists.txt
index 782d207f..7154da1f 100644
--- a/3rdparty/dcmtk/CMakeLists.txt
+++ b/3rdparty/dcmtk/CMakeLists.txt
@@ -6,6 +6,9 @@ FetchContent_Declare(
if(ECVL_WITH_DICOM)
if(ECVL_BUILD_DEPS)
+ if(POLICY CMP0115)
+ set(CMAKE_POLICY_DEFAULT_CMP0115 OLD)
+ endif()
FetchContent_GetProperties(dcmtk)
if(NOT dcmtk_POPULATED)
FetchContent_Populate(dcmtk)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 899c6327..57af48e6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "")
set(CMAKE_POSITION_INDEPENDENT_CODE ON) # To always generate position independent code
+set(CMAKE_VERBOSE_MAKEFILE ON)
if (WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
diff --git a/Jenkinsfile b/Jenkinsfile
index b980df82..fd17b2c8 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -15,7 +15,7 @@ pipeline {
steps {
timeout(60) {
echo 'Building..'
- cmakeBuild buildDir: 'build', cmakeArgs: '-DECVL_TESTS=ON -DECVL_BUILD_EDDL=ON -DECVL_DATASET=ON -DECVL_WITH_DICOM=ON -DECVL_WITH_OPENSLIDE=ON -DECVL_GPU=OFF', installation: 'InSearchPath', sourceDir: '.', cleanBuild: true, steps: [
+ cmakeBuild buildDir: 'build', buildType: 'Release', cmakeArgs: '-DECVL_TESTS=ON -DECVL_BUILD_EDDL=ON -DECVL_DATASET=ON -DECVL_WITH_DICOM=ON -DECVL_WITH_OPENSLIDE=ON -DECVL_GPU=OFF', installation: 'InSearchPath', sourceDir: '.', cleanBuild: true, steps: [
[args: '--parallel 4', withCmake: true]
]
}
@@ -25,7 +25,7 @@ pipeline {
steps {
timeout(15) {
echo 'Testing..'
- ctest arguments: '-C Debug -VV', installation: 'InSearchPath', workingDir: 'build'
+ ctest arguments: '-C Release -VV', installation: 'InSearchPath', workingDir: 'build'
}
}
}
@@ -46,8 +46,8 @@ pipeline {
timeout(60) {
echo 'Building..'
bat 'powershell ../../ecvl_dependencies/ecvl_dependencies.ps1'
- cmakeBuild buildDir: 'build', cmakeArgs: '-DECVL_TESTS=ON -DECVL_BUILD_EDDL=ON -DECVL_DATASET=ON -DECVL_WITH_DICOM=ON -DECVL_WITH_OPENSLIDE=ON -DOPENSLIDE_LIBRARIES=C:/Library/openslide-win32-20171122/lib/libopenslide.lib', installation: 'InSearchPath', sourceDir: '.', cleanBuild: true, steps: [
- [args: '--parallel 4', withCmake: true]
+ cmakeBuild buildDir: 'build', buildType: 'Release', cmakeArgs: '-DECVL_TESTS=ON -DECVL_BUILD_EDDL=ON -DECVL_DATASET=ON -DECVL_WITH_DICOM=ON -DECVL_WITH_OPENSLIDE=ON -DOPENSLIDE_LIBRARIES=C:/Library/openslide-win32-20171122/lib/libopenslide.lib', installation: 'InSearchPath', sourceDir: '.', cleanBuild: true, steps: [
+ [args: '--config Release --parallel 4', withCmake: true]
]
}
}
@@ -56,7 +56,7 @@ pipeline {
steps {
timeout(15) {
echo 'Testing..'
- bat 'cd build && ctest -C Debug -VV'
+ bat 'cd build && ctest -C Release -VV'
}
}
}
@@ -64,7 +64,7 @@ pipeline {
steps {
timeout(15) {
echo 'Calculating coverage..'
- bat '"C:/Program Files/OpenCppCoverage/OpenCppCoverage.exe" --source %cd% --export_type=cobertura --excluded_sources=3rdparty -- "build/bin/Debug/ECVL_TESTS.exe"'
+ bat '"C:/Program Files/OpenCppCoverage/OpenCppCoverage.exe" --source %cd% --export_type=cobertura --excluded_sources=3rdparty -- "build/bin/Release/ECVL_TESTS.exe"'
cobertura coberturaReportFile: 'ECVL_TESTSCoverage.xml'
bat 'codecov -f ECVL_TESTSCoverage.xml -t 7635bd2e-51cf-461e-bb1b-fc7ba9fb26d1'
}
diff --git a/README.md b/README.md
index 494ef84a..181b6457 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ The ECVL documentation is available [here](https://deephealthproject.github.io/e
## Requirements
- CMake 3.13 or later
-- C++ Compiler with C++17 support (e.g. GCC 6 or later, Clang 5.0 or later, Visual Studio 2017 or later)
+- C++ Compiler with C++17 support (e.g. GCC 7 or later, Clang 5.0 or later, Visual Studio 2017 or later)
- [OpenCV](https://opencv.org) 3.0 or later (modules required: `core`, `imgproc`, `imgcodecs`, `photo`, [`calib3d` since OpenCV 4.0 only. Note that `calib3d` depends on `features2d` and `flann`])
### Optional
@@ -193,16 +193,16 @@ Contributions of any kind are welcome!
Windows Server 2016 |
VS 2017 15.9.28307 |
- 3.4.13 |
- 0.8.3 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
|
Windows Server 2019 |
- VS 2019 16.8.30804 |
- 3.4.13 |
- 0.8.3 |
+ VS 2019 16.9.31229 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
@@ -228,31 +228,31 @@ Contributions of any kind are welcome!
Ubuntu 18.04.5 |
- GCC 6.5.0 |
- 3.4.13 |
- 0.8.3 |
+ GCC 7.5.0 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
|
Ubuntu 18.04.5 |
- GCC 10.1.0 |
- 3.4.13 |
- 0.8.3 |
+ GCC 11.1.0 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
Ubuntu 18.04.5 |
Clang 5.0.1 |
- 3.4.13 |
- 0.8.3 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
Ubuntu 18.04.5 |
Clang 10.0.0 |
- 3.4.13 |
- 0.8.3 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
@@ -273,8 +273,8 @@ Contributions of any kind are welcome!
macOS 10.15 |
Apple Clang 12.0.0 |
- 3.4.13 |
- 0.8.3 |
+ 3.4.14 |
+ 0.9.2b |
GitHub Actions |
|
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 51b5a876..14a49dec 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -38,8 +38,11 @@ if(ECVL_DATASET)
endif()
if(ECVL_BUILD_EDDL AND eddl_FOUND)
add_executable(example_ecvl_eddl "examples/example_ecvl_eddl.cpp")
+ add_executable(example_pipeline "examples/example_pipeline.cpp")
set_target_properties(example_ecvl_eddl PROPERTIES FOLDER "Examples")
target_link_libraries(example_ecvl_eddl ${ECVL_MODULES})
+ set_target_properties(example_pipeline PROPERTIES FOLDER "Examples")
+ target_link_libraries(example_pipeline ${ECVL_MODULES})
endif()
if(ECVL_BUILD_GUI AND wxWidgets_FOUND)
add_executable(example_ecvl_gui "examples/example_ecvl_gui.cpp")
diff --git a/examples/example_dataset_generator.cpp b/examples/example_dataset_generator.cpp
index b42acb09..57d4a5be 100644
--- a/examples/example_dataset_generator.cpp
+++ b/examples/example_dataset_generator.cpp
@@ -45,17 +45,18 @@ int main()
vector mask;
vector black;
- for (auto& index : d_segmentation.split_.training_) {
- if (d_segmentation.samples_[index].label_path_.value().filename().compare("black.png") == 0) {
- black.emplace_back(index);
+ auto& training = d_segmentation.GetSplit("training");
+ for (auto& sample_index : training) {
+ if (d_segmentation.samples_[sample_index].label_path_.value().filename().compare("black.png") == 0) {
+ black.emplace_back(sample_index);
}
else {
- mask.emplace_back(index);
+ mask.emplace_back(sample_index);
}
}
- d_segmentation.split_.training_.clear();
- d_segmentation.split_.training_.insert(d_segmentation.split_.training_.end(), mask.begin(), mask.end());
+ training.clear();
+ training.insert(training.end(), mask.begin(), mask.end());
// Dump the Dataset on file
d_segmentation.Dump(dateset_root_folder_segmentation / path(dateset_root_folder_segmentation.stem().string() + ".yml"));
diff --git a/examples/example_ecvl_eddl.cpp b/examples/example_ecvl_eddl.cpp
index c6f4a11d..e2cda679 100644
--- a/examples/example_ecvl_eddl.cpp
+++ b/examples/example_ecvl_eddl.cpp
@@ -13,7 +13,6 @@
#include
#include
-#include
#include "ecvl/core.h"
#include "ecvl/support_eddl.h"
@@ -34,6 +33,7 @@ int main()
// Create an augmentation sequence to be applied to the image
auto augs = make_shared(
+ AugCenterCrop(), // Make image squared
AugRotate({ -5, 5 }),
AugMirror(.5),
AugFlip(.5),
@@ -71,6 +71,7 @@ int main()
cout << "Executing TensorToView" << endl;
TensorToView(t, view);
+ // Create an augmentation sequence from stream
stringstream ss(
"SequentialAugmentationContainer\n"
" AugRotate angle=[-5,5] center=(0,0) interp=\"linear\"\n"
@@ -85,21 +86,28 @@ int main()
auto newdeal_augs = AugmentationFactory::create(ss);
newdeal_augs->Apply(tmp);
+ /*--------------------------------------------------------------------------------------------*/
+
// Create the augmentations to be applied to the dataset images during training and test.
- // nullptr is given as augmentation for validation because this split doesn't exist in the mnist dataset.
auto training_augs = make_shared(
AugRotate({ -5, 5 }),
AugAdditiveLaplaceNoise({ 0, 0.2 * 255 }),
AugCoarseDropout({ 0, 0.55 }, { 0.02,0.1 }, 0),
AugAdditivePoissonNoise({ 0, 40 }),
- AugResizeDim({ 30, 30 })
+ AugResizeDim({ 30, 30 }),
+ AugToFloat32(255),
+ AugNormalize({ 0.449 }, { 0.226 }) // mean of imagenet stats
);
auto test_augs = make_shared(
- AugResizeDim({ 30, 30 })
+ AugResizeDim({ 30, 30 }),
+ AugToFloat32(255),
+ AugNormalize({ 0.449 }, { 0.226 }) // mean of imagenet stats
);
- DatasetAugmentations dataset_augmentations{ {training_augs, nullptr, test_augs } };
+ // OLD version: now the number of augmentations must match the number of splits in the yml file
+ // DatasetAugmentations dataset_augmentations{ {training_augs, nullptr, test_augs } };
+ DatasetAugmentations dataset_augmentations{ {training_augs, test_augs } };
int batch_size = 64;
cout << "Creating a DLDataset" << endl;
@@ -128,6 +136,10 @@ int main()
d.SetSplit(SplitType::test);
d.LoadBatch(x, y);
+ // Save some input images
+ ImWrite("mnist_batch.png", MakeGrid(x, 8, false));
+ ImWrite("mnist_batch_normalized.png", MakeGrid(x, 8, true));
+
delete x;
delete y;
delete t;
diff --git a/examples/example_pipeline.cpp b/examples/example_pipeline.cpp
new file mode 100644
index 00000000..7cdfebe7
--- /dev/null
+++ b/examples/example_pipeline.cpp
@@ -0,0 +1,138 @@
+/*
+* ECVL - European Computer Vision Library
+* Version: 0.3.4
+* copyright (c) 2021, Università degli Studi di Modena e Reggio Emilia (UNIMORE), AImageLab
+* Authors:
+* Costantino Grana (costantino.grana@unimore.it)
+* Federico Bolelli (federico.bolelli@unimore.it)
+* Michele Cancilla (michele.cancilla@unimore.it)
+* Laura Canalini (laura.canalini@unimore.it)
+* Stefano Allegretti (stefano.allegretti@unimore.it)
+* All rights reserved.
+*/
+
+#include
+#include
+#include
+#include
+
+#include "ecvl/augmentations.h"
+#include "ecvl/core.h"
+#include "ecvl/support_eddl.h"
+#include "ecvl/core/filesystem.h"
+
+using namespace ecvl;
+using namespace ecvl::filesystem;
+using namespace eddl;
+using namespace std;
+
+int main()
+{
+ // Create the augmentations to be applied to the dataset images during training and test.
+ auto training_augs = make_shared(
+ AugRotate({ -5, 5 }),
+ AugAdditiveLaplaceNoise({ 0, 0.2 * 255 }),
+ AugCoarseDropout({ 0, 0.55 }, { 0.02,0.1 }, 0),
+ AugAdditivePoissonNoise({ 0, 40 }),
+ AugToFloat32(255)
+ );
+
+ auto test_augs = make_shared(AugToFloat32(255));
+
+ // Replace the random seed with a fixed one to have reproducible experiments
+ AugmentationParam::SetSeed(0);
+
+ DatasetAugmentations dataset_augmentations{ { training_augs, test_augs } };
+
+ constexpr int epochs = 5;
+ constexpr int batch_size = 200;
+ constexpr int num_workers = 4;
+ constexpr int queue_ratio = 5;
+ cout << "Creating a DLDataset" << endl;
+
+ // Initialize the DLDataset
+ DLDataset d("../examples/data/mnist/mnist_reduced.yml", batch_size, dataset_augmentations, ColorType::GRAY, ColorType::none, num_workers, queue_ratio, { true, false });
+ //DLDataset d("D:/Data/isic_skin_lesion/isic_skin_lesion/isic_classification.yml", batch_size, dataset_augmentations, ColorType::RGB, ColorType::none, num_workers, queue_ratio);
+
+ ofstream of;
+ cv::TickMeter tm;
+ cv::TickMeter tm_epoch;
+ auto num_batches_training = d.GetNumBatches(SplitType::training);
+ auto num_batches_test = d.GetNumBatches(SplitType::test);
+
+ for (int i = 0; i < epochs; ++i) {
+ tm_epoch.reset();
+ tm_epoch.start();
+ /* Resize to batch_size if we have done a resize previously
+ if (d.split_[d.current_split_].last_batch_ != batch_size){
+ net->resize(batch_size);
+ }
+ */
+ cout << "Starting training" << endl;
+ d.SetSplit(SplitType::training);
+
+ // Reset current split with shuffling
+ d.ResetBatch(d.current_split_, true);
+
+ // Spawn num_workers threads
+ d.Start();
+ for (int j = 0; j < num_batches_training; ++j) {
+ tm.reset();
+ tm.start();
+ cout << "Epoch " << i << "/" << epochs - 1 << " (batch " << j << "/" << num_batches_training - 1 << ") - ";
+ cout << "|fifo| " << d.GetQueueSize() << " - ";
+
+ // tuple, unique_ptr, unique_ptr> samples_and_labels;
+ // samples_and_labels = d.GetBatch();
+ // or...
+ auto [samples, x, y] = d.GetBatch();
+
+ // Sleep in order to simulate EDDL train_batch
+ cout << "sleeping...";
+ this_thread::sleep_for(chrono::milliseconds(500));
+ // eddl::train_batch(net, { x.get() }, { y.get() });
+
+ tm.stop();
+ cout << "Elapsed time: " << tm.getTimeMilli() << endl;
+ }
+ d.Stop();
+
+ cout << "Starting test" << endl;
+ d.SetSplit(SplitType::test);
+
+ // Reset current split without shuffling
+ d.ResetBatch(d.current_split_, false);
+
+ d.Start();
+ for (int j = 0; j < num_batches_test; ++j) {
+ tm.reset();
+ tm.start();
+ cout << "Test: Epoch " << i << "/" << epochs - 1 << " (batch " << j << "/" << num_batches_test - 1 << ") - ";
+ cout << "|fifo| " << d.GetQueueSize() << " - ";
+
+ // tuple, unique_ptr, unique_ptr> samples_and_labels;
+ // samples_and_labels = d.GetBatch();
+ // or...
+ auto [_, x, y] = d.GetBatch();
+
+ /* Resize net for last batch
+ if (auto x_batch = x->shape[0]; j == num_batches_test - 1 && x_batch != batch_size) {
+ // last mini-batch could have different size
+ net->resize(x_batch);
+ }
+ */
+ // Sleep in order to simulate EDDL evaluate_batch
+ cout << "sleeping... - ";
+ this_thread::sleep_for(chrono::milliseconds(500));
+ // eddl::eval_batch(net, { x.get() }, { y.get() });
+
+ tm.stop();
+ cout << "Elapsed time: " << tm.getTimeMilli() << endl;
+ }
+ d.Stop();
+ tm_epoch.stop();
+ cout << "Epoch elapsed time: " << tm_epoch.getTimeSec() << endl;
+ }
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
diff --git a/modules/core/include/ecvl/CMakeLists.txt b/modules/core/include/ecvl/CMakeLists.txt
index f513e3c0..9ec39a96 100644
--- a/modules/core/include/ecvl/CMakeLists.txt
+++ b/modules/core/include/ecvl/CMakeLists.txt
@@ -13,6 +13,7 @@ target_sources(ECVL_CORE
PRIVATE
core.h
+ core/any.h
core/arithmetic.h
core/arithmetic_impl.inc.h
core/cpu_hal.h
diff --git a/modules/core/include/ecvl/core/any.h b/modules/core/include/ecvl/core/any.h
new file mode 100644
index 00000000..6d00771a
--- /dev/null
+++ b/modules/core/include/ecvl/core/any.h
@@ -0,0 +1,93 @@
+/*
+* ECVL - European Computer Vision Library
+* Version: 0.3.4
+* copyright (c) 2021, Università degli Studi di Modena e Reggio Emilia (UNIMORE), AImageLab
+* Authors:
+* Costantino Grana (costantino.grana@unimore.it)
+* Federico Bolelli (federico.bolelli@unimore.it)
+* Michele Cancilla (michele.cancilla@unimore.it)
+* Laura Canalini (laura.canalini@unimore.it)
+* Stefano Allegretti (stefano.allegretti@unimore.it)
+* All rights reserved.
+*/
+
+// We haven't checked which any to include yet
+#ifndef INCLUDE_STD_ANY_EXPERIMENTAL
+
+// Check for feature test macro for
+# if defined(__cpp_lib_any)
+# define INCLUDE_STD_ANY_EXPERIMENTAL 0
+
+// Check for feature test macro for
+# elif defined(__cpp_lib_experimental_any)
+# define INCLUDE_STD_ANY_EXPERIMENTAL 1
+
+// We can't check if headers exist...
+// Let's assume experimental to be safe
+# elif !defined(__has_include)
+# define INCLUDE_STD_ANY_EXPERIMENTAL 1
+
+// Check if the header "" exists
+# elif __has_include()
+
+// If we're compiling on Visual Studio and are not compiling with C++17, we need to use experimental
+# ifdef _MSC_VER
+
+// Check and include header that defines "_HAS_CXX17"
+# if __has_include()
+# include
+
+// Check for enabled C++17 support
+# if defined(_HAS_CXX17) && _HAS_CXX17
+// We're using C++17, so let's use the normal version
+# define INCLUDE_STD_ANY_EXPERIMENTAL 0
+# endif
+# endif
+
+// If the macro isn't defined yet, that means any of the other VS specific checks failed, so we need to use experimental
+# ifndef INCLUDE_STD_ANY_EXPERIMENTAL
+# define INCLUDE_STD_ANY_EXPERIMENTAL 1
+# endif
+
+// Not on Visual Studio. Let's use the normal version
+# else // #ifdef _MSC_VER
+# define INCLUDE_STD_ANY_EXPERIMENTAL 0
+# endif
+
+// Check if the header "" exists
+# elif __has_include()
+# define INCLUDE_STD_ANY_EXPERIMENTAL 1
+
+// Fail if neither header is available with a nice error message
+# else
+# error Could not find system header "" or ""
+# endif
+
+// We previously determined that we need the experimental version
+# if INCLUDE_STD_ANY_EXPERIMENTAL
+# include
+namespace ecvl
+{
+using any = std::experimental::any;
+
+template
+auto any_cast(const T& t)
+{
+ return std::experimental::any_cast(t);
+}
+}
+# else
+# include
+namespace ecvl
+{
+using any = std::any;
+
+template
+auto any_cast(const T& t)
+{
+ return std::any_cast(t);
+}
+}
+# endif
+
+#endif // #ifndef INCLUDE_STD_ANY_EXPERIMENTAL
\ No newline at end of file
diff --git a/modules/core/include/ecvl/core/imgcodecs.h b/modules/core/include/ecvl/core/imgcodecs.h
index 68f4a19b..2768b82e 100644
--- a/modules/core/include/ecvl/core/imgcodecs.h
+++ b/modules/core/include/ecvl/core/imgcodecs.h
@@ -27,7 +27,7 @@ namespace ecvl
*/
enum class ImReadMode
{
- //IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).
+ UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).
GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.
//IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
@@ -43,12 +43,39 @@ be read for any reason, the function creates an empty Image and returns false.
@param[in] filename A std::filesystem::path identifying the file name.
@param[out] dst Image in which data will be stored.
-@param[in] flags An ImReadMode indicating how to read the image.
+@param[in] flags \ref ImReadMode indicating how to read the image.
@return true if the image is correctly read, false otherwise.
*/
bool ImRead(const ecvl::filesystem::path& filename, Image& dst, ImReadMode flags = ImReadMode::ANYCOLOR);
+/**
+@brief Loads an image from a buffer in memory. This is an overloaded function, provided for convenience.
+
+The buffer must be a raw encoded image (png, jpg).
+If the image cannot be read for any reason, the function creates an empty Image and returns false.
+
+@param[in] buffer A char* identifying the input buffer.
+@param[in] size Dimension of the input buffer.
+@param[out] dst Image in which data will be stored.
+@param[in] flags \ref ImReadMode indicating how to read the image.
+
+@return true if the image is correctly read, false otherwise.
+*/
+bool ImRead(const char* buffer, const int size, Image& dst, ImReadMode flags = ImReadMode::ANYCOLOR);
+
+/** @brief Loads an image from a buffer in memory. This is an overloaded function, provided for convenience.
+
+It differs from the above function only because it accepts a std::vector instead of a char*.
+
+@param[in] buffer A std::vector identifying the input buffer.
+@param[out] dst Image in which data will be stored.
+@param[in] flags \ref ImReadMode indicating how to read the image.
+
+@return true if the image is correctly read, false otherwise.
+*/
+bool ImRead(const std::vector& buffer, Image& dst, ImReadMode flags = ImReadMode::ANYCOLOR);
+
/** @brief Loads a multi-page image from a file.
The function ImReadMulti loads a multi-page image from the specified file. If the image cannot
diff --git a/modules/core/include/ecvl/core/support_dcmtk.h b/modules/core/include/ecvl/core/support_dcmtk.h
index 118fe2a6..f1b6b0e4 100644
--- a/modules/core/include/ecvl/core/support_dcmtk.h
+++ b/modules/core/include/ecvl/core/support_dcmtk.h
@@ -57,6 +57,12 @@ The function DicomWrite saves the input image into a specified file, with the DI
*/
extern bool DicomWrite(const ecvl::filesystem::path& filename, const Image& src);
+struct InitDCMTK
+{
+ InitDCMTK();
+ ~InitDCMTK();
+};
+
/** @example example_nifti_dicom.cpp
Nifti and Dicom support example.
*/
diff --git a/modules/core/src/imgcodecs.cpp b/modules/core/src/imgcodecs.cpp
index 4d8f7c2a..5d1e92f7 100644
--- a/modules/core/src/imgcodecs.cpp
+++ b/modules/core/src/imgcodecs.cpp
@@ -52,6 +52,21 @@ bool ImRead(const path& filename, Image& dst, ImReadMode flags)
}
}
+bool ImRead(const std::vector& buffer, Image& dst, ImReadMode flags)
+{
+ cv::InputArray ia(buffer);
+ dst = MatToImage(cv::imdecode(ia, (int)flags));
+
+ // TODO: Nifti and Dicom version?
+ return !dst.IsEmpty();
+}
+
+bool ImRead(const char* buffer, const int size, Image& dst, ImReadMode flags)
+{
+ const std::vector buf(buffer, buffer + size);
+ return ImRead(buf, dst, flags);
+}
+
bool ImReadMulti(const path& filename, Image& dst)
{
std::vector v;
diff --git a/modules/core/src/support_dcmtk.cpp b/modules/core/src/support_dcmtk.cpp
index 6e4fed7d..3e718de8 100644
--- a/modules/core/src/support_dcmtk.cpp
+++ b/modules/core/src/support_dcmtk.cpp
@@ -31,6 +31,16 @@ using namespace std;
namespace ecvl
{
+
+InitDCMTK::InitDCMTK()
+{
+ DJDecoderRegistration::registerCodecs();
+}
+InitDCMTK::~InitDCMTK()
+{
+ DJDecoderRegistration::cleanup();
+}
+
bool OverlayMetaData::Query(const std::string& name, std::string& value) const
{
if (name == "overlay") {
@@ -50,10 +60,9 @@ bool OverlayMetaData::Query(const std::string& name, std::string& value) const
bool DicomRead(const std::string& filename, Image& dst)
{
+ static InitDCMTK init_dcmtk; // Created only first time DicomRead is called
bool return_value = true;
- DJDecoderRegistration::registerCodecs();
-
DicomImage* image = new DicomImage(filename.c_str());
if (image == NULL) {
return_value = false;
@@ -93,7 +102,7 @@ bool DicomRead(const std::string& filename, Image& dst)
}
else {
for (int i = 0; i < planes; i++) {
- memcpy(dst.data_ + x * y * DataTypeSize(dst_datatype) * i, reinterpret_cast(dipixel_data)[i], x * y * DataTypeSize(dst_datatype));
+ memcpy(dst.data_ + x * y * DataTypeSize(dst_datatype) * i, reinterpret_cast(dipixel_data)[i], x * y * DataTypeSize(dst_datatype));
}
}
@@ -158,8 +167,6 @@ bool DicomRead(const std::string& filename, Image& dst)
dst = Image();
}
- DJDecoderRegistration::cleanup();
-
return return_value;
}
diff --git a/modules/dataset/include/ecvl/dataset_generator.h b/modules/dataset/include/ecvl/dataset_generator.h
index bef52168..72e85166 100644
--- a/modules/dataset/include/ecvl/dataset_generator.h
+++ b/modules/dataset/include/ecvl/dataset_generator.h
@@ -39,11 +39,8 @@ class GenerateDataset
dataset_root_directory_(dataset_root_directory)
{
for (auto& p : filesystem::directory_iterator(dataset_root_directory_)) {
- std::string tmp = p.path().stem().string();
-
- // Check if split folders exist
- if (tmp == "training" || tmp == "validation" || tmp == "test") {
- splits_.emplace_back(tmp);
+ if (filesystem::is_directory(p)) {
+ splits_.emplace_back(p.path().stem().string());
}
}
num_samples_.resize(splits_.size());
diff --git a/modules/dataset/include/ecvl/dataset_parser.h b/modules/dataset/include/ecvl/dataset_parser.h
index 770b333e..32c8b623 100644
--- a/modules/dataset/include/ecvl/dataset_parser.h
+++ b/modules/dataset/include/ecvl/dataset_parser.h
@@ -15,10 +15,12 @@
#define ECVL_DATASET_PARSER_H_
#include "ecvl/core.h"
+#include "ecvl/core/any.h"
#include "ecvl/core/filesystem.h"
#include "ecvl/core/optional.h"
#include
+#include
#include