
Fit concentric rings

maru
Hi,
I would like to fit a 2D gray scale image with concentric rings and get the radii and center of these rings. The radii of these rings are in a ratio of 1:2:3.
This 2D image is hard to be converted to a binary image with rings.
I found that the 2D Gauss fit and polygonal fit work on the gray scale images without converting them to binary images.
How can I build a fit function of 3 concentric circles to fit my image?
The gray scale image is attached as a text file.


Forum

Support

Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More
I loaded the text file you linked in your message; it is not at all like the image you posted. I have attached an image of the loaded data. It looks like in the process of saving the text file the data was clipped. You may be able to load the image data you posted directly without converting to a text file.
Without being able to see the form of the rings, it's hard to say how to write a fitting function for that data. Once you manage to get the image data into Igor intact, I would use Image->Line Profile to inspect the form of the rings to guide the search for a suitable fitting function.
If you can describe where this image is from, it may be that someone familiar with similar data may have more targeted advice.
June 13, 2019 at 10:08 am - Permalink
FWIW I could import the data and (after contrast adjustment) see the rings.
June 13, 2019 at 12:48 pm - Permalink
OK, sjr51- you win this time :)
After taking the log of the data (and ignoring NaNs from log(0)) I stand corrected.
And now- using Rainbow color table and reversing the colors the rings are definitely there.
If you do a line profile over the image you can see the shapes of the peaks- they look rather Lorentzian. They have pretty sharp tops and long tails. The middle and the saturation of the sides of the middle will complicate things a bit.
June 13, 2019 at 03:07 pm - Permalink
Are the variations in theta important? Or only the radial variation?
June 13, 2019 at 03:26 pm - Permalink
I am going to go out on a limb and hazard a guess: the most important variation is radial (this is some type of radially averaged diffraction pattern ... perhaps TEM or scattering or ... ???). In this case, I would find the center of the image, make a radial slice through it, and fit the resulting line profile. As the next step, I would slice a few radial lines, average them, and improve the S/N for fitting. As the final step, I would take an 360 degree rotation around the center, sum all slices for the best S/N, and fit that resulting profile.
When the theta variation is also important, I might start with the radial slice as the guess in the radial parameters, hold those constant, and fit a 3-D profile that includes only the theta variation. But ... Dealing with the interruptions from the grid lines will be a real PITA in this case.
June 13, 2019 at 04:17 pm - Permalink
In reply to Are the variations in theta… by johnweeks
Thanks for helping.
Theta is not important but the concentric circles could be ellipses sometimes.
June 13, 2019 at 05:02 pm - Permalink
I see that the grid lines are places where the image has Z value of -1. You can deal with the grid lines by creating a mask wave for the fit the masks out any place in the image that has a negative number:
Getting a function that will fit the radial profile may be a way to get started. Do you have any notion of a function that describes your rings?
Elliptical rings would make it more complicated but not by a lot.
June 13, 2019 at 05:09 pm - Permalink
In reply to I am going to go out on a… by jjweimer
Thanks for explaining the background. You guess is correct. The image is a 2D scattering pattern from a standard chemical compound. I need to know the center and radii of these rings to perform a series of other reduction process.
The problem is
1. the rings are not always circles, they could be ellipses.
2. the center sometimes outside the image.
3. and there are always grid lines (value = -1 or -2) that are the space between detector panels.
I have tried to make a dummy binary image with rings (in ring value = 1, out ring value = 0) and multiplied to the image I posted. The sum of the multiplied image will be a value showing the similarity between the dummy and real one.
Then, I change the radii and center of the dummy image and repeat the multiplication and sum process to find the biggest value, which should correspond to the most similar dummy image. However, this takes really a lot of time.
I hope that I can use fit functions or other better techniques to get the radii and center.
June 13, 2019 at 05:28 pm - Permalink
In reply to I see that the grid lines… by johnweeks
I have used for-loops to create the mask before. Your codes are really nice.
The fit function I want to use is attached. The rings have the same center and different radii.
June 13, 2019 at 05:49 pm - Permalink
My approach to fully automate this would be to pick the center of the image as a starting guess for the center of the circles. I would then extract a radial profile from that and use that radial profile to recreate the image. You can now use the difference between the real image and the recreated image to write a fit function and find the center of the circles and the radial profile, see the code below.
The nice thing about this approach is that you don't need to assume anything about your peak shapes, only that you have circular symmetry. You can then fit your peaks to the radial profile instead.
For my code to work your image has to be root:RawImage. The data should have no X or Y scaling.
The code only works with circular symmetry, but I'm sure you can add an extra fit parameter to make it work for ellipses as well.
Run CreateGraphs() first to display the data and then FindRadialCenter() to extract the radial profile and find the center of the circles.
Your raw data is full of NaNs and +/-INFs so CreateGraphs() first extrapolates what those values should be based on the nearest valid data points. The data before and after the correction will be displayed by CreateGraphs() together with the radial profile and the recreated image based on the radial profile.
Expect CreateGraphs() to take 10-20 seconds and FindRadialCenter() to take several minutes. I'm sure the code can be optimized, but I didn't care about that.
June 14, 2019 at 05:33 am - Permalink
In reply to My approach to fully… by olelytken
Thank you olelytken. I have run your procedure but could not get the center. Please find the attached image.
June 14, 2019 at 06:02 am - Permalink
Could you do better to guess/find the image center this way ...
* Sum the rows and find the maximum in the 1-D wave
* Sum the columns and find the maximum in the 1-D wave
June 14, 2019 at 06:38 am - Permalink
I just downloaded the code on my home computer and it works fine. I suspect it is a version issue. I'm still using the old Igor 6.37.
I have attached a pxp file with the result. Try to open that.
I think jjweimer's suggestion about a better starting guess for the center is great.
June 14, 2019 at 06:45 am - Permalink
Here is a screenshot of the result
June 14, 2019 at 06:58 am - Permalink
When I compare your screen shot and my screen shot, the difference is that in your screen shot the grid lines was not removed properly in the top right image.
In the data I have from you the grid lines have a value of -1 in the original data. When I take the logarithm of that I get NaN. My procedure therefore assumes the grid lines are all NaN.
Check your values. Is the value of the grid lines in your original data -1? Is the value of the grid lines NaN after you take the logarithm? (top left image in your screen shot)
June 17, 2019 at 12:52 am - Permalink
In reply to When I compare you screen… by olelytken
Thank you very much for explanation. Your procedure works now in my environment, Igor 8!
June 17, 2019 at 05:29 am - Permalink
The better way to deal with the grid lines is probably to use masks as suggested by johnweeks, but I didn't have time to experiment with that. It would also be nice to have a better starting guess for the center. jjweimer's suggestion is great if the center is inside the image, but I don't know what you could do if the center is outside the image.
June 17, 2019 at 09:10 am - Permalink
In reply to The better way to deal with… by olelytken
Thanks a lot for considering my issue. Is there any technique that I can extract the peak position (X,Y) of the rings into X and Y waves. If this is possible, I think I can simply fit the rings using the implicit ellipse fit functions to get the center and radii, even in the case that the center is outside the image.
June 18, 2019 at 07:09 pm - Permalink
I think what you are asking for is the Extract/INDX command. You can use that to extract the positions of all pixels with a value above a certain threshold. Once you have the index it is relatively simple to convert that into X and Y positions. You will need to somehow add a second criteria to the Extract command to avoid always picking up the intense pixels in the center. Maybe something based on the distance to the center?
June 19, 2019 at 01:39 am - Permalink
In reply to I think what you are asking… by olelytken
Thank you for the advice.
I have used FindPeak to scan the image and used a criteria based on the distance to the center and successfully extracted the X-Y coordinates of each ring!
June 20, 2019 at 12:16 am - Permalink
Now, I would like to fit the three rings simultaneously using ellipse functions with center positions as shared parameters.
I found that there is a package named Global fit and I went through the demo experiment.
However, I could not understand how to implement the function into my procedure.
Does anyone know how to do that? The data of the rings are attached.
June 20, 2019 at 12:31 am - Permalink
If the global fit cannot solve implicit function, can I use Optimize or some other functions to achieve the fit?
June 20, 2019 at 01:43 am - Permalink
Global Fit does not, in fact, support implicit functions or functions with more than one independent variable. To use Optimize you would have to write a merit function that computes something like chi-square for your system, and then optimize that function.
I haven't been following this thread sufficiently closely to know what data you are getting out at the end- is it x,y pairs describing where points fall on each ring? If so, you would need an implicit fit.
But if you know a reasonable functional form for the Z values of the rings, you could write a fitting function with two independent variables. From an x,y pair of input independent variable values, you can compute a radius and angle from x0,y0 describing the center. The center coordinates x0,y0 can be fit coefficients, too. Then using the radius and angle you can compute a Z value.
June 20, 2019 at 03:22 pm - Permalink
In reply to Global Fit does not, in fact… by johnweeks
They are x,y pairs describing where points fall on each ring.
I did not understand your suggestion from the Z-values part. Do Z values mean the complex values showing the position of points on the rings? Is this a suggestion about how to make a merit function for Optimize?
June 20, 2019 at 04:22 pm - Permalink
Hi,
I took a stab at it using an alternative technique to solve implicit functions.
First I concatenate the waves with a single ringX and single RingY. Then Create a wave ringID that maps to which ring the point corresponds 1,2, or 3.
I write an equation
r*ringID = sqrt((RingX-x0)^2 + (RingY-yo)^2
Next I create a dummy wave, dummy and set all the points to zero,(0).
dummy =sqrt((RingX-x0)^2 + (RingY-yo)^2 -r*ringID
I create fit function to fit the dummy wave with 3 input values, X,Y, and ID. and solve for x0,y0, and r.
It does fit and the values make sense. It assumes that the ratio is fixed and defined and the points can be assigned to the rings.
The experiment is attached. It could be expanded to handle ellipse (this is left to the reader. grin)
Andy
June 20, 2019 at 06:21 pm - Permalink
In reply to Hi, I took a stab at it… by hegedus
This is wonderful! It works perfectly and I could expand this to ellipse.
I have a few question about this fit technique.
1. This fit technique does not look like an implicit fit but it can handle implicit functions and even do something similar to a global fit. Why do we need an implicit fit or global fit if we can use this fit technique?
2. In your Igor experiment file, I found a few fit trials that gave not very satisfactory results. Is there anything I have to care to avoid the bad fits?
June 20, 2019 at 10:07 pm - Permalink
Hi,
It does NOT use implicit fits, using the dummy wave technique as proxy was my way to avoid it. I had developed this technique before I had learned about implicit fitting. It also seems more straight forward and expandable for me.
The earlier fits where troubleshooting of fitfunc. I had an error in it initially, w[2]/X3, instead of w[2]*X3. When I first tested the fit and did not get meaningful answers, I worked some ideas before finding error.
Andy
June 21, 2019 at 06:19 am - Permalink
In reply to Hi, It does NOT use… by hegedus
I got it now. Thanks.
June 23, 2019 at 04:30 pm - Permalink