Convert variations in 2 D boundary to 1 D


#1

My goal here is to get the variations in the boundary (see the image) and plot in 1D with respect to a constant axis (either x-axis or y-axis).

2D

Note: The yellow colored boundary is what I am concerned with.


Drawing a circle around a point
Measuring wall thickness of plastic extruded sample
#2

Good day!

[…] variations in the boundary […]

with respect to what, a circle?

Clueless,

Herbie

PS:
Here is a polar plot that shows the deviation of the contour from a circle around the “center of mass” of the contour:
PolarTransform_Contour
mean = 35.63 ±6.94 pixel

You may also have a look at this thread:
http://forum.imagej.net/t/radius-of-imperfect-concentric-circles/9709?u=herbie


#3

Other ways of doing what you want are:

  • elliptic Fourier descriptors
  • curvature /scale space analysis
  • fractal dimension (although the contour you showed does not look fractal)

#4

@Herbie

Yes, I need the variations with respect to the bounding circle. The image which you have put up is exactly what I am looking for. How did you come up with the Polar Plot?

Regards,
kbimagej


#5

@gabriel

Does ImageJ have any plugins which includes your method? Also, what do you mean by Fractal dimension?

Regards,
kbimagej


#6

Good day!

Here you can get the ImageJ-plugin for the polar transformation:
https://imagej.nih.gov/ij/plugins/polar-transformer.html

For me two ways of defining the crucial center for the transformation appear easily feasible:

  1. Center of mass (see “Set Measurements…”)
  2. Center of the fitting circle (see “Edit >> Selection >> Fit Circle”)

Please note that both approaches lead to slightly different results. You must decide…

Regards

Herbie


#7

Fractals:
http://onlinelibrary.wiley.com/doi/10.1111/j.1365-2818.2010.03454.x/abstract

An implementation for the elliptic fourier analysis:
http://imagejdocu.tudor.lu/doku.php?id=plugin:analysis:fourier_shape_analysis:start

I do not remember an existing plugin for the curvature analysis, but there are plenty of references on how to do it.


#8

Hi Herbie,

I got the centers for the ROI in the image posted. I understand the intuition that it has to do something with the variations in radius from the fitting circle’s radius and we have to iterate through varying angles i.e. theta to get the graph. How do I reciprocate this idea so that I get a similar graph as the one you posted using Polar Transformer plugin?

Regards,
kbimagej


#9

Good day,

do you have the the imageJ plugin “Polar_Transformer.class” installed?

  1. Then you have to have an image with the binary contour of your image open in ImageJ:
    Contour

  2. Start the plugin and uncheck all of the three check boxes in the appearing dialog. Then click OK.

  3. A new dialog appears and for the time being leave it with the given entry of 360. Then click OK.

  4. A new dialog appears in which you are to enter the center coordinates. Then click OK.

You’re done.

Regards

Herbie


#10

Hi Herbie,

Thanks for quick reply. I tried your method but I get a vertical image totally black. To get the binary contour, I saved the ROI from the ROI Manager and applied it on a new black image created through MS Paint. Is the process okay?

Many Thanks,
kbimagej


#11

Please use the binary contour I’ve provided and try with it.

Regards

Hebrie


#12

I got the graph with your image. But I am getting a black vertical image when I use my binary contour. Is there a problem with the way I have generated the binary contour?

Many Thanks,
kbimagej


#13

In this contribution
http://forum.imagej.net/t/convert-variations-in-2-d-boundary-to-1-d/9829/9?u=herbie
I’ve provided the binary contour image from which I get the polar transform shown earlier.

Please use this
Contour
binary contour image.

Regards

Herbie


#14

Let’s assume your original image
z~Original
with the selection is open in ImageJ.

In this case you can run the following macro to get the binary contour image:

orig = getImageID;
setForegroundColor( 255, 255, 255 );
newImage( "BinaryContour", "8-bit black", getWidth(), getHeight(), 1 );
run( "Restore Selection" );
run( "Draw", "slice" );
run( "Select None" );
selectImage( orig );
close();

Paste the above macro code to an empty macro window (Plugins >> New >> Macro) and run it.

