├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── assets
└── 2spooky.png
├── include
└── third_party
│ ├── halide_image_io.h
│ └── halide_target_check.h
├── spook.cpp
├── src
└── pipeline.cpp
└── test
├── images
└── horse.png
└── output
├── skel.png
└── spook_out.png
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | cmake-build-debug/
3 | .idea/
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(skeletonide)
3 | include_directories(include/third_party)
4 | add_executable(skelgen src/pipeline.cpp)
5 | target_link_libraries(skelgen Halide pthread dl png16 jpeg)
6 | add_custom_command(
7 | TARGET skelgen
8 | COMMAND skelgen
9 | )
10 | include_directories(${CMAKE_CURRENT_BINARY_DIR})
11 | add_executable(spook spook.cpp)
12 | add_dependencies(spook skelgen)
13 | link_directories(${CMAKE_CURRENT_BINARY_DIR})
14 | target_link_libraries(spook ${CMAKE_CURRENT_BINARY_DIR}/skeletonide.a Halide pthread dl png16 jpeg )
15 | add_custom_command(
16 | TARGET spook
17 | COMMAND mv spook ${CMAKE_HOME_DIRECTORY}
18 | )
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Srimukh Sripada
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # skeletonide
2 |
3 |
4 | Skeletonide is a parallel implementaion of Zhang-Suen morphological
5 | thinning algorithm written in Halide-lang. It can be used for fast
6 | skeletonization of binary masks. Can also be run on the GPU.
7 |
8 | When you build the project, it generates an ahead-of-time
9 | compiled static library from the halide pipeline. It is then
10 | linked with the caller code to generate a single binary.
11 |
12 | Note: The halide pipeline represents a single pass of the
13 | Zhang-Suen method. The iterations have to be handled by the
14 | caller code - see `spook.cpp` for an example. The number of
15 | iterations is hardcoded right now. It should depend on the
16 | completion flags returned by the halide pipeline.
17 |
18 |
19 | ## Usage
20 |
21 | See `spook.cpp` for an example. The example benchmarks the time
22 | taken to skeletonize a large image on the GPU. Pipeline code is in
23 | `src/pipeline.cpp`.
24 |
25 |
26 | ## Benchmarks
27 |
28 | We get the best performance when it is run on a GPU. The tests are
29 | run on the scikit-image's horse mask, but tiled 10x10 to create a large
30 | (3280, 4000) shaped test image. The time is averaged over 100 runs.
31 |
32 | | Implementation | CPU (i7-7700HQ) | GPU (GTX 1050m) |
33 | | ------------------------------------- | --------------- | --------------- |
34 | | Scikit-image `morphology.skeletonize` | **2073 ms** | NA |
35 | | Skeletonide | 3786 ms | **210 ms** |
36 |
37 | The scheduling of the Halide pipeline can be further tweaked through
38 | trial-and-error to achieve better CPU times. The slow performance on the CPU
39 | is partly explained by the fact that the pipeline only represents a single pass
40 | of the thinning algorithm. There is significant time penalty in handling the
41 | iterations from the outside as illustrated in `spook.cpp`.
42 | However, on the GPU, Skeletonide performs roughly 10x faster than the scikit-image's
43 | CPU implemetation without major modifications. Not a level playing field, obviously.
44 |
45 | The output on the scikit-image's horse mask:
46 |
47 | Mask:
48 | 
49 |
50 | Skeleton:
51 | 
52 |
53 | ## Build
54 |
55 | ```sh
56 | mkdir build
57 | cd build
58 | cmake ..
59 | cmake --build .
60 | # this will build the static library and its
61 | # header in `build/` and a single test binary
62 | # called `spook` in `skeletonide` - which can
63 | # be run `./spook` to see it in action.
64 | ```
65 |
66 | ## License
67 | MIT License
--------------------------------------------------------------------------------
/assets/2spooky.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postmalloc/skeletonide/05f76ef65e7d29efb19ebd27bd88de8f5e5db46b/assets/2spooky.png
--------------------------------------------------------------------------------
/include/third_party/halide_image_io.h:
--------------------------------------------------------------------------------
1 | // This simple IO library works the Halide::Buffer type or any
2 | // other image type with the same API.
3 |
4 | #ifndef HALIDE_IMAGE_IO_H
5 | #define HALIDE_IMAGE_IO_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include