| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "batushin_i_incr_contrast_with_lhs/stl/include/ops_stl.hpp" | ||
| 2 | |||
| 3 | #include <algorithm> | ||
| 4 | #include <cmath> | ||
| 5 | #include <cstddef> | ||
| 6 | #include <thread> | ||
| 7 | #include <utility> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "batushin_i_incr_contrast_with_lhs/common/include/common.hpp" | ||
| 11 | |||
| 12 | namespace batushin_i_incr_contrast_with_lhs { | ||
| 13 | |||
| 14 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | BatushinIIncrContrastWithLhsSTL::BatushinIIncrContrastWithLhsSTL(const InType &in) { |
| 15 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 16 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | GetInput() = in; |
| 17 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | GetOutput().resize(in.size()); |
| 18 | 48 | } | |
| 19 | |||
| 20 | 48 | bool BatushinIIncrContrastWithLhsSTL::ValidationImpl() { | |
| 21 | 48 | return !GetInput().empty(); | |
| 22 | } | ||
| 23 | |||
| 24 | 48 | bool BatushinIIncrContrastWithLhsSTL::PreProcessingImpl() { | |
| 25 | 48 | return true; | |
| 26 | } | ||
| 27 | |||
| 28 | namespace { | ||
| 29 | |||
| 30 | unsigned char NormalizePixel(unsigned char pixel, unsigned char min_val, double scale_factor) { | ||
| 31 | 216 | double normalized = static_cast<double>(pixel - min_val) * scale_factor; | |
| 32 | 216 | normalized = std::floor(normalized + 0.5); | |
| 33 | normalized = std::max(normalized, 0.0); | ||
| 34 | normalized = std::min(normalized, 255.0); | ||
| 35 | 216 | return static_cast<unsigned char>(normalized); | |
| 36 | } | ||
| 37 | |||
| 38 | unsigned int GetNumThreads() { | ||
| 39 | 96 | unsigned int threads = std::thread::hardware_concurrency(); | |
| 40 | 96 | return (threads == 0) ? 1 : threads; | |
| 41 | } | ||
| 42 | |||
| 43 | size_t ComputeChunkSize(size_t data_size, unsigned int num_threads) { | ||
| 44 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
96 | return std::max(static_cast<size_t>(1), data_size / num_threads); |
| 45 | } | ||
| 46 | |||
| 47 | size_t ComputeNumBlocks(size_t data_size, size_t chunk_size) { | ||
| 48 | 96 | return (data_size + chunk_size - 1) / chunk_size; | |
| 49 | } | ||
| 50 | |||
| 51 | struct MinMaxResult { | ||
| 52 | unsigned char min_val; | ||
| 53 | unsigned char max_val; | ||
| 54 | }; | ||
| 55 | |||
| 56 | MinMaxResult FindMinMaxInBlock(const std::vector<unsigned char> &data, size_t start, size_t end) { | ||
| 57 | unsigned char local_min = 255; | ||
| 58 | unsigned char local_max = 0; | ||
| 59 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 216 times.
|
432 | for (size_t idx = start; idx < end; ++idx) { |
| 60 | 216 | unsigned char val = data[idx]; | |
| 61 | local_min = std::min(local_min, val); | ||
| 62 | local_max = std::max(local_max, val); | ||
| 63 | } | ||
| 64 | // Используем designated initializers | ||
| 65 | return MinMaxResult{.min_val = local_min, .max_val = local_max}; | ||
| 66 | } | ||
| 67 | |||
| 68 | 48 | MinMaxResult MergeMinMaxResults(const std::vector<MinMaxResult> &results) { | |
| 69 | 48 | unsigned char global_min = 255; | |
| 70 | 48 | unsigned char global_max = 0; | |
| 71 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 48 times.
|
264 | for (const auto &result : results) { |
| 72 | 216 | global_min = std::min(global_min, result.min_val); | |
| 73 | 216 | global_max = std::max(global_max, result.max_val); | |
| 74 | } | ||
| 75 | // Используем designated initializers | ||
| 76 | 48 | return MinMaxResult{.min_val = global_min, .max_val = global_max}; | |
| 77 | } | ||
| 78 | |||
| 79 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | std::pair<unsigned char, unsigned char> FindMinMaxParallel(const std::vector<unsigned char> &data) { |
| 80 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (data.empty()) { |
| 81 | ✗ | return {0, 0}; | |
| 82 | } | ||
| 83 | |||
| 84 | 48 | const size_t data_size = data.size(); | |
| 85 | const unsigned int num_threads = GetNumThreads(); | ||
| 86 | const size_t chunk_size = ComputeChunkSize(data_size, num_threads); | ||
| 87 | const size_t num_blocks = ComputeNumBlocks(data_size, chunk_size); | ||
| 88 | |||
| 89 | 48 | std::vector<MinMaxResult> block_results(num_blocks, MinMaxResult{.min_val = 255, .max_val = 0}); | |
| 90 | 48 | std::vector<std::thread> threads; | |
| 91 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | threads.reserve(num_blocks); |
| 92 | |||
| 93 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 48 times.
|
264 | for (size_t block_idx = 0; block_idx < num_blocks; ++block_idx) { |
| 94 | 216 | size_t start = block_idx * chunk_size; | |
| 95 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | size_t end = std::min(start + chunk_size, data_size); |
| 96 | |||
| 97 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | threads.emplace_back([&data, &block_results, block_idx, start, end] { |
| 98 | 216 | block_results[block_idx] = FindMinMaxInBlock(data, start, end); | |
| 99 | }); | ||
| 100 | } | ||
| 101 | |||
| 102 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 48 times.
|
264 | for (auto &thread : threads) { |
| 103 |
1/2✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
|
216 | if (thread.joinable()) { |
| 104 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | thread.join(); |
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | 48 | MinMaxResult final_result = MergeMinMaxResults(block_results); | |
| 109 | 48 | return {final_result.min_val, final_result.max_val}; | |
| 110 | 48 | } | |
| 111 | |||
| 112 | 216 | void NormalizeBlock(const std::vector<unsigned char> &source, std::vector<unsigned char> &destination, size_t start, | |
| 113 | size_t end, unsigned char min_value, double scale_coefficient) { | ||
| 114 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 216 times.
|
432 | for (size_t idx = start; idx < end; ++idx) { |
| 115 | 216 | destination[idx] = NormalizePixel(source[idx], min_value, scale_coefficient); | |
| 116 | } | ||
| 117 | 216 | } | |
| 118 | |||
| 119 | 48 | void NormalizeImageParallel(const std::vector<unsigned char> &source, std::vector<unsigned char> &destination, | |
| 120 | unsigned char min_value, double scale_coefficient) { | ||
| 121 | 48 | const size_t data_size = source.size(); | |
| 122 | const unsigned int num_threads = GetNumThreads(); | ||
| 123 | const size_t chunk_size = ComputeChunkSize(data_size, num_threads); | ||
| 124 | const size_t num_blocks = ComputeNumBlocks(data_size, chunk_size); | ||
| 125 | |||
| 126 | 48 | std::vector<std::thread> threads; | |
| 127 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | threads.reserve(num_blocks); |
| 128 | |||
| 129 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 48 times.
|
264 | for (size_t block_idx = 0; block_idx < num_blocks; ++block_idx) { |
| 130 | 216 | size_t start = block_idx * chunk_size; | |
| 131 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | size_t end = std::min(start + chunk_size, data_size); |
| 132 | |||
| 133 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | threads.emplace_back([&source, &destination, start, end, min_value, scale_coefficient] { |
| 134 | 216 | NormalizeBlock(source, destination, start, end, min_value, scale_coefficient); | |
| 135 | 216 | }); | |
| 136 | } | ||
| 137 | |||
| 138 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 48 times.
|
264 | for (auto &thread : threads) { |
| 139 |
1/2✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
|
216 | if (thread.joinable()) { |
| 140 |
1/2✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
|
216 | thread.join(); |
| 141 | } | ||
| 142 | } | ||
| 143 | 48 | } | |
| 144 | |||
| 145 | void FillUniformBlock(std::vector<unsigned char> &output, size_t start, size_t end) { | ||
| 146 | ✗ | for (size_t idx = start; idx < end; ++idx) { | |
| 147 | ✗ | output[idx] = 128; | |
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | ✗ | void FillUniformImageParallel(std::vector<unsigned char> &output, size_t size) { | |
| 152 | const unsigned int num_threads = GetNumThreads(); | ||
| 153 | ✗ | const size_t chunk_size = ComputeChunkSize(size, num_threads); | |
| 154 | const size_t num_blocks = ComputeNumBlocks(size, chunk_size); | ||
| 155 | |||
| 156 | ✗ | std::vector<std::thread> threads; | |
| 157 | ✗ | threads.reserve(num_blocks); | |
| 158 | |||
| 159 | ✗ | for (size_t block_idx = 0; block_idx < num_blocks; ++block_idx) { | |
| 160 | ✗ | size_t start = block_idx * chunk_size; | |
| 161 | ✗ | size_t end = std::min(start + chunk_size, size); | |
| 162 | |||
| 163 | ✗ | threads.emplace_back([&output, start, end] { FillUniformBlock(output, start, end); }); | |
| 164 | } | ||
| 165 | |||
| 166 | ✗ | for (auto &thread : threads) { | |
| 167 | ✗ | if (thread.joinable()) { | |
| 168 | ✗ | thread.join(); | |
| 169 | } | ||
| 170 | } | ||
| 171 | ✗ | } | |
| 172 | |||
| 173 | } // namespace | ||
| 174 | |||
| 175 | 48 | bool BatushinIIncrContrastWithLhsSTL::RunImpl() { | |
| 176 | const std::vector<unsigned char> &source = GetInput(); | ||
| 177 | std::vector<unsigned char> &destination = GetOutput(); | ||
| 178 | |||
| 179 | 48 | auto min_max = FindMinMaxParallel(source); | |
| 180 | 48 | unsigned char min_value = min_max.first; | |
| 181 | 48 | unsigned char max_value = min_max.second; | |
| 182 | |||
| 183 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (min_value == max_value) { |
| 184 | ✗ | FillUniformImageParallel(destination, source.size()); | |
| 185 | ✗ | return true; | |
| 186 | } | ||
| 187 | |||
| 188 | 48 | const double scale_coefficient = 255.0 / static_cast<double>(max_value - min_value); | |
| 189 | 48 | destination.resize(source.size()); | |
| 190 | |||
| 191 | 48 | NormalizeImageParallel(source, destination, min_value, scale_coefficient); | |
| 192 | |||
| 193 | return true; | ||
| 194 | } | ||
| 195 | |||
| 196 | 48 | bool BatushinIIncrContrastWithLhsSTL::PostProcessingImpl() { | |
| 197 | 48 | return true; | |
| 198 | } | ||
| 199 | |||
| 200 | } // namespace batushin_i_incr_contrast_with_lhs | ||
| 201 |