Contour map generation under ImageJ

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

Contour map generation under ImageJ

CARL Philippe (LBP)
Dear ImageJ Experts,

What I want to do is to create a contour map, i.e. a picture (with height *
width pixels) of values to which I can then apply different LUTs in order to
look at my data.

And what I have now are only the values of discrete positions within this
picture.

Actually what I want to do is more or less what is described under the
following link:

http://www.geomore.com/how-to-contour-a-map/

And thus the question is how to generate the contour map, i.e. calculate the
values of each pixel within the picture.

Is there already an algorithm under ImageJ that is already doing such a
calculation?

Alternatively, what kind of calculation or algorithm would you recommend me
in order to calculate the values at each pixel?

I thank you very much in advance for your answer and help.

Best regards,

Philippe


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

Re: Contour map generation under ImageJ

Gabriel Landini
On Tuesday 10 Jul 2012 13:23:17 Philippe Carl wrote:
> What I want to do is to create a contour map, i.e. a picture (with height *
> width pixels) of values to which I can then apply different LUTs in order to
> look at my data.
 
> And what I have now are only the values of discrete positions within this
> picture.

If all the pixels in the image are your values, you can use the IsoPhotContour
plugins here:

http://www.dentistry.bham.ac.uk/landinig/software/software.html

If only some of your pixels are your values, then the method showed in the
link seems quite arbitrary ("using your eye like a ruler" !?) I doubt it will
be accurate or meaningful.

Maybe there is some algorithm (Laplacian diffusion comes to mind, but I am not
sure if that is appropriate) that can be applied to the "height" of the
samples to fill in the rest of the image pixels and then find the contour
lines of that new image.

Cheers
Gabriel

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

Re: Contour map generation under ImageJ

CARL Philippe (LBP)
In reply to this post by CARL Philippe (LBP)
Dear Wade,

I thank you very much for your message and you have very correctly
indentified the problem I would like to solve.

Also your picture with the blanket is indeed a very nice way to visualize
things and I haven’t thought about the issue of the stiffness.

Additionally there is another problem to solve or at least to answer which
are the conditions (or values) at limits, i.e. on the border of the picture.

The first algorithm I thought about is to make an iterative calculation
where you attribute to a given pixel the average value of all its neighbors
and reset again the known pixels to their initial values at each iteration
and this until the calculation is stable. But as such a code will be
working, it will be quite time consuming.

Another idea was to calculate the value of a given unknown pixel with a kind
of center of mass calculation. And as this calculation will be way faster,
it is more difficult for the values on the border of the picture.

