Goal : make a simplified web-app version of ilastik, ie an interactive learning and image segmentation app. On a given image, the user labels pixels of the different classes (cells, etc.) using annotations. Features are computed on pixels of annotations (with a default set of features, and the possibility to add other features), and a random forest classifier (from scikit-learn) is trained on labeled pixels in order to segment pixels outside of annotations. Ilastik has this live mode which can be turned on and off, where the segmentation is recomputed every time a new annotation is drawn.
From: https://www.ilastik.org/gallery.html#
Layout
- an Input to paste the URL of an image to be segmented
- dcc.Graph with the modebar button to draw open paths
- a small slider to tune the width of the path (to modify
layout.newshape
)
- radioitems or dropdowns or checklists to select the features (the grid they have for this in https://www.youtube.com/watch?v=kXzHbuJj9XQ is very neat but probably complicated to do)
- a small colored button for the first class, with a text input to name this class (eg cell)
- a button with "Add class" which will add another line with a colored button and a text input, for the next class (we could in fact have two rows from the start since there will always be more than two classes)
- a "segmentation button" to train the machine learning model and compute the segmentation
- a "live" button checklist button (unchecked by default) to trigger the segmentation every time a new annotation is added
- a store for the annotations
Callbacks
relayoutData when adding an annotation --> add an annotation to the Store
pressing segmentation (or annotation Store changed when in live mode) --> retrieve geometry of annotations, compute features using skimage.features
functions for this on pixels of the image, train random forest classifier and fit on unlabeled pixels. Output: dcc.Graph figure with segmentation overlaid on original image (as in https://scikit-image.org/docs/stable/auto_examples/segmentation/plot_label.html#sphx-glr-auto-examples-segmentation-plot-label-py, with label2rgb
), and annotations. The selected features should be used as a State in this callback.
pressing one the colored classes buttons : change the newshape line color
changing the "brush" slider: change the newshape line width
Open questions
Persistence of the machine learning model: ideally we would like to have a machine learning model which persist on the server for a given image. Indeed you can use warm_start
in a scikit-learn random forest classifier to accelerate the training stage. We could probably store the model inside a dictionary, the key being the URL of the image or a hash.
persistence of machine learning model.
Ideally the image should also persist on disk maybe in this dictionary.
Getting started
I suggest watching https://www.youtube.com/watch?v=kXzHbuJj9XQ to see where we want to go.
Then one should get familiar with the underlying scikit-image and scikit-learn functions, the best thing is probably to work in a Jupyter notebook to play a bit with the code in https://github.com/scikit-image/skimage-tutorials/blob/master/lectures/solutions/machine_learning.ipynb (paragraph Increasing the number of low-level features: trained segmentation using Gabor filters and random forests). [It could also be a great way to test jupyter-dash :-)].
In order to get the geometry of the annotation from the plotly shape, one can use
|
def path_to_indices(path): |
https://github.com/plotly/dash-canvas/blob/master/dash_canvas/utils/parse_json.py#L7 and
https://github.com/plotly/dash-canvas/blob/master/dash_canvas/utils/parse_json.py#L79. The steps are
- obtain coordinates of the path control points, from the shape returned in relayoutData
- get the coordinates of all pixels covered by this path (in-between the control points), thanks to
skimage.draw.bezier_curve
- thicken the curve to the desired width with
binary_dilation
.