ImageJ macro to measure distance between two lines/edges

What a great macro! Thanks for writing it.

Is there a way to make non-random lines? Can there be measurements at a set interval? Say every 25 pixels?

The macro uses spline interpolation to obtain coordinates of points along a line. This way, a small set of a few user-chosen points (coordinates) gets transformed to a much larger set of points, which otherwise would require the user to painfully draw a polyline with many more coordinates. The points in either the user-drawn or interpolated set may not be spaced uniformly (example figure).

So, the macro may be able to perform measurements at a set interval like 25 pixels only approximately and this will require a bit of complex coding… not sure if such a feature will be valuable.

Hi Santosh,
Thank you very much for your help.

I have another question. I need to import the measured distances to Rstudio software for analyzing my data, and I think I need the all measured distances in the output (.csv) file to have the complete dataset. Is it possible to modify the macro for this?

Also, in order to change the number of random measurements, we need to change the "settingUsedPointsMax = 30 " in the macro?

Updated version 1.1.1 (7 Dec. 2020) with option to save all individual measurements besides their summarized values (mean, etc.):

InteredgeDistance_v1.1.1_ImageJMacro.txt (13.2 KB)
Instructions_InteredgeDistance_macro_7Dec2020.pdf (816.3 KB)

1 Like

Hi Shiva, I released a new version (1.1.1) that allows individual values to be saved. Yes, to change the maximum number of random measurements from the default value of 15, set settingUsedPointsMax in the macro file to a different value. If usable measurements are less than settingUsedPointsMax (e.g., if a drawn polyline is too short), the macro will still produce output as long as there are at least settingUsedPointsMin measurements. So, to always have same number of measurements, set both settings to the same value.

Hi Santosh,
Thanks for the support. I ran the macro and I got the exported data as it was before (please see the attached screenshot) without individual measurements. Could you please let me know if I am missing sth or this is not the correct file?

You have to set settingSaveIndividualDistances to 1 instead of 0 in the macro txt file. Edit the file to have:

settingSaveIndividualDistances = 1;

The individual measurements will be in the last field as semi-colon-separated values, like 18.12;13;32;15.16

It worked! thanks for the help Santosh.

Dear Santosh,

I came up with another question seeking your advice on it.
When I am using this method to measure the distance, because of the edge roughness of lines I am getting pretty large standard deviations because of not straight lines included in measurements with larger distances than the actual distance between lines.
Do you have any idea how I can exclude these from measurements? or any other idea to have more accurate distance statistics?
Please see the attached photo as a reference.

thanks for the support.
Shiva

Hi Shiva, for a given point on a line from which distance to another line is measured, the macro measures distance from the point to all points on the other line, and then chooses the shortest distance. By definition, the shortest distance should look like perpendicular but it may not appear like a perpendicular because the two lines are not straight lines but polylines (and the local line segment at the point may not be congruous with the overall edge/line). There is no workaround. But I really don’t think this issue matters… the overall systemic error in your measurement (photography, edge detection, drawing of the two lines…) is more than any measurement error of the macro.

Thanks for the prompt reply Santosh. I understand the point.

Shiva

Hi Santosh, is there any way I can edit the macro in such a way that the user doesn’t need to draw the lines as the lines are already automatically drawn?

Thanks.

No if the ‘lines’ are a part of the image itself. But if the lines are drawn on the image within ImageJ, that is, they are ImageJ elements, then it might be possible to edit the macro so that it can ‘read’ the drawn lines.

Hi,

I have successfully used this macro from alpha2zee on my data - with some minor adaptations. We’re in the process of submitting and I was wondering if there is a proper way to cite this macro. Now, I have just added a direct link to this thread. Let me know!

Thanks!
Paula

I am glad that the macro was useful. Citing this thread as reference is reasonable though you can also consider simply putting the code (with your modifications) as Supplementary Data/Info accompanying the paper.

Hi @alpha2zee ,

Hope you’re doing well.
I have a question about measuring fluorescent coating coverage on the fibers. I want my macro to select a specific rectangular area (automatically or by me, but the area should be constant in every image) on the input images and gives the green coverage on the fiber. I am attaching two examples of my samples with two different covers. Do you think I can develop a macro on imagej for this? I hope to hear back from you.

@Shivaa
Can this be appropriate?

Shiva-1

run("Duplicate...", "title=1");
run("Duplicate...", "title=2");
run("Split Channels");
close("2 (blue)");
close("2 (red)");
selectWindow("2 (green)");

//setTool("rotrect");
makeRotatedRectangle(828, 1020, 1128, 942, 259);
waitForUser("Did you translate your rectangle");
roiManager("Add");
setAutoThreshold("Shanbhag dark");
//run("Threshold...");
//setThreshold(102, 255);
setOption("BlackBackground", true);
run("Convert to Mask");
roiManager("Select", 0);
run("Analyze Particles...", "display summarize add");
selectWindow("1");
roiManager("Show All without labels");

Thanks for your reply.
Actually no. My goal is to quantify the coating coverage and compare them with each other. for example image 1: 65% coating coverage, in image 2 :90%.

I get this

with this macro (by opening the two images).

run("Images to Stack", "name=Stack title=[] use");
run("Make Montage...", "columns=2 rows=1 scale=0.25");
run("Duplicate...", " ");
run("Lab Stack");
run("Stack to Images");
selectWindow("a*");
run("Duplicate...", " ");
setAutoThreshold("Mean");
//run("Threshold...");
setOption("BlackBackground", false);
run("Convert to Mask");

run("Fill Holes");
//setTool("wand");
run("Create Selection");
roiManager("Add");
roiManager("Select", 0);
roiManager("Split");
roiManager("Delete");

selectWindow("a*");
close("\\Others");
setAutoThreshold("Moments");
roiManager("Show All without labels");
roiManager("Measure");
run("Convert to Mask");
roiManager("Show All with labels");
roiManager("Select", 0);
run("Analyze Particles...", "summarize add");
roiManager("Show All without labels");
roiManager("Select", 1);
run("Analyze Particles...", "summarize add");
roiManager("Show All without labels");
close("Results");

Hi Mathew,
Thanks a lot. This is exactly what I need. I tried and I got the same result as you shared. However, when I am trying a different image I am getting the wrong output area=0 %(attached photo). Do you know what can be the problem?
The other issue is that since the fiber slope is different in all images, I think if we rotate it somehow and make it vertical and consider a constant area rectangle on its surface (macro can ask to place the default rectangle in our ROI ) the resultant percentage would give a better sense of coating coverage.