All Projects → LingDong- → Skeleton Tracing

LingDong- / Skeleton Tracing

Licence: mit
A new algorithm for retrieving topological skeleton as a set of polylines from binary images

Programming Languages

c
50402 projects - #5 most used programming language

Projects that are alternatives of or similar to Skeleton Tracing

Kdbush
A fast static index for 2D points
Stars: ✭ 412 (+70.95%)
Mutual labels:  algorithm, computational-geometry
Supercluster
A very fast geospatial point clustering library for browsers and Node.
Stars: ✭ 1,246 (+417.01%)
Mutual labels:  algorithm, computational-geometry
Turf
A modular geospatial engine written in JavaScript
Stars: ✭ 6,659 (+2663.07%)
Mutual labels:  algorithm, computational-geometry
Polysnap
A work in progress polygon operations library with integer snap-rounding
Stars: ✭ 14 (-94.19%)
Mutual labels:  algorithm, computational-geometry
Data structure and algorithms library
A collection of classical algorithms and data-structures implementation in C++ for coding interview and competitive programming
Stars: ✭ 133 (-44.81%)
Mutual labels:  algorithm, computational-geometry
Geokdbush
The fastest spatial index for geographic locations in JavaScript
Stars: ✭ 251 (+4.15%)
Mutual labels:  algorithm, computational-geometry
Flatbush
A very fast static spatial index for 2D points and rectangles in JavaScript
Stars: ✭ 1,031 (+327.8%)
Mutual labels:  algorithm, computational-geometry
Delaunator Cpp
A really fast C++ library for Delaunay triangulation of 2D points
Stars: ✭ 244 (+1.24%)
Mutual labels:  algorithm, computational-geometry
Turf Swift
A Swift language port of Turf.js.
Stars: ✭ 123 (-48.96%)
Mutual labels:  algorithm, computational-geometry
Delaunator
An incredibly fast JavaScript library for Delaunay triangulation of 2D points
Stars: ✭ 1,641 (+580.91%)
Mutual labels:  algorithm, computational-geometry
Earcut
The fastest and smallest JavaScript polygon triangulation library for your WebGL apps
Stars: ✭ 1,359 (+463.9%)
Mutual labels:  algorithm, computational-geometry
Rbush
RBush — a high-performance JavaScript R-tree-based 2D spatial index for points and rectangles
Stars: ✭ 1,881 (+680.5%)
Mutual labels:  algorithm, computational-geometry
Cavaliercontours
2D polyline library for offsetting, combining, etc.
Stars: ✭ 135 (-43.98%)
Mutual labels:  algorithm, computational-geometry
Greinerhormann
Greiner-Hormann polygon clipping algorithm. Does AND, OR, XOR. Plays nicely with Leaflet. Handles non-convex polygons and multiple clipping areas. ~3kb footprint, no dependencies
Stars: ✭ 176 (-26.97%)
Mutual labels:  algorithm, computational-geometry
Codejam
Set of handy reusable .NET components that can simplify your daily work and save your time when you copy and paste your favorite helper methods and classes from one project to another
Stars: ✭ 217 (-9.96%)
Mutual labels:  algorithm
Ngraph.path
Path finding in a graph
Stars: ✭ 2,545 (+956.02%)
Mutual labels:  algorithm
Play With Data Structures
慕课 liuyubobobo「玩转数据结构」课程的 Go 语言实现版本
Stars: ✭ 217 (-9.96%)
Mutual labels:  algorithm
Competitive Programming
My competitive programming guide,reading materials, link to system and design interview preparation and my own coding solutions from Codechef, Leetcode,Geeks for Geeks, HackerRank , spoj, codesignal, codebyte, codeblocks and other online judges
Stars: ✭ 206 (-14.52%)
Mutual labels:  algorithm
Fastrange
A fast alternative to the modulo reduction
Stars: ✭ 230 (-4.56%)
Mutual labels:  algorithm
Way To Algorithm
Algorithm Tutorial and Source Code
Stars: ✭ 221 (-8.3%)
Mutual labels:  algorithm

Skeleton Tracing

A new algorithm for retrieving topological skeleton as a set of polylines from binary images.

Available in all your favorite languages: C, C++, Java, JavaScript, Python, Go, C#/Unity, Swift, Rust, Julia, WebAssembly, Haxe, Processing, OpenFrameworks.

[Online Demo]

About the Chinese characters in the test image

Introduction

Traditionally, skeletonization (thinning) is a morphological operation to reduce a binary image to its topological skeleton, returning a raster image as result. However, sometimes a vector representation (e.g. polylines) is more desirable. Though contour-finding can be used to further trace the results, they usually give enclosing outlines instead of single strokes, and are prone to slight variations in stroke width caused by imperfection in the skeletonization process. In this demo we present a parallelizable divide-and-conquer based algorithm for skeleton tracing, which converts binary images into a set of polylines, i.e. arrays of (x,y) coordinates along the skeleton, in real time.

