diff --git a/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp b/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp new file mode 100644 index 000000000..011d2154a --- /dev/null +++ b/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "batkov_f_contrast_enh_lin_hist_stretch/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace batkov_f_contrast_enh_lin_hist_stretch { + +class BatkovFContrastEnhLinHistStretchSTL : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSTL; + } + explicit BatkovFContrastEnhLinHistStretchSTL(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace batkov_f_contrast_enh_lin_hist_stretch diff --git a/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/src/ops_stl.cpp b/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/src/ops_stl.cpp new file mode 100644 index 000000000..c4f258b51 --- /dev/null +++ b/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/src/ops_stl.cpp @@ -0,0 +1,138 @@ +#include "batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "batkov_f_contrast_enh_lin_hist_stretch/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace batkov_f_contrast_enh_lin_hist_stretch { + +namespace { + +std::pair FindMinMaxParallel(const InType &input, size_t num_threads) { + const size_t n = input.size(); + const size_t block = n / num_threads; + + std::vector mins(num_threads, std::numeric_limits::max()); + std::vector maxs(num_threads, std::numeric_limits::min()); + + { + std::vector threads; + threads.reserve(num_threads); + for (size_t thread_index = 0; thread_index < num_threads; ++thread_index) { + const size_t begin = thread_index * block; + const size_t end = (thread_index == num_threads - 1) ? n : begin + block; + + threads.emplace_back([&, thread_index, begin, end]() { + uint8_t local_min = std::numeric_limits::max(); + uint8_t local_max = std::numeric_limits::min(); + for (size_t i = begin; i < end; ++i) { + local_min = std::min(local_min, input[i]); + local_max = std::max(local_max, input[i]); + } + mins[thread_index] = local_min; + maxs[thread_index] = local_max; + }); + } + + for (auto &th : threads) { + th.join(); + } + } + + return {*std::ranges::min_element(mins), *std::ranges::max_element(maxs)}; +} + +std::pair FindMinMax(const InType &input, size_t parallel_threshold, size_t num_threads) { + if (input.size() < parallel_threshold || num_threads <= 1) { + const auto [min_it, max_it] = std::ranges::minmax_element(input); + return {*min_it, *max_it}; + } + + return FindMinMaxParallel(input, num_threads); +} + +std::array BuildStretchLut(float a, float b) { + std::array lut{}; + for (size_t pixel = 0; pixel < 256; ++pixel) { + lut.at(pixel) = static_cast(std::clamp((a * static_cast(pixel)) + b, 0.0F, 255.0F)); + } + return lut; +} + +void ApplyStretchParallel(const InType &input, OutType &output, size_t num_threads, + const std::array &lut) { + const size_t n = input.size(); + const size_t block = n / num_threads; + + std::vector threads; + threads.reserve(num_threads); + + for (size_t thread_index = 0; thread_index < num_threads; ++thread_index) { + const size_t begin = thread_index * block; + const size_t end = (thread_index == num_threads - 1) ? n : begin + block; + + threads.emplace_back([&, begin, end]() { + for (size_t i = begin; i < end; ++i) { + output[i] = lut.at(input[i]); + } + }); + } + + for (auto &th : threads) { + th.join(); + } +} + +} // namespace + +BatkovFContrastEnhLinHistStretchSTL::BatkovFContrastEnhLinHistStretchSTL(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; +} + +bool BatkovFContrastEnhLinHistStretchSTL::ValidationImpl() { + return !GetInput().empty(); +} + +bool BatkovFContrastEnhLinHistStretchSTL::PreProcessingImpl() { + GetOutput().resize(GetInput().size()); + return true; +} + +bool BatkovFContrastEnhLinHistStretchSTL::RunImpl() { + auto &input = GetInput(); + auto &output = GetOutput(); + + constexpr size_t kParallelMinMaxThreshold = 100000; + const size_t num_threads = static_cast(std::max(1, ppc::util::GetNumThreads())); + + uint8_t min_el{}; + uint8_t max_el{}; + std::tie(min_el, max_el) = FindMinMax(input, kParallelMinMaxThreshold, num_threads); + + if (min_el == max_el) { + std::ranges::copy(input, output.begin()); + return true; + } + + const float a = 255.0F / static_cast(max_el - min_el); + const float b = -a * static_cast(min_el); + const auto lut = BuildStretchLut(a, b); + ApplyStretchParallel(input, output, num_threads, lut); + return true; +} + +bool BatkovFContrastEnhLinHistStretchSTL::PostProcessingImpl() { + return !GetOutput().empty(); +} + +} // namespace batkov_f_contrast_enh_lin_hist_stretch diff --git a/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/functional/main.cpp b/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/functional/main.cpp index a19c0b600..09302eb52 100644 --- a/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/functional/main.cpp +++ b/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/functional/main.cpp @@ -12,6 +12,7 @@ #include "batkov_f_contrast_enh_lin_hist_stretch/common/include/common.hpp" #include "batkov_f_contrast_enh_lin_hist_stretch/omp/include/ops_omp.hpp" #include "batkov_f_contrast_enh_lin_hist_stretch/seq/include/ops_seq.hpp" +#include "batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp" #include "batkov_f_contrast_enh_lin_hist_stretch/tbb/include/ops_tbb.hpp" #include "util/include/func_test_util.hpp" #include "util/include/util.hpp" @@ -81,6 +82,8 @@ const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( kTestParam, PPC_SETTINGS_batkov_f_contrast_enh_lin_hist_stretch), ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_batkov_f_contrast_enh_lin_hist_stretch), + ppc::util::AddFuncTask( kTestParam, PPC_SETTINGS_batkov_f_contrast_enh_lin_hist_stretch)); const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); diff --git a/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/performance/main.cpp b/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/performance/main.cpp index 3bc32fc04..7315e4fe6 100644 --- a/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/performance/main.cpp +++ b/tasks/batkov_f_contrast_enh_lin_hist_stretch/tests/performance/main.cpp @@ -8,6 +8,7 @@ #include "batkov_f_contrast_enh_lin_hist_stretch/common/include/common.hpp" #include "batkov_f_contrast_enh_lin_hist_stretch/omp/include/ops_omp.hpp" #include "batkov_f_contrast_enh_lin_hist_stretch/seq/include/ops_seq.hpp" +#include "batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp" #include "batkov_f_contrast_enh_lin_hist_stretch/tbb/include/ops_tbb.hpp" #include "util/include/perf_test_util.hpp" @@ -55,6 +56,8 @@ const auto kAllPerfTasks = std::tuple_cat(ppc::util::MakeAllPerfTasks( PPC_SETTINGS_batkov_f_contrast_enh_lin_hist_stretch), ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_batkov_f_contrast_enh_lin_hist_stretch), + ppc::util::MakeAllPerfTasks( PPC_SETTINGS_batkov_f_contrast_enh_lin_hist_stretch)); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks);