Skip to content
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

Search refactor #59

Merged
merged 173 commits into from
Aug 24, 2021
Merged

Search refactor #59

merged 173 commits into from
Aug 24, 2021

Conversation

carshadi
Copy link
Member

@carshadi carshadi commented Aug 23, 2021

Closes #53

(WIP)

Highlights (non-exhaustive):

  • Faster, scalable path-finding and filling algorithms and data structures
  • Encapsulate search cost functions and heuristics into objects, which are injected into general search routines. This enables mixing and matching different cost functions, heuristics, and search strategies in a decoupled, convenient way.
  • Add a new probabilistic cost function for A* searches (taken from an A* implementation by the janelia workstation)
  • Imagery is now represented and handled internally using imglib2 data structures, providing the ability to perform searches over arbitrary RandomAccessibleIntervals. This sets the stage for future migration to BigDataViewer for tracing through the GUI, improved integration with sciview (@kephale ) and already allows us to trace and fill over arbitrarily large image volumes via scripting (examples coming soon).
  • 2 new, custom multi-scale vessel enhancement filters, implemented as ImageJ Ops. In my testing, these run faster than the Tubeness and Frangi vesselness filters currently available in ImageJ Ops. The new Frangi filter is implemented as close to the original paper as possible (well, attempted at least...), whereas the current Op Frangi filter is non-canonical in the way the hessian eigenvalues are combined. Additionally, the new Tubeness filter supports multi-scale integration, whereas the current Ops implementation is single-scale.
  • Support for real-time local filtering of the image during A*-search, heavily reliant on imglib2-cache. This is intended as a generalization of the current hessian analysis functionality, which computes a single-scale Tubeness measure for voxels explored during searches. We can instead perform filtering using existing Ops, or define custom filters either as Ops or Consumers (approach heavily inspired by https://github.com/saalfeldlab/hot-knife/blob/master/src/main/java/org/janelia/saalfeldlab/hotknife/util/Lazy.java)
  • Adaptive, local image statistics computations used by searches (optional), enables tracing over large volumes where computing the entire image statistics is prohibitive.
  • Various UI improvements, including the new computation settings panel and improved Fill Manager interface.

Some Benchmarks

For these tests I used the following image as input (chunk of mouse cortex), with the test path shown in magenta (real length = 582.5 micrometers, # nodes = 1540) and the intensity histogram of the stack shown right. The start node is fixed for all iterations, and the path is traced between it and every subsequent node in the path, keeping track of the time-to-completion for the search and the count of explored nodes.

fig_4 fig_hist

If we do this on the current master branch, we find that the searches quickly become slow as distance between the start and goal nodes increases (using TracerThread)

fig2

If we compare this with TracerThread and BiSearch (a new bidirectional A* implementation) after the proposed changes, we see at least a 30X speed improvement for both algorithms at the tail of the measurement while exploring similar numbers of nodes. Even though BiSearch explores more nodes on average than TracerThread, it is still significantly faster, with the gap between them growing as the search space becomes larger. This is due to some algorithm and data structure choices that reduce the computational burden compared to TracerThread, for example using only one image-like data structure to store the encountered nodes for the opposing searches instead of two. Unlike TracerThread, it is also guaranteed to produce the optimal path (assuming the implementation is correct), as it continues to refine the shortest-path graph even after the two searches initially meet (where the path may or may not be optimal).

fig1

Breaking Changes

We fundamentally changed how many of the tracing and Filling classes operate, which naturally led to API-break. We feel that this is necessary since many of the old method parameters are now obsolete, and the resulting API is simpler and more flexible. Users who have existing scripts which utilize tracing and filling classes (e.g., TracerThread, FillerThread) are encouraged to browse the new tracing sub-package of snt

There are almost certainly other items I'm forgetting...@tferr anything I missed?

carshadi and others added 30 commits April 3, 2021 01:11
- implement alternate bidirectional A* algorithm (appears to be somewhat faster in my initial tests)
- Use more lightweight data structures for all searches
  - greatly improves performance (both speed and memory usage, the former likely due to the latter)
  - TODO: make common interface for choosing some variety of sparse matrix (e.g., array (previous type), map, nested open hashtable, etc...) and heap (e.g., Pairing Heap, Binary Heap, etc...)
- do not maintain a concrete closed set, rely instead on status flags
- refactor common search code into abstract superclass
- progress towards multi-threaded filling and path searches
- improve flexibility of filling functionality
- progress towards fully headless autotracing
- other misc bug-fixes and improvements
GUI:
-organize prompt
- adopt "states" as in main UI
- propose lists of paths if none exists
- simplify some code chunks
Plugin:
- Reduce visibility of some public methods
- throw exception on illegal operations rather than failing silently
-...
- code cleanup
- rename fields for consistency
- do not disable valid components 
- add a 'defaults' button for threshold distances
- improve prompts
- fix typos
- etc...
- also print more stats upon success in SearchThread
- makes it easier to quickly map custom metrics
- fix whitespace
- add descriptors for descriptor functions
- misc code cleanup
- attempt an imglib2-based SearchImage type
- Will prettify it after we settle on which type(s) to present the end user after performance testing / any re-works that are necessary
- do away with nested map, prefer integer algebra for key generation
- misc code cleanup
SNTTable:  Allow direct insertion of columns
SNTChart: Allow recoloring of datasets
Viewer3D:
- Freeze/unfreeze methods;
- Allow paths to be added directly to a scene
- Streamline single-node annotations
This will require further work. Currently, it will just hide 'Max' choice from GUI
- Use dropdown menu choice
- Report 'max' only when using Tubenesss
carshadi and others added 27 commits August 20, 2021 17:44
- secondary image loaded status no longer depends on whether a file is loaded, since images can be generated dynamically.
- move image generation logic out of SNTUI#loadCachedDataImage
- shutdown IOSync if secondary data is a DiskCachedCellImg
- secondary layer checkbox is now functional
- inputs not being stored in preferences
- Ensure messages/errors are displayed near the prompt, not on the screen center
- Add instructions for 'click on structure'
- misc
- Remove Edit Sigmas manually/visually. These are now implemented in the ComputeSecondaryImg prompt
- Replace all "Show Secondary" images entries with a common in the "View>" menubar
- Minor adjustments of error messages
- Remove unused  methods
SNTUI: Tootips, capitalization, etc.
ComputeSecondaryImg: Extend 'defaults' to all parameters
- rename to BiSearch, BiSearchNode for API ease-of-use
- simplify logic
- I feel more comfortable doing this now that there are tests
- searches should not be responsible for drawing their own progress on the TracerCanvas
- this will make it so we are not locked to creating a drawing strategy every time a new search strategy is implemented (this may be difficult for some approaches), and will provide more flexibility if we migrate to a different tracing canvas altogether (e.g., BigDataViewer)
- also, since TracerCanvas is package-private, this will allow us to move all the tracing-related classes to a new sub-package
While at it some minor cleanup
@tferr tferr merged commit 44fae38 into master Aug 24, 2021
@tferr tferr deleted the search-refactor branch February 3, 2022 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request: Improved path-finding and filling algorithms
2 participants