Measuring wall thickness of plastic extruded sample

Hi there,
I work for a manufacturing industry producing cables. During the extrusion process of plastic material, we need to check if the product has the characteristics requested by the client. One of the most important parameter is the wall thickness. To check it, we bought a digital microscope to capture a snapshot of a product sample. The first image attached is the raw snapshot, the second one is the image after the threshold has been adjusted. What I need to measure is:

  • The maximum wall thickness;
  • The minimum wall thickness;
  • The mean wall thickness (as per international norms of the sector, the mean is calculated using 4 random wall thickness values, excluding the maximum and the minimum, but also a generic average value is ok).

In the future the above measurements should be automated as possible through a macro, because they should be done by an operator during the extrusion process.

I am very new to ImageJ and I am baffled with the amount of documentation and I am a bit lost, I would appreciate if someone could give me some hints on how to implement the above measurements; also some references to specific piece of documentation to read would be very helpful.

Thanks in advance,


Hey @gio

Take a look at this older Forum thread:

I think the info to get the measurements you want will be in there - so you can use MorpholibJ’s Geodesic Distance Transform functionality.

Give it a go… and let us know if you have more specific questions. :slight_smile:



Good day Gio,

you may consider using the polar transformation.

See these threads:

Here is a first attempt:

From the transformed image you may easily get the measures, e.g. by evaluation of the horizontal profiles of the transformed image.

Finally please don’t use JPG-compressed images. Lossy compression introduces artifacts!

Good luck


Hi @etadobson,
thank you for your reply.

I tried to use the Morpholibj plugin to get those distances, this is what I achieved.

  • I skeletonized the thresholded image.
  • I applied the Geodesic Distance Map function (MorphoLibJ -> Binary Images -> Geodesic Distance Map), using the skeleton as the marker and the thresholded image as the mask.
  • The result is the LUT image attached; please note that I had to convert the image to jpeg, because for some reason I can not upload the LUT image as generated by ImageJ.
  • I exported the LUT in a readable format i.e. a table listing for each index the value of red, green and blue (Image -> Color -> Show LUT and then click on List…)
  • The list is attached

I have a couple of questions I hope you can help me out with.

  • The table exported from the LUT image has 256 lines: they seem to me a very few number; maybe ImageJ exports just a little part of the data?
  • How can I read the results? For example, at the index 111 I have the following values: red = 215, green=32, blue = 38; how can I get a distance from those numbers?
  • How can I understand what point of the circle a certain index refers to? Actually, this is not really important, because I have to find the maximum, minimum and mean value, not in what point they are, but maybe in the future I will have to find also this datum.

Many thanks for your help,
gio (1.4 KB)

Hi @anon96376101,
thank you for your reply.

This is what I get so far using the polar transformation.

  • First of all, I measured the center of mass of the image (Analyze -> Set measurements… and then Analyze -> Measure).
  • Then I applied the Polar Transformer with the following parameters:
    • Method: Polar
    • Degrees used for polar space: 360
    • Default center for cartesian space: not ticked (when asked for the center, I used the center of mass measured earlier)
    • For polar transforms, use one line per angle: not ticked (when asked for the number of lines in angle dimension I put 730)
  • I inverted the the image I obtained (Edit -> Invert)
  • The result (very similar to what you posted) is attached: please note that I had to convert the image to png because for some reason I am not able to upload images as saved by ImageJ.


Now I am stuck to the part of evaluating the horizontal profiles of the transformed image.

  • I selected all
  • I drew the plot profile (Analyze -> Plot profile…)
  • I get the graph attached
  • I exported the data in the attached excel file

Plot (999 Bytes)

How can I read the data I got in order to calculate minimum, maximum and mean thickness?


Good day Gio,

as always in the end things aren’t as easy as they might appear at the beginning …

  1. The center of mass is only one of possible centers for the polar transformation, fitting circle is another. You may even consider the latter as a mean of the fitted inner and outer contour. You must decide …

  2. You may transform either the halftone or the binarized image. In both cases you should binarize the transformed image. The decision is yours …

  3. For the profile, draw a horizontal line selection at the vertical position you want to measure. The profile values are either 0 or 255 and you get the width from the distance between the jumps.

  4. You have to decide whether the binarized images give sufficient precision of the measurements.

You can automate all processing steps by using a macro. The macro recoder may help to get the code for the processing steps.
Furthermore, have a look at the documentations:



1 Like


Start reading the thread at this response:

