image-processingmultidimensional-arrayjuliasliding-window

Getting 2-dimensional sliding windows from an image in Julia


I need to get several sliding windows from an image using the Julia programming language. I am newcomer to the language and having a hard-time finding a performant solution.

The problem: Lets say I have a grayscale image of size 2000x2000 pixels. I need to get/collect all possible windows (aka sub-arrays) of size 8x8 from this image. In NumPy (Python) with is done simply by np.lib.stride_tricks.sliding_window_view(img, (8,8)). Where img is an array of shape 2000x2000 and the tuple (8,8) defines the window size is each dimension.

What have I tried: I have seen similar questions of SO before such as:

Unfortunately, I am not able to get these suggestions to work properly for my use case. For example the mapwindow function in ImageFiltering.jl doesn't support windows of even shape such as 8x8. Even calling the function with an explicit border parameter doesn't give the right result; mapwindow(collect, img, (9,9), border=Inner()).

What I expect: Given an array of 2000x2000 pixels, I need to return 1993x1993 (39,72,049) sub-arrays each of shape 8x8 pixels. There is no requirement of fancy stuff like padding or custom stepsize (this should simply be 1).

I have written a custom function (see below) that implements this but I don't want to reinvent the wheel since there should already be something pretty performant somewhere in Julia.

Thank you

function get_windows(img, window_size=8)
           X, Y = size(img)

           [img[i:i+window_size-1, j:j+window_size-1]
           for i in 1:X-window_size+1
           for j in 1:Y-window_size+1]
end

Solution

  • This seems to work with ranges. Consider this image 4x4:

    julia> img = Gray.(i*j/20 for i in 1:4, j in 1:4)
    4×4 Array{Gray{Float64},2} with eltype Gray{Float64}:
     Gray{Float64}(0.05)  Gray{Float64}(0.1)  Gray{Float64}(0.15)  Gray{Float64}(0.2)
     Gray{Float64}(0.1)   Gray{Float64}(0.2)  Gray{Float64}(0.3)   Gray{Float64}(0.4)
     Gray{Float64}(0.15)  Gray{Float64}(0.3)  Gray{Float64}(0.45)  Gray{Float64}(0.6)
     Gray{Float64}(0.2)   Gray{Float64}(0.4)  Gray{Float64}(0.6)   Gray{Float64}(0.8)
    

    You can do window of even shape (here 2x2) with the following code:

    julia> windows = mapwindow(collect, img, (0:1,0:1),border=Inner())
    3×3 OffsetArray(::Matrix{Matrix{Gray{Float64}}}, 1:3, 1:3) with eltype Matrix{Gray{Float64}} with indices 1:3×1:3:
    ...
    

    Lets see:

    julia> windows[1,1] # top left
    2×2 Array{Gray{Float64},2} with eltype Gray{Float64}:
     Gray{Float64}(0.05)  Gray{Float64}(0.1)
     Gray{Float64}(0.1)   Gray{Float64}(0.2)
    
    julia> windows[2,2] # middle
    2×2 Array{Gray{Float64},2} with eltype Gray{Float64}:
     Gray{Float64}(0.2)  Gray{Float64}(0.3)
     Gray{Float64}(0.3)  Gray{Float64}(0.45)
    
    julia> windows[3,3] # bottom right
    2×2 Array{Gray{Float64},2} with eltype Gray{Float64}:
     Gray{Float64}(0.45)  Gray{Float64}(0.6)
     Gray{Float64}(0.6)   Gray{Float64}(0.8)