HTH

Herbie


Getting co-ordinates of ROI
#15

@Herbie

Works like a charm. One last question though. I would like to find the number variations i.e. no. of local maximas and minimas. Any idea on this? I tried using Analyze Line Graph (Analyze -> Tools ->Analyze Line Graph). But it didn’t give me any result.

Many Thanks,
kbimagej


#16

I would like to find the number variations i.e. no. of local maximas and minimas.

This depends on what you regard as relative extrema. A tolerance value must be defined to give you these numbers. Have a look at
https://imagej.nih.gov/ij/developer/macro/functions.html
and especially:

Array.findMaxima(array, tolerance);
Array.findMinima(array, tolerance);

Now it’s time to learn macro coding …
https://imagej.nih.gov/ij/developer/macro/macros.html

Regards

Herbie


#17

just an add to the suggestion of @Herbie to use the macro and findMaxima method, you can also take a look to this FindPeaks tool (https://imagej.net/Find_Peaks) in the BAR (https://imagej.net/BAR) plugins collection
image


#18

Finally here is an ImageJ macro that gives you all of the desired values of a closed contour image and saves the polar transform data to disk:

// imagej-macro "maximum height" (Herbie G., 15. March 2018)
requires( "1.51w" );
nme = "Polar_Transformer.class";
if ( !File.exists( getDirectory( "plugins" ) + nme ) ) exit( "Macro requires PlugIn \"" + nme + "\" !" );
if ( nImages != 1 )  exit( "A single contour image must be open!" );
run( "8-bit" );
run( "Make Binary" );
orig = getImageID();
nme = split( getTitle(), "." );
tol = 18;
a = newArray( "Center of Mass", "Center of fitting Circle" );
Dialog.create( "Polar Transformation" );
	Dialog.addChoice( "Method", a, a[0] );
	Dialog.addNumber( "Tolerance", tol, 0, 2, "" );
Dialog.show();
method = Dialog.getChoice();
tol = 10 * round( Dialog.getNumber() );
if ( method == a[0] ) {
	List.setMeasurements;
	x = List.getValue( "XM" );
	y = List.getValue( "YM" );
	nme = nme[0] + "_CoM.csv";
} else {
	selectLine();
	run( "Fit Circle" );
	getSelectionBounds( x, y, w, h );
	x += w * 0.5;
	y += h * 0.5;
	run( "Select None" );
	nme = nme[0] + "_CoC.csv";
}
path = getDirectory( "Where to save the results?" ) + nme;
setBatchMode( true );
getRawStatistics( n, mn );
n *= mn / 255;
run( "Polar Transformer", "method=Polar degrees=360 number=[n] center_x=[x] center_y=[y]" );
run( "Make Binary" );
run( "Skeletonize" );
selectLine();
run( "Save XY Coordinates...", "save=[" + path + "]" );
open( path );
a = newArray( nResults );
selectWindow( "Results" );
for ( i=0; i < nResults; i++ ) a[i] = getResult( "X", i );
run( "Close" );
Array.getStatistics( a, mi, mx, mn, std );
print( method + ":  x = " + d2s( x, 2 ) + "; y = " + d2s( y, 2 ) + ";" );
print( "Mean radius = " + d2s( mn, 2 ) + fromCharCode( 177 ) + d2s( std, 2 ) + " pixel;" );
print( "( min = " + mi + "; max = " + mx + "; )" );
tol = round( tol / ( mx - mi ) );
relMx = Array.findMaxima( a, tol );
print( "Tolerance = " +  tol + ":  relMin = " + (relMx.length-1) + "; relMax = " + relMx.length + ";"  );
selectImage( orig );
run("Revert");
setBatchMode( false );
exit();
function selectLine() {
	yPos = getHeight() * 0.5;
	makeRectangle( 0, yPos, getWidth(), 1 );
	p = getProfile();
	p = Array.findMaxima( p, 0 );
	Array.reverse( p );
	doWand( p[0], yPos );
}
// imagej-macro "maximum height" (Herbie G., 15. March 2018)

HTH

Herbie