-
Notifications
You must be signed in to change notification settings - Fork 22
[WIP]Add skeletonization function #13
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
Open
Deepank308
wants to merge
3
commits into
JuliaImages:master
Choose a base branch
from
Deepank308:skeletonization
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+155
−2
Open
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| julia 0.7 | ||
| ImageCore 0.7.0 | ||
| Images 0.13.0 | ||
| ImageCore 0.7.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # checks if element is essential for connectivity | ||
| function compute_essential_indices() | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| essential_index_array = Array{Bool, 1}() | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| for index = 0:511 | ||
| append!(essential_index_array, maximum(find_components(index)) != maximum(find_components(index & ~2^4))) | ||
| end | ||
| essential_index_array | ||
| end | ||
|
|
||
| function find_components(index::Int64) | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| label_components(reshape(digits(index, base=2, pad=9), (3, 3)), trues(3, 3)) | ||
| end | ||
|
|
||
| function corner_table_lookup(img::AbstractArray{Bool, 2}, corner_table::AbstractArray{Int, 1}) | ||
| corner_score = zeros(Int, size(img) .+ 2) | ||
| score_table = [256 128 64; 32 16 8; 4 2 1] | ||
|
|
||
| for i = 2:size(img)[1] + 1 | ||
| for j = 2:size(img)[2] + 1 | ||
| if img[i - 1, j - 1] | ||
| corner_score[i - 1:i + 1, j - 1:j + 1] = corner_score[i - 1:i + 1, j - 1:j + 1] + score_table | ||
| end | ||
| end | ||
| end | ||
| corner_table[corner_score[2: size(img)[1] + 1, 2: size(img)[2] + 1] .+ 1] | ||
| end | ||
|
|
||
| function inner_skeleton_loop(img::AbstractArray{Bool, 2}, order::Array{Int, 1}, table::AbstractArray{Bool, 1}) | ||
| index = findall(img)[order] | ||
| score_table = [256 128 64; 32 16 8; 4 2 1] | ||
| result = zeros(Int, size(img)) | ||
| padded_image = zeros(Int, size(img) .+ 2) | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| padded_image[2: size(img)[1] + 1, 2: size(img)[2] + 1] = img | ||
| for i in index | ||
| result[i] = table[sum(padded_image[i[1]:i[1] + 2, i[2]:i[2] + 2] .* score_table) + 1] | ||
| padded_image[i[1] + 1, i[2] + 1] = result[i] | ||
| end | ||
| result | ||
| end | ||
|
|
||
| function skeletonize(img::AbstractArray{Bool}, algo::SkeletonizationAlgo) | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| skeletonize_impl(img, algo) | ||
| end | ||
|
|
||
| function skeletonize_impl(img::AbstractArray{Bool, 2}, algo::MedialAxis) | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
|
|
||
| # check if array has only 0s | ||
| if sum(img) == 0 | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| return img | ||
| end | ||
|
|
||
| # check if array has only 1s | ||
| if sum(img) == length(img) | ||
| img[1, 1:end] = false | ||
| img[1:end - 1, end] = false | ||
| img[end, 1:end - 1] = false | ||
| return convert(Array{Bool}, .~img) | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| end | ||
|
|
||
| # build look-up table | ||
| patterns = [0:1:511;] | ||
| num_pixels_in_patterns_kernel = sum.(digits.(patterns, base=2)) | ||
| center_is_foreground = convert(Array{Bool, 1}, patterns .& 2^4 .> 0) | ||
|
Deepank308 marked this conversation as resolved.
Outdated
|
||
| table = (center_is_foreground .& compute_essential_indices() .| (num_pixels_in_patterns_kernel .< 3)) | ||
| table = convert(Array{Bool, 1}, table) | ||
|
|
||
| # store distance transform | ||
| distance = distance_transform(feature_transform(.~img)) | ||
|
|
||
| # corners handling | ||
| corner_table = 9 .- num_pixels_in_patterns_kernel | ||
| corner_score = corner_table_lookup(img, corner_table) | ||
|
|
||
| # generate order for traversing the shape | ||
| dist_corner_pair = CartesianIndex.(round.(Int, distance[img] .* 10), corner_score[img]) | ||
| first_sort = sortperm(dist_corner_pair, by=x->x[2]) | ||
| second_sort = sortperm(dist_corner_pair[first_sort], by=x->x[1]) | ||
| order = first_sort[second_sort] | ||
|
|
||
| convert(Array{Bool, 2}, inner_skeleton_loop(img, order, table)) | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
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.
There's
using ImageMorphologyin Images.jl, and it will make package dependency complicate.@timholy How do we deal with this problem in general? Can we directly copy
Images.FeatureTransformmodule toImageMorphologyas temporary not-exported functions?https://github.com/JuliaImages/Images.jl/blob/bdfd044420fa6ffcd34760f804f0c3ce12186945/src/bwdist.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.
@johnnychen94 another example where we find something implemented in Images.jl that could live somewhere else. We really need to reorganize concepts around and break Images.jl into smaller packages for reuse. Right now a bunch of functionality lives in the umbrella package, and that is suboptimal.
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.
Looks like @Deepank308 needs this function implemented and merged ASAP to continue his GSoC ImageTracking project.
@juliohm I guess we can copy these methods to
FeatureTransform.jl(with comments) and remove it in the future, just like @zygmuntszpak does in https://github.com/zygmuntszpak/ImageBinarization.jl/blob/6e0c81867eaef67b463fa5d52febfca4d0f6196a/src/integral_image.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.
I don't know if copying/pasting helps @johnnychen94 , ideally we would start thinking more seriously about how to reorganize things. There is a lot of code living in the wrong place and we are just compromising the situation further by adopting multiple copies in submodules.
Uh oh!
There was an error while loading. Please reload this page.
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.
I might need another two weeks to start the porting work. Let's see how it works then.
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.
@johnnychen94 I don't need this function as of now in my implementations. I was just going through Skeletonization algorithm and found that Julia doesn't have it. So, I implemented and sent a PR.
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 this case, this PR might be pended until
FeatureTransformbeing ported to a standalone module.