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

imagej

#1

Hello, I am new to scripting in java but have some experience with imagej for basic image analysis.

What I would like to do is get imagej to identify the laser points in the images attached and simply measure the distance in pixels between them (lasers are set at known distance). I need the horizontal distances only (i.e. pixels between the top two lasers and the pixels between the bottom two lasers).

For many of the images this should be straight forward due to the relatively uniform background (image 1) however many images have colours in them similar to the laser points (second image). The third image shows the laser points being extended due to particles in the water column and the fourth image showing much fainter laser points due to a higher distance from the floor.

The idea behind this is to achieve an automated method to allow selection of good (i.e. image 1 and 2) and bad (i.e. image 3 and 4) quality images.

Many thanks!

1:

2:

3:

4:


#2

Hello @Jo7 and welcome to the ImageJ forum!

It looks like a very interesting problem. Regarding image 3, which points should be ideally selected as the lower positions of the lasers? The end of the red lines?


#3

Hello iarganda,

Thank you for your reply.

For image 3 the points of interest for the lower lasers are the top of the laser line where they hit the seabed (much fainter end) but this is masked considerably by the particles in the water to provide a reliable estimate for the distance between the lasers. In this instance I would disregard the estimate between the bottom two lasers and only keep the top measurement. It would be great if there was someway to code this too?


#4

You could use the particle analysis to identify the points with some criteria ImageJ offers (particle size, roundness, etc.- also to seperate bad measurements) and then measure the distances between the points.

Here an older thread I found from which you can adpat the code:


#5

Hello Bio7, Thank you for these suggestions. I apologise first for my lack of coding knowledge! I have managed to use the particle analysis to identify the points and add them to the ROI manager for a couple of images. I may need to tweak the thresholds in future when running on all images.

// Color Thresholder 1.50i
min=newArray(3);
max=newArray(3);
filter=newArray(3);
a=getTitle();
run(“HSB Stack”);
run(“Convert Stack to Images”);
selectWindow(“Hue”);
rename(“0”);
selectWindow(“Saturation”);
rename(“1”);
selectWindow(“Brightness”);
rename(“2”);
min[0]=200;
max[0]=255;
filter[0]=“pass”;
min[1]=83;
max[1]=255;
filter[1]=“pass”;
min[2]=112;
max[2]=255;
filter[2]=“pass”;
for (i=0;i<3;i++){
selectWindow(""+i);
setThreshold(min[i], max[i]);
run(“Convert to Mask”);
if (filter[i]==“stop”) run(“Invert”);
}
imageCalculator(“AND create”, “0”,“1”);
imageCalculator(“AND create”, “Result of 0”,“2”);
for (i=0;i<3;i++){
selectWindow(""+i);
close();
}
selectWindow(“Result of 0”);
close();
selectWindow(“Result of Result of 0”);
rename(a);

run(“Analyze Particles…”, " show=Overlay add");
// Colour Thresholding-------------

I have tried to use the code on the thread ‘How to batch measure distances between points’ as you suggested. I have used the following code but I get an error saying “No window with the title “Results” found”. NB this was written for version 1.51i but im on 1.50i should that make a difference.

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

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

I would really like the resulting lengths to be shown in a results window if possible? Please could you advise on how to go about this. Ideally as we have so many images to process the results table should include the image name if it doesn’t already by default?

Many thanks again for any help!
Jo


#6

Here the changed macro which works for the image “HGFR_CEND0915_HGFR009_STN_009_A1_002.JPG”.

Please not that I have simplified the threshold by measuring the red channel only instead of using the color threshold method. But you can also use the color threshold if necessary or a more complex classification method for segmentation.

You can apply this script on a folder of images with the “Image->Batch->Macro”, see:


/*Threshold and measure the image on the red channel!*/
setBatchMode(true); //do not show the images - faster!
title = getTitle;
run("Split Channels");
selectWindow(title + " (green)");
close();
selectWindow(title + " (blue)");
close();
setBatchMode(false);
selectWindow(title + " (red)");
setThreshold(208, 255);
setOption("BlackBackground", false);
run("Convert to Mask");
/*Adjust the measurements - Here we exclude particles of a certain size, etc.!*/
run("Set Measurements...", "area centroid redirect=None decimal=3");
run("Analyze Particles...", "size=40-Infinity add");

