Niccko commited on
Commit
c7180e6
·
1 Parent(s): 1fa7db9
Files changed (3) hide show
  1. app.py +10 -1
  2. fraunhofer_test.py +48 -33
  3. zern_generator.py +26 -0
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import gradio as gr
2
  from zern_generator import generate_zern_wavefront_fig, generate_batch
 
3
 
4
  css = """
5
  .container {
@@ -31,7 +32,9 @@ with gr.Blocks(theme=theme, css=css) as demo:
31
 
32
  resolution_num = gr.Number(value=256, label="Разрешение")
33
  num_zernikes = gr.Number(label="Количество коэффициентов Цернике", value=2, interactive=True)
 
34
  sliders_container = gr.Column(elem_classes=["container"])
 
35
  # file_inp.upload(get_zern_from_file, inputs=[file_inp], outputs=[*sliders_container.children])
36
 
37
 
@@ -56,19 +59,25 @@ with gr.Blocks(theme=theme, css=css) as demo:
56
  with gr.Tab(label="3D"):
57
  plot_3d = gr.Plot()
58
  with gr.Tab(label="Batch"):
59
-
60
  plot_batch = gr.Plot(label="Тестовые экраны (NOLL scheme)")
 
 
61
 
62
  with gr.Row():
63
  btn = gr.Button("Рассчитать")
64
  btn_batch = gr.Button("Рассчитать тестовые экраны")
 
65
 
66
 
67
  def on_button_click(resolution):
68
  return generate_zern_wavefront_fig(resolution, *[zerns[key] for key in sorted(zerns)])
 
 
 
69
 
70
 
71
  btn.click(on_button_click, inputs=[resolution_num], outputs=[plot_2d, plot_3d])
72
  btn_batch.click(generate_batch, inputs=[resolution_num], outputs=[plot_batch])
 
73
 
74
  demo.launch()
 
1
  import gradio as gr
2
  from zern_generator import generate_zern_wavefront_fig, generate_batch
3
+ from fraunhofer_test import generate_diff
4
 
5
  css = """
