LaurentRDC / scikit-ued

Collection of algorithms and routines for (ultrafast) electron diffraction and scattering
http://scikit-ued.readthedocs.io
GNU General Public License v3.0
134 stars 20 forks source link

Autocenter very inconsistent #45

Closed OliDG closed 4 months ago

OliDG commented 4 months ago

Version / Platform Info

Expected Behavior

autocenter() would find the center of the DP without hesitation

Actual Behavior

autocenter() fails to find the center of poly crystalline DP. tried with several DP of different quality, seems very random and unfortunately not reliable.

Explain what actually happens when the code is run.

Minimal Example of Issue

Create a mask using the shape of the beam stopper run the autocenter() center clearly not at the center

"Mask*DP" shows the masked DP that I expect to be processed via the autocenter() image


from skued import diffread, autocenter
from skued import nfold
import numpy as np
from pathlib import Path
import os.path
import matplotlib.pyplot as plt

[...]
rc, cc = autocenter(im, mask=mask)

av = nfold(im, mod = 18, center = [cc,rc])# ,mask = mask)
overlap_mask_im = im * mask
inv_mask = im * np.invert(mask)

fig, (ax1,ax2,ax3,ax4) = plt.subplots(1,4,figsize = (10, 4))
ax1.imshow(im, cmap='inferno')
ax1.scatter(cc, rc, color='r')
ax1.set_title('DP center point')
#ax1.get_xaxis().set_visible(False)
#ax1.get_yaxis().set_visible(False)

ax2.imshow(overlap_mask_im, cmap='inferno')
ax2.set_title('Mask*DP')

ax3.imshow(inv_mask, cmap='inferno')
ax3.set_title('Signal masked')

ax4.imshow(av, cmap='inferno')
ax4.set_title('Rot average')

plt.tight_layout()
plt.show()```

Regards,
Olivier
LaurentRDC commented 4 months ago

Hey Olivier,

That looks very strange.

Would you be willing to send the diffraction intensity and mask data you used in the plots above? You can do so here: laurent.renedecotret@mail.mcgill.ca

OliDG commented 4 months ago

diffraction.zip here are 2 datasets that look clean to me, having a different mask (plain large rectangle) changes radically the outcome, but is also not quite consistent... i am puzzled.

\Olivier

OliDG commented 4 months ago

I have been trying different masking and digging the method to understand what are the conditions for it to work, and I realize that even the example you give fails to get the center... sorry for the bad news...

image

LaurentRDC commented 4 months ago

the example you give fails to get the center... sorry for the bad news...

That's a dramatic statement. A method (without free parameters!) getting very close is not a failure, in the same way that a 98% grade on a test isn't a failure.

Is it perfect? Manifestly not. You can read this blog post to get some explanation about how it works. In short: any asymmetry in the diffraction patterns that are NOT diffraction signals will skew the results. For example, for the detectors I have used in the past, various subpixel arrays had different response functions that made parts of the diffraction patterns brighter or dimmer.

We have successfully used autocenter to quickly measure the shift between short-exposure diffraction patterns, and then detect the exact shift using another method described here. This has sped up our data processing pipeline by a factor of ~70x.

I will look at the data you provided and see if there is another problem going on.

LaurentRDC commented 4 months ago

I have found the problem: this line

The diffraction pattern is pre-processed to remove possible asymmetries in the background intensity. Removing this line gives the following results for your data:

image

I will make this pre-processing step optional, but I will not remove it to preserve backwards-compatibility.

LaurentRDC commented 4 months ago

A new version of scikit-ued (2.1.16) was just released.

With it, you can disable background normalization like so:

import matplotlib.pyplot as plt
from skimage.io import imread

from skued import autocenter

im = imread("0958_original.png", as_gray=True)
mask = imread("0958_mask.png", as_gray=True).astype(bool)

r, c = autocenter(im=im, mask=mask, normalize_bg=False)

fig, ax1 = plt.subplots(1, 1)

ax1.imshow(im * mask.astype(float))

ax1.scatter(c, r, color="r")
ax1.axhline(y=r, linestyle="dashed", linewidth=1, color="w")
ax1.axvline(x=c, linestyle="dashed", linewidth=1, color="w")

plt.show()

which gives the results you see in my previous comment.

Feel free to re-open this issue if things aren't working.

OliDG commented 4 months ago

Hi Laurent,

That was a quick fix! thanks! I need to temper the "fail to get the center" and I must even apologize. Somehow I was conviced that the result should be pixel precise (probably reading too much stuff in parallel..) and missed the point of your code: speed. Sorry for the unecessary report I made.

Thanks for the answer and the optional argument you implemented.

LaurentRDC commented 4 months ago

It was my pleasure to help. Do not hesitate to report other issues you encounter as you use this software

OliDG commented 4 months ago

:D I encounter the sentence that was stuck to my mind (https://laurentrdc.xyz/posts/autocenter.html): " We can put the two steps together and determine a pixel-perfect center: "

but the apologies can stay as all the rest says otherwise. Here is the docstring "determines the correction to the approximate center found by calculating" .)

Thanks again.

LaurentRDC commented 4 months ago

That is a fair point, and clearly it is not pixel perfect. I have updated my blog.