Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel detect minima #151

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clic/include/core/clesperanto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
31 changes: 31 additions & 0 deletions clic/include/tier1/cleDetectMinimaKernel.hpp
Original file line number Diff line number Diff line change
@@ -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<cle::Processor> & 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
6 changes: 6 additions & 0 deletions clic/src/core/clesperanto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
26 changes: 26 additions & 0 deletions clic/src/tier1/cleDetectMinimaKernel.cpp
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
20 changes: 17 additions & 3 deletions tests/detect_maxima_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ run_test(const std::array<size_t, 3> & shape, const cle::MemoryType & mem_type)
std::vector<type> valid(shape[0] * shape[1] * shape[2]);
std::fill(input.begin(), input.end(), static_cast<type>(0));
std::fill(valid.begin(), valid.end(), static_cast<type>(0));
int center = (shape[0] / 2) + (shape[1] / 2) * shape[0] + (shape[2] / 2) * shape[0] * shape[1];
input[center] = static_cast<type>(100);
valid[center] = static_cast<type>(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<type>(100);
// valid[center] = static_cast<type>(1);

// An example of a case where the maximal value is located at the bottom right
input[input.size() - 1] = static_cast<type>(100);
valid[valid.size() - 1] = static_cast<type>(1);

cle::Clesperanto cle;
cle.GetDevice()->WaitForKernelToFinish();
Expand Down Expand Up @@ -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<float>({ 3, 3, 2 }, cle::BUFFER))
{
return EXIT_FAILURE;
} */

// if (!run_test<float>({ 10, 1, 1 }, cle::IMAGE))
// {
// return EXIT_FAILURE;
Expand Down
152 changes: 152 additions & 0 deletions tests/detect_minima_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@


#include <random>

#include "clesperanto.hpp"

template <class type>
auto
run_test(const std::array<size_t, 3> & shape, const cle::MemoryType & mem_type) -> bool
{
std::vector<type> input(shape[0] * shape[1] * shape[2]);
std::vector<type> valid(shape[0] * shape[1] * shape[2]);
std::fill(input.begin(), input.end(), static_cast<type>(100));
std::fill(valid.begin(), valid.end(), static_cast<type>(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<type>(0);
// valid[center] = static_cast<type>(1);

// An example of a case where the maximal value is located at the bottom right
input[input.size() - 1] = static_cast<type>(0);
valid[valid.size() - 1] = static_cast<type>(1);

cle::Clesperanto cle;
cle.GetDevice()->WaitForKernelToFinish();
auto gpu_input = cle.Push<type>(input, shape, mem_type);
auto gpu_output = cle.Create<type>(shape, mem_type);
cle.DetectMinima(gpu_input, gpu_output);
auto output = cle.Pull<type>(gpu_output);

return std::equal(output.begin(), output.end(), valid.begin());
}

auto
main(int argc, char ** argv) -> int
{
if (!run_test<float>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int32_t>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint32_t>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int16_t>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint16_t>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int8_t>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint8_t>({ 10, 1, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<float>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int32_t>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint32_t>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int16_t>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint16_t>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int8_t>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint8_t>({ 4, 3, 1 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<float>({ 5, 6, 3 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int32_t>({ 5, 6, 3 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint32_t>({ 5, 6, 3 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int16_t>({ 5, 6, 3 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint16_t>({ 5, 6, 3 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<int8_t>({ 5, 6, 3 }, cle::BUFFER))
{
return EXIT_FAILURE;
}

if (!run_test<uint8_t>({ 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<float>({ 3, 3, 2 }, cle::BUFFER))
{
return EXIT_FAILURE;
} */

return EXIT_SUCCESS;
}