Strange results after "Fit Spline"

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Strange results after "Fit Spline"

vischer
Hello All,

The "Fit Spline" algorithm gives strange results for segmented lines consisting of long and short segments. The macro below is an extreme example: Four points are  arranged as straight horizontal line, thus one would expect that fitting a straight line would not change anything.
However, the fitting procedure extends the line with U-turns: the measured length jumps from 201 to 300.3 pix, and the profile (which automatically employs fitting) includes two peaks that are not on the line.

Meanwhile I found out that I can avoid the problem by uncommenting the line containing "Interpolate". But possibly ImageJ could avoid such unexpected behaviour in the first place.
By the way, the problem above also occurs if an end-point is recorded twice (replace 101 by 100 in the demo).

Norbert



close("spline-test");
newImage("spline-test", "8-bit ramp", 500, 500, 1);
makeRectangle(80, 50, 4, 100);
changeValues(0, 255, 255);

xx = newArray(100, 101, 300, 301);
yy = newArray(90, 90, 90, 90);
makeSelection("polyline", xx, yy);
waitForUser;
run("Set Measurements...", "perimeter");
run("Clear Results");

run("Measure");
//run("Interpolate", "interval=0.1");
run("Measure");

run("Fit Spline");
run("Measure");
run("Plot Profile");

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Strange results after "Fit Spline"

Michael Schmid
Hi Norbert,

the way how spline fitting works in ImageJ is the following:
There are two splines, one for the x coordinates and one for the y coordinates, each as a function of point number.

You can see the x spline if you change the y coordinates to
  yy = newArray(10, 20, 30, 40);

As there are two independent splines for x and y, the x values stay unchanged if the y values collapse to a single value, as in your example.

A fundamental change to how the splines work might break established procedures or macros, so I would tend to leave this unchanged.

Michael
________________________________________________________________
On Oct 12, 2013, at 22:51, Norbert Vischer wrote:

> Hello All,
>
> The "Fit Spline" algorithm gives strange results for segmented lines consisting of long and short segments. The macro below is an extreme example: Four points are  arranged as straight horizontal line, thus one would expect that fitting a straight line would not change anything.
> However, the fitting procedure extends the line with U-turns: the measured length jumps from 201 to 300.3 pix, and the profile (which automatically employs fitting) includes two peaks that are not on the line.
>
> Meanwhile I found out that I can avoid the problem by uncommenting the line containing "Interpolate". But possibly ImageJ could avoid such unexpected behaviour in the first place.
> By the way, the problem above also occurs if an end-point is recorded twice (replace 101 by 100 in the demo).
>
> Norbert
>
>
>
> close("spline-test");
> newImage("spline-test", "8-bit ramp", 500, 500, 1);
> makeRectangle(80, 50, 4, 100);
> changeValues(0, 255, 255);
>
> xx = newArray(100, 101, 300, 301);
> yy = newArray(90, 90, 90, 90);
> makeSelection("polyline", xx, yy);
> waitForUser;
> run("Set Measurements...", "perimeter");
> run("Clear Results");
>
> run("Measure");
> //run("Interpolate", "interval=0.1");
> run("Measure");
>
> run("Fit Spline");
> run("Measure");
> run("Plot Profile");

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Strange results after "Fit Spline"

vischer
Hi Michael,

yes, I assumed that an established algorithm was used, probably the same one as on:

http://mbostock.github.io/protovis/ex/splines.html

The problem is that some of the behaviour is not expected by the user;
obviously this happens when lengths of two adjacent segments differ by more than factor 5.
For example, at factor = 9, the length error is +5% (see macro below)

This is my observation:

1. line length is over-estimated  (see macro "Length Deviation" to create an error plot)
2. if factor > 5, artificial loops or u-turns are inserted
3. if factor > 5, the fitted line does not represent intuitive smoothing
4. getProfile silently does or does not invoke "fit Spline", depending on line width > 1
5. automatic smoothing of "getProfile" and "Straighten" can be avoided e.g. by run("Interpolate", "interval=0.1");

