Skip to content

Commit 78eb1d5

Browse files
More optimization
1 parent 25fa6e8 commit 78eb1d5

2 files changed

Lines changed: 246 additions & 105 deletions

File tree

include/bioimage_cpp/graph/feature_accumulation.hxx

Lines changed: 91 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,83 @@ inline void valid_axis_range(
225225
}
226226
}
227227

228+
// Sweep every (node, target) pair on a 2D grid for which `node + offset` stays
229+
// in bounds, restricted to the half-open y-slab [y_begin, y_end). The body
230+
// receives flat C-order indices for both endpoints and is expected to inline
231+
// at -O2 since this is a header-only template with a fully-known callable
232+
// type at instantiation.
233+
template <class Body>
234+
void sweep_offset_box_2d(
235+
const std::ptrdiff_t dy,
236+
const std::ptrdiff_t dx,
237+
const std::size_t height,
238+
const std::size_t width,
239+
const std::size_t y_begin,
240+
const std::size_t y_end,
241+
const Body &body
242+
) {
243+
std::size_t y_lo_full, y_hi_full, x_lo, x_hi;
244+
valid_axis_range(dy, height, y_lo_full, y_hi_full);
245+
valid_axis_range(dx, width, x_lo, x_hi);
246+
const auto y_lo = std::max(y_lo_full, y_begin);
247+
const auto y_hi = std::min(y_hi_full, y_end);
248+
if (y_lo >= y_hi || x_lo >= x_hi) {
249+
return;
250+
}
251+
const auto offset_stride = dy * static_cast<std::ptrdiff_t>(width) + dx;
252+
for (std::size_t y = y_lo; y < y_hi; ++y) {
253+
const auto row_offset = y * width;
254+
for (std::size_t x = x_lo; x < x_hi; ++x) {
255+
const auto node = row_offset + x;
256+
const auto target = static_cast<std::uint64_t>(
257+
static_cast<std::ptrdiff_t>(node) + offset_stride
258+
);
259+
body(static_cast<std::uint64_t>(node), target);
260+
}
261+
}
262+
}
263+
264+
// 3D variant of `sweep_offset_box_2d`. Restricts the sweep to a z-slab.
265+
template <class Body>
266+
void sweep_offset_box_3d(
267+
const std::ptrdiff_t dz,
268+
const std::ptrdiff_t dy,
269+
const std::ptrdiff_t dx,
270+
const std::size_t depth,
271+
const std::size_t height,
272+
const std::size_t width,
273+
const std::size_t z_begin,
274+
const std::size_t z_end,
275+
const Body &body
276+
) {
277+
std::size_t z_lo_full, z_hi_full, y_lo, y_hi, x_lo, x_hi;
278+
valid_axis_range(dz, depth, z_lo_full, z_hi_full);
279+
valid_axis_range(dy, height, y_lo, y_hi);
280+
valid_axis_range(dx, width, x_lo, x_hi);
281+
const auto z_lo = std::max(z_lo_full, z_begin);
282+
const auto z_hi = std::min(z_hi_full, z_end);
283+
if (z_lo >= z_hi || y_lo >= y_hi || x_lo >= x_hi) {
284+
return;
285+
}
286+
const auto slice_size = height * width;
287+
const auto offset_stride =
288+
dz * static_cast<std::ptrdiff_t>(slice_size) +
289+
dy * static_cast<std::ptrdiff_t>(width) + dx;
290+
for (std::size_t z = z_lo; z < z_hi; ++z) {
291+
const auto slice_offset = z * slice_size;
292+
for (std::size_t y = y_lo; y < y_hi; ++y) {
293+
const auto row_offset = slice_offset + y * width;
294+
for (std::size_t x = x_lo; x < x_hi; ++x) {
295+
const auto node = row_offset + x;
296+
const auto target = static_cast<std::uint64_t>(
297+
static_cast<std::ptrdiff_t>(node) + offset_stride
298+
);
299+
body(static_cast<std::uint64_t>(node), target);
300+
}
301+
}
302+
}
303+
}
304+
228305
template <class LabelT, class ValueT, class Stats>
229306
void scan_affinity_2d_chunk(
230307
const RegionAdjacencyGraph &rag,
@@ -240,25 +317,11 @@ void scan_affinity_2d_chunk(
240317
const auto number_of_nodes = static_cast<std::uint64_t>(height * width);
241318
for (std::size_t channel = 0; channel < offsets.size(); ++channel) {
242319
const auto &off = offsets[channel];
243-
std::size_t y_lo_full, y_hi_full, x_lo, x_hi;
244-
valid_axis_range(off[0], height, y_lo_full, y_hi_full);
245-
valid_axis_range(off[1], width, x_lo, x_hi);
246-
const auto y_lo = std::max(y_lo_full, y_begin);
247-
const auto y_hi = std::min(y_hi_full, y_end);
248-
if (y_lo >= y_hi || x_lo >= x_hi) {
249-
continue;
250-
}
251-
const auto offset_stride =
252-
off[0] * static_cast<std::ptrdiff_t>(width) + off[1];
253320
const auto channel_offset =
254321
static_cast<std::uint64_t>(channel) * number_of_nodes;
255-
for (std::size_t y = y_lo; y < y_hi; ++y) {
256-
const auto row_offset = y * width;
257-
for (std::size_t x = x_lo; x < x_hi; ++x) {
258-
const auto node = row_offset + x;
259-
const auto target = static_cast<std::uint64_t>(
260-
static_cast<std::ptrdiff_t>(node) + offset_stride
261-
);
322+
sweep_offset_box_2d(
323+
off[0], off[1], height, width, y_begin, y_end,
324+
[&](const std::uint64_t node, const std::uint64_t target) {
262325
const auto u = label_at(labels, node);
263326
const auto v = label_at(labels, target);
264327
const auto edge = edge_for_labels(rag, u, v);
@@ -268,7 +331,7 @@ void scan_affinity_2d_chunk(
268331
);
269332
}
270333
}
271-
}
334+
);
272335
}
273336
}
274337

@@ -289,41 +352,21 @@ void scan_affinity_3d_chunk(
289352
const auto number_of_nodes = static_cast<std::uint64_t>(depth * slice_size);
290353
for (std::size_t channel = 0; channel < offsets.size(); ++channel) {
291354
const auto &off = offsets[channel];
292-
std::size_t z_lo_full, z_hi_full, y_lo, y_hi, x_lo, x_hi;
293-
valid_axis_range(off[0], depth, z_lo_full, z_hi_full);
294-
valid_axis_range(off[1], height, y_lo, y_hi);
295-
valid_axis_range(off[2], width, x_lo, x_hi);
296-
const auto z_lo = std::max(z_lo_full, z_begin);
297-
const auto z_hi = std::min(z_hi_full, z_end);
298-
if (z_lo >= z_hi || y_lo >= y_hi || x_lo >= x_hi) {
299-
continue;
300-
}
301-
const auto offset_stride =
302-
off[0] * static_cast<std::ptrdiff_t>(slice_size) +
303-
off[1] * static_cast<std::ptrdiff_t>(width) +
304-
off[2];
305355
const auto channel_offset =
306356
static_cast<std::uint64_t>(channel) * number_of_nodes;
307-
for (std::size_t z = z_lo; z < z_hi; ++z) {
308-
const auto slice_offset = z * slice_size;
309-
for (std::size_t y = y_lo; y < y_hi; ++y) {
310-
const auto row_offset = slice_offset + y * width;
311-
for (std::size_t x = x_lo; x < x_hi; ++x) {
312-
const auto node = row_offset + x;
313-
const auto target = static_cast<std::uint64_t>(
314-
static_cast<std::ptrdiff_t>(node) + offset_stride
357+
sweep_offset_box_3d(
358+
off[0], off[1], off[2], depth, height, width, z_begin, z_end,
359+
[&](const std::uint64_t node, const std::uint64_t target) {
360+
const auto u = label_at(labels, node);
361+
const auto v = label_at(labels, target);
362+
const auto edge = edge_for_labels(rag, u, v);
363+
if (edge >= 0) {
364+
stats[static_cast<std::size_t>(edge)].add(
365+
affinities[channel_offset + node]
315366
);
316-
const auto u = label_at(labels, node);
317-
const auto v = label_at(labels, target);
318-
const auto edge = edge_for_labels(rag, u, v);
319-
if (edge >= 0) {
320-
stats[static_cast<std::size_t>(edge)].add(
321-
affinities[channel_offset + node]
322-
);
323-
}
324367
}
325368
}
326-
}
369+
);
327370
}
328371
}
329372

0 commit comments

Comments
 (0)