skeletonization

301 views
Skip to first unread message

Johannes Larsch

unread,
Dec 1, 2016, 10:11:31 AM12/1/16
to Bonsai Users

Hi,

I am trying to obtain a skeleton from a low resolution video of a zebrafish larva. See attached workflow.
I've tried the skeletonize node but I can't find parameters that give me the result I am looking for. I am getting a lot of extra branches. Is this expected given my input data and/or is there anything I can tune to obtain a single line on the skeleton of the animal?



As an alternative to your node I thought about a contour based approach. Since the shape has symmetry, it might be possible to find the extreme points of the contour using your dedicated node and then work forwards and backwards from one of the extreme points and average the two sides? For this, how would I access the contour points into a python node? I am confused by the properties of connectedComponent.Contour. What is the logic behind HPrev/HNext etc?  How would you go about collecting the entire contour into the python node?

J
fish.avi
skeletonize.bonsai
skeletonize.bonsai.layout

Gonçalo Lopes

unread,
Dec 1, 2016, 2:36:24 PM12/1/16
to Johannes Larsch, Bonsai Users
Hi Johannes,

This sounds like a fun exercise. First, regarding skeletonization (a.k.a. Topological Skeleton). In general, as you can see even in the wikipedia page, the topological skeleton is very sensitive to kinks in the external contour. In order to minimize this you can try smoothing the image, usually helps and play a bit with the skeletonization parameters.

Unforuntately the general rule is that it can be hard to extract a perfect line, as you've realized. You can also try a different skeletonization method such as doing different iterations of the Erode morphological operator. However, my experience is that in general this will give equally bad results.

Regarding the contour representation, yes, the Contour structure is a bit klunky. It comes from OpenCV and it takes into account that contours are usually extracted into a list, but can also have nested contours (i.e. holes within holes, etc). Whether the full hierarchy is computed depends on the Mode parameter of FindContours (to compute the full hierarchy, set it to Tree).

Anyway, HPrev/HNext and VPrev/VNext allows you to traverse through the hierarchy of contours (but not through the contour points themselves) . In general, I try to avoid doing this traversal by hand, and usually compute the BinaryRegionAnalysis / LargestBinaryRegion and just access the Contour property of each binary region.

If you just have a single Contour, then accessing the points in Python is trivial:

import clr
clr.AddReference("OpenCV.Net")
from OpenCV.Net import *
from System import Array

@returns(Array[Point])
def process(value):
  if value.Area > 0:
    points = value.Contour.ToArray[Point]()
  else:
    points = Array.CreateInstance(Point, 0)
  return points

The tests are to make sure there is a valid contour present, which happens only when the region has a non-zero area.

Btw, I believe most algorithms for skeleton extraction use local neighborhood analysis, meaning that you start at the tip, look at the density of the neighborhood, and walk to the middle of the density, look again, another step, etc, etc.

Probably there are more experienced zebrafish people in the list that can advise better.

Hope this helps!

--
You received this message because you are subscribed to the Google Groups "Bonsai Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.
Visit this group at https://groups.google.com/group/bonsai-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/bonsai-users/0833f8bc-6b0f-4c84-becf-9c7ed1efa9c6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Johannes Larsch

unread,
Dec 1, 2016, 5:15:03 PM12/1/16
to Bonsai Users, johanne...@gmail.com
Thanks pointing out how to get to the contour points. In the meantime, I've tried the ImageJ plugin Skeletonize 2D/3D and it works extremely well on my example data. I'll try and see if I can find out how they do it:
http://imagej.net/AnalyzeSkeleton

Gonçalo Lopes

unread,
Dec 1, 2016, 5:39:20 PM12/1/16
to Johannes Larsch, Bonsai Users
The ImageJ Skeletonize plugin definitely looks like a much more sophisticated solution, definitely not a straight topological skeleton :-)

Probably uses some kind of localized search strategy, I wonder how fast it can run on large videos.

On 1 December 2016 at 22:15, Johannes Larsch <johanne...@gmail.com> wrote:
Thanks pointing out how to get to the contour points. In the meantime, I've tried the ImageJ plugin Skeletonize 2D/3D and it works extremely well on my example data. I'll try and see if I can find out how they do it:
http://imagej.net/AnalyzeSkeleton

--
You received this message because you are subscribed to the Google Groups "Bonsai Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.
Visit this group at https://groups.google.com/group/bonsai-users.

Johannes Larsch

unread,
Dec 1, 2016, 6:58:19 PM12/1/16
to Bonsai Users, johanne...@gmail.com
this python transform sort of works but still not ideal:

(adapted from here):



import clr
clr.AddReference("OpenCV.Net")
from OpenCV.Net import *

@returns(IplImage)
def process(img):

  skel=IplImage(img.Size, IplDepth.U8, 1)
  skel.SetZero()
  eroded=IplImage(img.Size, IplDepth.U8, 1)
  temp=IplImage(img.Size, IplDepth.U8, 1)
 
  element = IplConvKernel(3,3,1,1,StructuringElementShape.Cross)
 
  done = 0

  while not done:
    CV.Erode(img, eroded, element)
    CV.Dilate(eroded, temp, element)
    CV.Sub(img, temp, temp)
    CV.Or(skel, temp, skel)
    CV.Copy(eroded,img)
  
    done = (CV.CountNonZero(img) == 0)

  return skel


the imagej plugin code is here:
Reply all
Reply to author
Forward
0 new messages