How do you measure the angle of curvature of a claw?

I accept I’m probably being profoundly stupid, but I’m at a loss on how to measure the angle of curvature of a (butterfly) claw. I want to use the methodology of Feduccia (1993) but, after four hours last night, gave up, defeated. Can anyone help?

Hi @nigelhaywood

Isn’t the angle just Y? Maybe I don’t get the question.

Sorry, I can see I was unclear!

I have an image of a claw (well, I’ve got a lot, in fact)

What steps should I take in ImageJ/FIJI to discover what Y is?

Oh! That looks like an interesting segmentation :slight_smile:

Some questions about the images:

  • Are all images similar?
  • Is the claw orientation always the same?
  • Is it possible to retake images with a fixed setup? (If this is possible, a setup where all claws are placed on a straight line would be helpful. The straight line could be the AB line and a identification of the claw pixel would be simple.)

Not fully automatically, I guess, but you could modify the 3 point circular ROI plugin http://www.mecourse.com/landinig/software/software.html to approach the inner curvature by clicking on 3 points (and modify it to set the centre of the circle on the image).
That should give you the radius and the centre (point E). Then you need to try to identify the intersection (points A and B) of the circle with the tip and base of the claw. The angle Tool might be useful to measure the angle.

2 Likes

Thank you both for your thoughts. I wondered about the three point plug in: I’ll have a look at that. But essentially all I want is something that will enable me to draw a straight line and bisect it at right angles. And do it again and again without erasing my earlier lines. All I need do is produce an angle for the angle measuring tool to measure. I think you both imagine I’m asking a much more sophisticated question! I really think I’m just failing to find something really obvious!

Hi @nigelhaywood,
I really don’t get what you want that it will be done in an automatic way and what not.

Which points/lines/circles do you want to draw by yourself?

have a nice day,
Emanuele

Forget automatic! I want to take a single photo, and draw the lines on it which are shown in the first picture. I can draw AB using the line tool. How can I draw CD, which bisects it at right angles? Then draw lines XA and XB, again using the line tool. Then bisect them at right angles with EE’ and EE’’. At which point I’ll have Y to measure with the angle tool.

2 Likes

Hi @nigelhaywood,

On the link below you will find a macro that helps you create lines that bissect the ones that you draw.

The idea is that you draw a line segment, and after you hit F2, it makes the bissection.


You can right-click on RAW to download the .ijm file.

A short tutorial on how to install and use it can be found here.

Nothing automatic, just helping with the Bissection bit ^^

1 Like

