diff --git a/clic/include/core/clesperanto.hpp b/clic/include/core/clesperanto.hpp index c1fc8561e..7f3c5baa8 100644 --- a/clic/include/core/clesperanto.hpp +++ b/clic/include/core/clesperanto.hpp @@ -108,6 +108,9 @@ class Clesperanto auto DetectMaximaBox(const Image & source, const Image & destination) -> void; + auto + DetectMinima(const Image & source, const Image & destination) -> void; + auto DifferenceOfGaussian(const Image & source, const Image & destination, diff --git a/clic/include/tier1/cleDetectMinimaKernel.hpp b/clic/include/tier1/cleDetectMinimaKernel.hpp new file mode 100644 index 000000000..0035e88c2 --- /dev/null +++ b/clic/include/tier1/cleDetectMinimaKernel.hpp @@ -0,0 +1,31 @@ + +#ifndef __TIER1_CLEDETECTMINIMAKERNEL_HPP +#define __TIER1_CLEDETECTMINIMAKERNEL_HPP + +#include "cleOperation.hpp" + +namespace cle +{ + +class DetectMinimaKernel : public Operation +{ +public: + explicit DetectMinimaKernel(const ProcessorPointer & device); + auto + SetInput(const Image & object) -> void; + auto + SetOutput(const Image & object) -> void; +}; + +inline auto +DetectMinimaKernel_Call(const std::shared_ptr & device, const Image & src, const Image & dst) -> void +{ + DetectMinimaKernel kernel(device); + kernel.SetInput(src); + kernel.SetOutput(dst); + kernel.Execute(); +} + +} // namespace cle + +#endif // __TIER1_CLEDETECTMINIMAKERNEL_HPP diff --git a/clic/src/core/clesperanto.cpp b/clic/src/core/clesperanto.cpp index 94b21cb8e..8894a2194 100644 --- a/clic/src/core/clesperanto.cpp +++ b/clic/src/core/clesperanto.cpp @@ -141,6 +141,12 @@ Clesperanto::SubtractImages(const Image & source1, const Image & source2, const this->AddImagesWeighted(source1, source2, destination, 1, -1); } +auto +Clesperanto::DetectMinima(const Image & source, const Image & destination) -> void +{ + DetectMinimaKernel_Call(this->GetDevice(), source, destination); +} + auto Clesperanto::DilateSphere(const Image & source, const Image & destination) -> void { diff --git a/clic/src/tier1/cleDetectMinimaKernel.cpp b/clic/src/tier1/cleDetectMinimaKernel.cpp new file mode 100644 index 000000000..3ac4177ea --- /dev/null +++ b/clic/src/tier1/cleDetectMinimaKernel.cpp @@ -0,0 +1,26 @@ + +#include "cleDetectMinimaKernel.hpp" +#include "cle_detect_minima.h" + + +namespace cle +{ + +DetectMinimaKernel::DetectMinimaKernel(const ProcessorPointer & device) + : Operation(device, 2) +{ + this->SetSource("detect_minima", oclKernel::detect_minima); +} + +auto +DetectMinimaKernel::SetInput(const Image & object) -> void +{ + this->AddParameter("src", object); +} + +auto +DetectMinimaKernel::SetOutput(const Image & object) -> void +{ + this->AddParameter("dst", object); +} +} // namespace cle \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e16fcd5e3..1ce7ffbb9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -124,6 +124,12 @@ target_link_libraries(detect_maxima_test PRIVATE CLIc::CLIc) set_target_properties(detect_maxima_test PROPERTIES FOLDER "Tests") # target_compile_features(detect_maxima_test PRIVATE cxx_std_17) +add_executable(detect_minima_test detect_minima_test.cpp) +add_dependencies(detect_minima_test CLIc) +target_link_libraries(detect_minima_test PRIVATE CLIc::CLIc) +set_target_properties(detect_minima_test PROPERTIES FOLDER "Tests") +# target_compile_features(detect_minima_test PRIVATE cxx_std_17) + add_executable(difference_of_gaussian_test difference_of_gaussian_test.cpp) add_dependencies(difference_of_gaussian_test CLIc) target_link_libraries(difference_of_gaussian_test PRIVATE CLIc::CLIc) @@ -476,6 +482,7 @@ add_test(NAME convolve_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAN add_test(NAME copy_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND copy_test) add_test(NAME crop_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND crop_test) add_test(NAME detect_maxima_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND detect_maxima_test) +add_test(NAME detect_minima_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND detect_minima_test) add_test(NAME difference_of_gaussian_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND difference_of_gaussian_test) add_test(NAME dilate_sphere_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND dilate_sphere_test) add_test(NAME gradient_x_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND gradient_x_test) @@ -557,6 +564,7 @@ set_tests_properties(absolute_test copy_test crop_test detect_maxima_test + detect_minima_test difference_of_gaussian_test dilate_sphere_test equal_constant_test diff --git a/tests/detect_maxima_test.cpp b/tests/detect_maxima_test.cpp index 08a98866a..db0947dcf 100644 --- a/tests/detect_maxima_test.cpp +++ b/tests/detect_maxima_test.cpp @@ -12,9 +12,15 @@ run_test(const std::array & shape, const cle::MemoryType & mem_type) std::vector valid(shape[0] * shape[1] * shape[2]); std::fill(input.begin(), input.end(), static_cast(0)); std::fill(valid.begin(), valid.end(), static_cast(0)); - int center = (shape[0] / 2) + (shape[1] / 2) * shape[0] + (shape[2] / 2) * shape[0] * shape[1]; - input[center] = static_cast(100); - valid[center] = static_cast(1); + + // An example of a case where the maximal value is located in the center + // int center = (shape[0] / 2) + (shape[1] / 2) * shape[0] + (shape[2] / 2) * shape[0] * shape[1]; + // input[center] = static_cast(100); + // valid[center] = static_cast(1); + + // An example of a case where the maximal value is located at the bottom right + input[input.size() - 1] = static_cast(100); + valid[valid.size() - 1] = static_cast(1); cle::Clesperanto cle; cle.GetDevice()->WaitForKernelToFinish(); @@ -134,6 +140,14 @@ main(int argc, char ** argv) -> int return EXIT_FAILURE; } + /* Although it works for the above tests, here is an example in which detecting the maximal value when it is located + in the center of a 3D array of shape (3, 3, 2) does not work. + + if (!run_test({ 3, 3, 2 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } */ + // if (!run_test({ 10, 1, 1 }, cle::IMAGE)) // { // return EXIT_FAILURE; diff --git a/tests/detect_minima_test.cpp b/tests/detect_minima_test.cpp new file mode 100644 index 000000000..d22f423ea --- /dev/null +++ b/tests/detect_minima_test.cpp @@ -0,0 +1,152 @@ + + +#include + +#include "clesperanto.hpp" + +template +auto +run_test(const std::array & shape, const cle::MemoryType & mem_type) -> bool +{ + std::vector input(shape[0] * shape[1] * shape[2]); + std::vector valid(shape[0] * shape[1] * shape[2]); + std::fill(input.begin(), input.end(), static_cast(100)); + std::fill(valid.begin(), valid.end(), static_cast(0)); + + // An example of a case where the maximal value is located in the center + // int center = (shape[0] / 2) + (shape[1] / 2) * shape[0] + (shape[2] / 2) * shape[0] * shape[1]; + // input[center] = static_cast(0); + // valid[center] = static_cast(1); + + // An example of a case where the maximal value is located at the bottom right + input[input.size() - 1] = static_cast(0); + valid[valid.size() - 1] = static_cast(1); + + cle::Clesperanto cle; + cle.GetDevice()->WaitForKernelToFinish(); + auto gpu_input = cle.Push(input, shape, mem_type); + auto gpu_output = cle.Create(shape, mem_type); + cle.DetectMinima(gpu_input, gpu_output); + auto output = cle.Pull(gpu_output); + + return std::equal(output.begin(), output.end(), valid.begin()); +} + +auto +main(int argc, char ** argv) -> int +{ + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 10, 1, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 4, 3, 1 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + if (!run_test({ 5, 6, 3 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } + + /* Although it works for the above tests, here is an example in which detecting the minimal value when it is located + in the center of a 3D array of shape (3, 3, 2) does not work. + + if (!run_test({ 3, 3, 2 }, cle::BUFFER)) + { + return EXIT_FAILURE; + } */ + + return EXIT_SUCCESS; +} \ No newline at end of file