Angle measurements for small lines in Fiji

Hi,

I’m getting unexpected results when I use Analyse > Measure for small straight lines in Fiji.

When they are of the order of a few pixels in length, the angle measurements (angle between line segment and the horizontal) seem incorrect. This is very clear for lines contained within a single pixel (<1px in length), which seem to always have angle 0. However line segment lengths are measured correctly. Is this a known issue?

I think that the coordinates of the ends are being rounded to the nearest pixel for the angle measurements, but not for the lengths.

Steps to reproduce:
create new image (File>New>Image…)
zoom in (to 3200%)
draw a single bright pixel (Pencil tool)
create small line segment contained within a single pixel (Straight line tool)
Analyse->Measure
Expected behaviour: angle should be non-zero.
Observed behaviour: zero angle.

Many thanks,

John

Hello John -

You are correct about this behavior, See my script, below, that
also reproduces what you describe.

I don’t know whether this is a “known issue” or not. I agree
with you that this behavior is sub-optimal, although one could
argue that this is “by design.”

You are correct that the Line endpoints are being converted
to the nearest pixel in the process of calculating the angle.
(I believe that they are being truncated rather than rounded,
although the issue is essentially the same.)

What’s odd is that the code is there to calculate the angle
without truncating. I think that Measure should calculate
the correct (untruncated) angles for Lines with sub-pixel
endpoints; it would be easy to fix; and I suspect that this
is just a historical artifact.

In the code, Analyzer.java, it looks like this issue can be
addressed by replacing the calls to:

   line.getAngle(line.x1,line.y1,line.x2,line.y2)

in lines 460 and 699 with:

   line.getFloatAngle(line.x1d,line.y1d,line.x2d,line.y2d)

(It looks like a similar issue arises with sub-pixel PolygonRois,
but the code paths are very different. See line 702,
double angle = ((PolygonRoi)roi).getAngle();.)

Here is a script that reproduces the issue and and illustrates
the use of Roi.getFloatAngle() to fix it:

# measure_angle_a1.py

from ij import IJ
from ij.gui import Line
from ij.gui import Roi
from ij.plugin.filter import Analyzer

print  IJ.getVersion()

imp = IJ.createImage ('line_roi', '8-bit ramp', 256, 256, 1)
imp.show()

Analyzer.setPrecision (5)

# Roi.getAngle() and Roi.getFloatAngle() ought to be static methods, but they're
# actually instance methods so we need an instance of Roi (or a subclass)
dummyRoi = Roi (0, 0, 0, 0)  

print  'integer Line:'
line = Line (101, 101, 102, 102)
print  'integer points:', line.x1, line.y1, line.x2, line.y2, ', getAngle():', dummyRoi.getAngle (line.x1, line.y1, line.x2, line.y2)
print  'double points:', line.x1d, line.y1d, line.x2d, line.y2d, ', getFloatAngle():', dummyRoi.getFloatAngle (line.x1d, line.y1d, line.x2d, line.y2d)
imp.setRoi (line)
IJ.run ('Measure')

print  'multi-pixel Line with "sub-pixel" endpoints:'
line = Line (101.1, 101.9, 102.9, 102.1)
print  'integer points:', line.x1, line.y1, line.x2, line.y2, ', getAngle():', dummyRoi.getAngle (line.x1, line.y1, line.x2, line.y2)
print  'double points:', line.x1d, line.y1d, line.x2d, line.y2d, ', getFloatAngle():', dummyRoi.getFloatAngle (line.x1d, line.y1d, line.x2d, line.y2d)
imp.setRoi (line)
IJ.run ('Measure')

print  'single-pixel "sub-pixel" Line:'
line = Line (100.1, 100.1, 100.9, 100.9)
print  'integer points:', line.x1, line.y1, line.x2, line.y2, ', getAngle():', dummyRoi.getAngle (line.x1, line.y1, line.x2, line.y2)
print  'double points:', line.x1d, line.y1d, line.x2d, line.y2d, ', getFloatAngle():', dummyRoi.getFloatAngle (line.x1d, line.y1d, line.x2d, line.y2d)
imp.setRoi (line)
IJ.run ('Measure')

# show that Analyzer.measure()  does the same thing as the "Measure" command
analyzer = Analyzer (imp)
analyzer.measure()
analyzer.displayResults()

Here is the Results table:

1	-45	1.41421
2	-45	1.81108
3	0	1.13137
4	0	1.13137

And here are the results printed out by the script:

2.0.0-rc-69/1.52r
integer Line:
integer points: 101 101 102 102 , getAngle(): -45.0
double points: 101.0 101.0 102.0 102.0 , getFloatAngle(): -45.0
multi-pixel Line with "sub-pixel" endpoints:
integer points: 101 101 102 102 , getAngle(): -45.0
double points: 101.1 101.9 102.9 102.1 , getFloatAngle(): -6.34019174591
single-pixel "sub-pixel" Line:
integer points: 100 100 100 100 , getAngle(): 0.0
double points: 100.1 100.1 100.9 100.9 , getFloatAngle(): -45.0

Thanks, mm

2 Likes

Thanks to @mountain_man, this bug is fixed in the latest ImageJ daily build (1.52t40).

1 Like

Thanks @mountain_man and @Wayne for your help.

John

Hello Wayne -

Thanks, Wayne.

I can confirm that the latest daily build (now 1.52t41) gives the
expected sub-pixel angle measurements.

Thanks, mm