How to batch measure distances between points

length
imagej
macro
distance
roi

#1

Hello,

So I am new to ImageJ and all it’s possibilities. I also have no experience with macros …

The thing I am planing to do, is to measure the growth lines in belemnites from scanned images with scale, for over 100 specimens.
For each specimens about 10 measurements should be taken. Now I was thinking about defining the different points between which the distances should be measured (see picture) and then have a macro measure the distances for me.
The measurements should be taken between 1 - 2; 3 - 4; 1-5, 6 - 7; 1 - 8; 9 - 9; etc.
Now I did find a Macro that does something similar, however it measures the cumulative distance between points on a line.
As with the later macro all my measurements for one specimen should be saved to the results table in one line with column labeling something like length1, height1, length2, height2, etc.
After measuring I should then be able to move to the next specimen (there are several specimen on one scanned image), redefine the different points in the same order and have the macro take the measurements.
As far as I can tell defining a ROI for each specimen (group of points) ex. Belemnite1, Belemnite2, etc. would label the the lines accordingly.

I hope I did explain myself comprehensibly and that someone can help me or point me in the right direction.
Thanks
Paul


#2

Good day Paul,

in this contribution

http://forum.image.sc/t/perpendicular-distance-between-2-lines-shortest-distance-between-2-lines/3862/5

a macro is suggested that contains all the necessary elements for your task (and more) but of course you need to tailor it according to your needs. Not a big deal after you’ve studied the macro.

Have success

Herbie


#3

Thank you Herbie for your suggestions

however I don’t really see how I should get that macro to work for me.

I did now try to modify the macro that I posted in my initial post:

macro "Measure distance betwee two points" { 
        getSelectionCoordinates(x, y);
        getPixelSize(unit, pw, ph);

 n = nResults;
distance = 0;

dx = (x[1] - x[0])*pw;
        dy = (y[1] - y[0])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Length 1", n, distance);

 dx = (x[3] - x[2])*pw;
        dy = (y[3] - y[2])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Hight 1", n, distance);

updateResults
    } 

This gives me the distance between point 1 and 2 and between point 3 and 4.

I now simply tried to duplicate part of the code to have a second measurement (point 1 and 5, 6 and 7). However the results for the later two distances do not give the correct values.
This is what I did:

macro "Measure distance betwee two points" { 
        getSelectionCoordinates(x, y);
        getPixelSize(unit, pw, ph);
 n = nResults;
distance = 0;

dx = (x[1] - x[0])*pw;
        dy = (y[1] - y[0])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Length 1", n, distance);

 dx = (x[3] - x[2])*pw;
        dy = (y[3] - y[2])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Hight 1", n, distance);

dx = (x[4] - x[0])*pw;
        dy = (y[1] - y[0])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Length 2", n, distance);

dx = (x[6] - x[5])*pw;
        dy = (y[7] - y[6])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Hight 2", n, distance);

updateResults
    } 

Any idea on how I can fix this?


#4

OK Paul,

I can’t see how you used parts of my macro.
Anyway, I shall tell you what I mean in a while.

For the time being, I shall like to ask you for an exact statement about the number of distances to be measured and for the exact point numbers.

I guess this is not perfectly correct:

The measurements should be taken between 1 - 2; 3 - 4; 1-5, 6 - 7; 1 - 8; 9 - 9; etc.

Stay tuned

Herbie


#5

Paul,

here is a first attempt for a total of eight points.

Please proceed exactly as follows:

Open a new macro window from "Plugins > New > Macro" and
enter the macro text that follows at the end of this message.

Select the "Point"-selection tool.

Click on point 1
Type Cmd-t (Mac) or Ctrl-t (PC)
Click on point 2
Type Cmd-t (Mac) or Ctrl-t (PC)
...
Click on point 8
Type Cmd-t (Mac) or Ctrl-t (PC)

Bring the "Macro.txt"-window to the front and type Cmd-r (Mac) or Ctrl-r (PC)

// Begin length macro
requires(“1.51i”);

points = 8;

run( “Set Measurements…”, " redirect=None decimal=3" );
roiManager ( “multi-measure measure_all” );
wait(100);
selectWindow( “ROI Manager” );
run( “Close” );

