I'd like to implement a simple blur, that is averaging 3x3 pixels in a single pass, without transposition.
What would be the best way to implement that in Rust? I'm looking for solution that would prevent the dreadful off-by-one and out of bounds access, but also wouldn't needlessly do bounds checks for every pixel.
In C it goes like this:
special_case_for_first_row();
for each row {
special_case_for_first_pixel();
for each pixel except first and last {
// FAST PATH
}
special_case_for_last_pixel();
}
special_case_for_last_row();
In Rust, with iterators that feel "1D", that's a bit awkward.
I imagine with iterators it would go something like this:
// chain iterators to duplicate first/last row
std::iter::once(&vec[0..width]).chain(vec.chunks(width)).chain(std::iter::once(&vec[vec.len()-width..]))
.windows(3).flat_map(|rows|{
// here should be more chaining to duplicate first/last pixel in each row
return rows[0].windows(3).zip(rows[1].windows(3).zip(rows[2].windows(3)))
.map(|(a,(b,c))|{
return a[0]+a[1]+a[2]+
b[0]+b[1]+b[2]+
c[0]+c[1]+c[2];
});
});
but that doesn't actually work, because .windows()
doesn't work on iterators. And I'm not sure if I can expect the compiler to figure out how to make optimized inner loop for this, without any bounds checks and with a running average.
Are iterators even a good tool for this problem? Should I write equivalent of the C loops instead? Or maybe writing a custom iterator would help?