Algorithm Description

Define a binary image to be a 2D matrix consisting of 0-pixels(background) and 1-pixels(foreground). The algorithm can be summarized as follows:

  1. Given a binary image, first skeletonize it with a traditional raster skeletonization algorithm, e.g. Zhang-Suen 1984 is used in this demo. (Without this step, the algoirthm still works to a certian extent, though the quality is generally reduced.)
  2. If the width and height of the image are both smaller than a small, pre-determined size, go to step 7.
  3. Raster scan the image to find a row or column of pixels with qualities that best match the following:
    • Has the least amount of 1-pixels on itself.
    • The 2 submatrices divided by this row or column do not have 1-pixels on their four corners.
    • When two or more candidates are found, pick the one that is closer to the center of the image.
  4. Split the image by this column or row into 2 submatrices (either left and right, or top and bottom depending on whether row or column is selected in the previous step).
  5. Check if either of the 2 submatrices is empty (i.e. all 0-pixels). For each non-empty submatrix, recursively process it by going to step 2.
  6. Merge the result from the 2 submatrices, and return the combined set of polylines.
    • For each polylines from one submatrix whose either endpoint coincide with the splitting row or column, find another polyline in the other submatrix whose endpoint meets it. If the matrix was split horizontally, then the x-coordinate of the endpoints should differ by exactly 1, and y-coordinate can differ between 0 to about 4 (depending on the steepness of the stroke potrayed), The reverse goes for vertical splitting.
  7. Recursive bottom. Walk around the 4 edges of this small matrix in either clockwise or ant-clockwise order inspecting the border pixels.
    • Initially set a flag to false, and whenever a 1-pixel is encountered whilst the flag is false, set the flag to true, and push the coordinate of the 1-pixel to a stack.
    • Whenever a 0-pixel is encountered whilst the flag is true, pop the last coordinate from the stack, and push the midpoint between it and the current coordinate. Then set the flag to false.
    • After all border pixels are visited, the stack now holds coordinates for all the "outgoing" (or "incoming") pixels from this small image section. By connecting these coordinates with the center coordinate of the image section, an estimated vectorized representation of the skeleton in this area if formed by these line segments. We further improve the estimate using the following heuristics:
    • If there are exactly 2 outgoing pixels. It is likely that the area holds a straight line. We return a single segment connecting these 2 pixels.
    • If there are 3 or more outgoing pixels, it is likely that the area holds an intersection, or "crossroad". We do a convolution on the matrix to find the 3x3 submatrix that contains the most 1-pixels. Set the center of all the segments to the center of the 3x3 submatrix and return.
    • If there are only 1 outgoing pixels, return the segment that connects it and the center of the image section.

Implementations

Click on links below to see each implementation's documentation and code.

  • C99 (parallelized with pthreads, libpng for reading and X11 for display)
  • C++ (thinly wrapped from C version)
  • JavaScript (WebAssembly compiled from C++ using emscripten)
  • Vanilla JS (Pure JavaScript implementation)
  • Pure Python (slow)
  • Python using C API (compiled from C using SWIG, compatible with numpy and opencv)
  • Java (includes a Processing demo)
  • OpenFrameworks addon (friendly wrapper on C++ version)
  • C# (demo script for Unity Engine)
  • Go (parallelized with goroutines)
  • Swift (demo with NSImage and AppKit)
  • Rust (simple rust implementation)
  • Julia (julia implementation with array views)

Benchmarks

The benchmarks below are produced on MacBook Pro Mid 2015 (2.5 GHz Intel Core i7, 16GB 1600 MHz DDR3). The input image is test_images/opencv-thinning-src-img.png (300x149px).

All the times refer to pure or "vanilla" implemenations, not wrappers of C/C++. Wrappers on C/C++ should be comparable to the performance of C plus some overhead. Exception is WebAssembly performance which depends heavily on browser and number of open tabs.

All the times refer to the "tracing" operation only, excluding the raster thinning step (which is not my algorithm (problem), but note that practically, raster thinning often takes longer than the tracing, especially for images with lots of white pixels).

For compiled languages, the highest possible optimization level is selected, unless otherwise specified.

Ordered by fastest to slowest.

Language Seconds/1000 Runs FPS % C speed Note
C 0.759748 1316 100% -O3
Go 1.1165248 895 68%
Rust 1.39878 714 54% -O
Java 1.722 580 44%
Swift 1.795619 556 42% -O
JavaScript 1.948 513 38% Node.js v12.10
C# 4.266101 234 17% Unity 2018.4.8f1
Julia 4.722 (2.791 amortized) 211 16% First frame takes 2 sec, the rest 0.002 sec
Python 1015.04818 1 0% Python 3.7

Developed at Frank-Ratchye STUDIO for Creative Inquiry at Carnegie Mellon University.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].