And another way (Jérôme Mutterer gave me this idea) is to use the polynomial
fit plugin (http://www.optinav.com/imagej.html) developed by Bob Dougherty
which seems to be working quite well (the conditions on the limits still
need to be cleared).

Could you explain me a little bit better your idea with the triangles? I’m
quite afraid to not have understand it.

My best regards,

Philippe

 

De : Wade Schuette [mailto:[hidden email]]
Envoyé : mardi 10 juillet 2012 18:50
À : [hidden email]
Cc : [hidden email]
Objet : Re: Contour map generation under ImageJ

 

Philippe,  

This is really a 2-Dimensional curve-fitting (surface fitting) problem.

I don't know the ImageJ libraries and whether something exists that
would work.   If not, you have to run some iterations and some math.
If math doesn't deter you, read on.

The problem is under-defined, but probably workable.   I tried using
"Contour"
in the SAS product JMP, but it produced an ugly result with sharp corners.

I think that, conceptually,  one way to tackle this is to think of it as
an open field with a number of telephone poles in it of different heights,
 and what you want to do is drape a somewhat stiff blanket over the field,
 constrained by the poles.

That formulation still leaves three parameters unresolved,  the effective
stiffness of the blanket, the stretchiness of the blanket, and the
strength and direction of the force trying to make the blanket fit the tops
of the poles.

Or,  instead of weight to get a downward force on the blanket, you could
attach elastic bands to the blanket, tie the other end to the top of the
poles, and try to increase the strength of those bands, which is to say
lessen the discrepancy from your surface to the match points.
(statistically,  reduce r-squared discrepancies ).

I could easily write a script to compute the up/down force on each point on
the blanket,  move it one time interval, recompute, etc. if just stretching
were involved, as that's just iterating for each point over the neighboring
4 points as if a spring were attached, with a force proportional to
stretch squared.     Adding mass to the point would make it a grid
of billiard-balls connected by springs, again straight-forward to
solve with iterations and probably cool to watch.

But I'm trying to figure out the mathematics of STIFFNESS, without
which you'll end up with a very spiky landscape, instead of the
smooth one you envision.

You won't know the parameters of "stiffness" and "stretchiness" to use,
but for what you're doing I suspect that any reasonable numbers would
work, and you can explore a little and see how sensitive the result is
to your choices of values.   You could find a set of parameters that
more or less matches the result in the web-page example you gave.

Regardless, you'll end up with a complete image that you can then
make contours on ( just changeValues ( z-1, z, black) for z's you
want to see.), or use LUTS on, or both.

I'm working on how to implement the stiffness of the 2-d blanket / splines,
just for fun.

A cruder way to do this is to just make a triangle from every combination
of 3 points such that no other point is included inside the triangles you
keep.
That basically covers the surface with connected triangles.

Then each triangle lies in a completely determined PLANE , that
you can assign vertical values to based on the three corners.  Then
you can hand sketch from that,  or just "SMOOTH" it and
use that as your contour map.   Again that may be "good enough"
for whatever you need this for.


Wade





On Tue, Jul 10, 2012 at 5:23 AM, Philippe CARL <[hidden email]>
wrote:

Dear ImageJ Experts,

What I want to do is to create a contour map, i.e. a picture (with height *
width pixels) of values to which I can then apply different LUTs in order to
look at my data.

And what I have now are only the values of discrete positions within this
picture.

Actually what I want to do is more or less what is described under the
following link:

http://www.geomore.com/how-to-contour-a-map/

And thus the question is how to generate the contour map, i.e. calculate the
values of each pixel within the picture.

Is there already an algorithm under ImageJ that is already doing such a
calculation?

Alternatively, what kind of calculation or algorithm would you recommend me
in order to calculate the values at each pixel?

I thank you very much in advance for your answer and help.

Best regards,

Philippe


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




--
R. Wade Schuette, CDP, MBA, MPH
698 Monterey Ave
Morro Bay CA 93442
cell: 1 (734) 635-0508
fax:  1 (734) 864-0318
[hidden email]


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

Re: Contour map generation under ImageJ

Wade Schuette
In reply to this post by CARL Philippe (LBP)
Philippe,

 I put some work from a rather hasty macro up on a weblog so I don't need
to email a thousand people a meg of images.   Basically, I connected the
dots by lines,  manually, then wrote a macro that interpolated from the
end-point-values of each line where the middle contour points (5, 10,15,
20, etc.) would be, and added those to the image.    Then,  I thresholded
that image to just show points for one contour level (say 15),  connected
those dots in a roughly circular order,  used Edit/Selection/Fit Ellipse to
change the polygon line I drew to a best-fit ellipse, and DREW that on the
picture.  Repeat for each contour level.

As I say, the problem is under-determined by the data, but this at least
gives you a pretty picture to look at that wasn't biased by nasty old human
judgment.

http://wadesblogtest.blogspot.com/2012/07/images-for-contour-question.html

The macro is too ugly to share, but I'll be glad to tweak it to run on a
data set you send me, and then I'll share it .  I'm just relearning Macros
in ImageJ, having bailed from the NIH-Image group a decade or so ago, when
Wayne switched it to Java and I didn't have the RAM (mentally) to make that
transition.


Regards,

Wade

Wade Schuette
Morro Bay, California, USA




On Wed, Jul 11, 2012 at 8:07 AM, Philippe CARL <[hidden email]>wrote:

> Dear Wade,
>
> I thank you very much for your message and you have very correctly
> indentified the problem I would like to solve.
>
> Also your picture with the blanket is indeed a very nice way to visualize
> things and I haven’t thought about the issue of the stiffness.
>
> Additionally there is another problem to solve or at least to answer which
> are the conditions (or values) at limits, i.e. on the border of the
> picture.
>
> The first algorithm I thought about is to make an iterative calculation
> where you attribute to a given pixel the average value of all its neighbors
> and reset again the known pixels to their initial values at each iteration
> and this until the calculation is stable. But as such a code will be
> working, it will be quite time consuming.
>
> Another idea was to calculate the value of a given unknown pixel with a
> kind
> of center of mass calculation. And as this calculation will be way faster,
> it is more difficult for the values on the border of the picture.
>
> And another way (Jérôme Mutterer gave me this idea) is to use the
> polynomial
> fit plugin (http://www.optinav.com/imagej.html) developed by Bob Dougherty
> which seems to be working quite well (the conditions on the limits still
> need to be cleared).
>
> Could you explain me a little bit better your idea with the triangles? I’m
> quite afraid to not have understand it.
>
> My best regards,
>
> Philippe
>
>
>
> De : Wade Schuette [mailto:[hidden email]]
> Envoyé : mardi 10 juillet 2012 18:50
> À : [hidden email]
> Cc : [hidden email]
> Objet : Re: Contour map generation under ImageJ
>
>
>
> Philippe,
>
> This is really a 2-Dimensional curve-fitting (surface fitting) problem.
>
> I don't know the ImageJ libraries and whether something exists that
> would work.   If not, you have to run some iterations and some math.
> If math doesn't deter you, read on.
>
> The problem is under-defined, but probably workable.   I tried using
> "Contour"
> in the SAS product JMP, but it produced an ugly result with sharp corners.
>
> I think that, conceptually,  one way to tackle this is to think of it as
> an open field with a number of telephone poles in it of different heights,
>  and what you want to do is drape a somewhat stiff blanket over the field,
>  constrained by the poles.
>
> That formulation still leaves three parameters unresolved,  the effective
> stiffness of the blanket, the stretchiness of the blanket, and the
> strength and direction of the force trying to make the blanket fit the tops
> of the poles.
>
> Or,  instead of weight to get a downward force on the blanket, you could
> attach elastic bands to the blanket, tie the other end to the top of the
> poles, and try to increase the strength of those bands, which is to say
> lessen the discrepancy from your surface to the match points.
> (statistically,  reduce r-squared discrepancies ).
>
> I could easily write a script to compute the up/down force on each point on
> the blanket,  move it one time interval, recompute, etc. if just stretching
> were involved, as that's just iterating for each point over the neighboring
> 4 points as if a spring were attached, with a force proportional to
> stretch squared.     Adding mass to the point would make it a grid
> of billiard-balls connected by springs, again straight-forward to
> solve with iterations and probably cool to watch.
>
> But I'm trying to figure out the mathematics of STIFFNESS, without
> which you'll end up with a very spiky landscape, instead of the
> smooth one you envision.
>
> You won't know the parameters of "stiffness" and "stretchiness" to use,
> but for what you're doing I suspect that any reasonable numbers would
> work, and you can explore a little and see how sensitive the result is
> to your choices of values.   You could find a set of parameters that
> more or less matches the result in the web-page example you gave.
>
> Regardless, you'll end up with a complete image that you can then
> make contours on ( just changeValues ( z-1, z, black) for z's you
> want to see.), or use LUTS on, or both.
>
> I'm working on how to implement the stiffness of the 2-d blanket / splines,
> just for fun.
>
> A cruder way to do this is to just make a triangle from every combination
> of 3 points such that no other point is included inside the triangles you
> keep.
> That basically covers the surface with connected triangles.
>
> Then each triangle lies in a completely determined PLANE , that
> you can assign vertical values to based on the three corners.  Then
> you can hand sketch from that,  or just "SMOOTH" it and
> use that as your contour map.   Again that may be "good enough"
> for whatever you need this for.
>
>
> Wade
>
>
>
>
>
> On Tue, Jul 10, 2012 at 5:23 AM, Philippe CARL <[hidden email]>
> wrote:
>
> Dear ImageJ Experts,
>
> What I want to do is to create a contour map, i.e. a picture (with height *
> width pixels) of values to which I can then apply different LUTs in order
> to
> look at my data.
>
> And what I have now are only the values of discrete positions within this
> picture.
>
> Actually what I want to do is more or less what is described under the
> following link:
>
> http://www.geomore.com/how-to-contour-a-map/
>
> And thus the question is how to generate the contour map, i.e. calculate
> the
> values of each pixel within the picture.
>
> Is there already an algorithm under ImageJ that is already doing such a
> calculation?
>
> Alternatively, what kind of calculation or algorithm would you recommend me
> in order to calculate the values at each pixel?
>
> I thank you very much in advance for your answer and help.
>
> Best regards,
>
> Philippe
>
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>
>
>
>
> --
> R. Wade Schuette, CDP, MBA, MPH
> 698 Monterey Ave
> Morro Bay CA 93442
> cell: 1 (734) 635-0508
> fax:  1 (734) 864-0318
> [hidden email]
>
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>



--
R. Wade Schuette, CDP, MBA, MPH
698 Monterey Ave
Morro Bay CA 93442
cell: 1 (734) 635-0508
fax:  1 (734) 864-0318
[hidden email]

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

Re: Contour map generation under ImageJ

Wade Schuette
OK, Philippe,  I believe what you REALLY need is called "biharmonic spline
interpolation".
I do not know if this is implemented in ImageJ.

I do know that it is implemented in MATLAB, but I don't have a copy of that.

There's one discussion of the subject and one person's MATLAB code here:
http://www.mathworks.com/matlabcentral/answers/17775
citing as a reference
Sandwell, D. T. (1987), Biharmonic spline interpolation of GEOS-3 and
SEASAT altimeter data, Geophysical Research Letters, Vol. 2, p. 139 – 142
available here:
http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CFcQFjAA&url=http%3A%2F%2Ftopex.ucsd.edu%2Fsandwell%2Fpublications%2F021_GRL_biharmonic_1987.pdf&ei=YCv-T_joMMXeqgGi072LCQ&usg=AFQjCNG-06IIHnP0iTcIdywcSPBENJcLZg

There's a (possibly different) page on the GRIDDATA procedure in MATLAB
that also seems to solve this problem:

Video tutorial on the subject of fitting a 2-d surface curve to an
irregularly sampled set of points:
http://blogs.mathworks.com/pick/2007/11/02/advanced-matlab-surface-plot-of-nonuniform-data/

Actually, go into Google and search this string:  "matlab griddata"
and you'll get many references to fitting irregularly sampled data and
creating a uniform grid out of it, suitable for contours or plotting or
whatever else you want to do next.

That function (GRIDDATA) is described here:
http://www.weizmann.ac.il/matlab/techdoc/ref/griddata.html

Wade




On Wed, Jul 11, 2012 at 1:41 PM, Wade Schuette <[hidden email]>wrote:

> Philippe,
>
>  I put some work from a rather hasty macro up on a weblog so I don't need
> to email a thousand people a meg of images.   Basically, I connected the
> dots by lines,  manually, then wrote a macro that interpolated from the
> end-point-values of each line where the middle contour points (5, 10,15,
> 20, etc.) would be, and added those to the image.    Then,  I thresholded
> that image to just show points for one contour level (say 15),  connected
> those dots in a roughly circular order,  used Edit/Selection/Fit Ellipse to
> change the polygon line I drew to a best-fit ellipse, and DREW that on the
> picture.  Repeat for each contour level.
>
> As I say, the problem is under-determined by the data, but this at least
> gives you a pretty picture to look at that wasn't biased by nasty old human
> judgment.
>
> http://wadesblogtest.blogspot.com/2012/07/images-for-contour-question.html
>
> The macro is too ugly to share, but I'll be glad to tweak it to run on a
> data set you send me, and then I'll share it .  I'm just relearning Macros
> in ImageJ, having bailed from the NIH-Image group a decade or so ago, when
> Wayne switched it to Java and I didn't have the RAM (mentally) to make that
> transition.
>
>
> Regards,
>
> Wade
>
> Wade Schuette
> Morro Bay, California, USA
>
>
>
>
>
> On Wed, Jul 11, 2012 at 8:07 AM, Philippe CARL <[hidden email]>wrote:
>
>> Dear Wade,
>>
>> I thank you very much for your message and you have very correctly
>> indentified the problem I would like to solve.
>>
>> Also your picture with the blanket is indeed a very nice way to visualize
>> things and I haven’t thought about the issue of the stiffness.
>>
>> Additionally there is another problem to solve or at least to answer which
>> are the conditions (or values) at limits, i.e. on the border of the
>> picture.
>>
>> The first algorithm I thought about is to make an iterative calculation
>> where you attribute to a given pixel the average value of all its
>> neighbors
>> and reset again the known pixels to their initial values at each iteration
>> and this until the calculation is stable. But as such a code will be
>> working, it will be quite time consuming.
>>
>> Another idea was to calculate the value of a given unknown pixel with a
>> kind
>> of center of mass calculation. And as this calculation will be way faster,
>> it is more difficult for the values on the border of the picture.
>>
>> And another way (Jérôme Mutterer gave me this idea) is to use the
>> polynomial
>> fit plugin (http://www.optinav.com/imagej.html) developed by Bob
>> Dougherty
>> which seems to be working quite well (the conditions on the limits still
>> need to be cleared).
>>
>> Could you explain me a little bit better your idea with the triangles? I’m
>> quite afraid to not have understand it.
>>
>> My best regards,
>>
>> Philippe
>>
>>
>>
>> De : Wade Schuette [mailto:[hidden email]]
>> Envoyé : mardi 10 juillet 2012 18:50
>> À : [hidden email]
>> Cc : [hidden email]
>> Objet : Re: Contour map generation under ImageJ
>>
>>
>>
>> Philippe,
>>
>> This is really a 2-Dimensional curve-fitting (surface fitting) problem.
>>
>> I don't know the ImageJ libraries and whether something exists that
>> would work.   If not, you have to run some iterations and some math.
>> If math doesn't deter you, read on.
>>
>> The problem is under-defined, but probably workable.   I tried using
>> "Contour"
>> in the SAS product JMP, but it produced an ugly result with sharp corners.
>>
>> I think that, conceptually,  one way to tackle this is to think of it as
>> an open field with a number of telephone poles in it of different heights,
>>  and what you want to do is drape a somewhat stiff blanket over the field,
>>  constrained by the poles.
>>
>> That formulation still leaves three parameters unresolved,  the effective
>> stiffness of the blanket, the stretchiness of the blanket, and the
>> strength and direction of the force trying to make the blanket fit the
>> tops
>> of the poles.
>>
>> Or,  instead of weight to get a downward force on the blanket, you could
>> attach elastic bands to the blanket, tie the other end to the top of the
>> poles, and try to increase the strength of those bands, which is to say
>> lessen the discrepancy from your surface to the match points.
>> (statistically,  reduce r-squared discrepancies ).
>>
>> I could easily write a script to compute the up/down force on each point
>> on
>> the blanket,  move it one time interval, recompute, etc. if just
>> stretching
>> were involved, as that's just iterating for each point over the
>> neighboring
>> 4 points as if a spring were attached, with a force proportional to
>> stretch squared.     Adding mass to the point would make it a grid
>> of billiard-balls connected by springs, again straight-forward to
>> solve with iterations and probably cool to watch.
>>
>> But I'm trying to figure out the mathematics of STIFFNESS, without
>> which you'll end up with a very spiky landscape, instead of the
>> smooth one you envision.
>>
>> You won't know the parameters of "stiffness" and "stretchiness" to use,
>> but for what you're doing I suspect that any reasonable numbers would
>> work, and you can explore a little and see how sensitive the result is
>> to your choices of values.   You could find a set of parameters that
>> more or less matches the result in the web-page example you gave.
>>
>> Regardless, you'll end up with a complete image that you can then
>> make contours on ( just changeValues ( z-1, z, black) for z's you
>> want to see.), or use LUTS on, or both.
>>
>> I'm working on how to implement the stiffness of the 2-d blanket /
>> splines,
>> just for fun.
>>
>> A cruder way to do this is to just make a triangle from every combination
>> of 3 points such that no other point is included inside the triangles you
>> keep.
>> That basically covers the surface with connected triangles.
>>
>> Then each triangle lies in a completely determined PLANE , that
>> you can assign vertical values to based on the three corners.  Then
>> you can hand sketch from that,  or just "SMOOTH" it and
>> use that as your contour map.   Again that may be "good enough"
>> for whatever you need this for.
>>
>>
>> Wade
>>
>>
>>
>>
>>
>> On Tue, Jul 10, 2012 at 5:23 AM, Philippe CARL <[hidden email]>
>> wrote:
>>
>> Dear ImageJ Experts,
>>
>> What I want to do is to create a contour map, i.e. a picture (with height
>> *
>> width pixels) of values to which I can then apply different LUTs in order
>> to
>> look at my data.
>>
>> And what I have now are only the values of discrete positions within this
>> picture.
>>
>> Actually what I want to do is more or less what is described under the
>> following link:
>>
>> http://www.geomore.com/how-to-contour-a-map/
>>
>> And thus the question is how to generate the contour map, i.e. calculate
>> the
>> values of each pixel within the picture.
>>
>> Is there already an algorithm under ImageJ that is already doing such a
>> calculation?
>>
>> Alternatively, what kind of calculation or algorithm would you recommend
>> me
>> in order to calculate the values at each pixel?
>>
>> I thank you very much in advance for your answer and help.
>>
>> Best regards,
>>
>> Philippe
>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>>
>>
>>
>> --
>> R. Wade Schuette, CDP, MBA, MPH
>> 698 Monterey Ave
>> Morro Bay CA 93442
>> cell: 1 (734) 635-0508
>> fax:  1 (734) 864-0318
>> [hidden email]
>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
>
>
> --
> R. Wade Schuette, CDP, MBA, MPH
> 698 Monterey Ave
> Morro Bay CA 93442
> cell: 1 (734) 635-0508
> fax:  1 (734) 864-0318
> [hidden email]
>



--
R. Wade Schuette, CDP, MBA, MPH
698 Monterey Ave
Morro Bay CA 93442
cell: 1 (734) 635-0508
fax:  1 (734) 864-0318
[hidden email]

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

Re: Contour map generation under ImageJ

dscho
In reply to this post by CARL Philippe (LBP)
Hi Philippe,

On Tue, 10 Jul 2012, Philippe CARL wrote:

> What I want to do is to create a contour map, i.e. a picture (with height *
> width pixels) of values to which I can then apply different LUTs in order to
> look at my data.
>
> And what I have now are only the values of discrete positions within this
> picture.
>
> Actually what I want to do is more or less what is described under the
> following link:
>
> http://www.geomore.com/how-to-contour-a-map/
>
> And thus the question is how to generate the contour map, i.e. calculate the
> values of each pixel within the picture.
>
> Is there already an algorithm under ImageJ that is already doing such a
> calculation?
>
> Alternatively, what kind of calculation or algorithm would you recommend me
> in order to calculate the values at each pixel?

I gave this description a quick try and here is an alpha version of a
plugin that does what you want. Note: I say it is an alpha version not
because I have time to develop it further, but because the quality is not
where you need it in my opinion. But it could give you a good start.

One way that should work is to evolve the (spline fitted) curves to
minimize their bending energy. Another would be to use b-splines instead.

To play with it, launch the Fiji Script Editor (you need Fiji anyway since
I used the Delaunay package) via File>Script. Paste the following source
code, select Language>Java, the save with File Save and run with
Run>Compile and Run.

-- snipsnap --
import delaunay.DelaunayTriangulation;
import delaunay.Pnt;
import delaunay.Simplex;

import ij.IJ;
import ij.ImagePlus;

import ij.gui.Overlay;
import ij.gui.PointRoi;
import ij.gui.PolygonRoi;
import ij.gui.Roi;

import ij.plugin.PlugIn;
import ij.process.ImageProcessor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class Contour_Map_Alpha implements PlugIn {
        public void run(String arg) {
                int width = 352;
                int height = 350;
                /*
                 * The particles have been obtained by running this macro:
                 *
                 * run("URL...", "url=http://www.geomore.com/wp-content/uploads/2012/04/contouring-2.jpg");
                 * setAutoThreshold("Default");
                 * run("Set Measurements...", "  center redirect=None decimal=3");
                 * run("Analyze Particles...", "size=10-200 circularity=0.50-1.00 show=[Overlay Outlines] display clear");
                 *
                 * pasting the output into a text editor and manually adding the third column by inspecting the image
                 */
                String text =
                        "255.878 55.957 15\n" +
                        "175.417 96.545 40\n" +
                        "123.675 127.575 41\n" +
                        "71.996 90.606 12\n" +
                        "166.429 147.925 45\n" +
                        "105.840 212.245 35\n" +
                        "56.742 287.025 0\n" +
                        "196.202 206.658 32\n" +
                        "243.238 254.097 0\n" +
                        "249.982 158.868 38\n";
                Set<MyPnt> pnts = parseData(text);

                ImagePlus image = IJ.createImage("Interpolated", "32-bit black", width, height, 1);
                ImageProcessor ip = image.getProcessor();

                // Delaunay Triangulation
                Simplex tri = new Simplex(new MyPnt[] { new MyPnt(-10000, -10000, 0), new MyPnt(+10000, -10000, 0), new MyPnt(0, +100000, 0) });
                DelaunayTriangulation dt = new DelaunayTriangulation(tri);
                for (MyPnt pnt : pnts)
                        dt.delaunayPlace(pnt);

                Overlay overlay = new Overlay();
                for (double level = 39.5; level > 0; level -= 10) {
                        List<Roi> contour = getContourLine(dt, level);
                        for (Roi roi : contour)
                                overlay.add(roi);
                }
                image.setOverlay(overlay);
                ip.setMinAndMax(0, 255);
                image.setRoi(makePointRoi(pnts));
                image.show();
        }

        private static Set<MyPnt> parseData(String data) {
                Set<MyPnt> result = new LinkedHashSet<MyPnt>();
                for (String line : data.split("\\n")) {
                        String[] columns = line.split("[\\t ]+");
                        result.add(new MyPnt(Double.parseDouble(columns[0]),
                                Double.parseDouble(columns[1]),
                                Double.parseDouble(columns[2])));
                }
                return result;
        }

        private static List<Roi> getContourLine(DelaunayTriangulation dt, double level) {
                List<Roi> result = new ArrayList<Roi>();
                Set<MyEdge> done = new HashSet<MyEdge>();
                Iterator iter = dt.iterator();
                while (iter.hasNext()) {
                        Simplex simplex = (Simplex)iter.next();
                        MyPnt[] list = getPnts(simplex);
                        MyPnt a = null, b = null;
                        for (int i = 0; i < list.length; i++) {
                                int i2 = i > 0 ? i - 1 : list.length - 1;
                                double between = isBetween(list[i2], list[i], level);
                                if (between < 0)
                                        continue;
                                MyEdge edge = new MyEdge(list[i2], list[i]);
                                if (done.contains(edge))
                                        continue;
                                done.add(edge);
                                List<MyPnt> polygon = new ArrayList<MyPnt>();
                                polygon.add(list[i2].interpolate(list[i], between));
                                boolean closed = true;
                                if (!completePolygon(dt, level, simplex, polygon, edge, done)) {
                                        Collections.reverse(polygon);
                                        closed = completePolygon(dt, level, null, polygon, edge, done);
                                }
                                float[] x = new float[polygon.size()];
                                float[] y = new float[polygon.size()];
                                for (int j = 0; j < x.length; j++) {
                                        x[j] = (float)polygon.get(j).coord(0);
                                        y[j] = (float)polygon.get(j).coord(1);
                                }
                                PolygonRoi roi = new PolygonRoi(x, y, x.length, closed ? Roi.POLYGON : Roi.POLYLINE);
                                roi.fitSpline();
                                result.add(roi);
                        }
                }
                return result;
        }

        private static boolean completePolygon(DelaunayTriangulation dt, double level, Simplex simplex, List<MyPnt> polygon, MyEdge edge, Set<MyEdge> done) {
                outer:
                for (;;) {
                        simplex = getNeighboringSimplex(dt, simplex, edge);
                        if (simplex == null)
                                return false;
                        MyPnt[] list = getPnts(simplex);
                        for (int i = 0; i < list.length; i++) {
                                int i2 = i > 0 ? i - 1 : list.length - 1;
                                double between = isBetween(list[i2], list[i], level);
                                if (between < 0)
                                        continue;
                                MyEdge newEdge = new MyEdge(list[i2], list[i]);
                                if (edge.equals(newEdge))
                                        continue;
                                if (done.contains(newEdge))
                                        return true;
                                polygon.add(list[i2].interpolate(list[i], between));
                                edge = newEdge;
                                done.add(edge);
                                continue outer;
                        }
                        return false;
                }
        }

        private static double isBetween(MyPnt a, MyPnt b, double level) {
                if (a.value == b.value)
                        return -1;
                if (isOutside(a) || isOutside(b))
                        return -1;
                if (a.value == level || b.value == level)
                        level -= 1e-15;
                double result = (level - a.value) / (b.value - a.value);
                return result > 1 ? -result : result;
        }

        private static boolean isOutside(Pnt a) {
                return a.coord(0) < 0 || a.coord(1) < 0 || a.coord(0) >= 350 || a.coord(1) >= 350;
        }

        private static Simplex getNeighboringSimplex(DelaunayTriangulation dt, Simplex originalSimplex, MyEdge edge) {
                Iterator iter = dt.iterator();
                while (iter.hasNext()) {
                        Simplex simplex = (Simplex)iter.next();
                        if (simplex == originalSimplex)
                                continue;
                        if (simplex.contains(edge.a) && simplex.contains(edge.b))
                                return simplex;
                }
                return null;
        }

        private static MyPnt[] getPnts(Simplex simplex) {
                List<MyPnt> list = new ArrayList<MyPnt>();
                Iterator iter = simplex.iterator();
                while (iter.hasNext())
                        list.add((MyPnt)iter.next());
                return list.toArray(new MyPnt[list.size()]);
        }

        private static class MyEdge {
                private MyPnt a, b;

                public MyEdge(MyPnt a, MyPnt b) {
                        this.a = a;
                        this.b = b;
                }

                @Override
                public boolean equals(Object other) {
                        MyEdge o = (MyEdge)other;
                        return (a.equals(o.a) && b.equals(o.b)) || (a.equals(o.b) && b.equals(o.a));
                }

                @Override
                public int hashCode() {
                        return a.hashCode() ^ b.hashCode();
                }
        }

        private static class MyPnt extends Pnt {
                public double value;

                public MyPnt(double x, double y, double value) {
                        super(x, y);
                        this.value = value;
                }

                public MyPnt(double[] coords, double value) {
                        super(coords);
                        this.value = value;
                }

                public double distanceTo(Pnt other) {
                        return subtract(other).magnitude();
                }

                // t == 0 means this, t == 1 means other
                public MyPnt interpolate(MyPnt other, double t) {
                        int len = dimCheck(other);
                        double[] coords = new double[len];
                        for (int i = 0; i < len; i++)
                                coords[i] = coord(i) * (1 - t) + other.coord(i) * t;
                        return new MyPnt(coords, value * (1 - t) + other.value * t);
                }

                public String toString() {
                        return super.toString() + "(" + value + ")";
                }
        }

        private static PointRoi makePointRoi(Set<MyPnt> pnts) {
                int n = pnts.size();
                float[] x = new float[n];
                float[] y = new float[n];
                int counter = 0;
                for (MyPnt pnt : pnts) {
                        x[counter] = (float)pnt.coord(0);
                        y[counter++] = (float)pnt.coord(1);
                }
                return new PointRoi(x, y, n);
        }
}

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

Re: Contour map generation under ImageJ

CARL Philippe (LBP)
Dear Johannes and Wade,

I thank you very much for sharing your ideas and code.

I will make a brainstorming of all this (and hope I will be able understand
all your code Johannes) to get a good solution for this issue.

And Johannes since you are one of the main author of Fiji (which I'm
actually using) I would have a (maybe silly) question to ask you.

I use the scripting window of Fiji in order to write my plugins and when you
execute a plugin for the first timed within Fiji it gets correctly executed
(if the code has no error of course).

But if you modify then the code and hit the "Run" button the new code gets
only correctly checked for errors, but on launching it is still the old code
that gets executed until "Help->Refresh Menus" has been pressed.

Is this a bug or can this be overcome in a way?

Of course, the instruction "Help->Refresh Menus" can be simplified by
defining a Shortcut on a hotkey (like for example F1), but it is still very
constraining.

I thank you very much fir your answer and suggestions.

My best regards,

Philippe


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

Re: Contour map generation under ImageJ

dscho
Hi Philippe,

On Fri, 13 Jul 2012, Philippe CARL wrote:

> I use the scripting window of Fiji in order to write my plugins and when you
> execute a plugin for the first timed within Fiji it gets correctly executed
> (if the code has no error of course).
>
> But if you modify then the code and hit the "Run" button the new code gets
> only correctly checked for errors, but on launching it is still the old code
> that gets executed until "Help->Refresh Menus" has been pressed.

This did not happen for me, I developed the class exclusively in the
Script Editor and never had to hit Help>Refresh Menus.

Just a hunch: Is it possible that you saved the .java file into
<ImageJ-Directory>/plugins/? If so, is the issue fixed by moving it (along
with the corresponding .class files) out of the ImageJ directory?

Ciao,
Johannes

P.S.: I do not want to shift this issue to the fiji-devel mailing list
because it is of the greater interest of the ImageJ community.

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

Re: Contour map generation under ImageJ

CARL Philippe (LBP)
Hi Johannes

 

Just a hunch: Is it possible that you saved the .java file into
<ImageJ-Directory>/plugins/? If so, is the issue fixed by moving it (along
with the corresponding .class files) out of the ImageJ directory?

 

You are completely right since not only I the plugin was saved in the
<ImageJ-Directory>/plugins/ folder, but also the issue was solved by moving
the whole folder with the .java file and all its libraries out of the
/plugins/ folder.

So I guess that a plugin under development shouldn't thus be saved in the
<ImageJ-Directory>/plugins/ folder.

I wasn't aware of that and I agree that this information may indeed of the
greater interest of the ImageJ community.

 

Besides that, I needed (for the plugin that I'm still working on right now)
the extension of the Plot and PlotWindow classes for functionalities towards
accepting ArrayList data input and allowing to display arrow plots (similar
to the quiver in Matlab), logarithmic (log in x and/or y) plots, minor ticks
(decimal and logarithmic), change of the label font and draw dotted lines.

May these extensions be of any interest for the community, and if yes where
should I upload the files?

 

Best regards,

 

Philippe


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