x = newArray( points );
y = newArray( points );
for ( i = 0; i<points; i++ ) {
x[i] = getResult( “X”, i );
y[i] = getResult( “Y”, i );
}
selectWindow( “Results” );
run( “Close” );

//lengths
print( "length_1-2 = " + d2s( length( x[0], y[0], x[1], y[1] ), 1) );
print( "length_3-4 = " + d2s( length( x[2], y[2], x[3], y[3] ), 1) );
print( "length_1-5 = " + d2s( length( x[0], y[0], x[4], y[4] ), 1) );
print( "length_6-7 = " + d2s( length( x[5], y[5], x[6], y[6] ), 1) );
print( "length_1-8 = " + d2s( length( x[0], y[0], x[7], y[7] ), 1) );

exit();
//-----------------------------------------------------
function length( x_0, y_0, x_1, y_1 ) {
return sqrt( pow( x_0 - x_1, 2 ) + pow( y_0 - y_1, 2 ) );
}
// End

The desired five lengths are displayed in the log-window.
If you really need the lengths in a result window, then please tell me exactly how they should be displayed and what else should be displayed there.

Best

Herbie


How can I measure the Euclidean distance (tortuosity) of vessels?
#6

I used part of the macro I posted in my first post, not yours.

For the number of distances I want to measure, it will be X times (depending on the specimen more or less measurements ca be taken) a pair of:

  1. A length (which ALL WAYS starts at point 1!), (1.) goes to 2, (2.) goes to 5, (3.) goes to 8, etc…

  2. A height/ width which goes from (1.) 3 to 4, (2.) 6 to 7, (3.) 9 to 10, etc.

This code now gives me the the length between 1 and 2 as well as the length between 3 and 4. I would like to expend it to give me all the other measurements.

macro "Measure distance betwee two points" { 
        getSelectionCoordinates(x, y);
        getPixelSize(unit, pw, ph);

 n = nResults;

Bel_Nr= "1234 ";     // IMPORTANT: insert Belemnite Nr. here !!!!

distance = 0;
setResult("Belem Nr.", n, Bel_Nr);

dx = (x[1] - x[0])*pw;
        dy = (y[1] - y[0])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Length 1", n, distance);

 dx = (x[3] - x[2])*pw;
        dy = (y[3] - y[2])*ph;
        distance = sqrt(dx*dx + dy*dy);
setResult("Hight 1", n, distance);

updateResults
    } 

I hope this makes it a bit clearer, it’s allways hard to put into works what I exactly want to do.

Thanks anyway


Automatically identify and measure the distance between two laser points within images
Automatically identify and measure the distance between two laser points within images
#7

I used part of the macro I posted in my first post, not yours.

Paul,

this is a bit strange, because you asked for help but then you use your own approach…

Please test the provided macro and tell us if it works for you.
Refinements are possible.

HTH

Herbie


#8

Ok I tested your macro, it seems not to work exactly as it should (?)

Am I right to assume that if I want to add more point I only need to change:
points = 8;
to the number of points I’m using and add and adapt more of these lines?
print( "length_1-8 = " + d2s( length( x[0], y[0], x[7], y[7] ), 1) );

I would prefer having the results in a table which should look something like this:

With the Belem Nr. being a number which an can change manually according to the specimen which I’m measuring.

Sorry for my last post, I wrote it at the same time as you. And sorry for the mess-up …
I’m very grateful for your help!


#9

Paul,

as I’ve written:

here is a first attempt for a total of eight points.

Now you write:

Ok I tested your macro, it seems not to work exactly as it should (?)

Could you please be more specific!
What doesn’t work?

As I’ve written:

Refinements are possible.

Please note that I’m willing to help, but I’m not a coding service.

Regards

Herbie


#10

After you wrote:

I just wanted to write what my idea for the whole thing was. I never assumed you would code all this for me. Sorry if it appeared that way.

These are the results that the macro gives me (it was not clear in the screenshot, sorry):

length_1-2 = 0.0
length_3-4 = 1438.0
length_1-5 = 1438.0
length_6-7 = 252.6
length_1-8 = 1438.0

These should all be different but I don’t relay see why they are not.

Regards
Paul


#11

Paul,

your result

These should all be different but I don’t relay see why they are not.

