-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: strided mapwindow #45
Conversation
Sorry for the delay here; I've been mulling over the API issues, and I agree it's not entirely straightforward. I keep returning to something like: dest = PooledArray{T}(inds)
mapwindow!(f, dest, img, window, border) and possibly a convenience method dest = pooledarray(f, img, window, inds) for the automatic computation of the eltype. But to be honest I'm not convinced that's any better. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really elegant work. 👍
Do you think some of the in-code @assert
s can be turned into tests? I'm not against leaving them in, though I'd want to know about their performance impact (I think they get eliminated with julia -O3
).
test/runtests.jl
Outdated
@@ -5,14 +5,14 @@ aif = detect_ambiguities(ImageFiltering, Kernel, KernelFactors, Base) | |||
asa = detect_ambiguities(StaticArrays, Base) | |||
@test isempty(setdiff(aif, asa)) | |||
|
|||
include("mapwindow.jl") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this deliberate or simply a temporary convenience?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a convenience, I can restore previous order if this is finished.
test/mapwindow.jl
Outdated
(mean, randn(10), (-1:1,), (1:2:8,)), | ||
(mean, randn(10,5), (-1:1,0:0), (1:2:8,1:3)), | ||
] | ||
border = ImageFiltering.borderinstance("replicate") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not just pass "replicate"
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we can!
None of the |
Introducing a new type of array seems a bit heavyweight for this. Is turning mapwindow(f,img,window,imginds; border=myborder) At least border does not influence the return type AFAICT. mapwindow! seems to be useful also independently of this PR. |
It does for
I agree. The only justification is whether it would be useful for "documenting" the results later. For example, if someone hands you an array that is a result of some pooling operation, does it help you to know where each "pixel" (result on a chunk) came from? Or do you not care? And yes, |
Depends on the application. Most of the time I just want to detect, whether some property is holds in an image. For this I don't care about the original pixels. But if you search something in an image, this sounds useful. In that case you might also want to chain some Finally one might want to use a strided struct PooledArray{T,N,A,I} <: AbstractArray{T,N}
data::A
indices::I
end This is even more heavyweight and looks a lot like an Here is a list of all options I can think of:
|
Another idea is making struct MapWindow{T,N,F,O,W,P} <: AbstractArray{T,N}
f::F
original_array::O
windowsize::W
pad::P
# maybe also buffer?
end
MapWindow(f, img, windowsize)[1:4, 5:6]
mapwindow!(f,dest, img,windowsize, border) = copy!(dest, MapWindow(f,img,windowsize, border)) |
I generally love lazy, but here the problem is that it kind of violates one of the implicit "contracts" of Of your list of 5 options above, I'd like to strike number 2. This is really a statement about what portion of the output you want to keep, so associating it with the input seems wrong. 4 seems somehow unnecessary. I find myself roughly equally attracted by 1, 3, and 5. I can go with the API you have now, if there isn't an obviously better alternative. Since I'm on the fence, I'd be happy to have you choose. |
Codecov Report
@@ Coverage Diff @@
## master #45 +/- ##
==========================================
- Coverage 90.12% 88.94% -1.18%
==========================================
Files 8 8
Lines 992 1049 +57
==========================================
+ Hits 894 933 +39
- Misses 98 116 +18
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #45 +/- ##
==========================================
+ Coverage 90.12% 90.48% +0.35%
==========================================
Files 8 8
Lines 992 1040 +48
==========================================
+ Hits 894 941 +47
- Misses 98 99 +1
Continue to review full report at Codecov.
|
I will go with mapwindow(f,img,window,border,imginds) for now. Maybe over time something better will emerge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small tweaks, then I think this is ready for a squash-and-merge. Thanks for an outstanding contribution!
It works as follows: | ||
```julia | ||
mapwindow(f, img, window, border, (2:5, 1:2:7)) == mapwindow(f,img,window,border)[2:5, 1:2:7] | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add "except more efficiently because it omits computation of the unused values."
src/mapwindow.jl
Outdated
@@ -41,78 +48,176 @@ and then `mapwindow(f, img, (m,n))` should filter at the 75th quantile. | |||
|
|||
See also: [`imfilter`](@ref). | |||
""" | |||
function mapwindow(f, img::AbstractArray, window::Dims, args...; kwargs...) | |||
function mapwindow(f,img,window;kw...) | |||
mapwindow(f, img, window, "replicate", kw...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
semicolon after "replicate"
. Usually stylistic, but here I think it's actually a bug (like it was in https://github.com/JuliaImages/ImageView.jl/pull/130/files).
Also perhaps add spaces between the arguments?
src/mapwindow.jl
Outdated
mapwindow(f, img, (-h:h,), args...; kwargs...) | ||
-h:h | ||
end | ||
resolve_window(window::AbstractArray) = resolve_window(img, (window...,)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does the img
come from?
src/mapwindow.jl
Outdated
img::AbstractArray{T,N}, | ||
window::Indices{N}, | ||
window::NTuple{N,Range}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about an AbstractUnitRange
here, since I think we wouldn't properly handle a non-1 step if it were supplied.
Thanks for the feedback. There are still some corner cases, that I need to test/fix. |
If there are no further objections, I will merge on Monday. |
test/mapwindow.jl
Outdated
end | ||
@test mapwindow(mean, randn(10), (3,), "replicate", 2:2:7) isa Array | ||
@test mapwindow(mean, randn(10), (3,), "replicate", 2:7) isa OffsetArray | ||
@test mapwindow(mean, randn(10), (3,)) isa Array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I didn't notice this earlier, but over time I've gotten more skeptical about testing the output type directly (this hit me with a vengance in JuliaImages/ImageCore.jl#52). Can something equivalent be done by testing the indices
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I don't like these tests either. Testing the indices is more sane.
Thanks so much, this is fantastic! |
See #44. Here is a first implementation. The API is a bit cumbersome and needs to be improved. Currently you have to call
mapwindow(f,img,window,border,imginds)
Any suggestions for a better API? I would also like to add two convenience functions:
strided(inds, stride)
converts a stride into something that can be passed to mapwindow:mappool(f,img,window)
which does image pooling. This is the special case, where the stride is the size of the window.