/*We have collected all ROI's (points) in the ROI Manager and now we measure them!*/
roiManager("Show All with labels");
roiManager("Show All");
/*Measure the points in the ROI Manager!*/
points = roiManager("count"); //How many ROI's are present!
roiManager("measure");
wait(100);
/*Close the ROI Manager window!*/
selectWindow("ROI Manager");
run("Close");
/*Get the values from the result table!*/
selectWindow("Results");
x = newArray(points);
y = newArray(points);
for (i = 0; i < points; i++) {
    x[i] = getResult("X", i);
    y[i] = getResult("Y", i);
}
/*Close the results window!*/
selectWindow("Results");
run("Close");
/*Calculate and display the length calling the function length()*/
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));
}

/*The function to calculate the euclidean distance!*/
function length(x_0, y_0, x_1, y_1) {
    return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}

And here the edited script (please change for your needs!):

Please note: Another option would be to import your images as an image sequence (stack) and then measure the slices of the stack which would collect all ROI’s and measurements in one operation.


#7

Hello Bio7,

Thank you so much. I have just tried it and it works a treat. It’s incredible thank you. I have spent so long manually doing this over the last two week it will save me so much time. I really appreciate the annotations you have added too so I can study and fully understand the functionality!

Cheers,
Jo


#8

Hello Bio7,

I have now run the macro on a few images and it seems to be working well. I have managed to work out the results table too so that I have the image name on the table. It now only records measurement 1-2 and 3-4, rather than any number of particles identified in the ROI manager (i.e. only when 4 particles are identified, no more), which is good.

I still need to do a couple of things which maybe you could point me in the right direction to do:

  1. When more particles are identified than the four true laser points (due to thresholds picking up extra pink things) I get an error and no measurements are taken, which is fine. Is there a way I could get the macro to record just the image name when the measurement fails? this way I have a list of failed images that I will need to evaluate separately. Alternatively how do I get the results table to record all measurements regardless of how many particles? Would I have to keep adding these sections to the macro? :
    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);

  2. You mentioned a couple of options for the batch processing. Is there a way to import an image sequence (stack) from multiple subfolders (I have 99 subfolders each with about 30-40 images in)? If not I will try the batch processing.

I don’t seem to have the script editor in my menu. I have tried to install the script editor but when I go to “help” menu there is no “updater” option to allow me to “add an update site”? Any ideas? I’m using version 1.50i. So basically I have no idea how to get the plugin plugged-in!

Thanks again for all your assistance!
Jo

Most recent macro with results table:

/Threshold and measure the image on the red channel!/
setBatchMode(true); //do not show the images - faster!
title = getTitle();
run(“Split Channels”);
selectWindow(title + " (green)");
close();
selectWindow(title + " (blue)");
close();
setBatchMode(false);
selectWindow(title + " (red)");
setThreshold(230, 255);
setOption(“BlackBackground”, false);
run(“Convert to Mask”);
/Adjust the measurements - Here we exclude particles of a certain size, etc.!/
run(“Set Measurements…”, “area centroid redirect=None decimal=3”);
run(“Analyze Particles…”, “size=60-Infinity add”);

/We have collected all ROI’s (points) in the ROI Manager and now we measure them!/
roiManager(“Show All with labels”);
roiManager(“Show All”);
/Measure the points in the ROI Manager!/
points = roiManager(“count”); //How many ROI’s are present!
roiManager(“measure”);
wait(100);
/Close the ROI Manager window!/
selectWindow(“ROI Manager”);
run(“Close”);
/Get the values from the result table!/
selectWindow(“Results”);
x = newArray(points);
y = newArray(points);
for (i = 0; i < points; i++) {
x[i] = getResult(“X”, i);
y[i] = getResult(“Y”, i);
}
/Close the results window!/
selectWindow(“Results”);
run(“Close”);
/Calculate and display the length calling the function length()/