differs from mine and that’s the reason why I wanted to proceed step by step. It makes no sense to come up with refined code if the basics don’t work.

After having entered eight points (1 … 8) according to the provided image, the ROI-manager looks like this:

The then started IJ-macro prints to the log-window:

Because the image has no scale set, the distances are in pixels.

If you get different results, make sure that you did exactly what I’ve written before. Especially make sure that you’ve not selected the multi-point tool.

Regards

Herbie


Automatically identify and measure the distance between two laser points within images
#12

Ok I probably had not the multi-point tool.
During my first test it worked, but not after that, so I may have changed back to the multi-point tool after some time.

Thank you a lot for your help.
I think I can handle it from here on. Don’t want to cause any inconvenience for you :slight_smile:


#13

Paul,

here is a macro version that prints the resulting lengths, no matter how many points are given:

// Begin length macro
requires(“1.51i”);

points = roiManager( “count” );
run( “Set Measurements…”, " redirect=None decimal=3" );
roiManager ( “multi-measure measure_all” );
wait(100);
selectWindow( “ROI Manager” );
run( “Close” );

x = newArray( points );
y = newArray( points );
for ( i = 0; i<points; i++ ) {
x[i] = getResult( “X”, i );
y[i] = getResult( “Y”, i );
}
selectWindow( “Results” );
run( “Close” );

//lengths
for ( i = 1; i<points; i+=3 ) {
print( “length_” + 1 + “-” + (i+1) + " = " + d2s( length( x[0], y[0], x[i], y[i] ), 1 ) );
print( “length_” + (i+2) + “-” + (i+3) + " = " + d2s( length( x[i+1], y[i+1], x[i+2], y[i+2] ), 1 ) );
}

exit();
//-----------------------------------------------------
function length( x_0, y_0, x_1, y_1 ) {
return sqrt( pow( x_0 - x_1, 2 ) + pow( y_0 - y_1, 2 ) );
}
// End

For evident reasons, using the Results Table for display is a bit more involved.

HTH

Herbie


#14

Paul,

here is a macro version that uses the Results Table for display:

// Begin length macro
requires(“1.51i”);

str = getString( “Enter the Belemnite Number”, “” );

points = roiManager( “count” );
run( “Set Measurements…”, " redirect=None decimal=3" );
selectWindow( “ROI Manager” );
run( “Close” );

x = newArray( points );
y = newArray( points );
for ( i = 0; i<points; i++ ) {
roiManager( “Select”, i );
List.setMeasurements;
x[i] = List.getValue( “X” );
y[i] = List.getValue( “Y” );
}
//lengths
setResult( “Belemnite Nr.”, nResults, str );
for ( i = 1; i<points; i+=3 ) {
val = d2s( length( x[0], y[0], x[i], y[i] ), 1 );
str = "Length " + 1 + “-” + (i+1);
setResult( str, nResults-1, val );
val = d2s( length( x[i+1], y[i+1], x[i+2], y[i+2] ), 1 );
str = "Length " + (i+2) + “-” + (i+3) ;
setResult( str, nResults-1, val );
}
updateResults();

exit();
//-----------------------------------------------------
function length( x_0, y_0, x_1, y_1 ) {
return sqrt( pow( x_0 - x_1, 2 ) + pow( y_0 - y_1, 2 ) );
}
// End

Have a nice weekend

Herbie


#15

Thank you very much :slight_smile:
you help was appreciated.

Best
Paul


#16

Thank you Herbie for posting this! I am finding it very useful.


#17

Good day Kristina,

glad to hear that the approach is still valuable after all those years.

I wish you the very best and much success for your work

Herbie


#18

Yes, thank you! It has made a huge stride in my work. Just need a few more adjustments as I would like to figure out the mean and sd for my measurements but hopefully I can figure it out in imageJ.


#19

With the result values in an ImageJ Results table, you can add at the end of the whole processing the code line:

run("Summarize");

This adds simple statistical values, such as Mean and SD to the end of the table columns.

(Don’t forget to give credit if you use the approach for a thesis, reports or publications.)

HTH

Herbie


#21

Wow, I am learning that I have no fluency in coding. It seems that there already exists loops in your code Herbie. So I think what I want to do is to loop the printout part of the code, to capture multiple lengths on different photos.