So far, I don't have a constructive suggestion, but for I now want to make aware of these pitfalls.

Norbert




//Length deviation of a straight line (100 px) consisting of 3 points
close("Line*");
run("Set Measurements...", "perimeter");
newImage("Line-spline-test", "8-bit ramp", 500, 200, 1);

totalLen = 100;
xx = newArray(0, 0,totalLen);
yy = newArray(90, 90, 90);
lengths = newArray(totalLen/2);//;left half only
run("Line Width...", "line=2");//profile then will employ smoothing
for (xPos = 0; xPos <totalLen/2; xPos++){
        xx[1] = xPos;
        makeSelection("polyline", xx, yy);
        pr = getProfile;
        run("Fit Spline");
        List.setMeasurements;
        lengths[xPos] = List.getValue("Length");
}
Plot.create("Fit Spline Error" ,"Position of 2nd point of 3-point-line (len=100 px)", "Measured length", lengths);
Plot.show;


>
>
>
> On 14. Oct 2013, at 11:02, Michael Schmid <[hidden email]> wrote:
>
> Hi Norbert,
>
> the way how spline fitting works in ImageJ is the following:
> There are two splines, one for the x coordinates and one for the y coordinates, each as a function of point number.
>
> You can see the x spline if you change the y coordinates to
>  yy = newArray(10, 20, 30, 40);
>
> As there are two independent splines for x and y, the x values stay unchanged if the y values collapse to a single value, as in your example.
>
> A fundamental change to how the splines work might break established procedures or macros, so I would tend to leave this unchanged.
>
> Michael
> ________________________________________________________________
> On Oct 12, 2013, at 22:51, Norbert Vischer wrote:
> Hello All,
>
> The "Fit Spline" algorithm gives strange results for segmented lines consisting of long and short segments. The macro below is an extreme example: Four points are  arranged as straight horizontal line, thus one would expect that fitting a straight line would not change anything.
> However, the fitting procedure extends the line with U-turns: the measured length jumps from 201 to 300.3 pix, and the profile (which automatically employs fitting) includes two peaks that are not on the line.
>
> Meanwhile I found out that I can avoid the problem by uncommenting the line containing "Interpolate". But possibly ImageJ could avoid such unexpected behaviour in the first place.
> By the way, the problem above also occurs if an end-point is recorded twice (replace 101 by 100 in the demo).
>
> Norbert
>
>
>
> close("spline-test");
> newImage("spline-test", "8-bit ramp", 500, 500, 1);
> makeRectangle(80, 50, 4, 100);
> changeValues(0, 255, 255);
>
> xx = newArray(100, 101, 300, 301);
> yy = newArray(90, 90, 90, 90);
> makeSelection("polyline", xx, yy);
> waitForUser;
> run("Set Measurements...", "perimeter");
> run("Clear Results");
>
> run("Measure");
> //run("Interpolate", "interval=0.1");
> run("Measure");
>
> run("Fit Spline");
> run("Measure");
> run("Plot Profile");

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html

Norbert Vischer
Research Engineer
Centre for Advanced Microscopy
Swammerdam Institute for Life Sciences (SILS)
University of Amsterdam
Science Park 904
1098 XH Amsterdam, the Netherlands

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Strange results after "Fit Spline"

Michael Schmid
Hi Norbert,

there are different types of splines; the web page mentioned by you (Protovis) uses cardinal splines.  ImageJ uses the usual cubic interpolation splines, which minimize the bending for standard y=f(x) problem.  These splines need inversion of a tridiagonal matrix to calculate the coefficients of the polynomial, so the coefficients of the polynomial depend on all other points.  Cardinal splines are easier to calculate because the coefficients of the polynomial at each point depends only on the neighboring points, but they are usually considered slightly inferior to the usual cubic interpolation splines.

