From b9658297a389b93fa00021d810259871826bc3ad Mon Sep 17 00:00:00 2001 From: weyland0 Date: Sun, 19 Apr 2026 14:12:07 +0300 Subject: [PATCH 1/3] add STL version --- .../stl/include/ops_stl.hpp | 22 ++++ .../stl/src/ops_stl.cpp | 123 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp create mode 100644 tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/src/ops_stl.cpp 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..5116a982c --- /dev/null +++ b/tasks/batkov_f_contrast_enh_lin_hist_stretch/stl/src/ops_stl.cpp @@ -0,0 +1,123 @@ +#include "batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp" + +#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]() { + for (size_t i = begin; i < end; ++i) { + mins[thread_index] = std::min(mins[thread_index], input[i]); + maxs[thread_index] = std::max(maxs[thread_index], input[i]); + } + }); + } + + 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); +} + +void ApplyStretchParallel(const InType &input, OutType &output, size_t num_threads, double a, double b) { + 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] = static_cast(std::clamp((a * static_cast(input[i])) + b, 0.0, 255.0)); + } + }); + } + + 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 double a = 255.0 / static_cast(max_el - min_el); + const double b = -a * static_cast(min_el); + ApplyStretchParallel(input, output, num_threads, a, b); + return true; +} + +bool BatkovFContrastEnhLinHistStretchSTL::PostProcessingImpl() { + return !GetOutput().empty(); +} + +} // namespace batkov_f_contrast_enh_lin_hist_stretch From 5c89ead485c099a2bc669e1ab6cddb0456e72acf Mon Sep 17 00:00:00 2001 From: weyland0 Date: Sun, 19 Apr 2026 14:12:31 +0300 Subject: [PATCH 2/3] add STL version in tests --- .../tests/functional/main.cpp | 3 +++ .../tests/performance/main.cpp | 3 +++ 2 files changed, 6 insertions(+) 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); From 607199cf2c43adc1ab63259c8a0678054348784d Mon Sep 17 00:00:00 2001 From: weyland0 Date: Sun, 19 Apr 2026 20:18:05 +0300 Subject: [PATCH 3/3] optimize the STL algorithm --- .../stl/src/ops_stl.cpp | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) 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 index 5116a982c..c4f258b51 100644 --- 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 @@ -1,6 +1,7 @@ #include "batkov_f_contrast_enh_lin_hist_stretch/stl/include/ops_stl.hpp" #include +#include #include #include #include @@ -31,10 +32,14 @@ std::pair FindMinMaxParallel(const InType &input, size_t num_t 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) { - mins[thread_index] = std::min(mins[thread_index], input[i]); - maxs[thread_index] = std::max(maxs[thread_index], input[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; }); } @@ -55,7 +60,16 @@ std::pair FindMinMax(const InType &input, size_t parallel_thre return FindMinMaxParallel(input, num_threads); } -void ApplyStretchParallel(const InType &input, OutType &output, size_t num_threads, double a, double b) { +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; @@ -68,7 +82,7 @@ void ApplyStretchParallel(const InType &input, OutType &output, size_t num_threa threads.emplace_back([&, begin, end]() { for (size_t i = begin; i < end; ++i) { - output[i] = static_cast(std::clamp((a * static_cast(input[i])) + b, 0.0, 255.0)); + output[i] = lut.at(input[i]); } }); } @@ -110,9 +124,10 @@ bool BatkovFContrastEnhLinHistStretchSTL::RunImpl() { return true; } - const double a = 255.0 / static_cast(max_el - min_el); - const double b = -a * static_cast(min_el); - ApplyStretchParallel(input, output, num_threads, a, b); + 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; }