Page MenuHomec4science

II-b FWHM - Measure Lengths Scripts
Updated 1,970 Days AgoPublic

Measuring the Full Width At Half Maximum is a common way to check for the resolution of an image on small structures. Or to measure the length of a structure.

the following scripts help automate this measurement by having the user trace a line profile and ImagEJ taking care of fitting a gaussian function which allows it to compute a FWHM value.

Manual Measure

//open an image 
run("Confocal Series (2.2MB)");
image_Name = getTitle();

//get some informations about the image
getDimensions(image_width, image_height, image_channels, image_slices, image_frames);
getVoxelSize(voxel_width, voxel_height, voxel_depth, voxel_unit);

// here we'll make a line in the middle of the image
y_line = image_height/2;
makeLine(0, y_line ,image_width , y_line);

// then we'll create a new iamge by re-slicing
// re-sampling through this line in the z-direction
run("Reslice [/]...", "output="+voxel_depth+" slice_count=1");
selectWindow("Reslice of "+image_Name);

// Now you could draw a line and get the length of this line 
// ther is a live measure in the main ImageJ/Fiji bar when you draw it 
// or you can measure
setTool("line");
while (roiManager("Count") < 1  ){
	waitForUser("Please make a line");
		if (selectionType > -1 ){
		roiManager("Add");
		roiManager("Measure");
	}
}

BUT this manual way even if it’s quick can lead to some bias in your measurements, because You have to decide WHERE you place the begin and the end of the line ?

When you want to measure the diameter of point object like a bead, what is commonly accepted is to measure the Full width at half maximum (have look at FWHM on wikipedia) using a Gaussian fit, but you may need to use a Super Gaussian fit , see below.

// do some cleaning of the environment before starting
run("Close All");
run("Clear Results");

// open an image 
// we need a sampling that is larger than the object
// in the previous image stop there were not enough z 
// above and below the object
run("T1 Head (2.4M, 16-bits)");
image_Name = getTitle();

//get some informations about the image
getDimensions(image_width, image_height, image_channels, image_slices, image_frames);
getVoxelSize(voxel_width, voxel_height, voxel_depth, voxel_unit);

// here we make a line
makeLine(0, 90, 256, 90);

// then we create a new image by re-slicing
run("Reslice [/]...", "output="+voxel_depth+" slice_count=1");
selectImage(nImages);
resliceImage = getTitle();

//Let's make a line
makeLine(25, 67, 240, 67);
waitForUser("We'll make a profile through this line and 'fit' a gaussian formula on it");
fitGaussian();
waitForUser("The inhomogenity of the signal causes trouble ");

// Let's blur a bit the image
selectImage(resliceImage);
run("Duplicate...", "title=["+resliceImage+"-Blurred]");
run("Gaussian Blur...", "sigma=5");
waitForUser("So we blur the image a bit before doing the fitting");
makeLine(25, 67, 240, 67);
fitGaussian();

selectImage(resliceImage+"-Blurred");
waitForUser("But this is still not 'perfect' \nbecause the length of the line you used \nwill affect your fitting and the results");
makeLine(0, 67, image_width, 67);
fitGaussian();



selectImage(resliceImage+"-Blurred");
waitForUser("One possible way is to fit a 'SuperGaussian', \nbut it needs estimates(see function below)");
makeLine(0, 67, image_width, 67);
fitSUPERGaussian();


// companion function to make the math for FWHM
function fitGaussian(){
	
	y = getProfile();
	x = Array.getSequence(lengthOf(y));
	Fit.doFit("Gaussian", x, y) ;
	Fit.plot;
			
	sortedParameter = Fit.p(3); // parameter d of gaussian
	rSquared = Fit.rSquared ; 
			
	FWHM = (2 * sqrt( 2 * log(2) ) ) * sortedParameter ;// http://fr.wikipedia.org/wiki/Largeur_%C3%A0_mi-hauteur
	setResult("FWHM ("+voxel_unit+")", nResults, FWHM * voxel_height);
	setResult("Label",nResults-1,image_Name);
	setResult("rSquared",nResults-1,rSquared);
	updateResults();
	selectWindow("Results");
}


function fitSUPERGaussian(){

	getVoxelSize(voxel_width, voxel_height, voxel_depth, voxel_unit);

	yCurrent = getProfile();											
	xPlot = Array.getSequence(lengthOf(yCurrent));			
			
	pidiv2 = PI/2;
	formulaString = "y = a + b * exp( "+pidiv2+"*(-pow ( abs(x-c), e/2 ) ) / ( pow( d* "+pidiv2+" , e/2 ) ) )";
	
	pourcentOfMax = 50	; // percent of the Maxmimal value of the Gaussian you want to consider as the diameter, 50 = FWHM
	fractionOfMax   = 1/pourcentOfMax *100; 
	
	baseline=0;
	maxOfCurve = 255;
	centerOfCurve = 125 ;
	fullWithFactor = 200; // estimated diameter
	gamma = 2 // is close to 2 for a gaussian
	initialGuesses = newArray(baseline, maxOfCurve, centerOfCurve, fullWithFactor, gamma);
	
	Fit.doFit(formulaString, xPlot, yCurrent,initialGuesses);
	Fit.plot();	
	parameterA	= Fit.p(0); 	// baseLine 
	parameterB 	= Fit.p(1);	// top - baseLine
	parameterC  = Fit.p(2);		// center
	parameterD 	= Fit.p(3);	// function of FW 
	parameterE 	= Fit.p(4);	// N, the great lord gamma
	rSquared 	= Fit.rSquared;
	
	radius 	=  parameterD * pow( (2/PI), (2/parameterE) - 1 ) * pow ( log(fractionOfMax), 2/parameterE) ; // in pixel
	
	setResult("FWHM ("+voxel_unit+")", nResults, 2*radius*voxel_width);
	setResult("Label",nResults-1,image_Name);
	setResult("rSquared",nResults-1,rSquared);
	updateResults();
	selectWindow("Results");

}
Last Author
oburri
Last Edited
Dec 3 2018, 10:45

Event Timeline

romainGuiet created this document.Sep 22 2017, 10:59
romainGuiet edited the content of this document. (Show Details)
romainGuiet edited the content of this document. (Show Details)Sep 22 2017, 12:55
romainGuiet changed the title from II-b Measure Lengths to II-b FWHM - Measure Lengths.Jun 5 2018, 17:36
romainGuiet changed the visibility from "Restricted Project (Project)" to "Public (No Login Required)".
oburri changed the title from II-b FWHM - Measure Lengths to II-b FWHM - Measure Lengths Scripts.Dec 3 2018, 10:44
oburri edited the content of this document. (Show Details)
oburri edited the content of this document. (Show Details)