setResult(“Image”, nResults, title);

for (i = 1; i < points; i += 3) {
val = d2s(length(x[0], y[0], x[i], y[i]), 1);
str = “Length_” + i + “-” + (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);
}
/The function to calculate the euclidean distance!/
function length(x_0, y_0, x_1, y_1) {
return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}


#9

(1) I think you can define some criteria. For instance if you have measured more or less particles you can notice this, log the name of the image and then return to the next image (see script below).

Here a complete macro which let you choose a directory and analyzes all folder and subfolders. I edited and added the following macro: https://imagej.nih.gov/ij/macros/BatchProcessFolders.txt to analyze a selected folder and subfolders recursively.
It skips the length measurement if more than 4 particles are in the ROI Manager (see line 67) and also writes a log file which is saved at the end of the whole procedure.

Please note that you can also define more criteria in your measurements to exclude certain particles (bad images by size or roundness indicating a disturbed laser light - or filter out small particles and then measure the particles).

/*
Threshold and measure the image on the red channel
of selected folder and subfolders!
*/

dir = getDirectory("Choose a Directory ");
count = 0;
/*We count the files for a progress display!*/
countFiles(dir);
n = 0;
/*Process all folders!*/
processFiles(dir);
/*Write a text file from the log!*/
selectWindow("Log");
save(dir + "/"+ "Log_Analysis.txt");
/*Close the log window!*/
run("Close");

/*Calculate progress!*/
function countFiles(dir) {
    list = getFileList(dir);
    for (i = 0; i < lengthOf(list); i++) {
        /*Ignore the log *.txt file or others in this folder if necessary
          Here we write one log file in the main folder so we exclude it here!*/
        if (endsWith(list[i], "/") || endsWith(list[i], ".txt")) {
            countFiles("" + dir + list[i]);
        } else {
            count++;
        }
    }
}
/*We analyze all folders and subfolders recursively!*/
function processFiles(dir) {
    list = getFileList(dir);
    for (i = 0; i < lengthOf(list); i++) {
        /*If we have a directory we recursively call this function for the nested folder!
          Ignore the log *.txt file or others in this folder if necessary
          Here we write one log file in the main folder so we exclude it here!*/
        if (endsWith(list[i], "/") || endsWith(list[i], ".txt")) {
            processFiles("" + dir + list[i]);
        } else {
            /*Not a folder so we have image files in this folder!*/
            showProgress(n++, count);
            path = dir + list[i];
            processFile(path);
            close();
        }
    }
}
/*The main analysis function!*/
function processFile(path) {
    setBatchMode(true); //do not show the images - faster!
    open(path);
    title = getTitle;
    run("Split Channels");
    selectWindow(title + " (green)");
    close();
    selectWindow(title + " (blue)");
    close();
    selectWindow(title + " (red)");
    setThreshold(208, 255);
    setOption("BlackBackground", false);
    run("Convert to Mask");
    setBatchMode(false);
    /*Adjust the measurements - Here we exclude particles of a certain size, etc.!*/
    run("Set Measurements...", "area centroid redirect=None decimal=3");
    run("Analyze Particles...", "size=40-Infinity add");
    /*We have collected all ROI's (points) in the ROI Manager and now we measure them!*/
    roiManager("Show All with labels");
    roiManager("Show All");
    /*Measure the points in the ROI Manager!*/
    points = roiManager("count"); //How many ROI's are present!
    /*Here we can define a criteria!*/
    if (points != 4) {
        IJ.log("Criteria not met: " + path);
        IJ.log("Number of points measured: " + points);
        /*Do not forget to close the ROI manager here else the points are simply added!*/
        selectWindow("ROI Manager");
        run("Close");
        return;
    }
    roiManager("measure");
    wait(100);
    selectWindow("ROI Manager");
    run("Close");
    /*
		Get the values from the result table!
		based on the macro: http://forum.image.sc/t/how-to-batch-measure-distances-between-points/3970/6
		*/
    selectWindow("Results");
    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");
    /*Calculate and display the length calling the function length()*/
    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));
    }
    IJ.log("Image successfully measured: " + path);
}
/*The function to calculate the euclidean distance!*/
function length(x_0, y_0, x_1, y_1) {
    return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}

