Analyzing cell layer thickness



I’m new to image processing and i’ve encountered a problem I can’t solve.
I have either histology or immunohistochemistry images of retina, in which the cell layers have been labeled and my mission is to define the borders of one specific cell layer (the thickest top layer between 3 layers in the images attached) and to determine the layer thickness in as many regions along the cell layer as possible.
I managed to mark the cell layers using threshold or Weka segmentation, but can’t proceed from that step…any suggestions?

Segmentation in OCT imaging
Measuring epithelium thickness using imageJ {HELP]
Accessible surface


Perhaps this older Forum post will answer your question?

Let us know either way… we can still help if you have more questions.

eta :slight_smile:


Thanks for the help, I really appreciate it.
So I implemented your suggestion and got the local thickness map (I’m attaching the results). Not sure how to proceed:

  1. how do I extract the diameter of each local thickness from the map (so I can replace the graphic results with a graph of thickness)
  2. I am only interested in one of the cell layers in the image. Is there a plugin that can help me choose only one of them while erasing the others? this is why I wanted to find a plugin that will find the boundaries of each cell layer…


I encountered this thread and wanted to ask how can I define the boundaries like he did on it. Any clue?



No worries! Are you running local thickness on your binarized image? Just follow @imagejan’s steps he mentions in the link I posted (he included helpful links in there as well). Try this first … then we can worry about data output.




That’s a tougher one. The reason he was able to extract that data was because he aligned it with the y-axis. From the looks of it - your images are on an angle… so you’d have to find that perpendicular angle and adjust that code accordingly… Especially if the angles change from image-to-image…

You could draw a segmented line on the local thickness image (you can automate this using skeletonization - see this old forum post and then plot the profile.

I hope someone else here on the Forum can also chime-in … in the meantime - I will see what I can find to help.

eta :slight_smile:


I followed his steps, the image I attached was the final output of the local thickness I ran on the binarized image I created…I think I’m ready for data output unless you think the results are not good



If you are happy with your thresholding (though I wouldn’t mind taking a look at your binarized image just to be sure)… then you can proceed. You can use Skeletonization then to draw the shortest-longest-path (ie - line right down the middle of you cell layer) and measure the local thickness along that line. Just take a look at this Segmentation Workshop starting at 1:46:00. It gives you an example using this old Forum post.

That should give you all the info you need to do your analysis… if you have more questions though - feel free to post again.

eta :slight_smile:


Thank you so much! I’m very close to my analysis but still not there…
So I tried color segmentation and definitely the Weka trainable segmentation creates better results.
I continued with the instructions but for some reason filling holes was not possible for me as long as my ROI was white on black background - I inverted and everything was fine (I added the image).
The second image I am attaching is the skeletonized image I extracted; it all went well until I analyzed the skeleton - for some reason, the results table did not appear with the measurements, only the third image I’m attaching was created instead…Any idea why that happened and how to correct it?


I forgot to mention - I thought that the problem might be cause because I was working on inverted image so I inverted the hole filled image and tries skeletonizing it - I couldn’t get the ROI skeletonization I got when the ROI was black, only the image I am attaching.


So @ofirforsht

Using the binary image you attached… I did the following steps:

  1. Threshold the binary image
  2. Create Selection - I also added it to the ROI Manager
  3. Skeletonize - I did have to do an inversion before this step to make sure the skeletonization was occurring within the bounds of your cell layer
  4. and Analyze Skeleton to calculate the longest shortest path (make sure you select that calculation)… this is your center line along the length of your cell layer

For me - this workflow was fine. Try again and let us know.

And then look at this old forum post for finding your values along that line:

That should do it!



Sorry for the hassle, but I followed your steps and still couldn’t get the results…I wanted to go through the steps again to see where I go wrong:

  1. I started with the original image - black ROI on white background. At which part did you invert the image?
  2. Thresholding the image does nothing, why did you do it? it’s already B&W. I did it (image>adjust>threshold and kept the auto threshold). thresholding makes the ROI black and background white again if I invert first.
  3. create selection chooses the ROI, so if I try to invert it will have to be before this step otherwise I will end up with entire image being white…
  4. Any attempt to skeletonize the image when the ROI is white on black background resulted in the weird skeletonization I posted in the last post (the second image, when the skeleton is constructed outside of the ROI instead of in it). BTW if I try to analyze skeleton on it I will get results…just irrelevant ones of a bad skeletonization.
    I would appreciate going (literally) step be step with me so I could reproduce your results.
    Thanks again for all the help


sorry for coming out from the blue,
but please check if all of you have the same background colors options, in:

  1. Edit->Options->Colors
  2. Process->Binary-> Options

and all of you are using “inverted” or “not inverted” LUTs LookUp Tables

Sometimes, it’s just that.

Emanuele Martini


Thanks for that!
in the binary options, black background is unchecked. After I checked it everything works perfect!


After getting the detailed branch list I looked and some of them seem to be very short.

  1. Is a branch only the length of one side of the longest shortest path (thus needs to be doubled to get the thicknes)?
  2. I see that some of them are not perpendicular to the longest shortest path and some are the short processes at the end of each branch - both types of lines will add noise to my results…how should I substract them from the results, considering that the cell layer thickness may vary so I can’t set a minimum-maximum thickness to gate them out?



You can use the longest-shortest path as the line selection from which to measure your local thickness. You don’t use the branches in this case… just read through all of the above links I provided.



So I went through the previous posts and I assume you refer to the getShortestPathPoints() function to be used on my Longest shortest path in order to get the array of lines along it…unfortunately I’m a newbie in java so I couldn’t understand how to implement this on my Longest shortest path.
The macro I recorded for the analysis of the binarized image is:

run("Analyze Particles...", "size=1000-Infinity display add");
run("Fill Holes");
setOption("BlackBackground", true);
run("Analyze Skeleton (2D/3D)", "prune=none calculate");
selectWindow("Longest shortest paths");
// ArrayList<point>[] getShortestPathPoints()  - not a clew how to proceed...

I would appreciate it if you could point me out on how to define the parameters for my output in order to get the array.



Sorry for the delay in response… The code you would need is in this older forum post that I had posted previously:

Just read through that forum thread and then give things a try… if you are still stuck - we can try to get you unstuck!

eta :slight_smile:


So I went through the post and I see the corrected Analyze skeleton, the problem is that I’m not sure how to use it… as I mentioned I’m a newbie so I would appreciate a step by step on how to use it.
Thanks for all your help!



In the Segmentation workshop at around 1:46:20… an example using Analyze Skeletons is used. So that should be enough to get you started. If you have more specific questions again - don’t hesitate to ask.

eta :slight_smile: