Skip to content

Commit 932bd8c

Browse files
author
Ethan F. Tseng
committed
Upload first version of code.
1 parent 4a6de9b commit 932bd8c

15 files changed

+1893
-1
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.swp
2+
**/*.out
3+
**/__pycache__
4+
**/.ipynb_checkpoints
5+
**/*.pyc
6+
**/.DS_Store
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "01f63883",
6+
"metadata": {},
7+
"source": [
8+
"# Monochromatic Neural Étendue Expansion Experimental Code"
9+
]
10+
},
11+
{
12+
"cell_type": "markdown",
13+
"id": "ac28b847",
14+
"metadata": {},
15+
"source": [
16+
"### This notebook can be used to produce the monochromatic étendue expanded experimental holograms shown in the manuscript and in the supplementary information.\n",
17+
"\n",
18+
"### In the cells below please select one expander type and one target image. For example, to produce a 64x étendue expanded hologram with the neural étendue expander please select 'neural_mono_64x'. To produce a 16x étendue expanded hologram with a random expander [Kuo et al. 2020] please select 'random_16x'. To produce a conventional hologram [Shi et al. 2021] please select 'conventional_16x' or 'conventional_64x'. The target images provided are labeled as '000.png', '001.png', and so on."
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"id": "8ef8193c",
25+
"metadata": {},
26+
"outputs": [],
27+
"source": [
28+
"import torch\n",
29+
"import matplotlib.pyplot as plt\n",
30+
"import numpy as np\n",
31+
"import os\n",
32+
"from imageio import imread"
33+
]
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": null,
38+
"id": "908f9ffd",
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"### --- BEGIN CONFIG --- ###\n",
43+
"# Choose only one of the following expanders.\n",
44+
"#expander_type = 'conventional_16x'\n",
45+
"#expander_type = 'conventional_64x'\n",
46+
"#expander_type = 'random_16x'\n",
47+
"#expander_type = 'random_64x'\n",
48+
"#expander_type = 'neural_mono_16x'\n",
49+
"expander_type = 'neural_mono_64x'\n",
50+
"\n",
51+
"# Choose only one of the following target images.\n",
52+
"#target_img_name = '000'\n",
53+
"target_img_name = '001'\n",
54+
"### --- END CONFIG --- ###\n",
55+
"\n",
56+
"if (expander_type == 'random_16x') or (expander_type == 'neural_mono_16x'):\n",
57+
" correction_factor = np.array([1.0])\n",
58+
" top_percentile = 99.9\n",
59+
" eff_corners = None\n",
60+
"elif (expander_type == 'conventional_16x'):\n",
61+
" correction_factor = np.array([1.0])\n",
62+
" top_percentile = 99.9\n",
63+
" eff_corners = [144,144,240,240]\n",
64+
"elif (expander_type == 'random_64x') or (expander_type == 'neural_mono_64x'):\n",
65+
" correction_factor = np.array([1.0])\n",
66+
" top_percentile = 99.0\n",
67+
" eff_corners = None\n",
68+
"elif (expander_type == 'conventional_64x'):\n",
69+
" correction_factor = np.array([1.0])\n",
70+
" top_percentile = 99.9\n",
71+
" eff_corners = [336,336,432,432]\n",
72+
"else:\n",
73+
" assert('Undefined expander.')\n",
74+
"print(eff_corners)"
75+
]
76+
},
77+
{
78+
"cell_type": "code",
79+
"execution_count": null,
80+
"id": "f1b94ccc",
81+
"metadata": {},
82+
"outputs": [],
83+
"source": [
84+
"def get_target_img(img_name):\n",
85+
" img = imread(img_name)\n",
86+
" if img.dtype == 'uint8':\n",
87+
" img = img.astype(np.float32) / 255.0\n",
88+
" elif img.dtype == 'uint16':\n",
89+
" img = img.astype(np.float32) / 65535.0\n",
90+
" elif img.dtype == 'float32':\n",
91+
" img = img / 1.0\n",
92+
" else:\n",
93+
" assert('Invalid image type')\n",
94+
" if len(img.shape) == 3:\n",
95+
" img = 0.299 * img[:,:,0] + 0.587 * img[:,:,1] + 0.114 * img[:,:,2] # Convert to gray scale\n",
96+
" return img\n",
97+
"\n",
98+
"def white_balance(cap_img, target_img, correction_factor, top_percentile, eff_corners = None):\n",
99+
" # Normalize so that max == 1.\n",
100+
" # We are only adjusting the ratios between the colors, not the overall brightness.\n",
101+
" if eff_corners == None:\n",
102+
" scale_factors = np.mean(target_img, axis=(0,1)) / np.mean(cap_img, axis=(0,1))\n",
103+
" else:\n",
104+
" cap_img_eff = cap_img[eff_corners[0]:eff_corners[2],eff_corners[1]:eff_corners[3]]\n",
105+
" scale_factors = np.mean(target_img, axis=(0,1)) / np.mean(cap_img_eff, axis=(0,1))\n",
106+
"\n",
107+
" scale_factors = scale_factors / np.max(scale_factors)\n",
108+
" cap_img = cap_img * scale_factors\n",
109+
"\n",
110+
" # Additional manual color balancing.\n",
111+
" cap_img = cap_img * correction_factor\n",
112+
"\n",
113+
" # Scale overall brightness so that top percentile of pixels are clipped.\n",
114+
" top_scale = np.percentile(cap_img, top_percentile)\n",
115+
" cap_img = cap_img / top_scale\n",
116+
" return np.clip(cap_img, 0.0, 1.0)"
117+
]
118+
},
119+
{
120+
"cell_type": "markdown",
121+
"id": "41a8642c",
122+
"metadata": {},
123+
"source": [
124+
"### Display Intensity Scaled Experimentally Captured Hologram ###"
125+
]
126+
},
127+
{
128+
"cell_type": "code",
129+
"execution_count": null,
130+
"id": "8acda60c",
131+
"metadata": {},
132+
"outputs": [],
133+
"source": [
134+
"target_img = get_target_img(os.path.join('Target_Images',target_img_name+'.png'))\n",
135+
"w_cap = np.load(os.path.join('Data',expander_type,'w',target_img_name+'.npy'))\n",
136+
"w_cap_wb = np.fliplr(white_balance(w_cap, target_img, correction_factor, top_percentile, eff_corners))\n",
137+
"w_cap_wb = np.stack([w_cap_wb, w_cap_wb, w_cap_wb], axis=-1)\n",
138+
"\n",
139+
"plt.figure()\n",
140+
"plt.title('Experimentally Captured Hologram')\n",
141+
"plt.imshow(w_cap_wb)"
142+
]
143+
},
144+
{
145+
"cell_type": "code",
146+
"execution_count": null,
147+
"id": "7fc758bd",
148+
"metadata": {},
149+
"outputs": [],
150+
"source": []
151+
}
152+
],
153+
"metadata": {
154+
"kernelspec": {
155+
"display_name": "Python 3 (ipykernel)",
156+
"language": "python",
157+
"name": "python3"
158+
},
159+
"language_info": {
160+
"codemirror_mode": {
161+
"name": "ipython",
162+
"version": 3
163+
},
164+
"file_extension": ".py",
165+
"mimetype": "text/x-python",
166+
"name": "python",
167+
"nbconvert_exporter": "python",
168+
"pygments_lexer": "ipython3",
169+
"version": "3.10.10"
170+
}
171+
},
172+
"nbformat": 4,
173+
"nbformat_minor": 5
174+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "01f63883",
6+
"metadata": {},
7+
"source": [
8+
"# Trichromatic Neural Étendue Expansion Experimental Code"
9+
]
10+
},
11+
{
12+
"cell_type": "markdown",
13+
"id": "ac28b847",
14+
"metadata": {},
15+
"source": [
16+
"### This notebook can be used to produce the trichromatic étendue expanded experimental holograms shown in the manuscript and in the supplementary information.\n",
17+
"\n",
18+
"### In the cells below please select one expander type and one target image. For example, to produce a 64x étendue expanded hologram with the neural étendue expander please select 'neural_tri_64x'. To produce a 16x étendue expanded hologram with a random expander [Kuo et al. 2020] please select 'random_16x'. To produce a conventional hologram [Shi et al. 2021] please select 'conventional_16x' or 'conventional_64x'. The target images provided are labeled as '000.png', '001.png', and so on."
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"id": "8ef8193c",
25+
"metadata": {},
26+
"outputs": [],
27+
"source": [
28+
"import torch\n",
29+
"import matplotlib.pyplot as plt\n",
30+
"import numpy as np\n",
31+
"import os\n",
32+
"from imageio import imread"
33+
]
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": null,
38+
"id": "908f9ffd",
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"### --- BEGIN CONFIG --- ###\n",
43+
"# Choose only one of the following expanders.\n",
44+
"#expander_type = 'conventional_16x'\n",
45+
"#expander_type = 'conventional_64x'\n",
46+
"#expander_type = 'random_16x'\n",
47+
"#expander_type = 'random_64x'\n",
48+
"#expander_type = 'neural_tri_16x'\n",
49+
"expander_type = 'neural_tri_64x'\n",
50+
"\n",
51+
"# Choose only one of the following target images.\n",
52+
"#target_img_name = '000'\n",
53+
"target_img_name = '001'\n",
54+
"### --- END CONFIG --- ###\n",
55+
"\n",
56+
"if (expander_type == 'random_16x') or (expander_type == 'neural_tri_16x'):\n",
57+
" correction_factor = np.array([1.0,1.0,1.2])\n",
58+
" top_percentile = 99.9\n",
59+
" eff_corners = None\n",
60+
"elif (expander_type == 'conventional_16x'):\n",
61+
" correction_factor = np.array([1.0,1.0,1.2])\n",
62+
" top_percentile = 99.9\n",
63+
" eff_corners = [144,144,240,240]\n",
64+
"elif (expander_type == 'random_64x') or (expander_type == 'neural_tri_64x'):\n",
65+
" correction_factor = np.array([1.0,1.1,1.6])\n",
66+
" top_percentile = 99.0\n",
67+
" eff_corners = None\n",
68+
"elif (expander_type == 'conventional_64x'):\n",
69+
" correction_factor = np.array([1.0,1.1,1.2])\n",
70+
" top_percentile = 99.9\n",
71+
" eff_corners = [336,336,432,432]\n",
72+
"else:\n",
73+
" assert('Undefined expander.')\n",
74+
"print(eff_corners)"
75+
]
76+
},
77+
{
78+
"cell_type": "code",
79+
"execution_count": null,
80+
"id": "f1b94ccc",
81+
"metadata": {},
82+
"outputs": [],
83+
"source": [
84+
"def get_target_img(img_name):\n",
85+
" img = imread(img_name)\n",
86+
" if img.dtype == 'uint8':\n",
87+
" img = img.astype(np.float32) / 255.0\n",
88+
" elif img.dtype == 'uint16':\n",
89+
" img = img.astype(np.float32) / 65535.0\n",
90+
" elif img.dtype == 'float32':\n",
91+
" img = img / 1.0\n",
92+
" else:\n",
93+
" assert('Invalid image type')\n",
94+
" if len(img.shape) == 2:\n",
95+
" img = np.stack([img, img, img], axis=-1)\n",
96+
" return img\n",
97+
"\n",
98+
"def white_balance(cap_img, target_img, correction_factor, top_percentile, eff_corners = None):\n",
99+
" # Normalize so that max == 1.\n",
100+
" # We are only adjusting the ratios between the colors, not the overall brightness.\n",
101+
" if eff_corners == None:\n",
102+
" scale_factors = np.mean(target_img, axis=(0,1)) / np.mean(cap_img, axis=(0,1))\n",
103+
" else:\n",
104+
" cap_img_eff = cap_img[eff_corners[0]:eff_corners[2],eff_corners[1]:eff_corners[3],:]\n",
105+
" scale_factors = np.mean(target_img, axis=(0,1)) / np.mean(cap_img_eff, axis=(0,1))\n",
106+
"\n",
107+
" scale_factors = scale_factors / np.max(scale_factors)\n",
108+
" cap_img = cap_img * scale_factors\n",
109+
"\n",
110+
" # Additional manual color balancing.\n",
111+
" cap_img = cap_img * correction_factor\n",
112+
"\n",
113+
" # Scale overall brightness so that top percentile of pixels are clipped.\n",
114+
" top_scale = np.percentile(cap_img, top_percentile)\n",
115+
" cap_img = cap_img / top_scale\n",
116+
" return np.clip(cap_img, 0.0, 1.0)"
117+
]
118+
},
119+
{
120+
"cell_type": "markdown",
121+
"id": "41a8642c",
122+
"metadata": {},
123+
"source": [
124+
"### Display Intensity Scaled Experimentally Captured Hologram ###"
125+
]
126+
},
127+
{
128+
"cell_type": "code",
129+
"execution_count": null,
130+
"id": "8acda60c",
131+
"metadata": {},
132+
"outputs": [],
133+
"source": [
134+
"target_img = get_target_img(os.path.join('Target_Images',target_img_name+'.png'))\n",
135+
"r_cap = np.load(os.path.join('Data',expander_type,'r',target_img_name+'.npy'))\n",
136+
"g_cap = np.load(os.path.join('Data',expander_type,'g',target_img_name+'.npy'))\n",
137+
"b_cap = np.load(os.path.join('Data',expander_type,'b',target_img_name+'.npy'))\n",
138+
"rgb_cap = np.stack([r_cap, g_cap, b_cap], axis=-1)\n",
139+
"rgb_cap_wb = np.fliplr(white_balance(rgb_cap, target_img, correction_factor, top_percentile, eff_corners))\n",
140+
"\n",
141+
"plt.figure()\n",
142+
"plt.title('Experimentally Captured Hologram')\n",
143+
"plt.imshow(rgb_cap_wb)"
144+
]
145+
},
146+
{
147+
"cell_type": "code",
148+
"execution_count": null,
149+
"id": "7fc758bd",
150+
"metadata": {},
151+
"outputs": [],
152+
"source": []
153+
}
154+
],
155+
"metadata": {
156+
"kernelspec": {
157+
"display_name": "Python 3 (ipykernel)",
158+
"language": "python",
159+
"name": "python3"
160+
},
161+
"language_info": {
162+
"codemirror_mode": {
163+
"name": "ipython",
164+
"version": 3
165+
},
166+
"file_extension": ".py",
167+
"mimetype": "text/x-python",
168+
"name": "python",
169+
"nbconvert_exporter": "python",
170+
"pygments_lexer": "ipython3",
171+
"version": "3.10.10"
172+
}
173+
},
174+
"nbformat": 4,
175+
"nbformat_minor": 5
176+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Permission is hereby granted, free of charge, to any person or organization
2+
obtaining a copy of the software and accompanying documentation covered by
3+
this license (the "Software") to use, reproduce, display, distribute,
4+
execute, and transmit the Software, and to prepare derivative works of the
5+
Software, and to permit third-parties to whom the Software is furnished to
6+
do so, all subject to the following:
7+
8+
The copyright notices in the Software and this entire statement, including
9+
the above license grant, this restriction and the following disclaimer,
10+
must be included in all copies of the Software, in whole or in part, and
11+
all derivative works of the Software, unless such copies or derivative
12+
works are solely in the form of machine-executable object code generated by
13+
a source language processor.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
18+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
19+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
20+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+
DEALINGS IN THE SOFTWARE.

0 commit comments

Comments
 (0)