@iarganda explains step-by-step how to extract the data you want… as far as the # of measures… that is most likely based on the length of your longest-shortest-path length. Each measure comes from a point/pixel along that line…



Hi @anon96376101
as far as regards the center for the polar transforms and the accuracy, this is not a real issue for me: this will be an in line check (so the operator is aware if the extrusion process is proceeding correctly or something is going really wrong), the real test will be made in the laboratory by a technician with a much more precise instrumentation.

As far as regards the macro, thank you for the link: I am experimenting. For future reference of other users interested in the topic, here is the core of my macro: it scans all the lines of the image, and give the minimum, maximum and average value (please note that results are in pixel, but to get the real values is just a matter of a division):

var on = 0;
var measures = 0;
var max = 0;
var min = 0;
var total = 0;
var avg = 0;

for(i=0; i<730; i++) {
	run("Clear Results");
	makeLine(0, i, 419, i);
	profile = getProfile();
	for (j=0; j<profile.length; j++)
		if (profile[j] > 0) on++;
	if(min == 0) min = on;
  if(on < min) min = on;
  if(on > max) max = on;
  if(on > 0) measures++;
  total += on; 
	on = 0;

avg = total / measures;

print("Minimum: " + min);
print("Maximum: " + max);
print("Average: " + avg);


nice to see you’ve found a solution for the width measurement from the polar transform of your images!

Here is an ImageJ-macro that does the whole processing from the original gray-level image:

// imagej-macro "pipe wall thickness" (Herbie G., 14. March 2018)
requires( "1.51v" );
nme = "Polar_Transformer.class";
if ( !File.exists( getDirectory( "plugins" ) + nme ) ) exit( "Macro requires PlugIn \"" + nme + "\" !" );
if ( nImages != 1 ) exit( "A single image must be open!" );
a = newArray( "Center of Mass", "Center of fitting Circles" );
Dialog.create( "Polar Transformation" );
	Dialog.addChoice( "Method", a, a[0] );;
method = Dialog.getChoice();
run( "8-bit" );
setAutoThreshold( "Default dark" );
setOption( "BlackBackground", false );
run( "Convert to Mask" );
doWand( 0, getHeight() * 0.5 );
x = List.getValue( "XM" );
y = List.getValue( "YM" );
n = round( List.getValue( "Perim." ) );
run( "Select None" );
if ( method == a[1] ) {
	outer = newArray( 0, y );
	inner = newArray( x, y );
	fitCircle( outer );
	fitCircle( inner );
	run( "Select None" );
	x = ( outer[0] + inner[0] ) * 0.5;
	y = ( outer[1] + inner[1] ) * 0.5;
	method =  "CoC-"; 
} else { method =  "CoM-"; }
setBatchMode( true );
run( "Polar Transformer", "method=Polar degrees=360 number=[n] center_x=[x] center_y=[y]" );
run( "Make Binary" );
wMax = 0;
wMin = getWidth();
wMean = 0;
for ( i=0; i<n; i++ ) {
	w = calcWidth( i );
	wMean += w;
	if ( w > wMax ) wMax = w;
	if ( w < wMin ) wMin = w;
wMean /= n;
print( method + "Minimum: "+ wMin + " pixel" );
print( method + "Maximum: "+ wMax + " pixel" );
print( method + "Mean: "+ d2s( wMean, 2 ) + " pixel" );
setBatchMode( false );
function fitCircle( a ) {
	doWand( a[0], a[1] );
	run ("Fit Circle" );
	getSelectionBounds( x, y, w, h );
	a[0] = x + w * 0.5;
	a[1] = y + h * 0.5;
function calcWidth( idx ) {
	makeRectangle( 0, idx, getWidth(), 1 );
	p = getProfile();
	s = 0;
	for ( i=0; i<p.length; i++ ) { if ( p[i] > 0 ) s++; }
	return s;
// imagej-macro "pipe wall thickness" (Herbie G., 14. March 2018)


1 Like

Thank you for that, very helpful and instructive!

Hello @gio

The LUT is just a color mapping between pixels values and their corresponding color representation. In ImageJ LUTs contain 256 colors, so that’s why.

The distance is not stored there but in the result distance image. Each pixel has a value which is the distance to the closest border.

1 Like

Hi there,

In the image “”, I am trying to determine the thickness of the red ring along the entire circumference. I would very much appreciate advice how to determine ring thickness in an automated fashion, since I have hundreds of samples. This post seems to pointing in the right direction. (1.2 MB)

To this end, The macro’s look promising. I have tried them, but got the following error.

Error: Statement cannot begin with ‘’ in line 1:
{ <> rtf1 \ ansi \ ansicpg1252 \ cocoartf1671

I have tried the polar transformation, by fitting a circle around the outer edge of the ring. The zip file shows the result.
Screenshot 2019-01-29 (398.6 KB)

I’m not sure what to do at this point and would appreciate your insights. Thank you in advance for your help,


Good day!

the above posted macro works perfectly with your sample image after some pre-processing has been applied:

Using the very approach—that is based on the polar transformation—leads to erroneous thickness measurements if the ring-like structure deviates considerably from a circle which appears to be the case for the structure in question. In such cases approaches based on the polar transformation are unsuited.



Thank you Herbie - that is great the Macro works, although it is unfortunate my sample deviates too much from a circle. I will look into other approaches and see what I can find.


Hello @anon96376101 ,

Thank you so much for the macro you posted above. Would you be able to assist me further in it’s use? I’m trying to use it to batch process some microCT image slices of a polymer tube.

I’ve had varied success while using it to process the same image, which would suggest that it is something I’m doing that is introducing the variation.

Taking a single image:INITIALTUBESEGMENTSCAN1crop|nullxnull
I’ll provide the raw uncropped image too:

- the larger outer circle is the container used to house the sample (inner circle) :slight_smile:

**EDIT: I had trouble uploading the images apparently;


I had the macro work as I expected once and have thus far been unable to repeat it.
Using the CoC method the outputs were:
CoC-Minimum: 17 pixel
CoC-Maximum: 25 pixel
CoC-Mean: 21.62 pixel

Which with my scale (75 pixels to 1 mm) equates to a range of around 226 - 333 micrometres, and a mean of 288 micrometres; which is basically spot on what I’ve manually measured using a microscope.

Unfortunately, I often get an error message, “this command requires a selection”, or what seems to be random measurements often what appears to be a single measurement, say 90 pixels for all three outputs etc

I’m quite new to imageJ so perhaps I’m just screwing up something obviously simple. Any input would be greatly appreciated!!


Distance map, then find watershed, you can get the mid-axis ring (the value means the local radius). then do a pixel statistic.

1 Like

Good day Kerr,

please tell us what the green circle means?

Is it a selection and where does it come from?



My macro works perfectly if you reset the scale to pixels. Presently, my macro doesn’t respect any scale set to an image and I won’t change this in the near future.

You may just introduce the following code line to my macro to do this automatically:

if ( nImages != 1 ) exit( “A single image must be open!” );

run("Set Scale...", "distance=0 known=0 pixel=1 unit=pixel");

a = newArray( “Center of Mass”, “Center of fitting Circles” );

These are the values I get:



1 Like

Hi Herbie, thanks so much for the quick response.

You are correct, your macro works absolutely fine when I don’t apply a scaling. I can do that after the measurement phase manually or in an excel document so it’s completely fine :slight_smile:
EDIT - or I can just follow your advice above, cheers :slight_smile:

Apologies for not being more thorough in my application of it.

In reference to your other question the green line is a “region of interest” line as part of the silly microCT software for taking the 2D slices and constructing a 3D version of the object. I went back and removed it from the images to save any issues arising :slight_smile:

The next stage of what I’m looking to do requires batch processing of thousands of these images. I’ve been mucking around editing parts of the code trying to remove the dialog option and force the CoC mode, so that I can leave it running (via the multiple image processor tool) without user input to cycle and measure through all these images. I seem to introduce changes that enable the code to run without error…but by skipping over the actual “content” (pre-processing and measurement + display)… :sweat_smile::sweat_smile: (fairly disappointed in myself, I thought my matlab experience would have helped more :cry:)

If you want to work with the whole image, i.e. avoid the extraction of the tube of interest, you could change the following code line

doWand( 0, getHeight() * 0.5 );


doWand( 90, getHeight() * 0.48 );
setBackgroundColor(0, 0, 0);
run("Clear Outside");

This change assumes that the container position in your images is about the same for all of your images.



This zipped macro code (1.7 KB)
batch processes all images in a folder.

The macro assumes that the images show the tube of interest and its container, such as:

The measurements are output to an ImageJ-results table, one row per image. The results are in millimeters and it is assumed that the scale is the same for all images. It is set in this code line:

pel = 74; // pixels per millimeter
1 Like