(2) Yes there are. However this macro should be sufficient for your needs. Use the macro recorder to get more commands which might be useful for you:

https://imagej.nih.gov/ij/docs/guide/146-31.html#sub:Record

Finally, if you don’t see the a special script editor but a normal editor you are working in ImageJ. An updater and script editor is ,e.g., available in FIJI a distribution of ImageJ.


#10

Hello Bio7,

Thank you again for all your advice. I’m now working with Fiji and this is a lot easier! I have added a few modifications (circularity & saving the mask to easily visually check what has been measured) to the macro and its working very well for me.

I am trying to add a results table again so that it is easier for me to extract the huge number of measurements and insert them into the full database of all images and associated data using v-lookup in excel or some R code. The problem I have now is that only one line of data is stored in the results table when running the batch code, rather than each image measurements being sequentially added to the end. Please let me know if there is an easy way to sequentially add results to table.

Many thanks!

See below for current code:

/*
Threshold and measure the image on the red channel
of selected folder and subfolders!
*/

dir = getDirectory("Choose a Directory ");
count = 0;
/We count the files for a progress display!/
countFiles(dir);
n = 0;
/Process all folders!/
processFiles(dir);
/Write a text file from the log!/
selectWindow(“Log”);
save(dir + “/”+ “Log_Analysis.txt”);
/Close the log window!/
run(“Close”);

/Calculate progress!/
function countFiles(dir) {
list = getFileList(dir);
for (i = 0; i < lengthOf(list); i++) {
/*Ignore the log .txt file or others in this folder if necessary
Here we write one log file in the main folder so we exclude it here!
/
if (endsWith(list[i], “/”) || endsWith(list[i], “.txt”)) {
countFiles("" + dir + list[i]);
} else {
count++;
}
}
}
/We analyze all folders and subfolders recursively!/
function processFiles(dir) {
list = getFileList(dir);
for (i = 0; i < lengthOf(list); i++) {
/*If we have a directory we recursively call this function for the nested folder!
Ignore the log .txt file or others in this folder if necessary
Here we write one log file in the main folder so we exclude it here!
/
if (endsWith(list[i], “/”) || endsWith(list[i], “.txt”)) {
processFiles("" + dir + list[i]);
} else {
/Not a folder so we have image files in this folder!/
showProgress(n++, count);
path = dir + list[i];
processFile(path);
close();
}
}
}
/The main analysis function!/
function processFile(path) {
setBatchMode(true); //do not show the images - faster!
open(path);
title = getTitle;
run(“Split Channels”);
selectWindow(title + " (green)");
close();
selectWindow(title + " (blue)");
close();
selectWindow(title + " (red)");
setThreshold(230, 255);
setOption(“BlackBackground”, false);
run(“Convert to Mask”);
setBatchMode(false);
/Adjust the measurements - Here we exclude particles of a certain size, etc.!/
run(“Set Measurements…”, “area centroid redirect=None decimal=3”);
run(“Analyze Particles…”, “size=40-Infinity circularity=0.40-1.00 show=[Overlay Masks] add”);
saveAs(“Jpeg”, dir + title + “_mask.jpg”);
/We have collected all ROI’s (points) in the ROI Manager and now we measure them!/
roiManager(“Show All with labels”);
roiManager(“Show All”);
/Measure the points in the ROI Manager!/
points = roiManager(“count”); //How many ROI’s are present!
/Here we can define a criteria!/
if (points != 4) {
IJ.log("Criteria not met: " + path);
IJ.log("Number of points measured: " + points);
/Do not forget to close the ROI manager here else the points are simply added!/
selectWindow(“ROI Manager”);
run(“Close”);
return;
}
roiManager(“measure”);
wait(100);
selectWindow(“ROI Manager”);
run(“Close”);
/*Get the values from the result table!
based on the macro: How to batch measure distances between points
*/
selectWindow(“Results”);
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”);

setResult("Image", nResults, title);
for (i = 1; i < points; i += 3) {
val =  d2s(length(x[0], y[0], x[i], y[i]), 1);
str = "Length_" + i + "-" + (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();
saveAs(“Results”, dir + “/”+“Results.csv”);

/*Calculate and display the length calling the function length()*/
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));
}
IJ.log("Image successfully measured: " + path);
}
/*The function to calculate the euclidean distance!*/
function length(x_0, y_0, x_1, y_1) {
return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}

