-
Notifications
You must be signed in to change notification settings - Fork 2
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
add enforce connectivity feature in analyze method #4
Conversation
1. Add superpixel creation test. 2. Superpixel creation test failed.
Superpixel analysis succeeded, but got stack overflow in synthesize.jl:30.
Seems unbounded problem when enforce_connectivity = true. Yet need further testing. Still stackoverflow error persists when trying synthesize image from SLIC-generated (analyze.jl) Superpixels.
As a reminder, I think there is a problem about the |
Thank you so much for doing this! I'm a bit busy these days, I'll try to manage this before next weekend! (Need some time to revisit the SLIC details) Also, the code was written long before when I wasn't so familiar with performance tweaks in Julia. So I'll need to revisit my own codes, too. |
Got it! Waiting for good news! |
Hi @johnnychen94, |
Sorry I have forgotten about this, too busy with the PhD research pressure 😨 . I'll check it this weekend, I promise. If you're sure that the implementation is correct, I can skip the check and just do some optimization/tweaks on it. |
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.
Without looking at the detailed algorithm, mostly it looks good.
We can add one more method so that there's no need to manually write Lab.(input_image)
_slic(alg::SLIC, img::AbstractArray{<:Colorant}) = _slic(alg, of_eltype(Lab, img))
of_eltype
is from MappedArrays, which gives a lazy version (no memory allocation) of Lab.(img)
.
@@ -0,0 +1,7 @@ | |||
using Images, ImageCore |
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.
We'll need to remove this eventually, but yeah this can be a good start-up demo for me :P
@@ -15,6 +15,6 @@ export | |||
imsize, | |||
# algorithms | |||
synthesize, Raw, Average, | |||
analyze, SLIC | |||
analyze, SLIC, _slic |
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.
The API I have in mind is
alg = SLIC(n_segments=100, compactness=10.0, max_iter=10, enforce_connectivity=false)
analyze(alg, img)
so _slic
here is just an internal implementation, we don't need to export this.
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.
FYI, according to the discussion in JuliaImages/ImageBinarization.jl#23, we may need to swap the arguments in future PR, i.e., analyze(img, alg)
src/analyze.jl
Outdated
if alg.enforce_connectivity | ||
nothing # TODO | ||
println("zergling") |
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.
We need to remove these print
s.
src/analyze.jl
Outdated
end | ||
end | ||
end | ||
nearest_segments = copy(nearest_segments_final) |
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.
What's the usage of this copy
?
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 copy
is not to change the source code.
But it will be fine to use nearest_segments_final
directly in the future.
|
||
start_label = 1 | ||
mask_label = start_label - 1 # indicates the label of this pixel has not been assigned | ||
nearest_segments_final = fill(mask_label, height, width) |
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.
It occurs to me that we can reuse the memory allocated by nearest_segments
.
src/analyze.jl
Outdated
if nearest_segments[y, x] == mask_label continue end | ||
if nearest_segments_final[y, x] > mask_label continue end |
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.
In Julia we usually use
if nearest_segments[y, x] == mask_label continue end | |
if nearest_segments_final[y, x] > mask_label continue end | |
nearest_segments[y, x] == mask_label && continue | |
nearest_segments_final[y, x] > mask_label && continue |
|
||
# Preform BFS to find the size of superpixel with | ||
# same lable number | ||
while bfs_visited < current_segment_size <= max_size |
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.
It might be worth adding @inbounds
to this deeply nested for loop so as to skip unnecessary checks during getindex
and setindex
, e.g., yy = coord_list[bfs_visited + 1, 1] + dy[i]
and coord_list[current_segment_size + 1, 1] = yy
while bfs_visited < current_segment_size <= max_size | |
@inbounds while bfs_visited < current_segment_size <= max_size |
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.
Though it sounds great, BFS usually needs to check bound.
I will try to research about BFS non-checking bounds method.
|
||
# merge the superpixel to its neighbor if it is too small | ||
if current_segment_size < min_size | ||
for i = 1:current_segment_size |
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.
if there's no if statements in the for-loop, it's usually a good suggestion to add @simd
macro to do the CPU level parallelization.
for i = 1:current_segment_size | |
@inbounds @simd for i = 1:current_segment_size |
also remove println
.
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.
To be clear. This and the @inbounds
comments are for minor performance tweaks. I'm not sure if these are useful, so benchmarks are needed. If you believe these are useless, feel free to ignore them.
These are very low-level tweaks where the for loops contains only trivial operations. As a simple example:
function arrsum(X)
rst = zero(eltype(X))
for i in 1:length(X)
rst += X[i]
end
rst
end
function arrsum_simd(X)
rst = zero(eltype(X))
@simd for i in 1:length(X)
rst += @inbounds X[i]
end
rst
end
julia> @btime arrsum($X)
833.455 μs (0 allocations: 0 bytes)
499930.1049151086
julia> @btime arrsum_inbounds($X)
207.907 μs (0 allocations: 0 bytes)
499930.1049150961
Thanks for your review! |
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.
Will there be more commits in? I can do the cleanups in #2 if there aren't more.
ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534" | ||
ImageDraw = "4381153b-2b60-58ae-a1ba-fd683676385f" | ||
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" | ||
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" | ||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" |
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.
We don't need these new deps: BenchmarkTools
, DelimitedFiles
, ImageMagick
, and Images
.
Those are only for demo purposes.
There won't be any commits in. |
Add enforce connectivity feature in analyze method.
The enforce connectivity implementation is based on scikit-image.
Because the original implementation uses 0-indexing, so I tried to translate into 1-indexing.
Though so far there are no any problems about
unbounded error
, it is ought to conduct test because I thinkthe implementation still have some problems in BFS part.
Feel free to edit and delete file changes. I am first time to Julia development, so I use some dirty ways to let
the test run.