6
  .container {
 
32
 
33
  resolution_num = gr.Number(value=256, label="Разрешение")
34
  num_zernikes = gr.Number(label="Количество коэффициентов Цернике", value=2, interactive=True)
35
+ defocus_amt = gr.Number(label="Величина дефокуса", value=2, interactive=True)
36
  sliders_container = gr.Column(elem_classes=["container"])
37
+
38
  # file_inp.upload(get_zern_from_file, inputs=[file_inp], outputs=[*sliders_container.children])
39
 
40
 
 
59
  with gr.Tab(label="3D"):
60
  plot_3d = gr.Plot()
61
  with gr.Tab(label="Batch"):
 
62
  plot_batch = gr.Plot(label="Тестовые экраны (NOLL scheme)")
63
+ with gr.Tab(label="Diff"):
64
+ plot_diff = gr.Plot(label="Разница в фокусе")
65
 
66
  with gr.Row():
67
  btn = gr.Button("Рассчитать")
68
  btn_batch = gr.Button("Рассчитать тестовые экраны")
69
+ btn_diff = gr.Button("Рассчитать разницу в фокусе")
70
 
71
 
72
  def on_button_click(resolution):
73
  return generate_zern_wavefront_fig(resolution, *[zerns[key] for key in sorted(zerns)])
74
+
75
+ def on_diff_button_click(defocus_amount):
76
+ return generate_diff(defocus_amount, *[zerns[key] for key in sorted(zerns)])
77
 
78
 
79
  btn.click(on_button_click, inputs=[resolution_num], outputs=[plot_2d, plot_3d])
80
  btn_batch.click(generate_batch, inputs=[resolution_num], outputs=[plot_batch])
81
+ btn_diff.click(on_diff_button_click, inputs=[defocus_amt], outputs=[plot_diff])
82
 
83
  demo.launch()
fraunhofer_test.py CHANGED
@@ -13,58 +13,73 @@ from multiprocessing import Pool
13
  from zern_generator import generate_zern_wavefront
14
  from scipy.ndimage import zoom
15
 
16
- fig, axs = plt.subplots(2, 2)
17
-
18
 
19
  f = 100 * 10 ** -3 # Форкусное расстояние линзы
20
 
21
 
22
  radius = 5 * 10 ** -3 # Радиус линзы
23
-
24
  span = (-(10 ** -2), 10 ** -2)
25
  lens = po.ThinLens(radius, f)
26
  z = 100 * 10 ** -3 # Расстояние
27
  wavelength = 500 * 10 ** -9 # Длина волны
28
-
29
  pixel_scale = 250 * 10 ** -4 # Размер пикселя
30
  npix = 2**9 # Размер сетки
 
31
 
 
 
 
 
32
 
33
- ddx = np.linspace(*span, npix)
34
- ddy = np.linspace(*span, npix)
35
- xv, yv = np.meshgrid(ddx, ddy)
36
- f2 = generate_zern_wavefront(xv, yv, [0, 0, 0, 3, 0], norm_radius=radius)
37
 
38
- dist_from_center = np.sqrt(xv**2 + yv**2)
39
- mask = dist_from_center <= radius
40
- f2[mask == 0] = 0
41
- f2[np.isnan(f2)] = 0
42
- k = 2*math.pi/wavelength
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- wf = np.zeros((npix, npix), dtype=np.complex64)
45
- wf[mask] = 1 + 0j
46
- wf += f2 * 1j
47
 
48
 
49
- D = 2e-6
50
- fscale = wavelength*z
51
 
52
- target_min, target_max = -50e-6, 50e-6
53
- v = np.fft.fftfreq(npix, d=D/npix)
54
- v = fscale * np.fft.fftshift(v)
55
- extent = [1e3 * v[0], 1e3 * v[-1], 1e3 * v[0], 1e3 * v[-1]]
 
56
 
57
- phase_mul = ((np.exp(1j*k*z) * np.exp(1j*k*(xv**2 + yv**2)/(2*z)))/(1j*wavelength*z))
58
- U_fraun = fft2(ifftshift(wf), overwrite_x=True)
59
- U_fraun = fftshift(U_fraun * phase_mul)
 
 
 
 
 
60
 
 
 
 
61
 
62
- I_fraun = np.abs(U_fraun)**2
63
- I_fraun = I_fraun / np.max(I_fraun)
 
 
 
 
 
 
64
 
65
- axs[0][1].imshow(I_fraun, cmap='grey', extent=(*span, *span))
66
- axs[1][1].plot(np.linspace(extent[0], extent[1], I_fraun.shape[0]),
67
- I_fraun[:, I_fraun.shape[0]//2], antialiased='none')
68
- axs[0][0].imshow(np.abs(wf)**2, cmap='grey', extent=(*span, *span))
69
- axs[1][0].imshow(f2, cmap='grey', extent=(*span, *span), interpolation='none')
70
- plt.show()
 
13
  from zern_generator import generate_zern_wavefront
14
  from scipy.ndimage import zoom
15
 
 
 
16
 
17
  f = 100 * 10 ** -3 # Форкусное расстояние линзы
18
 
19
 
20
  radius = 5 * 10 ** -3 # Радиус линзы
 
21
  span = (-(10 ** -2), 10 ** -2)
22
  lens = po.ThinLens(radius, f)
23
  z = 100 * 10 ** -3 # Расстояние
24
  wavelength = 500 * 10 ** -9 # Длина волны
 
25
  pixel_scale = 250 * 10 ** -4 # Размер пикселя
26
  npix = 2**9 # Размер сетки
27
+ k = 2*math.pi/wavelength
28
 
29
+ def gen_focal_image(xv, yv, input_wf):
30
+ phase_mul = ((np.exp(1j*k*z) * np.exp(1j*k*(xv**2 + yv**2)/(2*z)))/(1j*wavelength*z))
31
+ U_fraun = fft2(ifftshift(input_wf), overwrite_x=True)
32
+ U_fraun = fftshift(U_fraun * phase_mul)
33
 
 
 
 
 
34
 
35
+ I_fraun = np.abs(U_fraun)**2
36
+ return I_fraun / np.max(I_fraun)
37
+
38
+
39
+ def generate_zernike_screen(xv, yv, coeffs, norm_radius):
40
+ dist_from_center = np.sqrt(xv**2 + yv**2)
41
+ mask = dist_from_center <= norm_radius
42
+ f2 = generate_zern_wavefront(xv, yv, coeffs, norm_radius=radius)
43
+ f2[mask == 0] = 0
44
+ f2[np.isnan(f2)] = 0
45
+ return f2
46
+
47
+
48
+ def circle(xv, yv, radius, resolution):
49
+ dist_from_center = np.sqrt(xv**2 + yv**2)
50
+ mask = dist_from_center <= radius
51
+ wf = np.zeros((resolution, resolution), dtype=np.complex64)
52
+ wf[mask] = 1 + 0j
53
+ return wf
54
 
 
 
 
55
 
56
 
 
 
57
 
58
+ def generate_diff(defocus_amount, *zernikes):
59
+ zernikes = list(zernikes)
60
+ if len(zernikes) < 5:
61
+ zernikes += [0] * (5-len(zernikes))
62
+ fig, axs = plt.subplots(1, 3, figsize = (30, 15))
63
 
64
+ ddx = np.linspace(*span, npix)
65
+ ddy = np.linspace(*span, npix)
66
+ xv, yv = np.meshgrid(ddx, ddy)
67
+ wf = circle(xv, yv, radius, npix)
68
+ zernikes[4] += defocus_amount
69
+ f_plus = generate_zernike_screen(xv, yv, zernikes, norm_radius=radius)
70
+ zernikes[4] -= 2*defocus_amount
71
+ f_minus = generate_zernike_screen(xv, yv, zernikes, norm_radius=radius)
72
 
73
+ focal_image_plus = gen_focal_image(xv, yv, wf*np.exp(f_plus * 1j))
74
+
75
+ focal_image_minus = gen_focal_image(xv, yv, wf*np.exp(f_minus * 1j))
76
 
77
+ axs[0].imshow(focal_image_plus, cmap='grey', extent=(*span, *span))
78
+ axs[1].imshow(focal_image_minus, cmap='grey', extent=(*span, *span))
79
+ axs[2].imshow((focal_image_plus-focal_image_minus), cmap='grey', extent=(*span, *span))
80
+ axs[0].axis('off')
81
+ axs[1].axis('off')
82
+ axs[2].axis('off')
83
+ fig.show()
84
+ return fig
85
 
 
 
 
 
 
 
zern_generator.py CHANGED
@@ -9,6 +9,10 @@ span = (-1, 1)
9
 
10
 
11
  def generate_zern_wavefront(xv, yv, zerns, norm_radius = 1):
 
 
 
 
12
  num_zerns = len(zerns)
13
 
14
  degree = math.ceil((-3 + math.sqrt(8 * num_zerns + 1)) / 2)
@@ -58,3 +62,25 @@ def generate_batch(resolution):
58
  zern_index += 1
59
  plt.show()
60
  return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
 
11
  def generate_zern_wavefront(xv, yv, zerns, norm_radius = 1):
12
+ indexed_zerns = sorted(map(lambda x: (_mn_to_noll(*_osa_to_mn(x[0])), x[1]), enumerate(zerns)), key=lambda x: x[0])
13
+ print(indexed_zerns)
14
+ zerns = [x[1] for x in indexed_zerns]
15
+ print(zerns)
16
  num_zerns = len(zerns)
17
 
18
  degree = math.ceil((-3 + math.sqrt(8 * num_zerns + 1)) / 2)
 
62
  zern_index += 1
63
  plt.show()
64
  return fig
65
+
66
+
67
+ def _osa_to_mn(idx):
68
+ n = math.ceil((-3 + math.sqrt((9 + 8 * idx))) / 2)
69
+ m = 2 * idx - n * (n + 2)
70
+ return m, n
71
+
72
+ def _mn_to_noll(m, n):
73
+ first = (n * (n + 1)) // 2
74
+ second = abs(m)
75
+ third = 0
76
+ # I wanted to simplify the logic but it seems to work like a colander
77
+ if m > 0 and n % 4 in [0, 1]:
78
+ third = 0
79
+ elif m < 0 and n % 4 in [2, 3]:
80
+ third = 0
81
+ elif m >= 0 and n % 4 in [2, 3]:
82
+ third = 1
83
+ elif m <= 0 and n % 4 in [0, 1]:
84
+ third = 1
85
+ j = first + second + third
86
+ return j