|
8 | 8 | #include <numeric> |
9 | 9 | #include <stdexcept> |
10 | 10 | #include <string> |
11 | | -#include <unordered_map> |
12 | 11 | #include <unordered_set> |
13 | 12 | #include <vector> |
14 | 13 |
|
@@ -45,6 +44,12 @@ private: |
45 | 44 |
|
46 | 45 | using MutexStorage = std::vector<std::unordered_set<std::uint64_t>>; |
47 | 46 |
|
| 47 | +template <class T> |
| 48 | +struct WeightedGridEdge { |
| 49 | + T weight; |
| 50 | + std::uint64_t id; |
| 51 | +}; |
| 52 | + |
48 | 53 | inline bool check_mutex( |
49 | 54 | const std::uint64_t first, |
50 | 55 | const std::uint64_t second, |
@@ -97,22 +102,6 @@ inline std::vector<std::ptrdiff_t> c_order_strides(const std::vector<std::ptrdif |
97 | 102 | return strides; |
98 | 103 | } |
99 | 104 |
|
100 | | -inline bool is_valid_grid_edge( |
101 | | - const std::uint64_t node, |
102 | | - const std::vector<std::ptrdiff_t> &offset, |
103 | | - const std::vector<std::ptrdiff_t> &shape, |
104 | | - const std::vector<std::ptrdiff_t> &strides |
105 | | -) { |
106 | | - for (std::size_t axis = 0; axis < shape.size(); ++axis) { |
107 | | - const auto coord = static_cast<std::ptrdiff_t>(node / static_cast<std::uint64_t>(strides[axis])) % shape[axis]; |
108 | | - const auto neighbor = coord + offset[axis]; |
109 | | - if (neighbor < 0 || neighbor >= shape[axis]) { |
110 | | - return false; |
111 | | - } |
112 | | - } |
113 | | - return true; |
114 | | -} |
115 | | - |
116 | 105 | template <class T> |
117 | 106 | void mutex_watershed_grid( |
118 | 107 | const ConstArrayView<T> &affinities, |
@@ -178,58 +167,59 @@ void mutex_watershed_grid( |
178 | 167 | } |
179 | 168 |
|
180 | 169 | const auto number_of_edges = number_of_nodes * number_of_channels; |
181 | | - std::vector<std::uint64_t> edge_order(static_cast<std::size_t>(number_of_edges)); |
182 | | - std::iota(edge_order.begin(), edge_order.end(), std::uint64_t{0}); |
183 | | - std::sort(edge_order.begin(), edge_order.end(), [&](const std::uint64_t first, const std::uint64_t second) { |
184 | | - const T first_weight = affinities.data[first]; |
185 | | - const T second_weight = affinities.data[second]; |
186 | | - if (first_weight == second_weight) { |
187 | | - return first < second; |
| 170 | + std::vector<WeightedGridEdge<T>> edge_order; |
| 171 | + edge_order.reserve(static_cast<std::size_t>(number_of_edges)); |
| 172 | + for (std::uint64_t edge_id = 0; edge_id < number_of_edges; ++edge_id) { |
| 173 | + if (valid_edges.data[edge_id] != 0) { |
| 174 | + edge_order.push_back(WeightedGridEdge<T>{affinities.data[edge_id], edge_id}); |
188 | 175 | } |
189 | | - return first_weight > second_weight; |
| 176 | + } |
| 177 | + std::sort(edge_order.begin(), edge_order.end(), [](const auto &first, const auto &second) { |
| 178 | + if (first.weight == second.weight) { |
| 179 | + return first.id < second.id; |
| 180 | + } |
| 181 | + return first.weight > second.weight; |
190 | 182 | }); |
191 | 183 |
|
192 | 184 | DisjointSets sets(static_cast<std::size_t>(number_of_nodes)); |
193 | 185 | MutexStorage mutexes(static_cast<std::size_t>(number_of_nodes)); |
194 | 186 |
|
195 | | - for (const auto edge_id : edge_order) { |
196 | | - if (valid_edges.data[edge_id] == 0) { |
197 | | - continue; |
198 | | - } |
199 | | - |
| 187 | + for (const auto &edge : edge_order) { |
| 188 | + const auto edge_id = edge.id; |
200 | 189 | const auto channel = static_cast<std::size_t>(edge_id / number_of_nodes); |
201 | 190 | const auto u = edge_id % number_of_nodes; |
202 | | - if (!is_valid_grid_edge(u, offsets[channel], spatial_shape, spatial_strides)) { |
203 | | - continue; |
204 | | - } |
205 | 191 |
|
206 | 192 | const auto v_signed = static_cast<std::int64_t>(u) + static_cast<std::int64_t>(offset_strides[channel]); |
207 | 193 | const auto v = static_cast<std::uint64_t>(v_signed); |
208 | 194 | std::uint64_t root_u = sets.find(u); |
209 | 195 | std::uint64_t root_v = sets.find(v); |
210 | | - if (root_u == root_v || check_mutex(root_u, root_v, mutexes)) { |
| 196 | + if (root_u == root_v) { |
211 | 197 | continue; |
212 | 198 | } |
213 | 199 |
|
214 | 200 | const bool is_mutex_edge = channel >= number_of_attractive_channels; |
215 | 201 | if (is_mutex_edge) { |
216 | 202 | insert_mutex(root_u, root_v, mutexes); |
217 | 203 | } else { |
| 204 | + if (check_mutex(root_u, root_v, mutexes)) { |
| 205 | + continue; |
| 206 | + } |
218 | 207 | const auto new_root = sets.unite_roots(root_u, root_v); |
219 | 208 | const auto old_root = (new_root == root_u) ? root_v : root_u; |
220 | 209 | merge_mutexes(old_root, new_root, mutexes); |
221 | 210 | } |
222 | 211 | } |
223 | 212 |
|
224 | | - std::unordered_map<std::uint64_t, std::uint64_t> label_map; |
| 213 | + std::vector<std::uint64_t> root_labels(static_cast<std::size_t>(number_of_nodes), 0); |
| 214 | + std::uint64_t next_label = 1; |
225 | 215 | for (std::uint64_t node = 0; node < number_of_nodes; ++node) { |
226 | 216 | const auto root = sets.find(node); |
227 | | - auto found = label_map.find(root); |
228 | | - if (found == label_map.end()) { |
229 | | - const auto next_label = static_cast<std::uint64_t>(label_map.size() + 1); |
230 | | - found = label_map.emplace(root, next_label).first; |
| 217 | + auto &label = root_labels[static_cast<std::size_t>(root)]; |
| 218 | + if (label == 0) { |
| 219 | + label = next_label; |
| 220 | + ++next_label; |
231 | 221 | } |
232 | | - out.data[node] = found->second; |
| 222 | + out.data[node] = label; |
233 | 223 | } |
234 | 224 | } |
235 | 225 |
|
|
0 commit comments