Dear @nigelhaywood,
I wrote a python plugin that evaluate the angle Y after you give it manually the 3 points A,B,X.
Essentially it finds the circle passing through those three points ( http://www.regentsprep.org/regents/math/geometry/gcg6/RCir.htm ) and consequently the principal point E’ the center of the circle.
This point of course define the two lines A to E’ and B to E’ and the searched angle Y.
I attach you the results agains the figure with the method (as a test) and against your real case.
Please check if the result makes sense, and tell me if it does what you want.

from ij import IJ, WindowManager
from ij.plugin.frame import RoiManager
from ij.measure import ResultsTable
from ij.gui import WaitForUserDialog, Line, PointRoi
from java.awt import Color
import math
from ij.text import TextWindow


def draw_lines_by_points(P1, P2, roim, imp, line_name, line_color):
    x1 = (P1.XBase);
    x2 = (P2.XBase);
    y1 = (P1.YBase);
    y2 = (P2.YBase);
    # elongate lines
    m = (y1 - y2) / (x1 - x2);
    q = -(y1 - y2) / (x1 - x2) * x1 + y1;

        
    line = Line(x1, y1, x2, y2);
    if (line_color != None):
        line.setStrokeColor(line_color)
        line.setName(line_name)
        roim.addRoi(line);
        imp.setRoi(line);
    return m, q;    
    

roim = RoiManager().getInstance()
if roim.getCount()>0:
    WindowManager.getWindow("ROI Manager").close()
roim = RoiManager().getInstance()

# DRAW POINTS
imp = WindowManager.getCurrentImage()

roim.runCommand("UseNames", "true");
points_name = ["A", "B", "X"];
points_color = Color.RED;

IJ.setTool("point");
# add points and set proper names
for p in range(0, 3):
    WaitForUserDialog("DRAW POINTS", "DRAW - " + points_name[p] + " - point to start analysis then click OK").show()             
    roi_point = imp.getRoi();
    roi_point.setName(str(points_name[p]));
    roi_point.setStrokeColor(points_color);
    roim.addRoi(roi_point);

# get Points
p_A = roim.getRoi(0);
p_B = roim.getRoi(1);
p_X = roim.getRoi(2);

roim.runCommand(imp, "Show All with labels");
WaitForUserDialog("ADJUST POINTS", "Adjust points to draw lines then click OK").show()   

# draw AB,AX,BX
m_AB, q_AB = draw_lines_by_points(p_A, p_B, roim, imp, "AB", Color.GREEN);
m_AX, q_AX = draw_lines_by_points(p_A, p_X, roim, imp, "AX", Color.GREEN);
m_BX, q_BX = draw_lines_by_points(p_B, p_X, roim, imp, "BX", Color.GREEN);


img_width = imp.getWidth();
img_height = imp.getHeight();

# get Center of inner circle by 3 points
x_center = (m_AX*m_BX*(p_A.YBase-p_B.YBase)+m_AX*(p_X.XBase+p_B.XBase)-m_BX*(p_X.XBase+p_A.XBase))/(2*(m_AX-m_BX));
y_center = -1/m_AX*(x_center-(p_X.XBase+p_A.XBase)/2)+(p_X.YBase+p_A.YBase)/2;
P_center = PointRoi(int(x_center), int(y_center));

#draw P_center - X
m_XC, q_XC = draw_lines_by_points(p_X, P_center, roim, imp, "X-Center", Color.YELLOW);

# get Y (Angle E_1-A ^ E_1-B)
m_E_1_A, q_E_1_A = draw_lines_by_points(p_A, P_center, roim, imp, "E_1-A", Color.ORANGE);
m_E_2_A, q_E_2_A = draw_lines_by_points(p_B, P_center, roim, imp, "E_1-B", Color.ORANGE);

tan_Y = math.fabs((m_E_1_A-m_E_2_A)/(1+m_E_2_A*m_E_1_A));
Y = math.atan(tan_Y);


# update Results table
rt_exist = WindowManager.getWindow("Results_Claw_Curvature");
if rt_exist==None or not isinstance(rt_exist, TextWindow): 
    rt= ResultsTable();
else:
    rt = rt_exist.getTextPanel().getOrCreateResultsTable();



rt.incrementCounter();
rt.addValue("Image", imp.getTitle());
rt.addValue("Angle", 180-Y*180/math.pi);
rt.show("Results_Claw_Curvature");

I hope this helps,
have a nice day
Emanuele

1 Like

@emartini

Nice script! But as far as I understand, the line between E’ and Ax have to be perpendicular to Ax AND bisect Ax. Just by visual inspection this seems not be the case in your script?

I think oburri has nailed it. That’s outstanding - many, many thanks. I’m really grateful.

Best wishes,

Nigel

And, as well as Olivier, thanks to Emanuele, Gabriel, Tim-Oliver and Thorsten too.
Best wishes,
Nigel

Hi,

You can also have a look at Kappa which has been designed to analyze the curvature of biological filaments. The Fiji integration is limited for now but beside that the software works well.

2 Likes

That looks like a nice plugin! Don’t you want to create an update site for it?

1 Like

@twagner, @nigelhaywood
dear twnger, I double checked this morning and yes you are right :slight_smile:
I had put the wrong signs in the inner center formula - a minus instead of a plus.
This is the new version (I added also the EE’ and EE’’ perpendicular lines).
I tested it against the figure with the method and also the @oburri implementation.


This is the new corrected code:

from ij import IJ, WindowManager
from ij.plugin.frame import RoiManager
from ij.measure import ResultsTable
from ij.gui import WaitForUserDialog, Line, PointRoi
from java.awt import Color
import math
from ij.text import TextWindow


def draw_lines_by_points(P1, P2, roim, imp, line_name, line_color):
    x1 = (P1.XBase);
    x2 = (P2.XBase);
    y1 = (P1.YBase);
    y2 = (P2.YBase);
    # elongate lines
    m = (y1 - y2) / (x1 - x2);
    q = -(y1 - y2) / (x1 - x2) * x1 + y1;

        
    line = Line(x1, y1, x2, y2);
    if (line_color != None):
        line.setStrokeColor(line_color)
        line.setName(line_name)
        roim.addRoi(line);
        imp.setRoi(line);
    return m, q;    
    


imp = WindowManager.getCurrentImage();
roim = RoiManager().getInstance()
if roim.getCount()>0:
    WindowManager.getWindow("ROI Manager").close()
    
roim = RoiManager().getInstance()

# DRAW POINTS 

roim.runCommand("UseNames", "true");
points_name = ["A", "B", "X"];
points_color = Color.RED;

IJ.setTool("point");
# add points and set proper names
for p in range(0, 3):
    WaitForUserDialog("DRAW POINTS", "DRAW - " + points_name[p] + " - point to start analysis then click OK").show()             
    roi_point = imp.getRoi();
    roi_point.setName(str(points_name[p]));
    roi_point.setStrokeColor(points_color);
    roim.addRoi(roi_point);

# get Points
p_A = roim.getRoi(0);
p_B = roim.getRoi(1);
p_X = roim.getRoi(2);

roim.runCommand(imp, "Show All with labels");
WaitForUserDialog("ADJUST POINTS", "Adjust points to draw lines then click OK").show()   

# draw AB,AX,BX
m_AB, q_AB = draw_lines_by_points(p_A, p_B, roim, imp, "AB", Color.GREEN);
m_AX, q_AX = draw_lines_by_points(p_A, p_X, roim, imp, "AX", Color.GREEN);
m_BX, q_BX = draw_lines_by_points(p_B, p_X, roim, imp, "BX", Color.GREEN);


img_width = imp.getWidth();
img_height = imp.getHeight();

# get Center of inner circle by 3 points
x_center = (m_AX*m_BX*(-p_A.YBase+p_B.YBase)+m_AX*(p_X.XBase+p_B.XBase)-m_BX*(p_X.XBase+p_A.XBase))/(2*(m_AX-m_BX));
y_center = -1/m_AX*(x_center-(p_X.XBase+p_A.XBase)/2)+(p_X.YBase+p_A.YBase)/2;
P_center = PointRoi(int(x_center), int(y_center));
P_center.setName("E");
roim.addRoi(P_center);

#draw P_center - X
m_XC, q_XC = draw_lines_by_points(p_X, P_center, roim, imp, "X-Center", Color.YELLOW);

# get Y (Angle E_1-A ^ E_1-B)
m_E_1_A, q_E_1_A = draw_lines_by_points(p_A, P_center, roim, imp, "E_1-A", Color.ORANGE);
m_E_2_A, q_E_2_A = draw_lines_by_points(p_B, P_center, roim, imp, "E_1-B", Color.ORANGE);

tan_Y = math.fabs((m_E_1_A-m_E_2_A)/(1+m_E_2_A*m_E_1_A));
Y = math.atan(tan_Y);


# update Results table
rt_exist = WindowManager.getWindow("Results_Claw_Curvature");
if rt_exist==None or not isinstance(rt_exist, TextWindow): 
    rt= ResultsTable();
else:
    rt = rt_exist.getTextPanel().getOrCreateResultsTable();



rt.incrementCounter();
rt.addValue("Image", imp.getTitle());
rt.addValue("Angle", 180-Y*180/math.pi);
rt.show("Results_Claw_Curvature");

# line check perpendicular and bisecting
# E_AX perpendicular to AX pass by P_Circle
m_E_AX = 1 / m_AX;
x_p1 = P_center.XBase;
y_p1 = P_center.YBase;
y_p2 = (10.1);
x_p2 = (-y_p2 + m_E_AX * x_p1 + y_p1) / m_E_AX;
p2_R2 = PointRoi(int(x_p2), int(y_p2))
m2, q2 = draw_lines_by_points(P_center, p2_R2, roim, imp, "E_AX", Color.BLUE);

# E_BX perpendicular to AX pass by P_Circle
m_E_BX = 1 / m_BX;
x_p1 = P_center.XBase;
y_p1 = P_center.YBase;
y_p2 = (10.1);
x_p2 = (-y_p2 + m_E_BX * x_p1 + y_p1) / m_E_BX;
p2_R2 = PointRoi(int(x_p2), int(y_p2))
m2, q2 = draw_lines_by_points(P_center, p2_R2, roim, imp, "E_BX", Color.BLUE);


roim.runCommand(imp, "Show All with labels");

I put also a movie about how to use it.
claw_curvature_movie.zip (19.9 MB)

Have a nice day,
Emanuele

2 Likes

Thanks Emanuele, that’s a great script. Problem solved, I think. Thanks once again to you all. Though as I’m about to look at ways of assessing the morphology of butterfly wing patterns, some more very basic questions will, I’m afraid, be appearing before too long!

1 Like

Kappa needs some more work before being well integrated to Fiji and also upgraded to IJ2 API. I am planning to work on that by the end of 2016 and beginning of 2017.

I can create an update site in the meantime.

2 Likes

Hi Emanuele,

I’m deeply interested to use your plugin to measure curvature in theropod teeth. I could not, however, import it on ImageJ (I have a message saying “Undefined variable line 2 etc”). Could you perhaps send me the exact file, or tell me the steps to follow to use your plugin? I use Windows 10 if it changes something.

Many thanks in advance for your help!

Christophe

Hi Adim,

Similar to Emanuele’s plugin, I tried to use your Kappa software to see if I can apply it to measure curvature on theropod teeth. I download specifically Fiji and beside the huge amount of options that I will never use, your Kappa plugin was not integrated. I added it in the folder plugins of Fiji, as said in the manual, but cannot find the Kappa option in the list, in “Analyze”. Is it normal that the current version of Kappa is not working on Fiji? Could it be because I use Windows?

Many thanks in advance for your help.

Regards,

Christophe