├── ADMM.py
├── GD.py
├── LICENSE
├── README.md
├── admm_config.yml
├── environment.yml
├── gd_config.yml
├── rpi
└── preview.py
├── test_images
├── cal_logo_rgb.png
├── dog_rgb.jpg
├── google_chrome_logo_rgb.png
└── spiral_bw.gif
└── tutorial
├── ADMM.ipynb
├── GD.ipynb
├── psf_sample.tif
└── rawdata_hand_sample.tif
/ADMM.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import numpy.fft as fft
3 | from PIL import Image
4 | import matplotlib.pyplot as plt
5 | import yaml
6 |
7 | def loadData(show_im=True):
8 | psf = Image.open(psfname)
9 | psf = np.array(psf, dtype='float32')
10 | data = Image.open(imgname)
11 | data = np.array(data, dtype='float32')
12 |
13 | """In the picamera, there is a non-trivial background
14 | (even in the dark) that must be subtracted"""
15 | bg = np.mean(psf[5:15,5:15])
16 | psf -= bg
17 | data -= bg
18 |
19 | """Resize to a more manageable size to do reconstruction on.
20 | Because resizing is downsampling, it is subject to aliasing
21 | (artifacts produced by the periodic nature of sampling). Demosaicing is an attempt
22 | to account for/reduce the aliasing caused. In this application, we do the simplest
23 | possible demosaicing algorithm: smoothing/blurring the image with a box filter"""
24 |
25 | def resize(img, factor):
26 | num = int(-np.log2(factor))
27 | for i in range(num):
28 | img = 0.25*(img[::2,::2,...]+img[1::2,::2,...]+img[::2,1::2,...]+img[1::2,1::2,...])
29 | return img
30 |
31 |
32 | psf = resize(psf, f)
33 | data = resize(data, f)
34 |
35 | """Now we normalize the images so they have the same total power. Technically not a
36 | necessary step, but the optimal hyperparameters are a function of the total power in
37 | the PSF (among other things), so it makes sense to standardize it"""
38 |
39 | psf /= np.linalg.norm(psf.ravel())
40 | data /= np.linalg.norm(data.ravel())
41 |
42 | if show_im:
43 | fig1 = plt.figure()
44 | plt.imshow(psf, cmap='gray')
45 | plt.title('PSF')
46 | fig2 = plt.figure()
47 | plt.imshow(data, cmap='gray')
48 | plt.title('Raw data')
49 | plt.show()
50 | return psf, data
51 |
52 | def U_update(eta, image_est, tau):
53 | return SoftThresh(Psi(image_est) + eta/mu2, tau/mu2)
54 |
55 |
56 | def SoftThresh(x, tau):
57 | # numpy automatically applies functions to each element of the array
58 | return np.sign(x)*np.maximum(0, np.abs(x) - tau)
59 |
60 |
61 | def Psi(v):
62 | return np.stack((np.roll(v,1,axis=0) - v, np.roll(v, 1, axis=1) - v), axis=2)
63 |
64 |
65 | def X_update(xi, image_est, H_fft, sensor_reading, X_divmat):
66 | return X_divmat * (xi + mu1*M(image_est, H_fft) + CT(sensor_reading))
67 |
68 |
69 | def M(vk, H_fft):
70 | return np.real(fft.fftshift(fft.ifft2(fft.fft2(fft.ifftshift(vk))*H_fft)))
71 |
72 |
73 | def C(M):
74 | # Image stored as matrix (row-column rather than x-y)
75 | top = (full_size[0] - sensor_size[0])//2
76 | bottom = (full_size[0] + sensor_size[0])//2
77 | left = (full_size[1] - sensor_size[1])//2
78 | right = (full_size[1] + sensor_size[1])//2
79 | return M[top:bottom,left:right]
80 |
81 | def CT(b):
82 | v_pad = (full_size[0] - sensor_size[0])//2
83 | h_pad = (full_size[1] - sensor_size[1])//2
84 | return np.pad(b, ((v_pad, v_pad), (h_pad, h_pad)), 'constant',constant_values=(0,0))
85 |
86 |
87 | def precompute_X_divmat():
88 | """Only call this function once!
89 | Store it in a variable and only use that variable
90 | during every update step"""
91 | return 1./(CT(np.ones(sensor_size)) + mu1)
92 |
93 | def W_update(rho, image_est):
94 | return np.maximum(rho/mu3 + image_est, 0)
95 |
96 | def r_calc(w, rho, u, eta, x, xi, H_fft):
97 | return (mu3*w - rho)+PsiT(mu2*u - eta) + MT(mu1*x - xi, H_fft)
98 |
99 | def V_update(w, rho, u, eta, x, xi, H_fft, R_divmat):
100 | freq_space_result = R_divmat*fft.fft2( fft.ifftshift(r_calc(w, rho, u, eta, x, xi, H_fft)) )
101 | return np.real(fft.fftshift(fft.ifft2(freq_space_result)))
102 |
103 | def PsiT(U):
104 | diff1 = np.roll(U[...,0],-1,axis=0) - U[...,0]
105 | diff2 = np.roll(U[...,1],-1,axis=1) - U[...,1]
106 | return diff1 + diff2
107 |
108 | def MT(x, H_fft):
109 | x_zeroed = fft.ifftshift(x)
110 | return np.real(fft.fftshift(fft.ifft2(fft.fft2(x_zeroed) * np.conj(H_fft))))
111 |
112 | def precompute_PsiTPsi():
113 | PsiTPsi = np.zeros(full_size)
114 | PsiTPsi[0,0] = 4
115 | PsiTPsi[0,1] = PsiTPsi[1,0] = PsiTPsi[0,-1] = PsiTPsi[-1,0] = -1
116 | PsiTPsi = fft.fft2(PsiTPsi)
117 | return PsiTPsi
118 |
119 |
120 | def precompute_R_divmat(H_fft, PsiTPsi):
121 | """Only call this function once!
122 | Store it in a variable and only use that variable
123 | during every update step"""
124 | MTM_component = mu1*(np.abs(np.conj(H_fft)*H_fft))
125 | PsiTPsi_component = mu2*np.abs(PsiTPsi)
126 | id_component = mu3
127 | """This matrix is a mask in frequency space. So we will only use
128 | it on images that have already been transformed via an fft"""
129 | return 1./(MTM_component + PsiTPsi_component + id_component)
130 |
131 | def xi_update(xi, V, H_fft, X):
132 | return xi + mu1*(M(V,H_fft) - X)
133 |
134 | def eta_update(eta, V, U):
135 | return eta + mu2*(Psi(V) - U)
136 |
137 | def rho_update(rho, V, W):
138 | return rho + mu3*(V - W)
139 |
140 |
141 | def init_Matrices(H_fft):
142 | X = np.zeros(full_size)
143 | U = np.zeros((full_size[0], full_size[1], 2))
144 | V = np.zeros(full_size)
145 | W = np.zeros(full_size)
146 |
147 | xi = np.zeros_like(M(V,H_fft))
148 | eta = np.zeros_like(Psi(V))
149 | rho = np.zeros_like(W)
150 | return X,U,V,W,xi,eta,rho
151 |
152 |
153 | def precompute_H_fft(psf):
154 | return fft.fft2(fft.ifftshift(CT(psf)))
155 |
156 | def ADMM_Step(X,U,V,W,xi,eta,rho, precomputed):
157 | H_fft, data, X_divmat, R_divmat = precomputed
158 | U = U_update(eta, V, tau)
159 | X = X_update(xi, V, H_fft, data, X_divmat)
160 | V = V_update(W, rho, U, eta, X, xi, H_fft, R_divmat)
161 | W = W_update(rho, V)
162 | xi = xi_update(xi, V, H_fft, X)
163 | eta = eta_update(eta, V, U)
164 | rho = rho_update(rho, V, W)
165 |
166 | return X,U,V,W,xi,eta,rho
167 |
168 |
169 | def runADMM(psf, data):
170 | H_fft = precompute_H_fft(psf)
171 | X,U,V,W,xi,eta,rho = init_Matrices(H_fft)
172 | X_divmat = precompute_X_divmat()
173 | PsiTPsi = precompute_PsiTPsi()
174 | R_divmat = precompute_R_divmat(H_fft, PsiTPsi)
175 |
176 | for i in range(iters):
177 | X,U,V,W,xi,eta,rho = ADMM_Step(X,U,V,W,xi,eta,rho, [H_fft, data, X_divmat, R_divmat])
178 | if i % disp_pic == 0:
179 | print(i)
180 | image = C(V)
181 | image[image<0] = 0
182 | f = plt.figure(1)
183 | plt.imshow(image, cmap='gray')
184 | plt.title('Reconstruction after iteration {}'.format(i))
185 | plt.show()
186 | return image
187 |
188 |
189 |
190 | if __name__ == "__main__":
191 | ### Reading in params from config file (don't mess with parameter names!)
192 | params = yaml.load(open("admm_config.yml"))
193 | for k,v in params.items():
194 | exec(k + "=v")
195 |
196 | ### Loading images and initializing the required arrays
197 | psf, data = loadData(True)
198 | sensor_size = np.array(psf.shape)
199 | full_size = 2*sensor_size
200 |
201 | ### Running the algorithm
202 | final_im = runADMM(psf, data)
203 | plt.imshow(final_im, cmap='gray')
204 | plt.title('Final reconstructed image after {} iterations'.format(iters))
205 | plt.show()
206 | saveim = input('Save final image? (y/n) ')
207 | if saveim == 'y':
208 | filename = input('Name of file: ')
209 | plt.imshow(final_im, cmap='gray')
210 | plt.axis('off')
211 | plt.savefig(filename+'.png', bbox_inches='tight')
212 |
213 |
--------------------------------------------------------------------------------
/GD.py:
--------------------------------------------------------------------------------
1 |
2 | import numpy as np
3 | import numpy.fft as fft
4 | import matplotlib.pyplot as plt
5 | from PIL import Image
6 | import yaml
7 |
8 |
9 | def loaddata(show_im=True):
10 | psf = Image.open(psfname)
11 | psf = np.array(psf, dtype='float32')
12 | data = Image.open(imgname)
13 | data = np.array(data, dtype='float32')
14 |
15 | """In the picamera, there is a non-trivial background
16 | (even in the dark) that must be subtracted"""
17 | bg = np.mean(psf[5:15,5:15])
18 | psf -= bg
19 | data -= bg
20 |
21 | """Resize to a more manageable size to do reconstruction on.
22 | Because resizing is downsampling, it is subject to aliasing
23 | (artifacts produced by the periodic nature of sampling). Demosaicing is an attempt
24 | to account for/reduce the aliasing caused. In this application, we do the simplest
25 | possible demosaicing algorithm: smoothing/blurring the image with a box filter"""
26 |
27 | def resize(img, factor):
28 | num = int(-np.log2(factor))
29 | for i in range(num):
30 | img = 0.25*(img[::2,::2,...]+img[1::2,::2,...]+img[::2,1::2,...]+img[1::2,1::2,...])
31 | return img
32 |
33 | psf = resize(psf, f)
34 | data = resize(data, f)
35 |
36 |
37 | """ nmormalizing copy from shreyas"""
38 | psf /= np.linalg.norm(psf.ravel())
39 | data /= np.linalg.norm(data.ravel())
40 |
41 | if show_im:
42 | fig1 = plt.figure()
43 | plt.imshow(psf, cmap='gray')
44 | plt.title('PSF')
45 | plt.show()
46 | fig2 = plt.figure()
47 | plt.imshow(data, cmap='gray')
48 | plt.title('Raw data')
49 | plt.show()
50 | return psf, data
51 |
52 | def initMatrices(h):
53 | pixel_start = (np.max(h) + np.min(h))/2
54 | x = np.ones(h.shape)*pixel_start
55 |
56 | init_shape = h.shape
57 | padded_shape = [nextPow2(2*n - 1) for n in init_shape]
58 | starti = (padded_shape[0]- init_shape[0])//2
59 | endi = starti + init_shape[0]
60 | startj = (padded_shape[1]//2) - (init_shape[1]//2)
61 | endj = startj + init_shape[1]
62 | hpad = np.zeros(padded_shape)
63 | hpad[starti:endi, startj:endj] = h
64 |
65 | H = fft.fft2(hpad, norm="ortho")
66 | Hadj = np.conj(H)
67 |
68 | def crop(X):
69 | return X[starti:endi, startj:endj]
70 |
71 | def pad(v):
72 | vpad = np.zeros(padded_shape).astype(np.complex64)
73 | vpad[starti:endi, startj:endj] = v
74 | return vpad
75 |
76 | utils = [crop, pad]
77 | v = np.real(pad(x))
78 |
79 | return H, Hadj, v, utils
80 |
81 | def nextPow2(n):
82 | return int(2**np.ceil(np.log2(n)))
83 |
84 | def grad(Hadj, H, vk, b, crop, pad):
85 | Av = calcA(H, vk, crop)
86 | diff = Av - b
87 | return np.real(calcAHerm(Hadj, diff, pad))
88 |
89 | def calcA(H, vk, crop):
90 | Vk = fft.fft2(vk, norm="ortho")
91 | return crop(fft.ifftshift(fft.ifft2(H*Vk, norm="ortho")))
92 |
93 | def calcAHerm(Hadj, diff, pad):
94 | xpad = pad(diff)
95 | X = fft.fft2(xpad, norm="ortho")
96 | return fft.ifftshift(fft.ifft2(Hadj*X, norm="ortho"))
97 |
98 |
99 | def grad_descent(h, b):
100 | H, Hadj, v, utils = initMatrices(h)
101 | crop = utils[0]
102 | pad = utils[1]
103 |
104 | alpha = np.real(2/(np.max(Hadj * H)))
105 | iterations = 0
106 |
107 | def non_neg(xi):
108 | xi = np.maximum(xi,0)
109 | return xi
110 |
111 | #proj = lambda x: x #Do no projection
112 | proj = non_neg #Enforce nonnegativity at every gradient step. Comment out as needed.
113 |
114 |
115 | parent_var = [H, Hadj, b, crop, pad, alpha, proj]
116 |
117 | vk = v
118 |
119 |
120 |
121 | #### uncomment for Nesterov momentum update ####
122 | #p = 0
123 | #mu = 0.9
124 | ################################################
125 |
126 |
127 |
128 | #### uncomment for FISTA update ################
129 | tk = 1
130 | xk = v
131 | ################################################
132 |
133 | for iterations in range(iters):
134 |
135 | # uncomment for regular GD update
136 | #vk = gd_update(vk, parent_var)
137 |
138 | # uncomment for Nesterov momentum update
139 | #vk, p = nesterov_update(vk, p, mu, parent_var)
140 |
141 | # uncomment for FISTA update
142 | vk, tk, xk = fista_update(vk, tk, xk, parent_var)
143 |
144 | if iterations % disp_pic == 0:
145 | print(iterations)
146 | image = proj(crop(vk))
147 | f = plt.figure(1)
148 | plt.imshow(image, cmap='gray')
149 | plt.title('Reconstruction after iteration {}'.format(iterations))
150 | plt.show()
151 |
152 |
153 | return proj(crop(vk))
154 |
155 | def gd_update(vk, parent_var):
156 | H, Hadj, b, crop, pad, alpha, proj = parent_var
157 |
158 | gradient = grad(Hadj, H, vk, b, crop, pad)
159 | vk -= alpha*gradient
160 | vk = proj(vk)
161 |
162 | return xk
163 |
164 | def nesterov_update(vk, p, mu, parent_var):
165 | H, Hadj, b, crop, pad, alpha, proj = parent_var
166 |
167 | p_prev = p
168 | gradient = grad(Hadj, H, vk, b, crop, pad)
169 | p = mu*p - alpha*gradient
170 | vk += -mu*p_prev + (1+mu)*p
171 | vk = proj(vk)
172 |
173 | return vk, p
174 |
175 | def fista_update(vk, tk, xk, parent_var):
176 | H, Hadj, b, crop, pad, alpha, proj = parent_var
177 |
178 | x_k1 = xk
179 | gradient = grad(Hadj, H, vk, b, crop, pad)
180 | vk -= alpha*gradient
181 | xk = proj(vk)
182 | t_k1 = (1+np.sqrt(1+4*tk**2))/2
183 | vk = xk+(tk-1)/t_k1*(xk - x_k1)
184 | tk = t_k1
185 |
186 | return vk, tk, xk
187 |
188 |
189 | if __name__ == "__main__":
190 | ### Reading in params from config file (don't mess with parameter names!)
191 | params = yaml.load(open("gd_config.yml"))
192 | for k,v in params.items():
193 | exec(k + "=v")
194 |
195 | psf, data = loaddata()
196 | final_im = grad_descent(psf, data)
197 | print(iters)
198 | plt.imshow(final_im, cmap='gray')
199 | plt.title('Final reconstruction after {} iterations'.format(iters))
200 | plt.show()
201 | saveim = input('Save final image? (y/n) ')
202 | if saveim == 'y':
203 | filename = input('Name of file: ')
204 | plt.imshow(final_im, cmap='gray')
205 | plt.axis('off')
206 | plt.savefig(filename+'.png', bbox_inches='tight')
207 |
208 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, Waller Lab
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DiffuserCam-Tutorial
2 | #### See our [full tutorial](https://waller-lab.github.io/DiffuserCam/tutorial) for complete guides on setting up the DiffuserCam hardware and installing and running the software.
3 | Below is an overview of the organization of this repo.
4 |
5 |
6 | #### Home Directory
7 | The base directory contains python code for processing DiffuserCam raw data with two algorithms, gradient descent (`GD.py`) and alternating direction method of multipliers (`ADMM.py`). The corresponding `.yml` files should be modified to include the file path of the raw data that is to be processed.
8 |
9 | #### Rpi Folder
10 | This folder contains python code for previewing and capturing raw images using a Raspberry Pi camera.
11 |
12 | #### Tutorial Folder
13 | This folder contains iPython notebooks that walk the user step-by-step through the two algorithms, gradient descent (`GD.ipynb`) and alternating direction method of multipliers (`ADMM.ipynb`). Sample test data is included.
14 |
15 | #### Test_Images Folder
16 | This folder contains sample images that you can place on a phone or laptop screen for testing your Raspberry Pi DiffuserCam. We recommend you start with `sprial_bw.gif`.
17 |
18 |
19 |
--------------------------------------------------------------------------------
/admm_config.yml:
--------------------------------------------------------------------------------
1 | psfname: "./images/psf_box_exp8.tif" #path to psf image
2 | imgname: "./images/baffle_hand.tif" #path to raw data image file
3 | f: 0.25 #Downsampling factor (must be decimal, must be of form 1/2^k where k is positive integer)
4 | disp_pic: 4 #Number of iterations after which we display intermediate reconstruction
5 | mu1: 1.0e-6 #Decimal point is REQUIRED if using scientific notation
6 | mu2: 1.0e-5
7 | mu3: 4.0e-5
8 | tau: 0.0001
9 | iters: 1
10 |
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | name: diffuser_cam
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - python=3
6 | - numpy
7 | - matplotlib
8 | - pillow
9 | - pip
10 | - pyyaml
11 |
--------------------------------------------------------------------------------
/gd_config.yml:
--------------------------------------------------------------------------------
1 | psfname: "./images/psf_box_exp8.tif" #Path to PSF image
2 | imgname: "./images/baffle_hand.tif" #Path to raw data image
3 | f: 0.125 #Downsampling factor (must be decimal, must be 1/2^k where k is positive integer)
4 | iters: 100 #Number of iterations
5 | disp_pic: 20 #Number of iterations after which we display intermediate reconstruction
--------------------------------------------------------------------------------
/rpi/preview.py:
--------------------------------------------------------------------------------
1 | import picamera
2 | import picamera.array
3 | import numpy as np
4 | from PIL import Image
5 |
6 | if __name__== '__main__':
7 | camera = picamera.PiCamera()
8 | camera.resolution = camera.MAX_RESOLUTION
9 | camera.start_preview(resolution=(410,313),fullscreen=False,window=(20,20,820,616))
10 | camera.exposure_mode = 'auto'
11 |
12 | for i in range(1):
13 | customize = input('Change shutter speed? (y/[n])')
14 | if customize == 'y':
15 | speed = int(input('shutter speed (mus) : '))
16 | camera.shutter_speed = speed
17 | input('Press enter to take picture ')
18 | stream = picamera.array.PiBayerArray(camera)
19 | camera.capture(stream, 'jpeg', bayer=True)
20 | filename = input('Name of file: ')
21 | arr = np.sum(stream.array,axis=2).astype(np.uint8)
22 | img = Image.fromarray(arr)
23 | img.save(filename)
24 |
--------------------------------------------------------------------------------
/test_images/cal_logo_rgb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Waller-Lab/DiffuserCam-Tutorial/34674be3b063a266d8ce5279a31e8ac8779c1f1b/test_images/cal_logo_rgb.png
--------------------------------------------------------------------------------
/test_images/dog_rgb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Waller-Lab/DiffuserCam-Tutorial/34674be3b063a266d8ce5279a31e8ac8779c1f1b/test_images/dog_rgb.jpg
--------------------------------------------------------------------------------
/test_images/google_chrome_logo_rgb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Waller-Lab/DiffuserCam-Tutorial/34674be3b063a266d8ce5279a31e8ac8779c1f1b/test_images/google_chrome_logo_rgb.png
--------------------------------------------------------------------------------
/test_images/spiral_bw.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Waller-Lab/DiffuserCam-Tutorial/34674be3b063a266d8ce5279a31e8ac8779c1f1b/test_images/spiral_bw.gif
--------------------------------------------------------------------------------
/tutorial/GD.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Gradient Descent and FISTA"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "$\\newcommand\\measurementvec{\\mathbf{b}}\n",
15 | "\\newcommand\\measurementmtx{\\mathbf{A}}\n",
16 | "\\newcommand\\imagevec{\\mathbf{v}}\n",
17 | "\\newcommand\\psf{\\mathbf{h}}\n",
18 | "\\newcommand{\\crop}{\\mathbf{C}}\n",
19 | "\\newcommand\\full{\\mathbf{A}}\n",
20 | "\\newcommand{\\ftpsf}{\\mathbf{H}}$\n",
21 | "Gradient descent is an iterative algorithm that finds the minimum of a convex function by following the slope \"downhill\" until it reaches a minimum. To solve the minimization problem\n",
22 | "\\begin{equation*}\n",
23 | " \\operatorname{minimize} g(\\mathbf{x}),\n",
24 | "\\end{equation*}\n",
25 | "we find the gradient of $g$ wrt $\\mathbf{x}$, $\\nabla_\\mathbf{x} g$, and use the property that the gradient always points in the direction of steepest _ascent_. In order to minimize $g$, we go the other direction:\n",
26 | "$$\\begin{align*}\n",
27 | " \\mathbf{x}_0 &= \\text{ initial guess} \\\\\n",
28 | " \\mathbf{x}_{k+1} &\\leftarrow \\mathbf{x}_k - \\alpha_k \\nabla g(\\mathbf{x}_k),\n",
29 | "\\end{align*}$$\n",
30 | "where $\\alpha$ is a step size that determines how far in the descent direction we go at each iteration.\n",
31 | "\n",
32 | "Applied to our problem:\n",
33 | "$$\\begin{align*}\n",
34 | " g(\\imagevec) &= \\frac{1}{2} \\|\\full\\imagevec- \\measurementvec \\|_2^2 \\\\\n",
35 | " \\nabla_\\imagevec g(\\imagevec) &= \\full^H (\\full\\imagevec-\\measurementvec),\n",
36 | "\\end{align*}$$\n",
37 | "where $\\full^H$ is the adjoint of $\\full$, $\\measurementvec$ is the sensor measurement and $\\imagevec$ is the image of the scene.\n",
38 | "\n",
39 | "We use more efficient variants of this algorithm, like Nesterov Momentum and FISTA, both of which are shown below. \n",
40 | "\n"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "#### Loading and preparing our images"
48 | ]
49 | },
50 | {
51 | "cell_type": "code",
52 | "execution_count": 1,
53 | "metadata": {},
54 | "outputs": [],
55 | "source": [
56 | "import numpy as np\n",
57 | "import numpy.fft as fft\n",
58 | "import matplotlib.pyplot as plt\n",
59 | "from IPython import display\n",
60 | "from PIL import Image\n",
61 | "\n",
62 | "%matplotlib inline"
63 | ]
64 | },
65 | {
66 | "cell_type": "markdown",
67 | "metadata": {},
68 | "source": [
69 | "The code takes in two grayscale images: a point spread function (PSF) $\\texttt{psfname}$ and a sensor measurement $\\texttt{imgname}$. The images can be downsampled by a factor $f$, which must be a of the form $1/{2^k}$, for some non negative integer $k$ (typically between 1/2 and 1/8). "
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 2,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "psfname = \"./psf_sample.tif\"\n",
79 | "imgname = \"./rawdata_hand_sample.tif\"\n",
80 | "\n",
81 | "# Downsampling factor (used to shrink images)\n",
82 | "f = 1/8 \n",
83 | "\n",
84 | "# Number of iterations\n",
85 | "iters = 100"
86 | ]
87 | },
88 | {
89 | "cell_type": "code",
90 | "execution_count": 3,
91 | "metadata": {},
92 | "outputs": [],
93 | "source": [
94 | "def loaddata(show_im=True):\n",
95 | " psf = Image.open(psfname)\n",
96 | " psf = np.array(psf, dtype='float32')\n",
97 | " data = Image.open(imgname)\n",
98 | " data = np.array(data, dtype='float32')\n",
99 | " \n",
100 | " \"\"\"In the picamera, there is a non-trivial background \n",
101 | " (even in the dark) that must be subtracted\"\"\"\n",
102 | " bg = np.mean(psf[5:15,5:15]) \n",
103 | " psf -= bg\n",
104 | " data -= bg\n",
105 | " \n",
106 | " \"\"\"Resize to a more manageable size to do reconstruction on. \n",
107 | " Because resizing is downsampling, it is subject to aliasing \n",
108 | " (artifacts produced by the periodic nature of sampling). Demosaicing is an attempt\n",
109 | " to account for/reduce the aliasing caused. In this application, we do the simplest\n",
110 | " possible demosaicing algorithm: smoothing/blurring the image with a box filter\"\"\"\n",
111 | " \n",
112 | " def resize(img, factor):\n",
113 | " num = int(-np.log2(factor))\n",
114 | " for i in range(num):\n",
115 | " img = 0.25*(img[::2,::2,...]+img[1::2,::2,...]+img[::2,1::2,...]+img[1::2,1::2,...])\n",
116 | " return img \n",
117 | " \n",
118 | " psf = resize(psf, f)\n",
119 | " data = resize(data, f)\n",
120 | " \n",
121 | " \n",
122 | " \"\"\"Now we normalize the images so they have the same total power. Technically not a\n",
123 | " necessary step, but the optimal hyperparameters are a function of the total power in \n",
124 | " the PSF (among other things), so it makes sense to standardize it\"\"\"\n",
125 | " \n",
126 | " psf /= np.linalg.norm(psf.ravel())\n",
127 | " data /= np.linalg.norm(data.ravel())\n",
128 | " \n",
129 | " if show_im:\n",
130 | " fig1 = plt.figure()\n",
131 | " plt.imshow(psf, cmap='gray')\n",
132 | " plt.title('PSF')\n",
133 | " display.display(fig1)\n",
134 | " fig2 = plt.figure()\n",
135 | " plt.imshow(data, cmap='gray')\n",
136 | " plt.title('Raw data')\n",
137 | " display.display(fig2)\n",
138 | " return psf, data\n",
139 | " "
140 | ]
141 | },
142 | {
143 | "cell_type": "markdown",
144 | "metadata": {},
145 | "source": [
146 | "### Calculating convolutions using $\\texttt{fft}$\n",
147 | "We want to calculate convolutions efficiently. To do this, we use the \"fast fourier transform\" $\\texttt{fft2}$ which computes the Discrete Fourier Transform (DFT). The convolution theorem for DFTs only holds for circular convolutions. We can still recover a linear convolution by first padding the input images then cropping the output of the inverse DFT:\n",
148 | "\\begin{equation}\n",
149 | "h*x=\\mathcal{F}^{-1}[\\mathcal{F}[h]\\cdot\\mathcal{F}[x]] = \\texttt{crop}\\left[\\ \\texttt{DFT}^{-1}\\left\\{\\ \\texttt{DFT} [\\ \\texttt{pad}[h]\\ ]\\cdot\\texttt{DFT}[\\ \\texttt{pad}[x]\\ ]\\ \\right\\} \\ \\right]\n",
150 | "\\end{equation}\n",
151 | "\n",
152 | "Recovering the linear convolution correctly requires that we double the dimensions of our images. To take full advantage of the speed of the $\\texttt{fft2}$ algorithm, we actually pad $\\texttt{full_size}$, which is the nearest power of two that is larger than that size.\n",
153 | "\n",
154 | "We have chosen $\\texttt{full_size}$ in such a way that it provides enough padding to make circular and linear convolutions look the same after being cropped back down to $\\texttt{sensor_size}$. That way, the \"sensor crop\" due to the sensor's finite size and the \"fft crop\" above are the same, and we just need one crop function."
155 | ]
156 | },
157 | {
158 | "cell_type": "markdown",
159 | "metadata": {},
160 | "source": [
161 | "Along with initialization, we compute $\\texttt{H} = \\texttt{fft2}(\\texttt{hpad})$ and $\\texttt{Hadj} = \\texttt{H}^*$, which are constant matrices that will be needed to calculate the action of $\\measurementmtx$ and $\\measurementmtx^H$ at every iteration. "
162 | ]
163 | },
164 | {
165 | "cell_type": "markdown",
166 | "metadata": {},
167 | "source": [
168 | "Lastly, we must take into account one more practical difference. In imaging, we often treat the center of the image as the origin of the coordinate system. This is theoretically convenient, but fft algorithms assume the origin of the image is the top left pixel. The magnitude of the fft doesn't change because of this distinction, but the phase does, since it is sensitive to shifts in real space. An example with the simplest function, a delta function, is displayed below. In order to correct this problem, we use $\\texttt{ifftshift}$ to move the origin of an image to the top left corner and $\\texttt{fftshift}$ to move the origin from the top left corner to the center. "
169 | ]
170 | },
171 | {
172 | "cell_type": "code",
173 | "execution_count": 4,
174 | "metadata": {},
175 | "outputs": [
176 | {
177 | "data": {
178 | "image/png": "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\n",
179 | "text/plain": [
180 | ""
181 | ]
182 | },
183 | "metadata": {},
184 | "output_type": "display_data"
185 | },
186 | {
187 | "data": {
188 | "image/png": "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\n",
189 | "text/plain": [
190 | ""
191 | ]
192 | },
193 | "metadata": {},
194 | "output_type": "display_data"
195 | }
196 | ],
197 | "source": [
198 | "def no_shift():\n",
199 | " delta = np.zeros((5,5))\n",
200 | " delta[2][2] = 1\n",
201 | " fft_mag = np.abs(fft.fft2(delta))\n",
202 | " fft_arg = np.angle(fft.fft2(delta))\n",
203 | " \n",
204 | " fig, ax = plt.subplots(nrows=1, ncols=3)\n",
205 | " fig.tight_layout()\n",
206 | " ax[0].imshow(delta, cmap='gray')\n",
207 | " ax[0].set_title('Delta function in \\n real space')\n",
208 | "\n",
209 | " ax[1].imshow(fft_mag,vmin=-3,vmax=3,cmap='gray')\n",
210 | " ax[1].set_title('Magnitude of FT of \\n a delta function')\n",
211 | " \n",
212 | " ax[2].imshow(fft_arg,vmin=-3,vmax=3,cmap='gray')\n",
213 | " ax[2].set_title('Phase of FT of \\n delta function')\n",
214 | " \n",
215 | "no_shift() \n",
216 | "\n",
217 | "def shift():\n",
218 | " delta = np.zeros((5,5))\n",
219 | " delta[2][2] = 1\n",
220 | " delta_shifted = fft.ifftshift(delta)\n",
221 | " fft_mag = np.abs(fft.fft2(delta_shifted))\n",
222 | " fft_arg = np.angle(fft.fft2(delta_shifted))\n",
223 | " \n",
224 | " fig2, ax2 = plt.subplots(nrows=1, ncols=3)\n",
225 | " fig2.tight_layout()\n",
226 | " ax2[0].imshow(delta_shifted, cmap='gray')\n",
227 | " ax2[0].set_title('Delta function shifted in \\n real space')\n",
228 | "\n",
229 | " ax2[1].imshow(fft_mag,vmin=-3,vmax=3,cmap='gray')\n",
230 | " ax2[1].set_title('Magnitude of FT of a \\n shifted delta function')\n",
231 | " \n",
232 | " ax2[2].imshow(fft_arg,vmin=-3,vmax=3,cmap='gray')\n",
233 | " ax2[2].set_title('Phase of FT of a \\n shifted delta function')\n",
234 | " \n",
235 | "shift()"
236 | ]
237 | },
238 | {
239 | "cell_type": "markdown",
240 | "metadata": {},
241 | "source": [
242 | "For this notebook and the ADMM notebook, we follow the following convention so we don't have to worry about this issue again:\n",
243 | "1. All images in _real_ space are stored with the origin in the center (so they can be displayed correctly)\n",
244 | "2. All images in _Fourier_ space are stored with the origin in the top left corner (so they can be used for processing correctly)\n",
245 | "3. The above rules mean that, to perform a convolution between two real space images $h$ and $x$, we do $$\\texttt{fftshift}( \\texttt{ifft} [\\texttt{fft}[ \\texttt{ifftshift}(h) \\cdot \\texttt{ifftshift}(x) ] ] )$$ instead of $$\\texttt{ifft}[\\texttt{fft}[h \\cdot x]]$$\n",
246 | "The rules imply that if we store the fourier transform of $h$ for future use, instead of storing $\\texttt{fft}[h]$, we store $\\texttt{fft}[\\texttt{ifftshift}(h)]$."
247 | ]
248 | },
249 | {
250 | "cell_type": "code",
251 | "execution_count": 5,
252 | "metadata": {},
253 | "outputs": [],
254 | "source": [
255 | "def initMatrices(h):\n",
256 | " pixel_start = (np.max(h) + np.min(h))/2\n",
257 | " x = np.ones(h.shape)*pixel_start\n",
258 | "\n",
259 | " init_shape = h.shape\n",
260 | " padded_shape = [nextPow2(2*n - 1) for n in init_shape]\n",
261 | " starti = (padded_shape[0]- init_shape[0])//2\n",
262 | " endi = starti + init_shape[0]\n",
263 | " startj = (padded_shape[1]//2) - (init_shape[1]//2)\n",
264 | " endj = startj + init_shape[1]\n",
265 | " hpad = np.zeros(padded_shape)\n",
266 | " hpad[starti:endi, startj:endj] = h\n",
267 | "\n",
268 | " H = fft.fft2(fft.ifftshift(hpad), norm=\"ortho\")\n",
269 | " Hadj = np.conj(H)\n",
270 | "\n",
271 | " def crop(X):\n",
272 | " return X[starti:endi, startj:endj]\n",
273 | "\n",
274 | " def pad(v):\n",
275 | " vpad = np.zeros(padded_shape).astype(np.complex64)\n",
276 | " vpad[starti:endi, startj:endj] = v\n",
277 | " return vpad\n",
278 | "\n",
279 | " utils = [crop, pad]\n",
280 | " v = np.real(pad(x))\n",
281 | " \n",
282 | " return H, Hadj, v, utils\n",
283 | "\n",
284 | "def nextPow2(n):\n",
285 | " return int(2**np.ceil(np.log2(n)))"
286 | ]
287 | },
288 | {
289 | "cell_type": "markdown",
290 | "metadata": {},
291 | "source": [
292 | "#### Computing the gradient"
293 | ]
294 | },
295 | {
296 | "cell_type": "markdown",
297 | "metadata": {},
298 | "source": [
299 | "The most important step in Gradient Descent is calculating the gradient\n",
300 | "$$ \\nabla_\\imagevec \\ g(\\imagevec) = \\full^H (\\full\\imagevec-\\measurementvec)$$\n",
301 | "We do this in 2 steps:\n",
302 | "1. We compute the action of $\\full$ on $\\imagevec$, using $\\texttt{calcA}$\n",
303 | "2. We compute the action of $\\full^H$ on $\\texttt{diff} = \\texttt{Av-b}$ using $\\texttt{calcAHerm}$
\n",
304 | "\n",
305 | "Here, $\\texttt{vk}$ is the current padded estimate of the scene and $\\texttt{b}$ is the sensor measurement.\n"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": 6,
311 | "metadata": {},
312 | "outputs": [],
313 | "source": [
314 | "def grad(Hadj, H, vk, b, crop, pad):\n",
315 | " Av = calcA(H, vk, crop)\n",
316 | " diff = Av - b\n",
317 | " return np.real(calcAHerm(Hadj, diff, pad))"
318 | ]
319 | },
320 | {
321 | "cell_type": "markdown",
322 | "metadata": {},
323 | "source": [
324 | "We write $\\full$ as:\n",
325 | "$$ \\full\\imagevec \\iff \\mathrm{crop} \\left[ \\mathcal{F}^{-1} \\left\\{\\mathcal{F}(h) \\cdot \\mathcal{F}(v)\\right\\} \\right]$$\n",
326 | "In code, this becomes\n",
327 | "\\begin{align*} \n",
328 | "\\texttt{calcA}(\\texttt{vk}) & = \\texttt{crop}\\ (\\texttt{ifft}\\ (\\texttt{fft}(\\texttt{hpad}) \\cdot \\texttt{fft}(\\texttt{vk})\\ )\\ )\\\\\n",
329 | "& = \\texttt{crop}\\ (\\texttt{ifft}\\ (\\texttt{H} \\cdot \\texttt{Vk}))\n",
330 | "\\end{align*}\n",
331 | "where $\\cdot$ represents point-wise multiplication"
332 | ]
333 | },
334 | {
335 | "cell_type": "code",
336 | "execution_count": 7,
337 | "metadata": {},
338 | "outputs": [],
339 | "source": [
340 | "def calcA(H, vk, crop):\n",
341 | " Vk = fft.fft2(fft.ifftshift(vk))\n",
342 | " return crop(fft.fftshift(fft.ifft2(H*Vk)))"
343 | ]
344 | },
345 | {
346 | "cell_type": "markdown",
347 | "metadata": {},
348 | "source": [
349 | "We first pad $\\texttt{diff}$ , giving us $\\texttt{xpad}$, then we take the 2D fourier transform, $\\texttt{X} = \\mathcal{F}(\\texttt{xpad})$. The action of the adjoint of $A$ is\n",
350 | "\n",
351 | "$$ A^H \\mathbf{x} \\iff \\mathcal{F}^{-1} \\left\\{ \\mathcal{F}(\\psf)^* \\cdot \\mathcal{F}( \\operatorname{pad}\\left[x\\right]) \\right\\}$$\n",
352 | "This becomes\n",
353 | "\\begin{align*}\n",
354 | "\\texttt{calcAHerm}(\\texttt{xk}) &= \\texttt{ifft}\\ (\\ (\\texttt{fft}(\\texttt{h}))^H \\cdot \\texttt{fft}\\ (\\texttt{pad}(\\texttt{diff}))\\ ) \\\\\n",
355 | "& = \\texttt{ifft}\\ (\\texttt{Hadj} \\cdot \\texttt{X})\n",
356 | "\\end{align*}"
357 | ]
358 | },
359 | {
360 | "cell_type": "code",
361 | "execution_count": 8,
362 | "metadata": {},
363 | "outputs": [],
364 | "source": [
365 | "def calcAHerm(Hadj, diff, pad):\n",
366 | " xpad = pad(diff)\n",
367 | " X = fft.fft2(fft.ifftshift(xpad))\n",
368 | " return fft.fftshift(fft.ifft2(Hadj*X))"
369 | ]
370 | },
371 | {
372 | "cell_type": "markdown",
373 | "metadata": {},
374 | "source": [
375 | "#### Putting it all together"
376 | ]
377 | },
378 | {
379 | "cell_type": "markdown",
380 | "metadata": {},
381 | "source": [
382 | "This is the main function, which calculates the gradients and updates our estimation of the scene:\n",
383 | "\\begin{align*}\n",
384 | " &\\imagevec_0 = \\text{ anything} \\\\\n",
385 | " &\\text{for } k = 0 \\text{ to num_iters:}\\\\\n",
386 | " &\\quad \\quad \\imagevec_{k+1} \\leftarrow \\texttt{gradient_update}(\\imagevec_k) \\\\\n",
387 | "\\end{align*} \n",
388 | "\n",
389 | "There are different ways of doing the gradient update. The three we will show are regular GD, Nesterov momentum update, and FISTA.\n",
390 | "\n",
391 | "To guarantee convergence, we set the step size to be \n",
392 | "\\begin{align*} \n",
393 | "\\alpha_k &< \\frac{2}{\\|\\measurementmtx^H \\measurementmtx\\|}_2 \\approx \\frac{2}{\\lambda_{max}(\\mathbf{M}^H\\mathbf{M})}\n",
394 | "\\end{align*}\n",
395 | "\n",
396 | "To calculate this, we use the property that $\\mathbf{M}$ is diagonalizable by a Fourier Transform:\n",
397 | "$$\\begin{align*}\n",
398 | "\\mathbf{M}^H\\mathbf{M} &= \\left(\\mathbf{F}^{-1} \\mathrm{diag}(\\mathbf{Fh}) \\ \\mathbf{F}\\right)^H \\ \\mathbf{F}^{-1} \\mathrm{diag}(\\mathbf{Fh}) \\ \\mathbf{F} \\\\\n",
399 | "&= \\mathbf{F}^{-1} \\mathrm{diag}(\\mathbf{Fh})^* \\ \\mathrm{diag}(\\mathbf{Fh}) \\ \\mathbf{F} \\\\\n",
400 | "\\lambda_{max}(\\mathbf{M}^H\\mathbf{M}) &= \\max \\left(\\mathrm{diag}(\\mathbf{Fh})^* \\ \\mathrm{diag}(\\mathbf{Fh}) \\right)\n",
401 | "\\end{align*}$$\n",
402 | "In code, we have\n",
403 | "\\begin{align*}\n",
404 | "\\alpha = \\frac{1.8}{\\texttt{max} \\left(\\texttt{Hadj} \\cdot \\texttt{H}\\right)}\n",
405 | "\\end{align*}\n",
406 | "\n",
407 | "\n",
408 | "Since we are dealing with images, one constraint on the reconstructed image $\\imagevec_k$ is that all the entries have to be non-negative. We do this by doing projected gradient descent. The projection function $\\texttt{proj}$ we use is non-negativity, which projects $\\texttt{vk}$ onto the non-negative halfspace. "
409 | ]
410 | },
411 | {
412 | "cell_type": "code",
413 | "execution_count": 9,
414 | "metadata": {},
415 | "outputs": [],
416 | "source": [
417 | "def grad_descent(h, b):\n",
418 | " H, Hadj, v, utils = initMatrices(h)\n",
419 | " crop = utils[0]\n",
420 | " pad = utils[1]\n",
421 | " \n",
422 | " alpha = np.real(1.8/(np.max(Hadj * H)))\n",
423 | " iterations = 0\n",
424 | " \n",
425 | " def non_neg(xi):\n",
426 | " xi = np.maximum(xi,0)\n",
427 | " return xi\n",
428 | " \n",
429 | " #proj = lambda x:x #Do no projection\n",
430 | " proj = non_neg #Enforce nonnegativity at every gradient step. Comment out as needed.\n",
431 | "\n",
432 | "\n",
433 | " parent_var = [H, Hadj, b, crop, pad, alpha, proj]\n",
434 | " \n",
435 | " vk = v\n",
436 | " \n",
437 | " \n",
438 | " \n",
439 | " #### uncomment for Nesterov momentum update #### \n",
440 | " #p = 0\n",
441 | " #mu = 0.9\n",
442 | " ################################################\n",
443 | " \n",
444 | " \n",
445 | " \n",
446 | " #### uncomment for FISTA update ################\n",
447 | " tk = 1\n",
448 | " xk = v\n",
449 | " ################################################\n",
450 | " \n",
451 | " for iterations in range(iters): \n",
452 | " \n",
453 | " # uncomment for regular GD update\n",
454 | " #vk = gd_update(vk, parent_var)\n",
455 | " \n",
456 | " # uncomment for Nesterov momentum update \n",
457 | " #vk, p = nesterov_update(vk, p, mu, parent_var)\n",
458 | " \n",
459 | " # uncomment for FISTA update\n",
460 | " vk, tk, xk = fista_update(vk, tk, xk, parent_var)\n",
461 | "\n",
462 | " if iterations % 10 == 0:\n",
463 | " image = proj(crop(vk))\n",
464 | " f = plt.figure(1)\n",
465 | " plt.imshow(image, cmap='gray')\n",
466 | " plt.title('Reconstruction after iteration {}'.format(iterations))\n",
467 | " display.display(f)\n",
468 | " display.clear_output(wait=True)\n",
469 | " \n",
470 | " \n",
471 | " return proj(crop(vk)) \n",
472 | " "
473 | ]
474 | },
475 | {
476 | "cell_type": "markdown",
477 | "metadata": {},
478 | "source": [
479 | "#### Gradient descent algorithms"
480 | ]
481 | },
482 | {
483 | "cell_type": "markdown",
484 | "metadata": {},
485 | "source": [
486 | "##### Regular Gradient Descent\n",
487 | "Regular gradient descent is simply following the negative of the gradient until we reach the minimum:\n",
488 | "\n",
489 | "\\begin{align*}\n",
490 | " & \\texttt{gradient_update}(\\imagevec_k): \\\\\n",
491 | " &\\quad \\quad\\imagevec'_{k+1} \\leftarrow \\imagevec_k - \\alpha_k \\full^H(\\full\\imagevec_k - \\measurementvec) \\\\\n",
492 | " &\\quad \\quad \\imagevec_{k+1} \\leftarrow \\operatorname{proj}_{\\imagevec \\geq 0} (\\imagevec_{k+1}')\n",
493 | "\\end{align*} "
494 | ]
495 | },
496 | {
497 | "cell_type": "code",
498 | "execution_count": 10,
499 | "metadata": {},
500 | "outputs": [],
501 | "source": [
502 | "def gd_update(vk, parent_var):\n",
503 | " H, Hadj, b, crop, pad, alpha, proj = parent_var\n",
504 | " \n",
505 | " gradient = grad(Hadj, H, vk, b, crop, pad)\n",
506 | " vk -= alpha*gradient\n",
507 | " vk = proj(vk)\n",
508 | " \n",
509 | " return xk "
510 | ]
511 | },
512 | {
513 | "cell_type": "markdown",
514 | "metadata": {},
515 | "source": [
516 | "##### Nesterov Momentum\n",
517 | "GD works but it's slow. One way to speed it up is to consider a velocity term, $\\mathbf{p}$. Each update becomes:\n",
518 | "\n",
519 | "\\begin{align*}\n",
520 | " &\\texttt{gradient_update}(\\imagevec_k): \\\\\n",
521 | " &\\qquad \\mathbf{p}_{k+1} \\leftarrow \\mu \\mathbf{p}_k - \\alpha_k \\texttt{grad}(\\imagevec_k) \\\\\n",
522 | " &\\qquad \\imagevec_{k+1}' \\leftarrow \\imagevec_k - \\mu \\mathbf{p}_{k} + (1+\\mu)\\mathbf{p}_{k+1} \\\\\n",
523 | " &\\qquad \\imagevec_{k+1} \\leftarrow \\operatorname{proj}_{\\imagevec \\geq 0} (\\imagevec_{k+1}')\n",
524 | "\\end{align*}\n",
525 | "\n",
526 | "The parameter $\\mu$ is called the momentum and is strictly between 0 and 1."
527 | ]
528 | },
529 | {
530 | "cell_type": "code",
531 | "execution_count": 11,
532 | "metadata": {},
533 | "outputs": [],
534 | "source": [
535 | "def nesterov_update(vk, p, mu, parent_var):\n",
536 | " H, Hadj, b, crop, pad, alpha, proj = parent_var\n",
537 | " \n",
538 | " p_prev = p\n",
539 | " gradient = grad(Hadj, H, vk, b, crop, pad)\n",
540 | " p = mu*p - alpha*gradient\n",
541 | " vk += -mu*p_prev + (1+mu)*p\n",
542 | " vk = proj(vk)\n",
543 | " \n",
544 | " return vk, p"
545 | ]
546 | },
547 | {
548 | "cell_type": "markdown",
549 | "metadata": {},
550 | "source": [
551 | "##### FISTA \n",
552 | "Instead of Nesterov momentum, we can use FISTA, which speeds up the iterative process. Each iteration of the algorithm is as follows:\n",
553 | "\n",
554 | "\\begin{align*}\n",
555 | " &\\texttt{gradient_update}(\\imagevec_k):\\\\\n",
556 | " &\\qquad \\imagevec_k \\leftarrow \\imagevec_k - \\alpha_k \\texttt{grad}(\\imagevec_k) \\\\ \n",
557 | " &\\qquad x_{k} \\leftarrow \\texttt{proj}(\\imagevec_k) \\\\\n",
558 | " &\\qquad t_{k+1} \\leftarrow \\frac{1+\\sqrt{1+4t_k^2}}{2} \\\\\n",
559 | " &\\qquad \\imagevec_{k+1} \\leftarrow x_{k} + \\frac{t_k-1}{t_{k+1}} (x_{k}-x_{k-1}) \\\\\n",
560 | "\\end{align*}\n"
561 | ]
562 | },
563 | {
564 | "cell_type": "code",
565 | "execution_count": 12,
566 | "metadata": {},
567 | "outputs": [],
568 | "source": [
569 | "def fista_update(vk, tk, xk, parent_var):\n",
570 | " H, Hadj, b, crop, pad, alpha, proj = parent_var\n",
571 | " \n",
572 | " x_k1 = xk\n",
573 | " gradient = grad(Hadj, H, vk, b, crop, pad)\n",
574 | " vk -= alpha*gradient\n",
575 | " xk = proj(vk)\n",
576 | " t_k1 = (1+np.sqrt(1+4*tk**2))/2\n",
577 | " vk = xk+(tk-1)/t_k1*(xk - x_k1)\n",
578 | " tk = t_k1\n",
579 | " \n",
580 | " return vk, tk, xk"
581 | ]
582 | },
583 | {
584 | "cell_type": "markdown",
585 | "metadata": {},
586 | "source": [
587 | "#### Running the algorithm"
588 | ]
589 | },
590 | {
591 | "cell_type": "code",
592 | "execution_count": 13,
593 | "metadata": {},
594 | "outputs": [
595 | {
596 | "data": {
597 | "image/png": "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\n",
598 | "text/plain": [
599 | ""
600 | ]
601 | },
602 | "metadata": {},
603 | "output_type": "display_data"
604 | },
605 | {
606 | "data": {
607 | "image/png": "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\n",
608 | "text/plain": [
609 | ""
610 | ]
611 | },
612 | "metadata": {},
613 | "output_type": "display_data"
614 | }
615 | ],
616 | "source": [
617 | "psf, data = loaddata()\n",
618 | "final_im = grad_descent(psf, data)\n",
619 | "plt.imshow(final_im, cmap='gray')\n",
620 | "plt.title('Final reconstruction after {} iterations'.format(iters))\n",
621 | "display.display()\n"
622 | ]
623 | }
624 | ],
625 | "metadata": {
626 | "kernelspec": {
627 | "display_name": "Python [default]",
628 | "language": "python",
629 | "name": "python3"
630 | },
631 | "language_info": {
632 | "codemirror_mode": {
633 | "name": "ipython",
634 | "version": 3
635 | },
636 | "file_extension": ".py",
637 | "mimetype": "text/x-python",
638 | "name": "python",
639 | "nbconvert_exporter": "python",
640 | "pygments_lexer": "ipython3",
641 | "version": "3.6.5"
642 | }
643 | },
644 | "nbformat": 4,
645 | "nbformat_minor": 2
646 | }
647 |
--------------------------------------------------------------------------------
/tutorial/psf_sample.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Waller-Lab/DiffuserCam-Tutorial/34674be3b063a266d8ce5279a31e8ac8779c1f1b/tutorial/psf_sample.tif
--------------------------------------------------------------------------------
/tutorial/rawdata_hand_sample.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Waller-Lab/DiffuserCam-Tutorial/34674be3b063a266d8ce5279a31e8ac8779c1f1b/tutorial/rawdata_hand_sample.tif
--------------------------------------------------------------------------------