By the way, also the spline editor of Protovis shows overshoot if the points are in a line and the two last points are close together.  So, also there the length will be larger than the distance between the end points in such a case, similar to what your macro shows.

What I consider worse; it can also overshoot somewhere in the middle if points are spaced closely together.  This causes a glitch in a line profile, see this macro:

  newImage("Untitled", "32-bit black", 255, 255, 1);
  run("Macro...", "code=v=128+127*sin(PI*x*0.25)");
  makeLine(5,100,113,100,117,100,190,100);
  run("Fit Spline");
  run("Plot Profile");

I think that the solution could be the following:  The independent coordinate of the x- and y-spline should depend on the (Euclidian) distance between the points (currently, the point number is used).  This would reduce overshoot if there are short and long segments.  I am not sure, however, whether it would completely eliminate the overshoot at the end in all cases.


There are a few more points on Rois that are on my wishlist:
- In a rare cases, length calculation is suboptimal (this does not refer to the problem of spline overshoot).  I have tried to determine the length of spline segments analytically, which would be always accurate, but it leads to an integral over the square root of a 4th-order polynomial.  I think that it is impossible to do this analytically (also Mathematica can't do it).
- The length of the x axis in 'plot profile' is always rounded to the nearest integer (for uncalibrated images).  This might be easy to fix for straight lines, but more tricky for segmented lines.
- Segmented line profiles with interpolation and subpixel resolution could be improved at the vertices.
- With subpixel resolution, having line profiles with a spacing <1 pixel might be nice...

I have a few ideas for improving the algorithms, but this is not so easy, more like a long-term project.  Especially the length integration of the splines seems nasty to handle...

Best regards,

Michael
________________________________________________________________
On Oct 15, 2013, at 23:49, Norbert Vischer wrote:

> Hi Michael,
>
> yes, I assumed that an established algorithm was used, probably the same one as on:
>
> http://mbostock.github.io/protovis/ex/splines.html
>
> The problem is that some of the behaviour is not expected by the user;
> obviously this happens when lengths of two adjacent segments differ by more than factor 5.
> For example, at factor = 9, the length error is +5% (see macro below)
>
> This is my observation:
>
> 1. line length is over-estimated  (see macro "Length Deviation" to create an error plot)
> 2. if factor > 5, artificial loops or u-turns are inserted
> 3. if factor > 5, the fitted line does not represent intuitive smoothing
> 4. getProfile silently does or does not invoke "fit Spline", depending on line width > 1
> 5. automatic smoothing of "getProfile" and "Straighten" can be avoided e.g. by run("Interpolate", "interval=0.1");
>
> So far, I don't have a constructive suggestion, but for I now want to make aware of these pitfalls.
>
> Norbert
>
>
>
>
> //Length deviation of a straight line (100 px) consisting of 3 points
> close("Line*");
> run("Set Measurements...", "perimeter");
> newImage("Line-spline-test", "8-bit ramp", 500, 200, 1);
>
> totalLen = 100;
> xx = newArray(0, 0,totalLen);
> yy = newArray(90, 90, 90);
> lengths = newArray(totalLen/2);//;left half only
> run("Line Width...", "line=2");//profile then will employ smoothing
> for (xPos = 0; xPos <totalLen/2; xPos++){
> xx[1] = xPos;
> makeSelection("polyline", xx, yy);
> pr = getProfile;
> run("Fit Spline");
> List.setMeasurements;
> lengths[xPos] = List.getValue("Length");
> }
> Plot.create("Fit Spline Error" ,"Position of 2nd point of 3-point-line (len=100 px)", "Measured length", lengths);
> Plot.show;
>
>
>>
>>
>>
>> On 14. Oct 2013, at 11:02, Michael Schmid <[hidden email]> wrote:
>>
>> Hi Norbert,
>>
>> the way how spline fitting works in ImageJ is the following:
>> There are two splines, one for the x coordinates and one for the y coordinates, each as a function of point number.
>>
>> You can see the x spline if you change the y coordinates to
>> yy = newArray(10, 20, 30, 40);
>>
>> As there are two independent splines for x and y, the x values stay unchanged if the y values collapse to a single value, as in your example.
>>
>> A fundamental change to how the splines work might break established procedures or macros, so I would tend to leave this unchanged.
>>
>> Michael
>> ________________________________________________________________
>> On Oct 12, 2013, at 22:51, Norbert Vischer wrote:
>> Hello All,
>>
>> The "Fit Spline" algorithm gives strange results for segmented lines consisting of long and short segments. The macro below is an extreme example: Four points are  arranged as straight horizontal line, thus one would expect that fitting a straight line would not change anything.
>> However, the fitting procedure extends the line with U-turns: the measured length jumps from 201 to 300.3 pix, and the profile (which automatically employs fitting) includes two peaks that are not on the line.
>>
>> Meanwhile I found out that I can avoid the problem by uncommenting the line containing "Interpolate". But possibly ImageJ could avoid such unexpected behaviour in the first place.
>> By the way, the problem above also occurs if an end-point is recorded twice (replace 101 by 100 in the demo).
>>
>> Norbert
>>
>>
>>
>> close("spline-test");
>> newImage("spline-test", "8-bit ramp", 500, 500, 1);
>> makeRectangle(80, 50, 4, 100);
>> changeValues(0, 255, 255);
>>
>> xx = newArray(100, 101, 300, 301);
>> yy = newArray(90, 90, 90, 90);
>> makeSelection("polyline", xx, yy);
>> waitForUser;
>> run("Set Measurements...", "perimeter");
>> run("Clear Results");
>>
>> run("Measure");
>> //run("Interpolate", "interval=0.1");
>> run("Measure");
>>
>> run("Fit Spline");
>> run("Measure");
>> run("Plot Profile");
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>
> Norbert Vischer
> Research Engineer
> Centre for Advanced Microscopy
> Swammerdam Institute for Life Sciences (SILS)
> University of Amsterdam
> Science Park 904
> 1098 XH Amsterdam, the Netherlands
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Strange results after "Fit Spline"

Michael Schmid
Hi everyone,

actually it is easier than I thought to get rid of the overshoot of the splines.
The only problem: this makes ImageJ behave quite differently when splining lines or polygons with few points, see the two examples in the attached image.

Do you think that this could break existing procedures or macros?

Or should we have another obscure option, causing problems because ImageJ will behave differently at different computers?

Michael
________________________________________________________________

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html


On Oct 16, 2013, at 12:13, Michael Schmid wrote:

> Hi Norbert,
>
> there are different types of splines; the web page mentioned by you (Protovis) uses cardinal splines.  ImageJ uses the usual cubic interpolation splines, which minimize the bending for standard y=f(x) problem.  These splines need inversion of a tridiagonal matrix to calculate the coefficients of the polynomial, so the coefficients of the polynomial depend on all other points.  Cardinal splines are easier to calculate because the coefficients of the polynomial at each point depends only on the neighboring points, but they are usually considered slightly inferior to the usual cubic interpolation splines.
>
> By the way, also the spline editor of Protovis shows overshoot if the points are in a line and the two last points are close together.  So, also there the length will be larger than the distance between the end points in such a case, similar to what your macro shows.
>
> What I consider worse; it can also overshoot somewhere in the middle if points are spaced closely together.  This causes a glitch in a line profile, see this macro:
>
>  newImage("Untitled", "32-bit black", 255, 255, 1);
>  run("Macro...", "code=v=128+127*sin(PI*x*0.25)");
>  makeLine(5,100,113,100,117,100,190,100);
>  run("Fit Spline");
>  run("Plot Profile");
>
> I think that the solution could be the following:  The independent coordinate of the x- and y-spline should depend on the (Euclidian) distance between the points (currently, the point number is used).  This would reduce overshoot if there are short and long segments.  I am not sure, however, whether it would completely eliminate the overshoot at the end in all cases.
>
>
> There are a few more points on Rois that are on my wishlist:
> - In a rare cases, length calculation is suboptimal (this does not refer to the problem of spline overshoot).  I have tried to determine the length of spline segments analytically, which would be always accurate, but it leads to an integral over the square root of a 4th-order polynomial.  I think that it is impossible to do this analytically (also Mathematica can't do it).
> - The length of the x axis in 'plot profile' is always rounded to the nearest integer (for uncalibrated images).  This might be easy to fix for straight lines, but more tricky for segmented lines.
> - Segmented line profiles with interpolation and subpixel resolution could be improved at the vertices.
> - With subpixel resolution, having line profiles with a spacing <1 pixel might be nice...
>
> I have a few ideas for improving the algorithms, but this is not so easy, more like a long-term project.  Especially the length integration of the splines seems nasty to handle...
>
> Best regards,
>
> Michael
> ________________________________________________________________
> On Oct 15, 2013, at 23:49, Norbert Vischer wrote:
>
>> Hi Michael,
>>
>> yes, I assumed that an established algorithm was used, probably the same one as on:
>>
>> http://mbostock.github.io/protovis/ex/splines.html
>>
>> The problem is that some of the behaviour is not expected by the user;
>> obviously this happens when lengths of two adjacent segments differ by more than factor 5.
>> For example, at factor = 9, the length error is +5% (see macro below)
>>
>> This is my observation:
>>
>> 1. line length is over-estimated  (see macro "Length Deviation" to create an error plot)
>> 2. if factor > 5, artificial loops or u-turns are inserted
>> 3. if factor > 5, the fitted line does not represent intuitive smoothing
>> 4. getProfile silently does or does not invoke "fit Spline", depending on line width > 1
>> 5. automatic smoothing of "getProfile" and "Straighten" can be avoided e.g. by run("Interpolate", "interval=0.1");
>>
>> So far, I don't have a constructive suggestion, but for I now want to make aware of these pitfalls.
>>
>> Norbert
>>
>>
>>
>>
>> //Length deviation of a straight line (100 px) consisting of 3 points
>> close("Line*");
>> run("Set Measurements...", "perimeter");
>> newImage("Line-spline-test", "8-bit ramp", 500, 200, 1);
>>
>> totalLen = 100;
>> xx = newArray(0, 0,totalLen);
>> yy = newArray(90, 90, 90);
>> lengths = newArray(totalLen/2);//;left half only
>> run("Line Width...", "line=2");//profile then will employ smoothing
>> for (xPos = 0; xPos <totalLen/2; xPos++){
>> xx[1] = xPos;
>> makeSelection("polyline", xx, yy);
>> pr = getProfile;
>> run("Fit Spline");
>> List.setMeasurements;
>> lengths[xPos] = List.getValue("Length");
>> }
>> Plot.create("Fit Spline Error" ,"Position of 2nd point of 3-point-line (len=100 px)", "Measured length", lengths);
>> Plot.show;
>>
>>
>>>
>>>
>>>
>>> On 14. Oct 2013, at 11:02, Michael Schmid <[hidden email]> wrote:
>>>
>>> Hi Norbert,
>>>
>>> the way how spline fitting works in ImageJ is the following:
>>> There are two splines, one for the x coordinates and one for the y coordinates, each as a function of point number.
>>>
>>> You can see the x spline if you change the y coordinates to
>>> yy = newArray(10, 20, 30, 40);
>>>
>>> As there are two independent splines for x and y, the x values stay unchanged if the y values collapse to a single value, as in your example.
>>>
>>> A fundamental change to how the splines work might break established procedures or macros, so I would tend to leave this unchanged.
>>>
>>> Michael
>>> ________________________________________________________________
>>> On Oct 12, 2013, at 22:51, Norbert Vischer wrote:
>>> Hello All,
>>>
>>> The "Fit Spline" algorithm gives strange results for segmented lines consisting of long and short segments. The macro below is an extreme example: Four points are  arranged as straight horizontal line, thus one would expect that fitting a straight line would not change anything.
>>> However, the fitting procedure extends the line with U-turns: the measured length jumps from 201 to 300.3 pix, and the profile (which automatically employs fitting) includes two peaks that are not on the line.
>>>
>>> Meanwhile I found out that I can avoid the problem by uncommenting the line containing "Interpolate". But possibly ImageJ could avoid such unexpected behaviour in the first place.
>>> By the way, the problem above also occurs if an end-point is recorded twice (replace 101 by 100 in the demo).
>>>
>>> Norbert
>>>
>>>
>>>
>>> close("spline-test");
>>> newImage("spline-test", "8-bit ramp", 500, 500, 1);
>>> makeRectangle(80, 50, 4, 100);
>>> changeValues(0, 255, 255);
>>>
>>> xx = newArray(100, 101, 300, 301);
>>> yy = newArray(90, 90, 90, 90);
>>> makeSelection("polyline", xx, yy);
>>> waitForUser;
>>> run("Set Measurements...", "perimeter");
>>> run("Clear Results");
>>>
>>> run("Measure");
>>> //run("Interpolate", "interval=0.1");
>>> run("Measure");
>>>
>>> run("Fit Spline");
>>> run("Measure");
>>> run("Plot Profile");
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>> Norbert Vischer
>> Research Engineer
>> Centre for Advanced Microscopy
>> Swammerdam Institute for Life Sciences (SILS)
>> University of Amsterdam
>> Science Park 904
>> 1098 XH Amsterdam, the Netherlands
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html

splinedSelection.png (15K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Strange results after "Fit Spline"

Kenneth Sloan
A superior scheme is to have t depend on the sqrt of the distance between the points.  This is an old and well known result.

--
Kenneth Sloan
[hidden email]


On Oct 16, 2013, at 11:55 , Michael Schmid <[hidden email]> wrote:
>  
> > I think that the solution could be the following:  The independent coordinate of the x- and y-spline should depend on the (Euclidian) distance between the points (currently, the point number is used).  This would reduce overshoot if there are short and long segments.  I am not sure, however, whether it would completely eliminate the overshoot at the end in all cases.
> >
> >  

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Strange results after "Fit Spline"

Rasband, Wayne (NIH/NIMH) [E]
In reply to this post by vischer
On Oct 12, 2013, at 4:51 PM, Norbert Vischer wrote:

> Hello All,
>
> The "Fit Spline" algorithm gives strange results for segmented lines consisting of long and short segments. The macro below is an extreme example: Four points are  arranged as straight horizontal line, thus one would expect that fitting a straight line would not change anything.
> However, the fitting procedure extends the line with U-turns: the measured length jumps from 201 to 300.3 pix, and the profile (which automatically employs fitting) includes two peaks that are not on the line.
>
> Meanwhile I found out that I can avoid the problem by uncommenting the line containing "Interpolate". But possibly ImageJ could avoid such unexpected behaviour in the first place.
> By the way, the problem above also occurs if an end-point is recorded twice (replace 101 by 100 in the demo).

Thanks to Michael Schmid, this bug is fixed in the ImageJ 1.48e daily build, available at

   http://wsr.imagej.net/download/ij.jar

You will be able to upgrade using Help>Update ImageJ when the U.S. Government shutdown ends.

-wayne


> close("spline-test");
> newImage("spline-test", "8-bit ramp", 500, 500, 1);
> makeRectangle(80, 50, 4, 100);
> changeValues(0, 255, 255);
>
> xx = newArray(100, 101, 300, 301);
> yy = newArray(90, 90, 90, 90);
> makeSelection("polyline", xx, yy);
> waitForUser;
> run("Set Measurements...", "perimeter");
> run("Clear Results");
>
> run("Measure");
> //run("Interpolate", "interval=0.1");
> run("Measure");
>
> run("Fit Spline");
> run("Measure");
> run("Plot Profile");

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html