Closed askaradeniz closed 3 years ago
After reading this paper that you have shared earlier. I believe . Commit a34bd62d9100bb90f248e098e56d1bd45265d2e7 enables the key word IR Fresnel
, which stands for impulse response Fresnel propagation is the same as Angular spectrum
methodAngular Spectrum
for propagation type string.
Bandlimited angular spectrum
method takes the fourier transform of an impulse response in the Angular Spectrum
method, and multiplies it with a mask that low passes frequencies. The cut-off for that low pass operation is a function of wavelength and hologram size and calculated using Equation 13 in their paper. I have also added an implementation of Bandlimited angular spectrum
method for wave
. With da947041fa7509924b858bb5146867b401d4987e, you should now be able to use the key word Bandlimited Angular Spectrum
while using odak.wave.propagate_beam()
definition.
@askaradeniz may I kindly ask you to verify if this is providing a better result for your example? If so, we should together plan on migrating that to learn
submodule. But first we have to verify. As a reminder, in the test
folder, there is a test script called test_beam_propagation.py
, I left a commented line there for you to switch to this new beam propagation method in case you want to use that test script.
Also thanks to @praneethc as he verified my understanding of the paper.
@kunguz Thank you very much for your time. It works nice when I try the example test case in test_beam_propagation.py
.
However, I am having some trouble with obtaining results for images. These are the results:
IR Fresnel
Bandlimited IR Fresnel
This is the code I used for the image example:
from odak import np
from odak.wave import wavenumber, calculate_amplitude
from odak.tools import load_image, resize_image
import cv2
from skimage.measure import compare_psnr
from odak.wave import propagate_beam
## Load image.
im = load_image("data/0103.png")
if np.__name__ == 'numpy':
im = np.float64(im/255.)
else:
im = im/255.
im = im[:,:, 0]
im = im[:512,:512]
## Construct field.
field = np.zeros((im.shape[0],im.shape[1]),dtype=np.complex64)
field[:,:] = im[:,:]
#random_phase = np.pi*np.random.random(field.shape)
random_phase = 0
field = field*np.cos(random_phase) + 1j*field*np.sin(random_phase)
## Prop. variables.
#propagation_type = "Bandlimited IR Fresnel"
propagation_type = "IR Fresnel"
wavelength = 0.5*pow(10,-6)
pixeltom = 6*pow(10,-6)
distance = 0.2
k = wavenumber(wavelength)
## propagate to slm plane.
hologram = propagate_beam(field,k,distance,pixeltom,wavelength,propagation_type)
## propagate to image plane.
reconstruction = propagate_beam(hologram,k,-distance,pixeltom,wavelength,propagation_type)
reconstruction_amplitude = calculate_amplitude(reconstruction)
ratio = (np.sum(reconstruction_amplitude * im, (-2, -1))
/ np.sum(reconstruction_amplitude * reconstruction_amplitude, (-2, -1)))
reconstruction_amplitude *= ratio
reconstruction_amplitude = np.clip(reconstruction_amplitude, 0, 1)
print(compare_psnr(im, reconstruction_amplitude))
reconstruction_amplitude = np.uint8(reconstruction_amplitude*255)
cv2.namedWindow("recon_amp", cv2.WINDOW_NORMAL)
cv2.imshow("recon_amp", reconstruction_amplitude)
cv2.namedWindow("target_amp", cv2.WINDOW_NORMAL)
cv2.imshow("target_amp", im)
cv2.waitKey(0)
Can you please rerun your code using 1021a28cc869822e5b6d4e3702fb3d609f586117?
Hopefully you will get this with bandlimiting: and this is without bandlimiting:
It works great!
Using the above code with distance=0.1
, I got the following results.
IR Fresnel
Bandlimited IR Fresnel
This is encouraging. I am trying to invite one person to translate this piece of code from odak.wave
to odak.learn
. Before we proceed any further, let's wait for that person to reply. She may be able to able to assist us (@praneethc knows about this person). But if you think we can port it super quick in 5 mins, let's do that --which I believe we can using the same amount of time that I dedicated to write this reply :) --. This heavily depends on your need at this point, so it is your call. We can either wait or you (@askaradeniz) can port.
Okay, I think we can wait for the reply while I work on the other issues.
On a second note, Angular spectrum
and Impulse Response
methods for beam propagation are different. Previously, I stated that they are the same, this is wrong. I checked the kernel in Computational Fourier Optics
book by David Voelz, Impulse response slightly differs. Later, I saw that this paper also identifies them as two separate papers.
This commit bcfce8c2667a7553ae404615661df354acba67e1 introduces two separate keys for propagation_type
for the odak.wave.propagate_beam
definition. These are Angular Spectrum
and IR Fresnel
.
I wrote the pytorch version of the band-limited angular spectrum function and created a pull request to #14 .....
Thanks @rongduo , I will now go ahead and merge your version
With b674184480a2a95cbb6925a3228f774daef182f0, I confirm that the test/test_learn_propagate_beam.py
returns a meaningful outcome, thanks to @rongduo and @askaradeniz .
Input field: Propagated field: Backpropagated field:
It looks like we get different results from torch and numpy versions of Bandlimited Angular Spectrum
method (https://github.com/kunguz/odak/commit/6a7470798b401d4934522ec7ebddc78d2c3b2e38).
This is an example output of compare
function written in test_learn_beam_propagation.py
:
Mismatched elements: 250000 / 250000 (100%)
Max absolute difference: 394.44279377
Max relative difference: 474.19269395
x: array([[-61.937 +89.58j , 32.14 -102.063j, 36.588 +44.577j, ...,
78.629 +52.555j, -75.779 -20.299j, 63.486 -35.612j],
[ 54.121 +19.182j, -27.26 +16.655j, -59.53 -9.736j, ...,...
y: array([[ -6.57 +296.346j, -105.022-301.575j, 261.531+215.636j, ...,
-11.587 -8.539j, -43.761 +84.96j , 55.72 -199.442j],
[ -24.799-185.679j, 118.832+198.915j, -265.152-154.982j, ...,...
Looks like we need help here. @askaradeniz are you available to revise the code and identify the origin of this difference?
If I'm not missing something, the only difference I noticed are these two lines: https://github.com/kunguz/odak/blob/6a7470798b401d4934522ec7ebddc78d2c3b2e38/odak/wave/classical.py#L48 https://github.com/kunguz/odak/blob/6a7470798b401d4934522ec7ebddc78d2c3b2e38/odak/learn/wave/classical.py#L44 I tried to change this line but the results still do not match.
That is a good catch. Let me rephrase this once again as I created new definitions to avoid a stand-alone beam_propagation code with tons of code.
So here is the latest and greatest for h in the band-limited angular spectrum method:
We need two things here, one is to migrate to the same h in the odak.learn.wave
submodule. Plus, we need to move band-limited-angular-spectrum method to a definition just as in odak.wave
:
https://github.com/kunguz/odak/blob/4304e956809188694ce74d00d3f54b42e3e8cf24/odak/wave/classical.py#L82-L119
and we need to reflect that change to the if statement in odak.learn.wave
by following odak.wave
again:
https://github.com/kunguz/odak/blob/4304e956809188694ce74d00d3f54b42e3e8cf24/odak/wave/classical.py#L35-L36
@rongduo do you have availability for us to help fix this so that we get the same result from both in odak.wave
and odak.learn.wave
? Thanks!
I have recently merged @rongduo 's update by rebasing. Torch implementation still does not match with numpy/cupy implementation. But the absolute difference decreased from 300s to 15. The bottleneck here is slight differences in odak.learn.wave.set_amplitude
and torch's ffts. @askaradeniz I will close this issue, but before I do that, please verify if this produces decent holograms at your end.
Current:
Mismatched elements: 250000 / 250000 (100%)
Max absolute difference: 14.61796575
Max relative difference: 104.98545789
x: array([[-233.767+825.579j, 403.702-631.955j, -13.526-349.845j, ...,
-316.94 +131.304j, -120.413 +29.046j, 431.921-208.002j],
[ 595.648+113.056j, 88.465-388.643j, 146.171-622.236j, ...,...
y: array([[-232.49 +8.239e+02j, 400.054-6.306e+02j, -10.546-3.497e+02j,
..., -318.999+1.294e+02j, -114.324+2.835e+01j,
429.296-2.082e+02j],...
Previous
Mismatched elements: 250000 / 250000 (100%)
Max absolute difference: 394.44279377
Max relative difference: 474.19269395
x: array([[-61.937 +89.58j , 32.14 -102.063j, 36.588 +44.577j, ...,
78.629 +52.555j, -75.779 -20.299j, 63.486 -35.612j],
[ 54.121 +19.182j, -27.26 +16.655j, -59.53 -9.736j, ...,...
y: array([[ -6.57 +296.346j, -105.022-301.575j, 261.531+215.636j, ...,
-11.587 -8.539j, -43.761 +84.96j , 55.72 -199.442j],
[ -24.799-185.679j, 118.832+198.915j, -265.152-154.982j, ...,...
It works well. Thanks @kunguz and @rongduo .
It would be good if we had an alternative beam propagation method in
wave
andlearn
submodules.Band-Limited Angular Spectrum Method
is described in this paper and also discussed in here. It seems to work well with practical applications.