#11

There a several possibilities, for example you can append a result to a file. However I also found a extravagant way to create an extra table for all results, see:

http://imagej.1557.x6.nabble.com/How-to-create-a-customised-results-table-and-add-data-to-it-within-a-macro-td5000701.html

Here with the code I posted before (I did not use your code. Please make you changes).

/*
Threshold and measure the image on the red channel
of selected folder and subfolders!
*/

/*Create a new Table for all measurements!*/
title1 = "TheFinalResults";
title2 = "[" + title1 + "]";
f = title2;
run("New... ", "name=" + title2 + " type=Table");
print(f, "\\Headings:Image\tLength");
/*Start the measurements!*/
dir = getDirectory("Choose a Directory ");
count = 0;
/*We count the files for a progress display!*/
countFiles(dir);
n = 0;
/*Process all folders!*/
processFiles(dir);
/*Write a text file from the log!*/
selectWindow("Log");
save(dir + "/"+ "Log_Analysis.txt");
/*Close the FinalResults window!*/
run("Close");
selectWindow("TheFinalResults");
/*Save all correct measurements!*/
saveAs("FinalResults", dir + "/" + "TheFinalResults.csv");
/*Close the results window!*/
run("Close");

/*Calculate progress!*/
function countFiles(dir) {
    list = getFileList(dir);
    for (i = 0; i < lengthOf(list); i++) {
        /*Ignore the log *.txt file or others in this folder if necessary
          Here we write one log file in the main folder so we exclude it here!*/
        if (endsWith(list[i], "/") || endsWith(list[i], ".txt")) {
            countFiles("" + dir + list[i]);
        } else {
            count++;
        }
    }
}
/*We analyze all folders and subfolders recursively!*/
function processFiles(dir) {
    list = getFileList(dir);
    for (i = 0; i < lengthOf(list); i++) {
        /*If we have a directory we recursively call this function for the nested folder!
          Ignore the log *.txt file or others in this folder if necessary
          Here we write one log file in the main folder so we exclude it here!*/
        if (endsWith(list[i], "/") || endsWith(list[i], ".txt")) {
            processFiles("" + dir + list[i]);
        } else {
            /*Not a folder so we have image files in this folder!*/
            showProgress(n++, count);
            path = dir + list[i];
            processFile(path);
            close();
        }
    }
}
/*The main analysis function!*/
function processFile(path) {
    setBatchMode(true); //do not show the images - faster!
    open(path);
    title = getTitle;
    run("Split Channels");
    selectWindow(title + " (green)");
    close();
    selectWindow(title + " (blue)");
    close();
    selectWindow(title + " (red)");
    setThreshold(208, 255);
    setOption("BlackBackground", false);
    run("Convert to Mask");
    setBatchMode(false);
    /*Adjust the measurements - Here we exclude particles of a certain size, etc.!*/
    run("Set Measurements...", "area centroid redirect=None decimal=3");
    run("Analyze Particles...", "size=60-Infinity add");
    /*We have collected all ROI's (points) in the ROI Manager and now we measure them!*/
    roiManager("Show All with labels");
    roiManager("Show All");
    /*Measure the points in the ROI Manager!*/
    points = roiManager("count"); //How many ROI's are present!
    /*Here we can define a criteria!*/
    if (points != 4) {
        IJ.log("Criteria not met: " + path);
        IJ.log("Number of points measured: " + points);
        /*Do not forget to close the ROI manager here else the points are simply added!*/
        selectWindow("ROI Manager");
        run("Close");
        return;
    }
    roiManager("measure");
    wait(100);
    selectWindow("ROI Manager");
    run("Close");
    /*
		Get the values from the result table!
		based on the macro: http://forum.image.sc/t/how-to-batch-measure-distances-between-points/3970/6
		*/
    selectWindow("Results");
    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");
    /*Calculate and display the length calling the function length()*/
    for (i = 1; i < points; i += 3) {
    	result1="length_" + 1 + "-" + (i + 1) + " = " + d2s(length(x[0], y[0], x[i], y[i]), 1);
        print(result1);
        /*Add the results to the final results table!*/
        print(f, path + "\t" + result1);
        result2="length_" + (i + 2) + "-" + (i + 3) + " = " + d2s(length(x[i + 1], y[i + 1], x[i + 2], y[i + 2]), 1);
        print(result2);
        /*Add the results to the final results table!*/
        print(f, path + "\t" + result2);
    }
    IJ.log("Image successfully measured: " + path);
}
/*The function to calculate the euclidean distance!*/
function length(x_0, y_0, x_1, y_1) {
    return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}

