Skip to content

ImageMorphology.erode for a DiskArray #241

@bjarthur

Description

@bjarthur

i was hoping a simple little rewrite of this section of code to use broadcasting would magically make erode fast for a boolean Zarr array, but alas, no:

diff --git a/src/extreme_filter.jl b/src/extreme_filter.jl
index 1d63ace..35af06c 100644
--- a/src/extreme_filter.jl
+++ b/src/extreme_filter.jl
@@ -527,10 +527,11 @@ function _extreme_filter_bool!(f, out, A::AbstractArray{Bool}, Ω)
     R_inner = (first(R) + δ):(last(R) - δ)
 
     select = _fast_select(f)
-    @inbounds for p in R_inner
-        out[p] = select(A, p, Ω)
-    end
+    @info 1
+    out[R_inner] .= select.(Ref(A), R_inner, Ref(Ω))
+    @info 2
     for p in EdgeIterator(R, R_inner)
+        @info p
         out[p] = select(A, p, Ω)
     end
     return out

my test harness prints "1" and then hangs for the call to erode! with the ZArray:

using ImageMorphology, Zarr
a = rand(Bool, 256,256,256);
z = ZArray(a);
oa = similar(a);
oz = similar(z);
se = strel_diamond((3, 3, 3));
erode!(oa, a, se);
erode!(oz, z, se);

i'm guessing it's because the logic in select has too many branches, or perhaps because it indexes the Zarray on two different lines (544 and 550).

is there any hope to an elegant solution here? if so, i'll keep banging my head on it.

in the meantime, i've got this hack:

using ImageMorphology

for (fun, filt) in (("erode!", typemax), ("dilate!", typemin))
    fun_sym = Symbol(fun)
    @eval ImageMorphology.$fun_sym(out, img; dims=coords_spatial(img), r=nothing, chunk) =
        ImageMorphology.$fun_sym(out, img, strel_box(img, dims; r), chunk=chunk)

    @eval @doc """
        $($fun)(out, img, se; chunk)
    
    $($fun) `img` in chunks.  Doing so can be much faster than the generic
    element-wise algorithm if `img` is backed by, for example, a Zarr array.
    `chunk` should be a tuple with an element for each dimension.  The chunk
    can nominally be of any size but generally should be larger than `se` and
    the underlying chunk size of `img`.

    # Examples

    $($fun)(out, img, se; chunk=(64,64,64))
    """ ImageMorphology.$fun_sym
    @eval function ImageMorphology.$fun_sym(out, img, se; chunk)
        pad = extrema.(axes(se))
        PAD1 = CartesianIndex(ntuple(i->pad[i][1], length(pad)))
        PAD2 = CartesianIndex(ntuple(i->pad[i][2], length(pad)))
        ZERO = CartesianIndex(ntuple(_->0, ndims(img)))
        ONE = CartesianIndex(ntuple(_->1, ndims(img)))
        SIZEIMG = CartesianIndex(size(img))
        CHUNK = CartesianIndex(chunk)
        chunk_pad = [c+length(range(p...))-1 for (c,p) in zip(chunk,pad)]
        img_chunk = Array{eltype(img)}(undef, chunk_pad...)
        out_chunk = similar(img_chunk)
        for I in CartesianIndices((:).(ntuple(_->1, ndims(img)), chunk, size(img)))
            img_chunk .= $filt(eltype(img))
            R = min(SIZEIMG, I+CHUNK-ONE)
            IMG1 = max(ONE, I+PAD1)
            IMG2 = min(SIZEIMG, R+PAD2)
            img_chunk[ONE:IMG2-IMG1+ONE] .= img[IMG1:IMG2]
            ImageMorphology.$fun_sym(out_chunk, img_chunk, se)
            OUT1 = ONE-PAD1 + min(ZERO, I+PAD1-ONE)
            OUT2 = OUT1+R-I
            out[I:R] .= out_chunk[OUT1:OUT2]
        end
    end
end

thanks in advance for any help!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions