GCC Code Coverage Report


Directory: ./
File: tasks/badanov_a_select_edge_sobel/stl/src/ops_stl.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 92 94 97.9%
Functions: 10 10 100.0%
Branches: 51 64 79.7%

Line Branch Exec Source
1 #include "badanov_a_select_edge_sobel/stl/include/ops_stl.hpp"
2
3 #include <algorithm>
4 #include <cmath>
5 #include <cstddef>
6 #include <cstdint>
7 #include <mutex>
8 #include <thread>
9 #include <vector>
10
11 #include "badanov_a_select_edge_sobel/common/include/common.hpp"
12
13 namespace badanov_a_select_edge_sobel {
14
15
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 BadanovASelectEdgeSobelSTL::BadanovASelectEdgeSobelSTL(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 GetInput() = in;
18 80 GetOutput() = std::vector<uint8_t>();
19 80 }
20
21 80 bool BadanovASelectEdgeSobelSTL::ValidationImpl() {
22 const auto &input = GetInput();
23 80 return !input.empty();
24 }
25
26
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 56 times.
80 bool BadanovASelectEdgeSobelSTL::PreProcessingImpl() {
27 const auto &input = GetInput();
28
29 80 width_ = static_cast<int>(std::sqrt(input.size()));
30 80 height_ = width_;
31
32
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 56 times.
80 if (width_ * height_ != static_cast<int>(input.size())) {
33 24 width_ = static_cast<int>(input.size());
34 24 height_ = 1;
35 }
36
37 80 GetOutput() = std::vector<uint8_t>(input.size(), 0);
38
39 80 return true;
40 }
41
42 40 void BadanovASelectEdgeSobelSTL::ApplySobelOperator(const std::vector<uint8_t> &input, std::vector<float> &magnitude,
43 float &max_magnitude) {
44 40 const int height = height_;
45 40 const int width = width_;
46
47
2/4
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
40 if (height < 3 || width < 3) {
48 max_magnitude = 0.0F;
49 return;
50 }
51
52 40 unsigned int num_threads = std::thread::hardware_concurrency();
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (num_threads == 0) {
54 num_threads = 2;
55 }
56
57 40 int rows_to_process = height - 2;
58
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 8 times.
40 unsigned int rows_per_thread = rows_to_process / num_threads;
59 40 rows_per_thread = std::max<unsigned int>(rows_per_thread, 1);
60 40 num_threads = (rows_to_process + rows_per_thread - 1) / rows_per_thread;
61
62 40 std::vector<std::thread> threads;
63 40 std::mutex max_mutex;
64 40 float global_max = 0.0F;
65
66
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 40 times.
232 for (unsigned int thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
67 192 unsigned int start_row = 1 + (thread_idx * rows_per_thread);
68
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 152 times.
192 int end_row = static_cast<int>((thread_idx == num_threads - 1) ? (height - 1) : (start_row + rows_per_thread));
69
70
1/2
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
192 threads.emplace_back([&, start_row, end_row]() {
71 192 float local_max = 0.0F;
72
73
2/2
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 192 times.
528 for (int row = static_cast<int>(start_row); row < end_row; ++row) {
74
2/2
✓ Branch 0 taken 3744 times.
✓ Branch 1 taken 336 times.
4080 for (int col = 1; col < width - 1; ++col) {
75 3744 float gradient_x = 0.0F;
76 3744 float gradient_y = 0.0F;
77
78 3744 ComputeGradientAtPixel(input, row, col, gradient_x, gradient_y);
79
80 3744 const float magnitude_value = std::sqrt((gradient_x * gradient_x) + (gradient_y * gradient_y));
81 3744 const size_t idx = (static_cast<size_t>(row) * static_cast<size_t>(width)) + static_cast<size_t>(col);
82 3744 magnitude[idx] = magnitude_value;
83
84 3744 local_max = std::max(magnitude_value, local_max);
85 }
86 }
87
88 192 std::scoped_lock lock(max_mutex);
89
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 174 times.
210 global_max = std::max(local_max, global_max);
90 192 });
91 }
92
93
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 40 times.
232 for (auto &thread : threads) {
94
1/2
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
192 thread.join();
95 }
96
97 40 max_magnitude = global_max;
98 40 }
99
100 3744 void BadanovASelectEdgeSobelSTL::ComputeGradientAtPixel(const std::vector<uint8_t> &input, int row, int col,
101 float &gradient_x, float &gradient_y) const {
102 3744 gradient_x = 0.0F;
103 3744 gradient_y = 0.0F;
104
105
2/2
✓ Branch 0 taken 11232 times.
✓ Branch 1 taken 3744 times.
14976 for (int kernel_row = -1; kernel_row <= 1; ++kernel_row) {
106
2/2
✓ Branch 0 taken 33696 times.
✓ Branch 1 taken 11232 times.
44928 for (int kernel_col = -1; kernel_col <= 1; ++kernel_col) {
107 33696 const size_t pixel_index =
108 33696 (static_cast<size_t>(row + kernel_row) * static_cast<size_t>(width_)) + static_cast<size_t>(col + kernel_col);
109 33696 const uint8_t pixel = input[pixel_index];
110
111 33696 const int kx_idx = kernel_row + 1;
112 33696 const int ky_idx = kernel_col + 1;
113 33696 const int kernel_x_value = kKernelX.at(static_cast<size_t>(kx_idx)).at(static_cast<size_t>(ky_idx));
114 33696 const int kernel_y_value = kKernelY.at(static_cast<size_t>(kx_idx)).at(static_cast<size_t>(ky_idx));
115
116 33696 gradient_x += static_cast<float>(pixel) * static_cast<float>(kernel_x_value);
117 33696 gradient_y += static_cast<float>(pixel) * static_cast<float>(kernel_y_value);
118 }
119 }
120 3744 }
121
122 40 void BadanovASelectEdgeSobelSTL::ApplyThreshold(const std::vector<float> &magnitude, float max_magnitude,
123 std::vector<uint8_t> &output) const {
124
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 32 times.
40 if (max_magnitude <= 0.0F) {
125 std::ranges::fill(output, 0);
126 8 return;
127 }
128
129 32 const float scale = 255.0F / max_magnitude;
130 const size_t size = magnitude.size();
131 32 const int threshold = threshold_;
132
133 32 unsigned int num_threads = std::thread::hardware_concurrency();
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (num_threads == 0) {
135 num_threads = 2;
136 }
137
138 32 std::vector<std::thread> threads;
139 32 size_t chunk_size = (size + num_threads - 1) / num_threads;
140
141
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 32 times.
160 for (unsigned int thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
142 128 size_t start = thread_idx * chunk_size;
143
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 32 times.
128 size_t end = (thread_idx == num_threads - 1) ? size : (start + chunk_size);
144
145
1/2
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
128 threads.emplace_back([&, start, end]() {
146
2/2
✓ Branch 0 taken 4736 times.
✓ Branch 1 taken 128 times.
4864 for (size_t i = start; i < end; ++i) {
147
2/2
✓ Branch 0 taken 3288 times.
✓ Branch 1 taken 1448 times.
8024 output[i] = (magnitude[i] * scale > static_cast<float>(threshold)) ? 255 : 0;
148 }
149 128 });
150 }
151
152
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 32 times.
160 for (auto &thread : threads) {
153
1/2
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
128 thread.join();
154 }
155 32 }
156
157
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 40 times.
80 bool BadanovASelectEdgeSobelSTL::RunImpl() {
158 const auto &input = GetInput();
159 auto &output = GetOutput();
160
161
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
80 if (height_ < 3 || width_ < 3) {
162 40 output = input;
163 40 return true;
164 }
165
166 40 std::vector<float> magnitude(input.size(), 0.0F);
167 40 float max_magnitude = 0.0F;
168
169
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 ApplySobelOperator(input, magnitude, max_magnitude);
170
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 ApplyThreshold(magnitude, max_magnitude, output);
171
172 return true;
173 }
174
175 80 bool BadanovASelectEdgeSobelSTL::PostProcessingImpl() {
176 80 return true;
177 }
178
179 } // namespace badanov_a_select_edge_sobel
180