Just some notes:

It would be better to seperate the input folder form the output folder (mask images and results) so that the inputfolder stays clean (makes it more reproducible - and you don’t have to exclude non image filetypes) by selecting a parent folder (or different parent folders) as the output folder(s).

If you have 4 points as criterias you could also measure the distances without a loop.

You can easily edit the final results table to your needs to make it more informative!


#12

Hello Bio7,

Thanks for the alternative way for making results table.

I have tried modifying it. I now have three columns (although for some reason I get some extra text in column two heading?):
“Image” “Length_1-2” “Length_3-4”

I cant seen to get macro to put result2 into column three (Length_3-4). It just places it as a new row. Its not crucial but it just means some more editing in excel after.

Sorry for al the questions and thanks again!

/*
Threshold and measure the image on the red channel
of selected folder and subfolders!
*/

/Create a new Table for all measurements!/
title1 = “TheFinalResults”;
title2 = “[” + title1 + “]”;
title3 = “[” + title2 + “]”;
f = title2
run("New… “, “name=” + title2 + title3 + " type=Table”);
print(f, “\Headings:Image\tLength_1-2” + “\Headings:Image\tLength_3-4”);

/Start the measurements!/

dir = getDirectory("Choose a Directory ");
count = 0;
/We count the files for a progress display!/
countFiles(dir);
n = 0;
/Process all folders!/
processFiles(dir);
/Write a text file from the log!/
selectWindow(“Log”);
save(dir + “/”+ “Log_Analysis.txt”);
/Close the log window!/
run(“Close”);

