-
Notifications
You must be signed in to change notification settings - Fork 24
Fourier Ring/Shell Correlation module #634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
|
I noticed now that there are two types of apodization in 3D:
Do we need to keep both? If so, we need to implement three different kinds of apodization, the two I mentioned above and the one for the 2D images only. |
ptypy/utils/metrics.py
Outdated
| window1D2 = hanning_like_window(nr, apod_width) | ||
| window1D3 = hanning_like_window(nc, apod_width) | ||
|
|
||
| windowaxial = np.outer(window1D2, window1D3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use two nested outer products here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I did it wrong, but in my case, it did not work. Could you make a quick draft of what you meant, please?
|
|
||
| # Apodization of the borders | ||
| window = apodization(input1, apod_width) | ||
| img1_apod = input1 * window |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The input images probably aren't "whitened". Here, multiplying with a window sends the edge values to 0. I think that artifacts would be reduced if we use instead img1_apod = window * (input1 - input1.mean()) + input1.mean().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Supposing I understood your remark well, the idea of the implemented apodization here was to transition slowly to 0 at the edges, thereby avoiding a sharp transition. If the edge values are not truly zero, given that the discrete FFTs produce numerous replicas around, you may end up with the classical (input) x (rect function), leading to artifacts when implementing the discrete FFTs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks. Now I see what you meant. Well, the apodization steps are now coded in independent auxiliary functions. Therefore, we can easily change them to play with different approaches without having to rewrite the main code. One could try to do what you said.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one question: you mentioned earlier the idea of doing img1_apod = window * (input1 - input1.mean()) + input1.mean(). But, I noticed you still use the function window, which will bring the values to zero at the borders. If I understand correctly, we are supposed to remove the window from the multiplication, and do only img1_apod = (input1 - input1.mean()) + input1.mean(), right? Or would you happen to have another window function in mind? Or, by window, you mean the natural windowing (selecting the region within the Nyquist frequency range) we do when performing the discrete FFTs ?
ptypy/utils/metrics.py
Outdated
|
|
||
| print("Calculating the correlation...") | ||
| index = ringthickness(F1) # indexes for the ring thickness | ||
| for ii in range(len(f)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a way to make this faster using numpy's digitize and bincount. I have an example code I can show you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be happy to review your example code, which could save me time if I were to do it myself. Does the bincount work in both 2D and 3D arrays?
|
I made a couple of changes in the apodization functions, given their importance. You can see the commit 22e8129 I think we could merge |
|
Just in case this can be of interest, I've just found out that |
|
There are now two functions, |
|
Just a few comments for cleaning up at the end. We should move any example code/notebooks into the |
ptypy/utils/metrics.py
Outdated
| def fouriercorr_plot(FRC, T, fn, plot_name): | ||
| """ | ||
| Routine to plot the FRC curves | ||
|
|
||
| Parameters | ||
| ---------- | ||
| FRC : array-like | ||
| 1D array containing the FRC values | ||
|
|
||
| T : array-like | ||
| 1D array containing the 1-bit threshold | ||
|
|
||
| fn : array-like | ||
| 1D array containing the normalized frequencies | ||
| """ | ||
|
|
||
| plt.figure() | ||
| plt.clf() | ||
| plt.plot(fn, FRC.real, "-b", label="FRC") | ||
| plt.plot(fn, T, "--r", label="1 bit threshold") | ||
| plt.legend() | ||
| plt.xlim(0, 1) | ||
| plt.ylim(0, 1.1) | ||
| plt.xlabel("Spatial frequency/Nyquist [normalized units]") | ||
| plt.ylabel("Magnitude [normalized units]") | ||
| plt.show() | ||
| plt.savefig(plot_name) | ||
| return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove this from the module, can instead show how to plot in the example notebooks. Should also remove the matplotlib import consequently
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just removed the plotting part and the matplotlib import.
|
I removed the dependence on matplotlib and the plotting section. I also adjusted the docstring style in One crucial point is that the user needs the pixel value so that dividing it by the intersection value allows for an estimate of the spatial resolution. At any point in the FSC/FRC calculations, we are inputting the pixel size. Will |
…n compute_intersection to match the style typically used in ptypy

This is a clean starting point based on the initial draft #606 for FRC calculation from @jcesardasilva and additional code added for FSC calculation by @Letizia97 (see also #605)
TODO
metrics.pywith two main FRC/FSC functions at the top and all utiliy functions below (@jcesardasilva )