Quantifying microtubule "wiggles"

Sample image and/or code

  • Upload an original image file here directl y or share via a link to a file-sharing site (such as Dropbox) – (make sure however that you are allowed to share the image data publicly under the conditions of this forum).
  • Share a minimal working example of your macro code.

Background

These images show microtubules in WT and mutant cell lines. I would like to figure out ways to quantify this “wiggleness”.

Analysis goals

I would like to obtain some measure of deformity.

Challenges

The challenge here is finding a parameter to quantify. I am using Fiji for this purpose.

2 Likes

Thanks for posting here.

I had a chat with @apoliti and am experimenting with a solution based on directional filtering. The idea is to measure how straight the mircotubules are locally by “fitting a line into them”. The longer the line one can fit, the straighter they are. I guess local curvature could maybe be defined as something like 1/L where L would be the length of the largest line that could be fit.

I am pasting the current ImageJ macro below.

// Requirements
// - IPJB Plugins (MorpholibJ)

run("Close All");

// Create example image
//
newImage("Untitled", "8-bit black", 100, 100, 1);
run("Line Width...", "line=2");
setForegroundColor(1, 1, 1);
makeLine(15, 62, 90, 82);
run("Fill", "slice");
makeLine(86, 8, 85, 62);
run("Fill", "slice");
makeOval(20, 8, 48, 48);
run("Draw", "slice");
makeOval(38, 79, 7, 7);
run("Draw", "slice");
makeOval(34, 21, 21, 22);
run("Draw", "slice");
run("Select None");
rename("input");
//run("Divide...", "value="+255);
setMinAndMax(0, 1);
	
// Measure curvature using directional line filters
//
lmin = 3;
lmax = 100;
dl = 5;

// TODO: It feels as sampling the line lenghts in a non-linear way could be more appropriate...

setBatchMode(true);
for (l = lmin; l <= lmax; l+=dl) {
	selectWindow("input");
	run("Directional Filtering", "type=Max operation=Opening line=&l direction=32");
	run("Multiply...", "value=&l");
	rename("line_"+l);
}
run("Images to Stack", "name=lines title=line use");
run("Z Project...", "projection=[Max Intensity]");
run("Enhance Contrast", "saturated=0.1");
run("Fire");
rename("straightness");
run("Calibration Bar...", "location=[Upper Left] fill=White label=Black number=5 decimal=0 font=12 zoom=0.3 overlay");
setBatchMode("exit and display");

This produces this result for a binary test image:


I would be great to hear what other people (e.g. @dlegland ) would think about this approach! For example, in above image the algorithm suffers a bit from the pixelation of the oblique line…

I also have another question regarding performance. For large images above computations are quite expensive and I was thus wondering whether there may a CLIJ implementation for directional opening filters with a linear structural element (@haesleinhuepf)?

3 Likes

Wow, “directional opening”. :thinking: Would this work if it was implemented as a rotation, opening in X only and then rotate back?

1 Like

Yes, sounds like it. An issue may be that I only care about the “maximal response” or each pixel, i.e. the orientation that gives the maximal value for the opening operation, i.e. “along the line”. MLJ does this automatically, this is what Max stands for in run("Directional Filtering", "type=Max ...

Using your approach I think one would have to have a temporary image stack (in above example: 32 slices, one per orientation ... direction=32") and then do a maximum “z = direction” projection of this stack to obtain the maximum response. All of this could happen in one go on the GPU as one would only need the final result image. Is that technically possible?

Hi @Christian_Tischer
I’m wondering if skeletonising objects (ie oblique line) would improve your algo?

1 Like

I agree. I’m not 100%ly sure how to do this. I assume it’s a couple of loops of angles and radii for the maximum/minimum operation. Then you need to sum the interediate results and do some projection. Thoug, it feels a bit like from the back through the chest into the eye.

Consider setting up a workflow doing this with the assistant to figure out what needs to be done:

You can then export the corresponding code (see below) and build in some for-loops. If you think that might be something of general purpose, I’m happy to turn it into a clij plugin.

Cheers,
Robert

// To make this script run in Fiji, please activate 
// the clij and clij2 update sites in your Fiji 
// installation. Read more: https://clij.github.io

// Generator version: 0.4.2.18

// Init GPU
run("CLIJ2 Macro Extensions", "cl_device=");

// Load image from disc 
open("C:/Users/rober/AppData/Local/Temp/temp1612970471135.tif");
image1 = getTitle();
Ext.CLIJ2_pushCurrentZStack(image1);

// Copy
Ext.CLIJ2_copy(, );
Ext.CLIJ2_pull(image2);
Ext.CLIJ2_release(image2);
// Load image from disc 
open("C:/Users/rober/AppData/Local/Temp/temp1612970492601.tif");
image3 = getTitle();
Ext.CLIJ2_pushCurrentZStack(image3);
// The following auto-generated workflow is made for processing a 2D or 3D dataset.
// For processing multiple channels or time points, you need to program a for-loop.
// You can learn how to do this online: https://www.youtube.com/watch?v=ulSq-x5_in4

// Copy
Ext.CLIJ2_copy(image3, image4);
Ext.CLIJ2_release(image3);

Ext.CLIJ2_pull(image4);

// Rotate2D
angle = 360.0;
rotateAroundCenter = 1.0;
Ext.CLIJ2_rotate2D(image4, image5, angle, rotateAroundCenter);
Ext.CLIJ2_release(image4);

Ext.CLIJ2_pull(image5);

// Minimum2D Box
radius_x = 6.0;
radius_y = 0.0;
Ext.CLIJ2_minimum2DBox(image5, image6, radius_x, radius_y);
Ext.CLIJ2_release(image5);

Ext.CLIJ2_pull(image6);

// Maximum2D Box
radius_x = 6.0;
radius_y = 0.0;
Ext.CLIJ2_maximum2DBox(image6, image7, radius_x, radius_y);
Ext.CLIJ2_release(image6);

Ext.CLIJ2_pull(image7);
Ext.CLIJ2_release(image7);

2 Likes

In fact, I was thinking about this as well! However in the actual data (see first post) the microtubules are sometimes a bit “messy” and I was not sure whether a skeleton would always produce something useful. But for sure, an excellent point! Thank you!

Hi there,

yes, the idea of combining the result of directional filtering with several orientation is good! I have directional granolmetry module that wortks this way, but implemented in Matlab at the moment…

To improve the quality of the result, I suggest improving the number of directions. Then it will be possible to better approximate the oblique line.

Implementation note: the directional filter plugin works by computing erosion/dilation on oblique line stucturing element. In Mathematical Morphology papers, faster implementation can be obtained by restricting strel to “periodic lines”. I guess this can be used for accelerating with CLIJ. Otherwise checking the code that generate the disctete orietned lines in MorphoLibJ could lead to faster implementation.

final note: skeletonizing will not improve directional filtering, on contrary! this will produces too thin structures, and it will be difficult to identify the right local orientation of each pixel…

Best!

1 Like

Hi @Christian_Tischer,

I don’t think you can remove the pixelation problem if you remain in the discrete space. Something like a spline approximation should bring you back in a continuous domain. The problem is that you need to segment first, and this is what one would like to avoid for very messy images.

2 Likes

Hi all,

Thanks a lot for the input! It sounds like there are multiple approaches possible!