/Calculate progress!/
function countFiles(dir) {
list = getFileList(dir);
for (i = 0; i < lengthOf(list); i++) {
/*Ignore the log .txt file or others in this folder if necessary
Here we write one log file in the main folder so we exclude it here!
/
if (endsWith(list[i], “/”) || endsWith(list[i], “.txt”)) {
countFiles("" + dir + list[i]);
} else {
count++;
}
}
}
/We analyze all folders and subfolders recursively!/
function processFiles(dir) {
list = getFileList(dir);
for (i = 0; i < lengthOf(list); i++) {
/*If we have a directory we recursively call this function for the nested folder!
Ignore the log .txt file or others in this folder if necessary
Here we write one log file in the main folder so we exclude it here!
/
if (endsWith(list[i], “/”) || endsWith(list[i], “.txt”)) {
processFiles("" + dir + list[i]);
} else {
/Not a folder so we have image files in this folder!/
showProgress(n++, count);
path = dir + list[i];
processFile(path);
close();
}
}
}
/The main analysis function!/
function processFile(path) {
setBatchMode(true); //do not show the images - faster!
open(path);
title = getTitle;
run(“Split Channels”);
selectWindow(title + " (green)");
close();
selectWindow(title + " (blue)");
close();
selectWindow(title + " (red)");
setThreshold(240, 255);
setOption(“BlackBackground”, false);
run(“Convert to Mask”);
setBatchMode(false);
/Adjust the measurements - Here we exclude particles of a certain size, etc.!/
run(“Set Measurements…”, “area centroid redirect=None decimal=3”);
run(“Analyze Particles…”, “size=50-Infinity circularity=0.60-1.00 show=[Overlay Masks] add”);
saveAs(“Jpeg”, dir + title + “_mask.jpg”);
/We have collected all ROI’s (points) in the ROI Manager and now we measure them!/
roiManager(“Show All with labels”);
roiManager(“Show All”);
/Measure the points in the ROI Manager!/
points = roiManager(“count”); //How many ROI’s are present!
/Here we can define a criteria!/
if (points != 4) {
IJ.log("Criteria not met: " + path);
IJ.log("Number of points measured: " + points);
/Do not forget to close the ROI manager here else the points are simply added!/
selectWindow(“ROI Manager”);
run(“Close”);
return;
}
roiManager(“measure”);
wait(100);
selectWindow(“ROI Manager”);
run(“Close”);
/*Get the values from the result table!
based on the macro: How to batch measure distances between points
*/
selectWindow(“Results”);
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”);

/Calculate and display the length calling the function length()/
for (i = 1; i < points; i += 3) {
result1= d2s(length(x[0], y[0], x[i], y[i]), 1);
print(result1);
/Add the results to the final results table!/
print(f, title + “\t” + result1);
result2= d2s(length(x[i + 1], y[i + 1], x[i + 2], y[i + 2]), 1);
print(result2);
/Add the results to the final results table!/
print(f, title + “\t” + result2);
}
IJ.log("Image successfully measured: " + path);
}

/*The function to calculate the euclidean distance!*/
function length(x_0, y_0, x_1, y_1) {
return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}

#13

Here with one row (I also ignored *.csv files - just as I mentioned it’s better to have the results in it’s own parent dir.):

/*
Threshold and measure the image on the red channel
of selected folder and subfolders!
*/

/*Create a new Table for all measurements!*/
title1 = "TheFinalResults";
title2 = "[" + title1 + "]";
f = title2;
run("New... ", "name=" + title2 + " type=Table");
print(f, "\\Headings:Image\tMeasured Points_top\tLength1\tMeasured Points_bottom\tLength2");
/*Start the measurements!*/
dir = getDirectory("Choose a Directory ");
count = 0;
/*We count the files for a progress display!*/
countFiles(dir);
n = 0;
/*Process all folders!*/
processFiles(dir);
/*Write a text file from the log!*/
selectWindow("Log");
save(dir + "/" + "Log_Analysis.txt");
/*Close the FinalResults window!*/
run("Close");
selectWindow("TheFinalResults");
/*Save all correct measurements!*/
saveAs("FinalResults", dir + "/" + "TheFinalResults.csv");
/*Close the results window!*/
run("Close");

/*Calculate progress!*/
function countFiles(dir) {
    list = getFileList(dir);
    for (i = 0; i < lengthOf(list); i++) {
        /*Ignore the log *.txt file or others in this folder if necessary
          Here we write one log file in the main folder so we exclude it here!*/
        if (endsWith(list[i], "/") || endsWith(list[i], ".txt") || endsWith(list[i], ".csv")) {
            countFiles("" + dir + list[i]);
        } else {
            count++;
        }
    }
}
/*We analyze all folders and subfolders recursively!*/
function processFiles(dir) {
    list = getFileList(dir);
    for (i = 0; i < lengthOf(list); i++) {
        /*If we have a directory we recursively call this function for the nested folder!
          Ignore the log *.txt file or others in this folder if necessary
          Here we write one log file in the main folder so we exclude it here!*/
        if (endsWith(list[i], "/") || endsWith(list[i], ".txt") || endsWith(list[i], ".csv")) {
            processFiles("" + dir + list[i]);
        } else {
            /*Not a folder so we have image files in this folder!*/
            showProgress(n++, count);
            path = dir + list[i];
            processFile(path);
            close();
        }
    }
}
/*The main analysis function!*/
function processFile(path) {
    setBatchMode(true); //do not show the images - faster!
    open(path);
    title = getTitle;
    run("Split Channels");
    selectWindow(title + " (green)");
    close();
    selectWindow(title + " (blue)");
    close();
    selectWindow(title + " (red)");
    setThreshold(208, 255);
    setOption("BlackBackground", false);
    run("Convert to Mask");
    setBatchMode(false);
    /*Adjust the measurements - Here we exclude particles of a certain size, etc.!*/
    run("Set Measurements...", "area centroid redirect=None decimal=3");
    run("Analyze Particles...", "size=60-Infinity add");
    /*We have collected all ROI's (points) in the ROI Manager and now we measure them!*/
    roiManager("Show All with labels");
    roiManager("Show All");
    /*Measure the points in the ROI Manager!*/
    points = roiManager("count"); //How many ROI's are present!
    /*Here we can define a criteria!*/
    if (points != 4) {
        IJ.log("Criteria not met: " + path);
        IJ.log("Number of points measured: " + points);
        /*Do not forget to close the ROI manager here else the points are simply added!*/
        selectWindow("ROI Manager");
        run("Close");
        return;
    }
    roiManager("measure");
    wait(100);
    selectWindow("ROI Manager");
    run("Close");
    /*
		Get the values from the result table!
		based on the macro: http://forum.image.sc/t/how-to-batch-measure-distances-between-points/3970/6
		*/
    selectWindow("Results");
    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");
    /*Calculate and display the length calling the function length()*/
    for (i = 1; i < points; i += 3) {
        meas1 = "length_" + 1 + "-" + (i + 1);
        result1 = d2s(length(x[0], y[0], x[i], y[i]), 1);
        print(result1);
        /*Add the results to the final results table!*/
        //print(f, path + "\t" + result1);
        meas2 = "length_" + (i + 2) + "-" + (i + 3);
        result2 = d2s(length(x[i + 1], y[i + 1], x[i + 2], y[i + 2]), 1);
        print(result2);
        /*Add the results to the final results table!*/
        print(f, path + "\t" + meas1 + "\t" + result1 + "\t" + meas2 + "\t" + result2);
    }
    IJ.log("Image successfully measured: " + path);
}
/*The function to calculate the euclidean distance!*/
function length(x_0, y_0, x_1, y_1) {
    return sqrt(pow(x_0 - x_1, 2) + pow(y_0 - y_1, 2));
}

#14

Hi Bio7,

Thank you so much. I’ve think just worked it out as you posted and got all the extra bits into my table including number of points and even cut out .jpg on file name!
/t is tab! Such small steps but I am one step closer to understanding some code! Thank you very much for your assistance.

I would very much like to acknowledge your assistance with this macro in our report. Would you prefer to be addressed as Bio7 or another name?

Would you also be able to tell me if you think my next problem is possible to resolve in imagej. I don’t need to do this right away but would like to know if it is an option.

I would like to be able to draw a square of known size on each image in an attempt to try and standardise the area of interest in future similar surveys. I will probably need to measure all four distances and tell imagej to use the four laser measurements as a scale for each side of the square. Is this possible?

The alternative to this is to average the laser measurements and draw a right-angle square, but this would not be very accurate for images that are angled from the floor?

Cheers,
Jo


#15

You can use my real name: (http://bio7.org/?page_id=1327) for this.

I would like to be able to draw a square of known size on each image in an attempt to try and standardise the area of interest in future similar surveys. I will probably need to measure all four distances and tell imagej to use the four laser measurements as a scale for each side of the square. Is this possible?

Yes, that is possible by drawing a rectangle or overlay (non-destructive, etc.) on the image, e.g. from the laser points or calibrate the image from the known distances of the laser points for some measurements.

drawRect(x, y, width, height)

Overlay.drawRect(x, y, width, height)

There are also plugins available for perspective deformations (which I haven’t tried yet):