├── 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": "iVBORw0KGgoAAAANSUhEUgAAAZoAAAChCAYAAAD+zHm5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAGnRJREFUeJzt3Xu8XGV97/HPNwm3QC4F0toEzKbihYtFEaGCbTmILRAQ24OoIN4FVFqw8EIRtKkK4jl4SU9yjgoiCRdRK1KhWrGtgYMKhEuohSCXQAgESAiEJAJy+/WP59nJ2pOZPTM7a+257O/79dqv1+xZa571m7V+a/1mrTXzPIoIzMzMqjKu0wGYmVl/c6ExM7NKudCYmVmlXGjMzKxSLjRmZlYpFxozM6tUVxUaSQdKeqjE9v5A0nWS1kn6clnttrjs9ZL+qIJ275B0YNnt9ruy15ukByQdXFZ7hXYPkHRPzp+3l91+izFsI+kqSU9J+n4nYiibpIWSPtzpOBrp5LGqJo4vSHpc0qNltltqock73zN5Za2R9EtJJ0oa0XJK2JmPBx4HJkfEqZvRzrDqJXFEbBcRS8teVkTsERELy263Snk7Pidpx5rnF0sKSQNVx1Bcb5JmS7qk6mWO0OeAuTl/rqydWNjH1hf+/rzw+Ld5nRanv7zNGI4C/gDYISLeUcabGg016+YxSd+WtF2n42rRsMcqSRflfai4Xd9Z8/9LNblxbDsBSNoZOBXYPSJeVs7bSqo4ozkiIiYBM4FzgU8C36pgOa2YCdwZ/lVqN7gfePfgP5JeC2zTuXC61kzgjibzHJEL0eDftYOPgT3yPFML0x8cQQx3R8QL7QbfBY7I62Fv4I3AWR2Op1WtHKv+V812/27xf+BBhubGpSOIYXVErBzpm2goIkr7Ax4ADq55bl/gJWDP/P9WwHmklfIY8HVgmzztQOCh/Pji/LpngPXA6fn57wOPAk8B1wF7NIjlIuB54Ln8+oPzc18ozLNheYX4TwP+M7f/XWDrwvQjgcXAWuA+4BDgbOBF4Nm8nLl53gB2zY+nAAuAVcAyUvKPy9PeD1yf18mTpAPyoa2sY2A28L3c9jrSAWqfMrdpiXlxFrCo8Nx5wJl5PQ3k52YBt+X1uxyYXdPOe/P6Ww18pp11MThv3mbP5dxYD9xeL3dze5cU/j+usOwza5Y9DvhUzonVOY7th1kfHwHuBZ4AfgRMz8/fx9Cc36qVfaxm+kBepxOabJPdgIXAmryu3paf/4ea9fOhTudPm3lW3Ib/G7g6P14IfB74Rc6Pa4AdC/M2PK4AhwF35tc9DJxWmHY46ZiwBvgl8MfDxLc/sCgvYxGwf37+ImqOVXVeexGFY1cr77/BPHWPRXnfeCbn33rgolK3TZUbuvD8g8BH8+Ov5Z1re2AScBXwxTztQDY98NcWrg/m122V21o8TDxDNk6d/+st7yZgeo5vCXBinrZvTpC35g0zA3hNIYk/XLPsYqFZAPxzjnsAuJu8A5MKzfOkg8944KPACkDN1jHpYPgsaUcYD3wRuKHsHbisvAB+QzrAjScVkpkMLTQHAq/N6/ePSR9E3p6n7Z53gDcDW5IK1fOtros66+2SejEW/t8wT2HZf5bz7ivAC4X2TgFuAHbK078BfKfBujiIdIlk7zzv/wGua7YPtTF9gCaFBtiCVOg+ndflQaSD6KsbrZ9e+KvZxjuTCujn8/8LSYX8VaQz6YXAuYXXNjyuAI8Af5of/x6wd368N7AS2C/n3PtyDPU+IGxP+iB5HDCBdHb/JOnyJDQpJM2mt5IbeZ7hjkUHUjgelvk3Wl8GWAFsL0mkA+onIuKJiFgHnAO8q9WGIuLCiFgXEb8j7RB7SZpSYqz/GBErIuIJUhF8XX7+Q8CFEfGziHgpIh6OiLuaNSZpPPBO4Iwc9wPAl0kJN2hZRJwfES8C84E/JF0jb8X1EfHj/NqLgb1afF0nXEw6K3krcBfp0+EGEbEwIn6d1+9/At8B/jxPPgq4KiKuj4jngM+SDqhFVa2Lo0ifjK/LefcZ0ie/QScAZ0bEQ4W8PErShDptHUvKo1vzvGcAb2rzPtWV+R7oGkmb3MdpwZ8A25EOtM9FxH8AV1O4tNnDrpS0hnSV4FrS8WXQtyPi7oh4hnTWObhvNzuuPA/sLmlyRDwZEbfm5z8CfCMiboyIFyNiPvA70vqtNQu4JyIujogXIuI7pH3giDbe22mF7f54G68DWj4WVWK0Cs0M0mWCacBE4JbBFQb8a36+KUnjJZ0r6T5Ja0kVHGDHYV7WruK3LZ4m7ZCQPiHdN4L2diR9alxWeG4ZaZ1sssyIeDo/bPUmZm28Wzc4wHWDi4FjSGdxC2onStpP0s8lrZL0FHAiG7ftdNJZELBhPa2uaaKqdVG77N/WLHsm8MNCTi8hXU6t92FhOoVciIj1ua0ZdeZt5O0RMTX/jeSbadOB5RFRLJa1OdmrBtfNzIj4WC4qg+ru2y0cV/4n6Ux5maRrJb0pPz8TOLVw8F9DOk5MrxPXkO2etbvOzyts95Ec81o5FlWi8kIj6Y2kN3I96ZLBM6Trn4MrbEqkG1n11H5iPYZ0n+Rg0rXGgcHFtBjOb0mFblA736xYDryiwbThbuA9TvpENLPw3Mup+TQ/FkTEMtI9qMOAK+rMchnpsurOETGFdP9ucNs+Qro0BaSv4AI7jDSUOs8NlxuPkA4gg8ueWLPs5aT7alMLf1tHRL1tvIJCLkjaNrc1mvmwAti55tugYzIns2GPKxGxKCKOBH4fuJJ0NgRpu59ds90n5rOVWkO2ezba67xjx6LKCo2kyZIOBy4nXe/9df4EdT7wVUm/n+ebIekvGzTzGFD8Lcok0qnpatJB4Zx6LxrGYuAwSdtLehnp2nqrvgV8QNJbJI3Lcb+mQZwb5Ms43wPOljRJ0kzg74Bu/Xpt1T4EHJTPCmpNAp6IiGcl7Us6AAz6J+AISftL2pJ007rVDxi1HgMGag60i4F3SdpC0j6ky2XFZR8u6c152Z9j6L7zddL2nQkgaZqkIxss+zJSHr1O0lakHL4xX8YYLTeSCuvp+f0eSLqEc/koxtBNGh5XJG0p6VhJUyLiedIXVV7Mk88HTsxn4pK0raRZkibVWcaPgVdJOkbSBEnvJN37u7rKN1bUyWNRFYXmKknrSNX+TNKN0w8Upn+SdCPyhnya+m/Aqxu09UXgrHxaehrpcssyUgW+k3QDth0XA7eTTo2vIX2rrCURcRPpfXyV9KWAa9n4yWAO6Zr8k5L+sc7L/4a0Yy8lndldBlzYZux9ISLui4ibG0z+GPC5nD+fZeMnRyLiDtJ6vJx0hrGOdCP2dyMIY/BHiKslDV5v/wzpjPVJUhG7rGbZH8/PPZLnKf6weA7pTOyaHPsNpBvEm4iIf8/L+kFu6xW0cY+yDPke19uAQ0mfcv8v8N5W7jn2qWbHleOAB/Lx6kTgPQA5jz8CzCXlxL2ky8KbiIjVpG+onUoqaKcDh0dE2/daNlNHjkXK3zYw6yn5h3hrgFdGxP2djsfMGuuqLmjMhiPpCEkT832N84Bfs/HGrZl1KRca6yVHkm6qrgBeCbwrfEpu1vV86czMzCrlMxozM6vUmCw0kgaUerjt1h822maQ9H5J17c470WSvlDisv9K0vLce+7ry2q3heUeK+ma0Vper1IbwwXkY8SuJS1XSr1JPynppjLabGPZP5H0vtFcZq0xWWjM6lE54yGdB5wUqffc28qIq1a9D0oRcWlE/EUVy7NSPpC8mdT10k4RsW9JYW1CdYbAiIhDc/c4HdOThcZnItbFWunm38aemcADDX6o3Pd6ptDkT3Afl3QPcE9+7jWSfibpCUm/kXR0Yf5Zkm6TtDZfypjdxrI+KelhpQHcfiPpLfn52ZL+SdJ387RbJe1VeN2nlPpLWifpTkl/VdPuRyQtKUzfOz8/XdIPlPr4ul/S327e2up9kubk7bZW0i2S/nSYeXeQ9KM8703UdBU0XJ4U5tkW+AkwXRsHjpouaV9Jv8o/Gn5E0lyl3gFqX7+VpPWkXnxvl3Rffn7I5ZfiJ+PBMyhJp0pamdv/QGHebSR9WdIypdEur1fqeue6PMuaHOebai8XKvWgsCi/bpGk/QvTFkr6vKRf5Fy8RjWD0vULSW+VdFdeD3Op6U1C0gfzPvmkpJ8q9+5QM8/xpM5QT8/r+6r8/LD7e+H1HwIuIHWeul7SP9RurzzfhlzJeTJP0r/k9m+U9IrCvHsUcvoxSZ+WdAipR+7BAdFuz/NuuFyo1KvJWTmnVkpaoNx5qDaeKb9P0oNKI22eOcJVP9RIunzuxB+pf6qfkbrb3gbYltT7wAdI3W7vTfqV8x6xscvrRl3OD9CgK3VSLwXL2ThGyADwivx4NqmvoKNIXa2fRuq7a4s8/R2kzvPGkXpJ/S3wh4VpD5MGYxKwK+lTzjjgFtIv4bckdWWzFPjLTq/zDm/v95D6AJtA+jX1oxTGBqqZ93JSLwLbAnvm9Xx9ntYsTy4id79OnW7SgTeQeuOdkHNhCXBKkzzddZj/a5f3AqlLmy1IfcA9Dfxenj6P1J39DFIB25/Ujf0m+Use1yg/btYl/UKG6TK/X/5InUiuLeyvn8jr+8N5+ttJv+bfLa+ns4Bf1tt21Ommn2H29zqxbNg+9f5vsLwnSMOTTAAuBS7P0yaRepU4Fdg6/79fnjabTYfAWFh4zx/M7/mPSJ2KXgFcnKcN5tX5OS/2IvW8sdtmb4tOJ0MbSROkPrIG/38n8P9r5vkG8PcNXv814Ks1K7ReodmV1LXJweQCUpg2m6FjnIyjMFZFnbYWA0fmxz8FTq4zz37AgzXPnUHq0rzj671b/kgHyr3qPD+eVPxfU3juHDYedIfNE5oUmjrLOwX4YZM8bafQPMPQgrGSVNjG5Wn13vMm+cvQQnMccFPNa34FvD8/XgicVZj2MeBfO72NK8iZ99bsryJ1HTR40P0JhYHd8jp/GphZu+1obTyYDft7nWkbtk+9/xss74LCtMOAu/LjdwO3NVjObIYvNP8OfKww7dV5/xn8IBWk+0iD028i/V5ts7ZFz1w6y5YXHs8E9tPQLrqPJfe6q+G7nG8oIu4lHUxmAyslXS6p2O13sbv4l0iJOz0v872SFhfi2bOwzEbDDMwkXa4pvo9P0/p4NH0pX05aki95rCH1qltv+00j7STF3Ch2gz5snrQQx6skXS3pUaW+rs5pEMdIrY6hQyYPdl+/I+nT6kiGpmilS/pGw2H0k9rhHYJNjyFzCnnxBKkYtdRtfpP9vQxlD1kCm+bGMtL+UzzelJ4bvVZoir8uXQ5cG0O76N4uIj6apw/X5fzwC4m4LCLezMYRIL9UmFzsLn4cqev6Ffna7vnASaRLFFOB/yoss9EwA8uB+2vex6SIOKyVWPuR0v2YTwJHky4jTSV1ZFpv+60iXQ7ZufDcywuPm+VJUb1fL/8/0gBVr4yIyaQPAe30Gv00Ixua4nHSiKH1cqbZr6y7oUv6blA7vIMYmifLgRNqcmObiPhlnbaGrPMW9vdmhgxLodSbfKtGOmQJbJobLyftP4+1sfy29VqhKbqa1O32cUpdnW8h6Y2SdsvTh+tyviFJr5Z0kFIX7s+SLl+8WJjlDZL+Wumbb6eQrmHeQLoXEKQDH/mm7p6F111AGiHvDUp2zcl6E7BW6QsI2ygNwrSn0jg+Y9UkUvKvAiZI+iwwud6Mkbo+vwKYrdQP2u6kIXUHNcuToseAHTR0xNZJpOv865WGhahXoIazGDgmb9dD2Dhi6LDy2fKFwFeUvpQwXumm/1ak9fISDYamoAu6pO8S/wLsUdhf/5ahhf7rwBmS9gCQNEXSOxq0VTsUSLP9vZnbc2yvk7Q16QpKq64GXibpFKUvoUySNNhbeL0hMIq+A3xC0i5KHdOeA3y35qy6dD1baCINA/0XpC7WV5BO975EulkKw3Q538RWwLmkT5SPkgY7+nRh+j+TrvsP3mz964h4PiLuJA2L+ivSxn4t8ItCvN8Hziadaa0jDaC0fT5QHkEaVvb+vNwLSJeKxqqfkq6f3006tX+WoZc8ap1EOr1/lHRt+9uDE1rIEwrz3kXaEZfmyyHTSV/4OIa0zc6njaElspNJ23fwkl07Qy+fRuo4dBHpss6XgHGRRhc9G/hFjnPI0MHRPV3Sd1R+v+8g7c+rSf3jFffJH5LW6eX5suh/kYZOqOdbpOGc10i6stn+3kJsd5O+BPJvpG/RtvQD4/zadaTf5BxByud7gP+RJ9cbAqPoQtJwKdeRjjfPkoYOqJT7OmuD0lekd42I93Q6FjOzXtGzZzRmZtYbXGjMzKxSvnRmZmaV8hmNmZlVyoXGzMwqVUkvyJJ8Pa5LREQ7Py7siMmTJ8e0adM6HYYBS5cufTwiunpjTJw4MaZOnVpae6tWrSqtLYCBgYHS2lq5cmVpbQHssssupbZ3++23t5Qv7m7fOm7atGmce+65nQ7DgKOPPrq265quM3XqVE444YTS2ps7d25pbQHMmTOntLbKjm3BggWltjdt2rSW8sWXzszMrFIuNGZmVikXGjMzq5QLjZmZVaqlQiPpEKUhcO+V9Kmqg7Le5nyxdjln+lvTQiNpPGlI2UNJXY2/O3fFbrYJ54u1yznT/1o5o9kXuDcilkbEc6Tx2Y+sNizrYc4Xa5dzps+1UmhmMHQskIdocahTG5OcL9Yu50yfa6XQ1Ptl+Sa//Jd0vKSbJd28+WFZD2s7X9auXTsKYVkXa5ozxXx5+umnRyksK0srheYhho6zvRNppMIhIuKbEbFPROxTVnDWk9rOl8mT647SbGNH05wp5svEiRNHNTjbfK0UmkXAK/MY01uShsT9UbVhWQ9zvli7nDN9rmlfZxHxgqSTSOO4jwcujIg7Ko/MepLzxdrlnOl/LXWqGRE/Bn5ccSzWJ5wv1i7nTH9zzwBmZlYpFxozM6uUC42ZmVXKhcbMzCrlQmNmZpXyUM5m1lNWrVpV6hDH8+fPL60tKHf45bKHXp43b16p7bXKZzRmZlYpFxozM6uUC42ZmVXKhcbMzCrlQmNmZpVyoTEzs0q50JiZWaVcaMzMrFIuNGZmVikXGjMzq5QLjZmZVcqFxszMKuVCY2ZmlXKhMTOzSrnQmJlZpVxozMysUi40ZmZWKRcaMzOrlAuNmZlVakKnA+iEiCitLUmltWVmzQ0MDDBnzpzS2ps7d25pbQEsWLCgtLbmzZtXWltQ/nttlc9ozMysUi40ZmZWKRcaMzOrlAuNmZlVyoXGzMwq1bTQSNpZ0s8lLZF0h6STRyMw603OF2uXc6b/tfL15heAUyPiVkmTgFsk/Swi7qw4NutNzhdrl3OmzzU9o4mIRyLi1vx4HbAEmFF1YNabnC/WLudM/2vrHo2kAeD1wI11ph0v6WZJN5cTmvW6VvNl7dq1ox2adalGOVPMl6eeeqoTodlmaLnQSNoO+AFwSkRscmSIiG9GxD4RsU+ZAVpvaidfJk+ePPoBWtcZLmeK+TJlypTOBGgj1lKhkbQFKQEujYgrqg3Jep3zxdrlnOlvrXzrTMC3gCUR8ZXqQ7Je5nyxdjln+l8rZzQHAMcBB0lanP8Oqzgu613OF2uXc6bPNf16c0RcD7iLYmuJ88Xa5Zzpf+4ZwMzMKuVCY2ZmlXKhMTOzSrnQmJlZpcbkUM4eftmsd61cubLUIYnLHHoZyh1+ueyhl+fPn19qe7NmzWppPp/RmJlZpVxozMysUi40ZmZWKRcaMzOrlAuNmZlVyoXGzMwq5UJjZmaVcqExM7NKudCYmVmlXGjMzKxSLjRmZlYpFxozM6uUC42ZmVXKhcbMzCrlQmNmZpVyoTEzs0q50JiZWaVcaMzMrFIuNGZmVqkJnQ7AzKwdu+yyCwsWLCitvXnz5pXWFsDcuXNLa2v+/PmltQXlxtYOn9GYmVmlXGjMzKxSLjRmZlYpFxozM6uUC42ZmVWq5UIjabyk2yRdXWVA1h+cL9Yu50z/aueM5mRgSVWBWN9xvli7nDN9qqVCI2knYBZwQbXhWD9wvli7nDP9rdUzmq8BpwMvVRiL9Q/ni7XLOdPHmhYaSYcDKyPilibzHS/pZkk3lxad9ZyR5MvatWtHKTrrRq3kTDFfVq9ePYrRWRlaOaM5AHibpAeAy4GDJF1SO1NEfDMi9omIfUqO0XpL2/kyefLk0Y7RukvTnCnmyw477NCJGG0zNC00EXFGROwUEQPAu4D/iIj3VB6Z9STni7XLOdP//DsaMzOrVFu9N0fEQmBhJZFY33G+WLucM/3JZzRmZlYpFxozM6uUC42ZmVXKhcbMzCrlQmNmZpVSRJTfqLQKWNZkth2Bx0tfeHm6Ob5WY5sZEdOqDmZztZgv0B/bpFP6Jmf6JF+gu+MrNV8qKTStkHRzN/ci0M3xdXNsVerm993NsUH3x1eFbn/P3Rxf2bH50pmZmVXKhcbMzCrVyULzzQ4uuxXdHF83x1albn7f3RwbdH98Vej299zN8ZUaW8fu0ZiZ2djgS2dmZlapjhQaSYdI+o2keyV9qhMxNCJpZ0k/l7RE0h2STu50TLUkjZd0m6SrOx3LaHC+bJ6xli/QvTnTC/kC5efMqBcaSeOBecChwO7AuyXtPtpxDOMF4NSI2A34E+DjXRYfwMnAkk4HMRqcL6UYM/kCXZ8zvZAvUHLOdOKMZl/g3ohYGhHPkUbUO7IDcdQVEY9ExK358TrSyp7R2ag2krQTMAu4oNOxjBLny2YYg/kCXZwz3Z4vUE3OdKLQzACWF/5/iC5b0YMkDQCvB27sbCRDfA04HXip04GMEufL5hlr+QI9kjNdmi9QQc50otCoznNd99U3SdsBPwBOiYi1nY4HQNLhwMqIuKXTsYwi58sIjdF8gR7ImW7MF6guZzpRaB4Cdi78vxOwogNxNCRpC1ISXBoRV3Q6noIDgLdJeoB0OeAgSZd0NqTKOV9GbizmC3R5znRxvkBFOTPqv6ORNAG4G3gL8DCwCDgmIu4Y1UAakCRgPvBERJzS6XgakXQgcFpEHN7pWKrkfCnHWMkX6O6c6ZV8gXJzZtTPaCLiBeAk4KekG2Hf64YEKDgAOI5UyRfnv8M6HdRY5XyxdnV5zozJfHHPAGZmVin3DGBmZpVyoTEzs0q50JiZWaVcaMzMrFIuNGZmVikXGjMzq5QLjZmZVcqFxszMKvXfz2DAKi2cU6gAAAAASUVORK5CYII=\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": "iVBORw0KGgoAAAANSUhEUgAAAU0AAAEICAYAAADbZaYbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJztvXuQr1tZHvi8vbt3w1EUFLUQyIAzaMqZPyJloRlHQ4WYCBqPM6MpNDWioYYx3pNY4aA1wZqai0YnasoUzsnIAFMGxNtAGZ2RsQTHqkA8IAgIyhEVjhxB4wW87u7ea/7o39vn6aefd33r+3Xv3r2366nq6u/3fevyrsv3rve21hetNUxMTExMjGHndhMwMTExcSdhMs2JiYmJFZhMc2JiYmIFJtOcmJiYWIHJNCcmJiZWYDLNiYmJiRWYTHPirkZEPCUiWkTs3m5aJu4OTKY5ccsQEb8ZEX8WEX8cEb8TES+LiI++3XRViIhnRsRDt5uOiauNyTQnbjX+bmvtowH8NQCfAeBFt5meiYlzYTLNiUtBa+13APw/OGaeAICI+MKI+KWI+HBEvD8ivp2evTwi/snm+okbFftrN7//k4j4/YgIrScirkXEd0fE70XEewF8oTz/6oh4V0R8JCLeGxH/3eb+RwH4aQCfvJGM/zgiPjkinhER/y4i/jAiHo6I74+I6xffQxN3CibTnLgURMSTADwbwIN0+08AfCWAx+KYuf3DiPiSzbM3AHjm5vpvAHjv5j8AfB6A/6/5PcD/LYAvwrFU+5kAvlSef2jz/GMAfDWA74mIp7fW/mRD3wdaax+9+fsAgCMA/wjA4wH8dQDPAvC1qztg4q7BZJoTtxr/V0R8BMD7ccywXpwPWmuvb629vbV2s7X2ywBeiUcY4xsAfG5E7OCYSf5zAJ+zefY3Ns8d/h6A722tvb+19vsA/hd+2Fr7t621X2/HeAOAnwHwuRXxrbU3t9be2Fo7bK39JoD/jWic+EuIyTQnbjW+pLX2GBxLjX8VxxIbACAiPisifi4ifjci/gjA1+Tz1tqvA/hjHKvznwvgJwF8ICI+DX2m+ck4ZtCJ3+KHEfHsiHjjRr3/QwDPYZoUEfGpEfGTG0fWhwH8z730E3c/JtOcuBRspLqXAfhuuv1vALwWwJNbax8L4AcAsJ3yDThWr6+31n578/srATwOwFuLqh4G8GT6/VfyIiL2AfzYhoZPaq09FsBPUZ1O3X8JgHcDeFpr7WMAfKvQOPGXDJNpTlwmvhfA50dEOoMeA+D3W2t/HhHPAPAVkv4NAL4ewM9vfr8ewDcA+IXW2lFRx6sBfGNEPCkiHgfgPnp2HcA+gN8FcBgRzwbwt+n5BwF8fER8LN17DIAPA/jjiPirAP7hcGsn7kpMpjlxaWit/S6AVwD47ze3vhbA/7Cxef4zHDM8xhtwzLSSaf4CgHvot8O/xrGX/m0A3gLgx6n+jwD4xk09f4BjJv1aev5uHNtV37vxln8ygG/ZpPvIpuwfXtXoibsOMQ8hnpiYmBjHlDQnJiYmVmAyzYmJiYkVuGVMMyK+ICJ+NSIejIj7lnNMTExMXH3cEptmRFwD8GsAPh/AQwB+EcCXt9Z+5cIrm5iYmLhE3Krjsp4B4MHW2nsBICJeBeBeAJZpRsQd440y253L+3xPn1fluHz5m6+XygCAXBD1vz7v1c+/lZalclx5VVuUTnetyPu9fujR1uvnpfJ6dK0Bl3Ge8kbnwkjapfx8z82tar6NlrsNLmgsfq+19glL6W4V03wiTu/KeAjAZ3GCiHgBgBfQ7wupeJtyRhmhvlg7Oztnrq9du3ZyvbOzc+Y68/N1Ve7Ozg6uX7+O69ePz4e4fv36ybPd3V3s7u6e5MlJc/PmTRwdHYcwHh0d4ebNm7h58+bJM3etuHbt2gk9XP/u7i6uXbt2pm9aaydl5YvE7dnb2zspl6+Z/oODAxweHgIAbty4gRs3bgAADg4OTtHMdWpfch8w3AudfZ407O3tnaKNkeUdHR2d9O3BwQFaaye/HT3aT1nW0njo2OSYM90JNx4KZShMp97L9DqeTBvPrxyzw8PDk/tJP5fBZTNT1XocvUuLJl9XTHxk0fjzP//z37IPBLeKaTqqTrW8tXY/gPuBO0vSnJiY+MuNW8U0H8LprWxPAvCBW1QXgPUS5jbpeZV3UiSwLGmydMo0cLqUHvb29rC/v38iAe3u7p6ShlhSYCmL61BpiK/d6puSbtZz/fr1E2mMJVCu++bNm6dWeG7btWvXTtqj9GcaltKAY6kl6wRwSoLh/nK0ZHlOOlWw5MuSJtNy8+bNE2lK0Vo7aRv3O9PG9GU/ZXk8HpWk6aRWrofborS59nN5165dO1UPtznzHx0dnaFz6d3J8c8yVepj6VL7Ju/z/KzMOKxd8LX7fZG4VUzzFwE8LSKeCuC3ATwXZ7fIXSrWMMmeDW6JUVbXOVkrFU5VcuAR1ZhfbGZgPClzghweHp5hmhVzckxzZ2cHu7u7JzQwM1FmwOWo2uv6gJnmzs7OKbX35s2bp5irm/DMGHhx4fYpPfySZj4uj9vJ5SeTUGauDIfLrkw33E/MdI6Ojk6uuWzuG50nvNjwdTW/s5xqrmnf5TWr4EqnA+fPfnHjwe3nsYmIM6r6Gttojx5u/4iqv4RbwjRba4cR8fU43s52DcBLW2vvvBV1TUxMTFwmbtnHplprP4XjE2RuOUY90WvTOMnQqdGsgm4rabKUtb+/DwAnUqZTIVnKSEkty2IpSVd2VicZTPP+/v6JBMYOG5U0VSXnsrIevmbnVdLN5XDfsNSX91UFZklTJUonpagGoX3L/ZT1JI1cT6bROrn9TtJMJwq3k8uvaNZ+4XaraULhxsap9yoNVqYG4BFp0zlKM7+aGzhN5SBSWtx4cj09Lcr1g7veBnf0F/pGbCtr8+mLpR5yZi4V0+RJrQynYpqZjm2Ye3t7Z7zXeb2zs3My+PryMZjmytbHadQkoO3hvunZRB3TZMbE6lvmWWKanIY9+dm2pbAXHs9k4GzuSLCHmOuv+lhRMbI0QTjvM9sXHaNLOrjdSwyT6ed5y2NVebKTroxe4MUucXh4WC5u3Fdsbqja5uyelSmownmY4Zq8cxvlxMTExArc0ZJmBbdCVapEL51Khj2POUuUzlmjkiaAU3mcCp5SH0uanIc9nAleoVMCXVKpU1XNOlUCqyQavl9FCagUnvUfHBx0+9p5ddmMwXVku5fAtKRTjZ0q3J9OhdZ+YJpHzEApgbm+SS81l13Rz/kTlcPLSf4u6kKdP1ouq+QsrVeOIQb3p74DXE81H3qqdS8+cwTbSKd3HdPsMce1jNIxzSU7pqpPan/iCZuMiZlUquTAWVVZg8urAVc1klUg1x/sRU5auD2ubzg/M7NU/5wazfbWmzdv4uDg4IQ+7Xd96TOdU6fV26ptZyajfekWFPUqc1gMt11NLBUzULU328BqLJsruG+THq7Tqee9jQpVGJzaMTVwH8ApJp/5mU4NdargzB0MXigzjTMjJN0Ozi56KzDV84mJiYkVuOskzQpLEqeTGHqOoFGpUz2VzknE8Yuqjlcec16ZnQTEvysJxtWfbamcP5UEqBK16w+mgyWYTO+8qkyDbr105gmFSvEsafJ4srf36OjISoPq3GBJU2NINQY127W7u3tq3CqJzrU/5ybPgYRKVmp6YemUpWimxQXd5/hxP7k52JM41Wyw5BXntrrri/KEb5v3rmaaa7zr1QCN2DR7KiS/VFU6DX3J+2lfVNU362S7XzVpeZL16mdbqbaNy6qYvqpwzo7pGGWm0RCVyozBL2+W69qe6djcoQuQMoNkFLyPmvebqwpchZcpM2RmNBJKo6hebmWyHHamC43zfnOew8PDU/2p4+9stzyfdMyqkLZqQVRU9mK1dTq75yh6Jq4epno+MTExsQJ3rKQ54q3UdNWKxc+cdMnXTtJUadBJY/qMPeacn6UCjSVk1YpXdl5xl1Tzah84S0xOxc//7sQidYhoH7iTgLgOlTS1bo5Ndeq0kxay/v39/TObBbidCZYId3d3raSpzgyVlhnsVFFHkpOouQ8ZVWytA0uHrO1U5hbdBuok1SzXaVW9fej6rjhtp9eeykzWq3NbyXEt7kimuUbtdvccw1xSz51NkxmVU6Gd15LVRmaOLqwor92E14nogozzhatUcmaganvllyTLY0bL+dXWWanR6slWzzzvVuIFyXnM2VaYbeXxYBPHox71qBOamdFnPuB0oLYySg6rUfucWzg0RCevHZPgPnR2O2WayugY1Xx06rZrJ7dLzQ4VA+RwrIrRsh2zZ1JYGzbEdtzMz3N/2zCkJdxRTLPHLJcYJf92/92qpjZA/e1i39Tup0xTJQDgNNNSaZTLVigTyXs8WVSKdGdjqiRS2THz1KXM4/opy2KbHjtFOB1PeJXKWQpnSdvZ4LKtvFhp2FZea5wr95tjmoeHhye0aFhQJcFpbKy+yI65VUxTHVG62yahTqmK6amN20mAbt5y2QndossMtNLKFNxP3OYRTXBp2yzf47JdrPIaTJvmxMTExArcUZLmNhjxznE6tWnqfbXdZTqnzqp6rqFJLuRH1fOeapVQ1VBVIZYUnR1VpWYG2y6rY+KYxnyu9GU6Z4dU8wJLint7e6dUaZZanY1R8+tefpZmVY2u1FsXIqQ2zYiwarOqjHwEnpoonPdZzSucv7evXiVYlRAT2X431/M+a0j5XPuD25nHEzpJszIx8diqFsB9W0nk3N/aNzpuTgJdo8LfdUxzlElWeSqbpqocyhAdA9EXmV+ySj1WG56Wx4PvDntw5gHHNNQep0zLqboa78fpVe1lm6baSV0dnEcPXs50esAFM82qD7UsF3+p4JeUTQL6YnOfKXNktZ/v572kx/Wn20XEbXYLDzM2pU1Vb3bMVeaBirFzfmZGPQcNQ1V612ZNx2PFbeGtp455OkapjH4bpjnV84mJiYkVuCskzcrh00tfSZRLTiH3rLqv0qhKl5V6rhKTa48e1+XUuZS+lj5s5qTjrJPP91QvO0uKvFOnkgC5fnaWpJSW9bB0yCocn0p/dHR0SkrS/mTpmCMGOD/3m6rarLZWkh2PC0tDLMWrNBsRZQRC5TFniUvpYU2I+4wlV56T3AbuTx2nrIPHVcvWXVSjkibTr2p03lenH2sbVR6GSpFLDqK7Uj3fxsu1Js8oA3WhRarO9LzKlffcqZZq0wTOhrwApw+V4Pv5Urp6KvuktlO/EeSiB7gOjSlUkwabEVjl2t3dxT333HNSJzMTZkZsg+RQJu5bppmvdVeM7lBiOLuhPlebWvUC6jxxYV9cFjMGXgTz2u0iclEXXCe3mRerLOvg4OCU6ULpZ6blYlh3dnZOjaczbWke9WrzfFYmzDS5U6e076tFiPuv2pm1hKmeT0xMTKzAlZc0e9KiOnB6aZwEOSJd8mq5bR6+dtKZOlIqSVMdLNXqqPmdFOv2myf9SoPbkaRScyJXclZvM52q1Ilr144/sfHoRz/6hDZuJ0tGLn9KmnrivaOTD5jQ9iRU/XN15jgv7dLhsrMvmE4nLek+fJbsmM4sk/ugd51l/MVf/MWp9vF/bX+Wwf3EMaxZP6vQ/A4o+JlKmkwL16OaVjVWPWmR6aniVEdx5ZnmWpxXJef7jpk4OBsS4Bkj2wodY1J1khktqxlVO5VJsA1NGUtPnWM1ntNx3zAzZtVSbcHcH/xycv577rnnlO00Ub3M+iKreu5st0xLMuPKxMH1uGunmruXVqMSNOzLvcx64AczRlZj1a7uGGgunKyGM3OqAvd5nPnA6CpwH4AN39I0PG4aVsSoDgBhWyej6v9bga3V84h4ckT8XES8KyLeGRHftLn/cRHxuoh4z+b/4y6O3ImJiYnbi/NImocA/klr7S0R8RgAb46I1wH4KgA/21r7joi4D8B9AF64bSWV+DyitldqQm8lrJ7xypv/K8mkt/o7R5CqU+p44ZWZr52zhT3cee2cPyqBqcPKmRG4b9ip5PqXx00dIdrmVM2rPeaVF5RpVmldnWGJKiBcJRttD9fH5ThVU8FSn3673jk7evv1GZUmxBpFzgEXKM6qv+5p1ygJVsMdnEfbgaMJdL+/SpZrtEZHx5KTblS1V2zNNFtrDwN4eHP9kYh4F4AnArgXwDM3yV4O4PXYkmmOdtpIOsdAe8zRXSsDcGWraqpMwjEj9Z47NQs4GyKhITdZbnXCjZ5sxLQl1A7KX5DMfJmH2+xOy9F+VPU27Y6PetSjTpklnOqrZTEtSa/bRcQqMKvg2bds49SDd7M+vk6oWskLmjIfNcNU5oIq5IjNM6rqjjDNiDh1pmc+Y6bFJhZtq2IkZEdtjwyn0ivDZEbfA8/Bi2CII7gQm2ZEPAXAZwB4E4BP2jBUtNYejohPLPK8AMALLqL+iYmJicvCuZlmRHw0gB8D8M2ttQ+PSoettfsB3L8pwy4FurJeJEbU80qy1HxVHlWtqthGlmycI4frq4z1vdOTqsB5JxGn48h51rN8beeS11L7ADiWBvPItv39/dIp4srL/9xmDcJ3UjSr+ru7u2f2JDs1XiXqhB7TpvF/bjx1s4KWV231c9Ks6w+nuajnX88NzbnB0q3GsyqtTiJmqT3nI0uRLu6VHVTZbu5Llao5DadzNHJd+t5w+m2k0HMxzYjYwzHD/KHW2o9vbn8wIp6wkTKfAOBD5yj/POStKr+61vRL9tLKppmTeinkSNVBZU7O7tbbaaQB7Y6BKXPXMCNO5/qPvaD6rDJXPOpRjzphckkXq6ocJeDUYzVJXL9+/RTTZPo5REYZPS88zg7LdDH0mDZmuEyzLlS9cBkXfqNlM5ixqF1b7cJuPHrqvdLGDNWp5Ddu3Dj5ncf2ORuwtp+jFyozxAgcA+wtNpqmsmc7bM0047i2HwTwrtbav6BHrwXwPADfsfn/mm3r6NRd3hu1b+rvJVvlEkYmok5YF/LD0qXWzxNOpT9+MVUCYyZaMUq+ZkdKtY3T2feAs8xI7YN8+hCf7clQm547rEHp5xPauZ3aVwqmt7JjOinr8PDwjN3OtVmvtSy3pZBf8p62o1Kbo18ZsJbHtLkzWbOelEi53h4zdTuZlGZmmkojY2dn59QiWrWl1z+MEQGph/NImp8D4L8B8PaIeOvm3rfimFm+OiKeD+B9AL7sHHVMTExMXCmcx3v+CwAqNv2sbcsdrLtcIS7CDro2v9q9nMqUkuVSOrcKql0qryu7maqDlUpemQrUs74k6Ti6nKTHdky1m1bHjFXSBLc/y+VvCbEEyJ7jRB54wmpjNW7OWxwRpU1U8/M4amSBk9p0boxAbaXcl1qfMz24SA1On8/0kI4cw9baqeB2lg7ZRNIbT7VhshS69E4uaUNr8i3hSu8IWsMAq3jO82CprEqFG1H1K7VLbWg9hlypg7pV0jmcKqaZ6rxj4tp2p1Lpy5dlAsCjH/3oUyq5U82yLGfT0z7juMx0JmX6TMcvnDIJdqCxqliNjTodVI1mOp2qnPUmKtttNeaODqf6q42ZTRycvzIXZZ4slxkiq/GssvOpW7m4jJgb3DxTR1BPPWes5RWcZ41DaOsdQRMTExN/GXGlJc2rgJ6ktZTHORQqqamqs5IuVQVU50/erzz26ohSaVRXfqC/a0Y97Jl/d3f35CAO3hOuElcluTpHi7YzP57mzBga0K7XzmOuZbh7OnbqiOF03H8sgVWmD+3/nrTL48YqeSVpqkmBJVUut+fZd2cD8NxKCZq94S7YnPuf52BKmUvvnjqbeuajpcD9NRrqX0qmeR67J7/s1YRn9NSsJXtVT0XWCV9dLz3Lsvjl0xd96SQfbluWm7/39/dP7JhsKlAVXOFOuFGTRDLg3E3UYy567eyLFdxLmn3kFjTN2/PiVvl7DLqywzpPvI6f9gszwGoR5/L4pCWN0+TzOHWHWD7jr4hyfmfXryIllsZWoe/7NrGZjKmeT0xMTKzAlZQ0L9KZc9EYkU50peT7qsbqfc7vrp2DoeetrdTwynPKDpRE5WRzhv6U+CrnT1W+esxdTKqq52pScBKMqoYMdZ4kVO1z6dWR5PolaWZaGJVTRNvamwNupw3/Vimrcr5U9/XIuMr7z9KlSoPA8ZF0wGmJ2JlLXH7tJydd5zWPZ3WE3HlxJZnmkv3hvFgq04WYLKGaiKp+OaY5SltPLXHe86zfqedLqmXVbjcR+eVNBszf++FQoEQGhycq+6LSwV5+PmiY0zqbXj539jyth2lR5p150vvvxtHZ77JOpaGycbu+yPrcHKpClvKa7Y3OnMQed54P2v8jTNPNnSqIf2Q+qmmrZ9Zy0Qi9wPltom6mej4xMTGxAldS0mSMrARrHTuZ3kmUlZqjULWlgqpfztje8xSqZFLV4VQ79Z6rsb0yI2idS32r0hhvadQj31y8napWPDbqCHIHk3B6oH/MGvdRJW2qaufMGHlOJ0sz7hRy3ffNbdKxcWAaU7rl8npty3I5Tx5Uom3TOFXeHslSpJojKu+5OqPcvKskSOcE5DSViUylSzefXJ5s/yiuPNMc9YjdCowyUL1fMSall9M5Bt47k5Chk6+nzvFEdGWvmTxqYwSOmQl/gpcZi9oaR8rV9rB63rOxVuUqg3eqtIZWMcPRw32X7L1u3zW3gRmoe4G1zao66+eSgbOfDc5yMs9S1AabeHLMqvnJc4vrd4w7UdlrlV62VyZGIx6S1luBqZ5PTExMrMCVljR7kuTIarUNKufPGsnIPaukwSyb1ax8llvWNG3COZ/UC6k0aF4tV9P2JAG+zroygN1taawCpnt921o7pcK6LaFZljMpVKphSmzOM8wSHEunKmlqHpZinaquDhz97rnr64g4tSFAP2LH1xV67wqrs3zNqnZl1mF1eK15rIednR3ryHPl6LNb5TFnXGmmOYqLUNWdmqUMVH9vo2pyWS6/TgRWAXsHFzjmrHZUpWeprCWwrS092WnDdC+TMkpuF6etvNx6TmZFN4esaH8o7UybW7iyTVk/M+3Mp/X0zhZlJqjB/q7fWVVOk4QGjicdWW8v6kP7trLd6jxxXu6q3KVn1TWjNwer90b314/Usw1DvSuY5jboMVrX2dt0bs/BosxXjeDAI7bONSfEOKmgkhp7C8WSpBnxSCymfpZWbViV3bAKX+F6qx1NagdW2ioGWUlGbLdjxqAHoChjZtr4NCXXluwXZ++tmJGej8qopEs3V51TpMewehJ55TDjsVWhYGS3UmLUycrpeMHQenrX22DaNCcmJiZW4EpLmrfSQz5Sbs+2qc9cYPFS2W7FZntOzw6qXnGWgNQG6GxQTjqr2sxwqrKTNJnWys6kqz/TwHZE521WWnvScSWdK5x0qpsF3KEgSo9KViy1qYrv6Okd5zciwen16JzkflC6nHTYs1GzFMh59NodJJIY8ZRXpq0R1bwqZwlXmmn2MKJe9yaKvqRLk8oZnRmVodzRldeVrbI6HUZtS/xisbNAQ4wqFbCyz7I6pnmYgTHT7B34McKQOcSEmQm3TZ0/2o4R5xWn0Re4ctqoY43h7LCOaWVadYy5EDA9qapy2vG1zqdqrrk+SVTxm/xfGV3m4R1e+a44RlnRqap6z/lToVK9R+6vwVTPJyYmJlbgjpU0eziPSj+6+qja7FTAbelS6bIKuXEfTHPOhSUJzLXZSeF6SAbv/WZJWyWySirUYGgnRavHvJKmdDzcMzc2TgJh6U4jAaowp8rBoX3Lv5lOZ1bJawZLxM4Jo3X0tC69x85I5xzUth0dHdkT4bVvGHqvMmlUUG1Ax9lpUj0H6DaS5pVkmiPq3K2ydTKWGGjllWUblm5hrMI6GPqSO0+uelWrgx+YhmyTayfXXbWZGZ0yE24Xl8kvQ6VyqSea6+G2KS2jdrul8CdtQ1W/e/kqFZTL1TxOded69Kuho7GIvXHjaxeBoHQzY6k87pXaq/Ve5Luq85lNOkdHR2cWNUebG581zPPc6nlEXIuIX4qIn9z8fmpEvCki3hMRPxwR189bx8TExMRVwUVImt8E4F0APmbz+zsBfE9r7VUR8QMAng/gJWsKXOvI2RZOTF9yLjFYSuB7lROhcsr09uX2VHLnYXaOIC5vyVlRqelZfzpl9vb2zuxwAc5+uuLo6MhKY1o2l+P6LcFqIpfDkmKvDVxOJWk6DSHTqJpaSTOVU4lp1xhU5zFXOCfPCJzUp+PWM2OsfdcqyX/ElMVOSOD0+5WxsIrDw8MTaTPLruY61+MOkFnCuZhmRDwJwBcC+J8A/OM4rvlvAviKTZKXA/h2rGSa58UI0+2pc6OTcsnbqqoQ/9ZyXJ58eZ19r1LJHWNeUkHcTiNneuDQImb6ynQrRqkLHeepGGXPc6wMndPwi9ezYakpI/M4e/GS3c3NJ25X0uXMADpuvI0xkf1a7fyp7LiOJtc3I4yjYnrORMN5nIlklFFV48ybQpJhcuQJM0Re7FxkxxqmeV71/HsB/FMAObIfD+APW2u5HDwE4IkuY0S8ICIeiIgHzknDxMTExKVha0kzIr4IwIdaa2+OiGfmbZPUijettfsB3L8pq0qzWi1Yk+c8KrmqvU5icR7RSiJ1+fO653BJVOVqO5wXlO+rU4WlIQ0uZ+iqntKQSp0O2c5KbVuS/LOf3QYDlfS0HGcuqfaEs2SX7XJzSOnXtrixqswA7KHOa90yqPVUfcftVWifVd53TVep+/rMjUdFswNHWji1Xc1COm68eWQbjznjPOr55wD44oh4DoBH4dim+b0AHhsRuxtp80kAPrBtBWsZpmKJga4tf2mSAGftVNUE0/pdupxgrmxlzlUaVZ1Hdkwwc4iIUwdWaDqXv9rpoQeRaF+4vu3RWdk9szz+r9d6T/ttLQNXT3ivXa5ORuXtTYbJ/enocfldG5xdt4Kbn8pAdSdb1feV4NGr09nCq3cRqDcrOFv4UtsVWzPN1tqLALxoU+EzAXxLa+3vR8SPAPhSAK8C8DwAr1lb9nmZ5VI5a2wp1ctTrbjMzDQ8oqq7kuxSgnLSUCWd6koOwL5klSNIaeTviWtZLn1KsGywr6Qxvq8L0FL4DLeTtzlqP3H9jm734qrUV20BVKbD5bj5hSIvAAAgAElEQVRx7i2C6pRh2qt4zJFF2M3batx5oeuVW83BKp06aNy8deMyErdZ9YU+0znqaBnFrdgR9EIcO4UexLGN8wdvQR0TExMTtwUXEtzeWns9gNdvrt8L4BnnLO/kurcCLIUM9SQoxZIqkauS8wKqBOjQU8+1LJUsq/AXV3bP21yFXmh7d3Z2TlRyPg6N83Hfuj3EI6EcPUnJ3efnGn5VSWP8W80DKqFXY+jCp1IC5LoqeyHT7DQJ17YEe4R7djutR/fxV9qGtjFRzXtuZyVpOknf0VlJkCpdj6AnjY5GwIziSu4IGsV51PglJlldj6RluFAH4Cyjc6FETj3vOZm0zio2zV1z+/I7P0pnL8Slx7Tcy+QcWY7pVC8jn6KeaZaYgXv5mWk5ZsDlsa3WHTTcW4i4jWpOyGu380nzM51aH9/nraca9uUOxmAzBJedfcGqdppeeuYi9z/zuD5ag2qce6aMJTvw7VbPJyYmJu5aXElJkyWbHpZWiaXVY0QddOowcHbFrDy5I0Z0lRq1rEo95/tOMsrryqvq6L9+/Tr29/dPSbtcljOoc9lZXyWZV5KJhga5MdBA/yqgXb3/Dr0dWtpGdf649ld1qdTqzDTcBs3DTjGV+lxd+Z/nBktgVTRDRJz6dK7Oexe1UZmLnClrRCvjwPQeeloN33ftrN6HNWFIV5JpbiMyb4NK/a7q1Qk/su2tylup2rrrp3cwhnuxnP1oxBOdqm5+ftcdvNsrc4kxa526aFTMpLIBcjjX6IR3L7aqzq59aq91dbJ6rqYC5yHv0ddjMJUZguHs2q4NHJZzeHho+yLnYDLUXqyxa0teu3mrC6dGUywxx2oO5nUVXldFkIxiqucTExMTK3AlJc1bgaXVu8rjVkj9PSIRZ1msNrGxvjo/sneow4gEyPRVnt7d3d0Tx09+TZKlQO6DnqRV1c9q96h05JwHlTRYOTccPWo6cVLPiGSSeZzzR/c0c51Lx/Q5VPOs6k+tk6HnYfJ9HnN1YDoTkdK2JEkvodKQ1CzCNPciJSqJchvpknElmeaoWj5iJ1lbZ8/u1rPnVMy1yl+VpapRLx3XMeIR1Pbki8AHcbg6XXu4/t7JRdVztVs6JpnX/MIm+KDcfBGqg39d+/U3M4oqSsAxVm4Db9Vj+l2fOVTed22XayebAZSB6ZjwxgP2ni/NTe2DSj1XOrWNS1EGDpVdmcutwpR6C99UzycmJiZuMa6cpHkRzp9q9Rq55t8qmQE+sLcnjan6kvn1ExXOE57XlQrkJBddRXuSVUqXqZJnmdXWTeC0ZMLlVodIKHg7XeWh1Xss3fX2zju1U1VjlWir+NbKcVKZJRQjKjW3RyXVSs3kAzsODw9tv7t54kwP1RmaOzs7Z+JQK0+4g5PmRhyEI85F7Q+VLkc84ueVNK8c06xE99F8a/JUanSVpjowo1JnnVrjGGAvT081ci95r/3MJK5fv37qs7tqs6r6w4UFqa1Uw1qcesvI525B0JfJnZiULw/3B9sXK/MGmygUS+qggzM98P0sT80Kej+fJZhJ5l/ed4fycp85O3BvDJTe3u+eKUvbNsKcqrlbLTQjDFKfr8lTYarnExMTEytwZSTNapVem38k75KDxBm61UGi0pkri5/1jPM9R4i2zUkmvXMd2UGQ7Uj63enkPUmzkiCdWqUqc5bFAcyVOqb9MaIq91RAN55LcZlV23rj5iTd3nys6lFpis0OrJ4fHBzYOlXzYDorp0ivL0e1v2o8q4B6YGxb5aikqmU4nlLRuAZXhmluo16vyd9jlHq/8mQro+SXUc9Q1DpV/a6876NQRll5ZrlsZZQuOF/LqlQjZmD5jO+7l5nTcZ+ouqUvkquTz5V0E38kSoGPLFOGzLZCZ1LJfnWMV1Xtyr7YY8A9JjdyVFzP+71k63OL09IxbWpOUMZbRTZUbdH5tbSjqQdus7a/YqY9XBmmeV6sZTrVhK3sjjrR3QuUqCbykq0oUU1QfpkBH/bjnFIuNpRPCdI2c908yfXUcDep9X7VZifN8Mk8zkGiL7P2EzPdpcUzbcIVo6jycj+pY2npxVPHni6clWPP0aj1KcOs7Is9ibzqC2VUbqx13KvDkittYVv7YsJJsExbpcluU++0aU5MTEyswF0jaY7ASYv530mQumKrGssYsftw2aM2NK1DQ0GYNuB4xeXjzqpDLnoecgUfh8ZSp5N6UuJwdliVpFg6Zro5cJ3LZkn75s1HTod3dnA2STiNICLOqPhLe51Vze6FYzlzEbdR6anMKyrNqb3SwQWdO6lP1WGnUagdlcdA7/dU+qVAd/cOVO9EZW+tMKKer8GVY5ruBXC4qDSatlLVe+X1DOdVOh08lyfT9JwfwOlDeNXWyip59WE0povVGuB0LKDaFKvQDx1DZ0ZgRu/MEO63vrCVGu2YE3Dadqt2sYqZ6JiPOJK0DxlatguzqswQvU/4VuYiZ/9z85hp1ljQg4MDGxvKIU/KQHt20Mqs0zMhjKrRS2aZqZ5PTExMXDKunKS5DUYlympVqVS7SlpaKq9aMSvHh5ZTSTA9yaraTVOp5Eone7JZCq5UMFVtVUpzfdhaK9vm+kfrZCmLw210/HZ3d61TiCUwp3Y6qYxpdg4zN/eWvLrOdMEOL54bqir3HEGuXE2nqBw83M8sUXJwvUqdaurozQ93rW07r5OIJXc3V7ZV068M09zGtrBtfteBo/Y9p07ohHN2sqUJUJkEeALzC1xNKlZBM8TInUEJnP1kA3B6omWavD48PCztmNW2ux5jrDz2fK12zIODgxO61FbqVDDdQqgLgFODuf1VDG5eO0bLqF5YBbedmdTBwcHJddpxnVdYaVWG5aIWKq+2s2n2zAV6fxsVuLf49LzsPM69xcrNsW3V9HOp5xHx2Ij40Yh4d0S8KyL+ekR8XES8LiLes/n/uPPUMTExMXGVcF5J8/sA/N+ttS+NiOsA7gHwrQB+trX2HRFxH4D7cPxZ3wtDb8VWSW0k37bqfbVi97x+lUqeUDOAk+KS5kqa0wBu9qYvSbxKn0oTThrUeyNj4PaBs4nA0dejRR0hfACJ83AvSZqcvjLNqNTtYljVAaPSIDvGWKJ3HmoXNJ5w84brraRtlmJ57Pm+tq3nsKnqd/erNqSJiOcHS+vufch03J+MSpPcRvXfmmlGxMcA+DwAX7Wp/AaAGxFxL4BnbpK9HMef9r1Qpkk0rErfU5NG1HMd/CUGonX3VHP3YubkcZNO7VZcFnuL2WNeMX1Vp7JuwNuqqvYpHcDZCZ/39bDlajtdpU4qzXyt20K5TbwYVAHY3JYltc/ZASua88xOp8ZqZACbIdhzzWUvecz5vlPDe+FDrs8SS4wm63Qmp52dR05Q4nHnfsmFjseQaeKoi4pJMpSZbmvLPClvdY5H8CkAfhfA/xERvxQR/3tEfBSAT2qtPQwAm/+f6DJHxAsi4oGIeOAcNExMTExcKs6jnu8CeDqAb2itvSkivg/HqvgQWmv3A7gfACJiSEauROuR1cJJU2u9cyOqCKPyBiZGtmFWEhVLCXnEWz6vHD+qnnM9laqpkskSUkJgKYPb6b7VrlJ2JUFqGq2DT5933xZ36riqodl+7ove2DinSJan6VXK0TrZK52SpsbJViaJqg9zLJYcOaNe+p625K7db5Yu3Tw5Ojo6Y77hMyDcVuLsG1Xxe7Ruo5oD52OaDwF4qLX2ps3vH8Ux0/xgRDyhtfZwRDwBwIfOUUcXa0TrbW0Z1U4NZSAjzEjp4YndKzuh3+6pwox4gqn3mOtwfZCMgO1rrp187VR7tqMybVWgfU+FqswQarvNsvf29k4xah4btectqedqa2VUO6TUjLF0ZifTA5z2mCvT5PJ0Qaqu1VzgGKhea/+PMM7KxFKhV44yPcdcdTw4faXSM8PdRjUHzqGet9Z+B8D7I+LTNreeBeBXALwWwPM2954H4DXb1jExMTFx1XBe7/k3APihOPacvxfAV+OYEb86Ip4P4H0AvuycdVwIWBWoJCyHEZWU81fOkkpa0ue8wjp1zhnOuSxVe3uSkruvauuI1NxzyiQdwNlvZjN6ZatjRutMCdZ5zDmvU0Gd6jviLMj+5/L4GedV55WbK9WWRFWVuW16FoK7n/3nJMUquL+nhelYc/1VZIj+Hn2nuA431/naSaecpnr/tlHRz8U0W2tvBfCZ5tGzzlPuWmwrZq/pMKfOLoUP8WStvMs9ukZttqz2Vi9S/naMIeL0N340hGppEdB6+MuOTD8H2leMiGnQejSfHqhcqeRVJICqra5tiipkiZkmL25ub7lT6atwKvUq86KoY839wW1ZYmLaflXvGWpLZlSmrMomrM/02jFntmmqSUeZa6XGu/rX8IIrsyPoslHZaHq2m8oOqGk4fyWpVc4flTT5v95z36J2B0lUTFcloKy/Cjnh9lQvAocY8T2XRyVd11c9xwO/SNXZlsrYlBmNvCyOgaU9lOl0C4UyoCXHlNajzJDjbvWb9OkI4zoODw/P1OvAEmx1rWUruM1qe3T2VtUWuM3KMN28W6JlSVvYFvPAjomJiYkVuGMkzYtcKRycNNVTbXrpnJST96rDH9x1/k6oRDl6NmZFc68fKk9wJRFXqpVKvgwNBnd0quTrJBaVhrTNbJ/tjW3Vh679TlJ1bWavvotmqMaBpTT+amh1Puje3t5JOm0nj1VVX2Uz7GFJOnV09nbtrMWS7XUk7aXbNC8DVceOdHhlkNcJVDE9TQPUB3YkA+CzLXVAVIVcgqo5FTNSpqkqYI9R5P0Ru08VZsVpsn6mk9OzPY/LrRhaxdhYTc10jhmpfbZ6SbiskTAzp/LyOHHMKF9rWA7PyUolTtr29vbO7PDiTzLz/ZyPjk7XB9WCnPGiLm+1cLr/vUW9QhVzqbZhpqdCNe+3wVTPJyYmJlbgykuazgC8bTkjalHluHHPKnWyUtkq1bunqut/dX7k9ZJTKe+zalSpnerwcdfaNlVHWSWtvL2JVNlc32uAcvU1UG03l+McXq21UupTFXrksApVld1XP/f29s70O0vbLEXz86Rzb29vyGOu5avDyjmfKixpZS5t0rwUJqTXjG2kQK1zNARqLa4809yGWVaMtseAK/W858V1LzZDVWu3WyefOXWWy8ln1YHCjmk6s4NjLO6+Yy6OUShdaVvj3TmsnrrdMczMkoZqEXFf0NQyqrb1+pnbqbRwGmU4TBsvDu6rn1kGwy2I+lwXSlfPzs7OqdhONR3xoR8umqDqs+zXJaantmuNJ+WwKTdXGVUfZX4eT1bhe8xwiYGuYaRTPZ+YmJhYgSsvad5KbLPKjMA5aNSj2IutZLBE2lN1nXSkEnUVwO1WdhcozmkrCTBVc/b4cvygk+bygAauwzlFeg4vprPnLa5UyEorqdTZlGwcbTxOfJiKi2F1+blc7TNV97nf3HmebueTMze4PuD7zpHDdXMsZraZ+6qa905Ly/vbOI8Svfl93vf+jmSa57VvAmMdxgM8WmfFDPNFqhhdVZbarXphNgqerFmna7e+FGr7XLJp6mEZlU1PmR6Xm0HYWrYuNKMYoZnL5L5Sj3t15qTSVqnNVd/u7u6ehEP1xlJV4P39/ZP8HI3ATKr6rEf1FdEquLw3z3S8lE7+rLTz5mvfsBlIFwNl0I4Gho5h4iIEpKmeT0xMTKzAHSlpquPgvPlHDN2ZZim4XA+l0GsnNamzguvWz1WMOo+U9qxnCVmu61+OrQRwSprivtCPuakzzNFSSTpMv17zPee80GulU4PmnYPi5k1/5qaOJ0uXvY/Z6Vi7I8t6KrPu33cSpF7z8XKVx3/k2v3ulVW9RyPt1Oe9eyPPnXNUr0dx5Zlmz+O9LZZUocomWTFEDbFxTCKvKzuNa6eqOVX91UupKmTv5XXeZE1XhcI4W+NSmJGqzer9dAuBvmQjc8ONAV9XL1DliWa6OHCdowTYPMHMI8ejYhwuaoPbqZ8v4XT6XSE9j7MX4QH0bccXgYrRjqLa4+9sz/pMsQ0zZkz1fGJiYmIFrryk6XARq9+I+gDgjArOEpT7dENPzdHyq9hPllI09q1yJLkVlx0bmcepIz31t6fqVmYIV47WydKcOiu0TodKTeylU1WZJU3nPAHOnmfJ7WcNg6MEMgjdgZ0cbvNB3k/wfHDfreczON1p73ntTBeV86XXr6MSWaVJ6RzgNvO1zgfuDxclkGU5aX2k/rtKPd+GQVZ5eved3UuP3tLfbM9yE1HDSAB/EEbPQ9kbzJGJmOUnbSOTYzSywPWFmiEqOvkzGvplyN7kdy/5Gq96wr3UWaequkyXtlPP9ATqHVqu/ytVk9ur3ztShpjXjoEuqeZLdnHdNaRj08vjzB3VguTuL3n83ddEXbqRd2gNrgzT3MZ2OeIgqPKpFOgYnZMmmVFWtrKKFh5Uto/xRFQH0Qgco8yyRp0/1SRT2+eI44DbWe060ZhHTqdtq+x7VYyl/q5sryppMD38CV1HV88RxPNBGQ63wcV9ahv29vZw/fp1AKcPg0naWLp011nuiETFC7z2y1J+ZVhV2zRsyzFNpYH7sVp01Ka5DTMcxbRpTkxMTKzAlZE0z4OexNmTjKpA8epQiEqiHLGv9VROtTWyWl1JfVyGhs9wek3HqKTaSjLR68oGVkm+Kk2olFHZeJl+F7LEdrq1cBJQT6VNLM0h5+3Nsa2+y8PX1a4fleLdFyz5OiVlJ/XpOFW2Qv7f60cdT7cpoFLVK5uyovd+a9iay6N2bKcRLOGOYppL6rg+66mQ1W4EnfzKJJdezqXQHY7Hc9/mXlLPR+yYTs3LZ86G1bOr6WSqFg399o9jjlq+vsiVquXK4TrVtFMxUbUzttZOqbEcvuMYS+VI02f83KmcFTNhE03u+smTkar83IeuLepUYfQWR31veN64uaY2yNGPtrn7LqY0551+87z3Sd7K4cbptzELnks9j4h/FBHvjIh3RMQrI+JREfHUiHhTRLwnIn44jr9UOTExMXFXYGtJMyKeCOAbAXx6a+3PIuLVAJ4L4DkAvqe19qqI+AEAzwfwkguhtk/Pqf/ufrV66rXLP1q/gldS3kMbEac8yAmVBlVVcqqFOksq2lSKHm3biCOIy1RnR9Ufel+/6KjpKjUrnzk6q7KAs8ekOYmYpSQt15klsiyGqqaVBJbl7e/vnzh/dEeYSneV1NkzfVSmAycpq1bG/c79ofl7qLQVfq7SYW+uKc1rwPSP4rzq+S6AR0fEAYB7ADwM4G8C+IrN85cD+Hacg2n2xOfqpa86WNMspWMVtte51cujXkP+/Cjn4wnCjFUnvHvm6Nc+c23iSa7bIzWvY7oablP1QW8yaj9VzM3ZZNmkUi14WpYuNJX3ucdAem1JOtmzr+2stjtGxAmjvH79uo0HZkbI5Wn9Th2vvPR5zQuIU+X10yLaHy5szr1X1U42Hs+efX7p3hLUjOJoXcLW6nlr7bcBfDeA9+GYWf4RgDcD+MPWWopQDwF4ossfES+IiAci4oFtaZiYmJi4bJxHPX8cgHsBPBXAHwL4EQDPNkntctBaux/A/ZuyGt1f5PprVOieiO8klGr1SuljyaDNqzyrnCllcp2VwZvzsDTBz9Rj7lb/7EsXuJyqnrtfedmrXVAaxK+qlaNNV/xKjeeymDa3392BJRsAp9RZjWes1FbXN06yrhwkKmm6wHkOjleatZ+cpFo5lZzU6dT7/O36QrUNHoOcA+5ovyWzUCVdrtEqe+/rSATEiEakOI96/rcA/EZr7Xc3BPw4gP8cwGMjYncjbT4JwAfOUccwRuyTnHZEHK9UGUXPC1nZNFUl5gnLaVjVq0I0uF7HmJxdkNvmzBBLL4luHdVQoGoy9lRo1x9KC9dfRTzwy8CmA6fCVrbXyiRR1VkxTa5Tvco5vsDprZeVuSjLct53tzvG0VbNVWWUWr8bt4oZ5v1qset9KZPLZrOM2onXwr3Ha+ywp2g7Bx3vA/DZEXFPHLf8WQB+BcDPAfjSTZrnAXjNOeqYmJiYuFLYWtJsrb0pIn4UwFsAHAL4JRyr2/8WwKsi4n/c3PvBNeWuMciuLbfneavqr5wT1T2+r5LMtWvXrATCHkmVWNT5w89YIq3Uxp7kzeVWe4+r/dUqGbE0x23gtqkavyTFZLrq5Hp3rfm1bxNKZ1W/9p/7yiaXmemcepySIUdNOOlSJUB2ElbOqyoWMueZcwSNSlqV1Oj6S9uivytTgctX5anyL6njmn7kvsO5vOettRcDeLHcfi+AZ5yjzFvGOBNLXtAl9UWfjYIZJU9E9eqOqFZKQ8XUR+xGGr5TMUo9yad6UbSfHGNwNDjvrdr63Dmd+czRz+VVKqjrm4o5J836uQy9Zrjv87g2qClHcXBwcPKXv3nnjwtlcmYIx2iq9y77ohfSxrS7NNW81THo/a7eyaUy3fPKjDKKufd8YmJiYgXuqG2Ua6FqxXkl2EqSGEW1GlcOBadC5jU7kioVVPP0pFZ1djg1tDqh3pXrHCmstrL33km6mYclWvXeqwrtjvRj6d71dULjECsvvUq6Knn2+jy93ZW5gfNqHuBYsrxx44Y9N7NyEqY0NWJe0jHg+0vO1art2gYej1HJv4cqXaUV6lztmd8q3NVMc1tsY+cZZc7ONrTk8a8YbEVzpTarecClS4apn+TNaxdmtESvo7/a8QHUnyrWcyq1Ds6T0CgFVs2yHXw/UY2NRg+4CAJ9YfnFVMbvaFP1XHf9ODVc1XNlpm6BHJlXSU/Vh85WqlEC3Ae6c8mV5eBoZjNM2vV5XEcZL7dpBHc901wrXVadp5LFCGPoMZZ8rumcBFXZ1HoMhK+d80XzMGPq2TQr+6SWV/VNbyInDVXMYq9Ot91Q87CUobY6R3fW7xa6vM+09aRLzu8YcubLPuLFxTHGHnQOOxujtqcKucq2uhjWKrY1mXZlb3VSp9OmeAz0oI5Mx2kq9MZ4jQR9Uv9wyomJiYmJqylp6kqzBtvYLlV1qVRo/s92P5XUKlW9V7aTrPI08N75nnmdqO4z7QqVoNjWplJfpU6OqDc9z2VEWM/8iAShXmhuqx7EofbVpb7iMev1p0pN2jaXR9vCUp+TNJlupa2qI8fWqedqq+R2Zvq81n5TsEkh+7xS4yv1nDGiBSyZsni8nNreG9seriTTHGF6o4yxx4CrF72agFVsYMUoHcNk9VpV4rxWddjVqUy3V/8SQ1O6rl27duqUnUo9ds6nJUcU39OXgplzMlB9SZ3tNvvfhaNUsa3Oycb95RiTLk6V80ZV0BGVsCrLMakqhIzb5hiwQhdBZ+NOBrjEoJyDpXL4uPmgTLIXzzmyQFdhUtW7sgZTPZ+YmJhYgSspaY5irRF3RJ3UlVclw0rqG1GT9L8LpVGpc+QDbuqs0P6oJE5uix5Fxjt/XHsqb6eGHHG9VbhJRJwJbXJOncyX93tff3QOBqeajaidfF1JV0wb198LDK+kPBfwzvXzuLu5wXlUCuc96pW5KL383C4+No/pqdRuTtszy7j72p8cDbBtmJCTvLeVNO9opslwdhrG0oR3E9iJ9dUzF3rCzCivnRquTFPvu/hDraeaCJUnVc0LatOsvOTuJJ0llXwpREUXJG0nf9ai2hGkdS/ZJKt5sgT1ljuVfsl7zXBbUXmhWCrL2SFd29zCpX3jGH3aKpfGUOmsmGtl+1Uae2XxdWUT1T4aEZJGMdXziYmJiRW4cpLmeZ1AvWc9yShRxeUBZyUyJwFWKpOTGivnT6rE6mzoOX8qb3MVf6eSnUq6LCE7FUyPpVPJu3LK8LVKytVuH/bkVhKwquFO0lVvqnqVndNQTTSuPv2t+Z1n2LXTIeL0uass9VV1qqbRMxk5idyp0BxzObKjpzJZjSDrd2WrY2/pXc50TqLuaWQ9XDmmOYJtVCs3iCODqnZDN+ErBqTMZySPMmBl3JXaqdv4KvRMB0lzT+2tbJKuzzJPTkj9JhLXz/WqiSHvu89qVOAXyzGNPHGK7Xiuzh5j671objxybHvmn6S5pw6PLP49W61jthWTc4Hq1e4eXhwqOp2X3aFilEvt5nYtpeM0a/jJVM8nJiYmVuDKSZrbGugrLDmIOE3vWUoclUpcOWVUanNSj6rxKnGxgd55Piv0VCamU00NSnMl9VTBx/y7MvazFJ5nc3KeREqhee3q0L5gbyv3rapplUSs4LHV/neSipbLMaduTjDdQC3N5XbEJXNJT7pUKbPStrLcPLPTnRbP/ezmxqg5LPOMSpcj0mlPij0vrhzT7GGtKF1N5PztmBbfdwzMeXiVaTq7m6pkVf2aZrR9id7iUJ0S1DsUg18GfnkODw/ty8B9wmUwDcBp260L4ndjoOX27KgVKm9rxUxUPVeG6GzJ+vIqzW5BURue+zRvpqkWLoYuQM4+WM1BtZsqo3QHHzs76JLHemThVywxxqXxHWXmPUz1fGJiYmIF7hhJc43avqSG5wq3JPWpCl6p5D3jPqOKp1Qv7nnbqBLukkTMKnBP1b158+bJqeGV51LVVn3GKnlKmnqCVNLk2ll5uFmyqU7V6UltPL9U22Cnjpp7nMNFrzWPUzVZva7Oycxvky9tSdQ6nJlG28y0sASndfa81+7rqoqdndNfVO1FHVQnOrFEPIJtJcoKV5JpVh3Jz9eK9crMlDlUjCWRTKaq1w1Mz67SU030RXB08gvTs61Vi0ClDrNqCOCU5/Tg4ODUy+Ta7hakRO9szmpB0T50XunsC7eDJF/6vM87W1gNZVqrvnH97Ba+SgVmWpWeSu1WJlntqNF6qznEc6BnM9Qwp56X3OXvmQ7Yjlmh996ozbtKX5k+XP+tYaxXkmleJHqS38j9ng3Noer8iqkC9dYynfC9l8SVywuA/mapj1/4dJbk78PDQ9y4cePk2h2Aqwxc+8zFoHKIUS5Gzh6q/VAxBn5JDw4OVjkutG/U+eSYuYYy6djoM7In5scAACAASURBVE7DdDrpbunaMS3tr8q+WNkEVVLvhTmNMB19V5hR81zjPh9horqIah7Xnt77tQ3TXLRpRsRLI+JDEfEOuvdxEfG6iHjP5v/jNvcjIv5lRDwYEb8cEU8fpmRiYmLiDsCIpPkyAN8P4BV07z4AP9ta+46IuG/z+4UAng3gaZu/zwLwks3/rbBWBT8PlgKOnRRUSYBss0k41YrBKztD7WlulVSJqfJOahC7oz+lMZY0RyQ1DoviTwqzBFd9glfNCNovLKVUdiyWKA8PD09sr5xHbZqttVM0VCq50sP5uQ8T1TjltQsUryQgF340GnLDZVWqqvPYOxsm/2Zp29XtMGLLr+zX7t1y7dVnI1LnKP2MRabZWvv5iHiK3L4XwDM31y8H8HocM817AbyiHVPwxoh4bEQ8obX28DBFg+AJuy1c/qUyK3sOTyo+YKI3GE5N4fIj4tQkVbvRkt0v7ztmUNkxlbkzo+QXWEOOKpPCtWvXzjh8XJ5sa9Lm+qm6ThrdB8d6TFMXxYpRVgyHma7CvZhJZ/VJX07nnFe5mGkfu7orNbxXtqPLfWJD21Shsje6fnZtcUyP77t30TmsKgZ6y9TzAp+UjHDz/xM3958I4P2U7qHNvTOIiBdExAMR8cCWNExMTExcOi7aEeSWPsvCW2v3A7gfACKiSvNIwYNS5XnTjUgPwOkVWx0pzuitK1mlMqnnuEqnZbF0yVKWevxd21QaU/WQr9X7rG1Tk8De3t4pp0pPZeJ2szTCeVz/pWS59GlblZh0g4JDNeajKp5K7erBryTSynuefeLodO9Lz6usfcP9p305osY7Ka+iV5/pvBmFzqElz/620iVjW6b5wVS7I+IJAD60uf8QgCdTuicB+MCWdQDod7ibRPrCjZTTq2+kfh4stuf11Ff1UHLsmdKf/zlPMiKH3nbDSqXRCeReAMcAtJ3pLc/PZehBHFw3235HPObVApLecn7R06bJZXF+9dhXNk2lSdVA12dVnt42SN1B5ZhOb15xP1XXrj+cGn5wcHDSf7ogqRpfLeiqEi9haWF35boy3JbZigadW6PYVj1/LYDnba6fB+A1dP8rN170zwbwR+0W2DMnJiYmbhcWJc2IeCWOnT6Pj4iHALwYwHcAeHVEPB/A+wB82Sb5TwF4DoAHAfwpgK++BTQv0XvuNCMGdl7JWDrMdJmmWn3zef7P1fvatWtdw3leHx4e2kBvlTJUImVppVJlKolOHQqchmnc398/5fxxe/HVjKEOsEpKqCRdVsk5/rHqy+wLt69cJc3qUwu9fnJOuqTZmTV0LJa890xD3q/mbS+PSsF5zVI706znD1TzoSfdbqMWcx7nYFqK82RUEQ+jGPGef3nx6FkmbQPwdcO1nxOVCnWR9k99Kdj26F76Sj3PScUTlk/i0foyjYJfcn75mDnytU5SVgcrZqjtd4yhYpr7+/tnmKZTvZzayHVWEQOVPe7o6OgkCJ8ZAOd3Z5WO2Hur68p0obbTyvvdWygqBu7K5fR6P/uyWniceq7MsHfwsFv43Vzv2Vb12i10vIj0mK7rQ2WO29oyE/PAjomJiYkVuNLbKLdx5DBGpc6e4Tmh3jlVB1gy6K3K7PyoVLBUja5du3bmtPOKbhdQr7RVq3lPSnLSleZnM8D169cXg9izLPbwaqBzFcTO0gs7J27cuGElJVXrKomlF5vZMw+otKt9o3mciu9oq84F2N3dtWYV7TOtw9XJjiCNba3yq3TtJHrVyioNQbUVhXOOZv/k81GV/CJxpZnmEth2V93nQak8tNUk1zSVSg08MmHzMwqZt7KBaVmcR22VjnH2XvjeYuPa7PYaV33h7HZ7e3vY398HgFOnJWkZyqjcS57p3cvE12rD1INyXX+6BZRfQGc64GtVZ5kB8H53NS8oA3YLD+epTr1SLzqbaBhcp1sEXbC/MjNd7Ks5negJCFqPY856eIprd7a9xygrhuoEB+2XUUz1fGJiYmIF7mhJcy1UOlsytvNKmF7tXOVZ+mN16ujo6FSgOZfFTiIXaF2BPebufrXfvIrXBOrtdGrEr5wyTPP+/v4Z+kc9uXxdOZy4TL7PZ3tWkpI6WFzdmq6KDXXSkzvaTenWel3ZrAmpdKuScpW/13/5zDl5NI9Kqj2V2l2n1FiZBFxf6DOFc65qXGYlhV6E84dxVzBNfrFvRdn5X5loZfdaKgfo7zdXBujCkaoj3/S655l3nlNuo+bjsnhP+ZLX2TGwntpaqYBcltphK/tYjwFqmyqmU32JsedVHglbq5iJO6ov71eoGFuiUol7CyfT6Ob3yLxfgmOaOh8YyigrVCaq6n1Yg7uCaW4bYlQ5Yhxy8o5ukXT39Rm/uBUzVcmRX8zqrE9to4sZVNsWv1TVy8Dt10OER8Niekyqchwwelv4Kkar9Y3QU+2UUbtp1rn0zSRuFzOqBDNKnRtMn86VaqGpbNZuiyTTpte6YCoD6jEndziLtse1Re2bIwvqEgNcsmmuwbRpTkxMTKzAlZQ0e1KTw4h6vmTDrOxePamlss9pOpe+R6+q4EtqZ1W/ayev7JV3s8LOzs6JSr63t7e4R1jL64X19CRNp+rrQSLuCDPgbHA9t6WyY7JKXn2+trV2JrTJSYfaXpZiGaphOC1E57maEZwEm+PcO4yD02lZqnmoWaSad6wJsYkhy1T63bWb99y20TwXjSvJNJfQM+w7dUbTZLol9dw5EdT2pDSNqoZ8j+lktWaEviWoGYHVtKW4wgSr5O4b5I4O5xRhWlQdreIcdWGqmIQy2qSJY/ycwyzzHB4ennLy8YEV7mNyWadTb9murAy/t9Ayo3ThSzovmAGrU4fbVR1mUoUC6VhUtlvXBu7bKvyH81amBl1c3BxyC2212I4INaOY6vnExMTECtyRkuYoRlTwHnqrT2UQr+pIKccdk8a/3X0n3a5pi1NvetKCSuTp8NGT13v1VUHXLAGqxOAkJVXHelIGSyNJM0scOmYqKSZYheWdRirpVnvcb968eSKRVzRzm/J/5TippHp1Kjk6sy25L//GjRunJE23I4jvq+mjcj45j/2S15olWO0nNb+4NjtnIKertDvu823U+LuGaY6osKqaVbYuBg+kxiKuYWDVi6vPHQPTsxbz/tKAuxfU2TF1Bw3TpjtllpAvj4s5VHVJGdCS97xSudz9pJXHTF/MiDhhjqwS5w4j4DQzYXo0frEy23AetQ/qGDrzQtJWlctquGMgjmkyo6xsnRpm1WOo2n7FiP1e+0XLXGKUbg64fu5dj2Kq5xMTExMrcOUlzYsKWh8tR6Uz9WSPxHZWEhBw+mANp7Y5AzrXyWpn5RTRwHduS6XO9SRN5yxgtVElsdHIBKWlUtWcNFBJsAm3w4rpz9/s4XWSViXN5H2mmftMVUpuV0W3O9hEoe1m2tynSFLKdJKzSpROVc80LsC/MvHk3OC5tPTeOEfQiHTpTAVcBpev19tKmleeaVboMa1KJR8FD0rPhrfWrsgqPqvEOzs7p9REhp4ByUyXrzk/e1fTdqdt04BnRX6uQhmNU22uXbt2iplyOr5XneGZhwZXTJPr7vU574TidnJ+XVzUjpb9UQXRJ9SOynOlYnrKDLifeBFyts1MUy0o1YKYn65gpscLQl7zJy6UgfaYZsVsVPhw7RlF1U43ZypTkJu3lRloCVM9n5iYmFiBO1bSVGeDw6iHuleH/l67UvKqWMWMMg4ODsqPprEEw/GHlWSTdTrpTtVhXmn5HM/eyuy8m65tTnJyKvCSsV7VPNUolvbfHxwc2JjNbANLVz2VnOliOrk8F6fZc3RUKmxvDvK4Vap6queubUdHRyfSpTq/OE5V1fVKOtO+cdK6zjuH7HPXd64evnbzhvPrPFuixeGOZZprGWUPI52tg8ITodo3zMxkyYNYqWZKzxLjVyajKrELS+FrVQGPjo5OhRxl/r29Pau2629lblUAtaq+enqNtl/7Ymdn5xSdbHJwdljtP2Y0lR3TvfBurmiYED+v5ldlBnLpK1WzYpqqnnO/M9PMa2cDdX2jY65zy5kLqr7VsnoMWftuCZWws42pALiDmOZFOYQYVUf2JJ7KKTLqIKpsWHytdrbcuqjlM22OGeoRdSNG9DwZ3DEaPpFdF4RqMnPf9F4kldSqa4ZKjdlPzoab6RxdvT5Umispa43U6KRT1hy4fGdrq5iOY5rugGZnu+X4TZU0qx1BVR8kk+Xfvd1Grg9dfy2lGdUEt2WWiUWbZkS8NCI+FBHvoHvfFRHvjohfjoifiIjH0rMXRcSDEfGrEfF3zkXdxMTExBXDiKT5MgDfD+AVdO91AF7UWjuMiO8E8CIAL4yITwfwXAD/KYBPBvD/RsSnttb8B19WQCWRNfn02tk/WLKqpIye6l9JFLoa8/d/+HDZzM/fgDk6OsLu7m654jKdHGKjR7ap5Mp9oNdpB+X2pI2VPxt8cHBQBrCr1MW/e17pKoi78shzej1rlCMLnNSX+ZfsXiy1Ma2VxKM0bztnq/5UGpZsmqOSpto01dteecz5OtNkev5dee9ZGtUyXV9Xtu81OK/WOvIJ35+PiKfIvZ+hn28E8KWb63sBvKq19hcAfiMiHgTwDAD/7lxUXgCcXUgZRT7jwa4QEScqDEMZLTt1OIaSGRir52zDS0agn+R16TiUSZlxxRydmpj5+JoZPTP3yvnE5eki5EwFTKvWX4HT5/ZONnHk2PB9LjuZ6VI4VaUCc3q9rhxzLh1fOwbk8jtGo4sQhw9V34RnBqbOHg05cv3B7XEmjZFYV7egKjPUuTKitq/FGkZ6ESFH/wDAT2+unwjg/fTsoc29M4iIF0TEAxHxwAXQMDExMXEpOJcjKCK+DcAhgB/KWyaZXQJaa/cDuH9TzlbLBDtV+N7IKq/SRPXtnkrqbK2VEmCWwZ/EyDoq5w9fq9RYmQtY0kxaepIm06kqYE/S5L5x1z0JSZ+NGP57J8G7sB7us0zDfeA85r193JXpRmnuSTc9yWU0oqO6X9Hm1OGUGlk9d8HtqsLz/cqByFAJUjdPLEVN9PJz27T9Cmcm03fgvNiaaUbE8wB8EYBntUcoegjAkynZkwB8YHvyavCLXjHKJbtdz/YI4Iz6xmoK52G7I7+wzCTy8xCsUrKqyAyQ1faKaWqIDTNq3ZlSTZ7epHNMlMvWbYo6kV09vPDo+PH46CEbSkeCaVHbZbU7x51JyTTk9ZIarnNO04wyTTeHqzZrPzGd7NnXHUHMHDkPq+o99VwjLZQe4PRimbRUjLryxGs0hfPSc51s+lFwf1ZptsVW6nlEfAGAFwL44tban9Kj1wJ4bkTsR8RTATwNwL8/P5kTExMTVwOLkmZEvBLAMwE8PiIeAvBiHHvL9wG8bsPN39ha+5rW2jsj4tUAfgXHavvXtQvwnI/AqepL6dlrq04J4KxKriuWUx903zNLnaMqOUtDLEWyBBERJyp5JWluA3cwCavkTKfDmrhChnMI6LNKatTIBpY6q9hMJ4VU0lTVvupE8lEwnWrGcCYFdpRkOudYc7ubuG0uTlLzO6+89kEl9ea1c+woLSzpqnru2rmkKVXPK41iG8RF6vrbIiJaz6am1+6/e8n15VGGtWRfVG9x9Yy91xUzXKrTfdkxGWA+29vbO5WOPz2Rgd3VmZ9Fv5/pY9efTj3XNPwiVB57tcE5hrGEyqap7XHXrq3uxezRpIvz2jxMj47NUj8oM1L6HdN0tkFlTprO5XftrCILsly1i2rZWr+q8M6ksGacKoZeMc0/+IM/eHNr7TNtgYR5YMfExMTEClz5bZSVE6OnhjtjvXMKVdIQG9RTcsvAbl6xWKpjh487okwlTXYYcTA2309VPSVKVtt2d3dP1cn9VAWH83XPk6zPqn3gnKbnOKmkuapOLcOpwNqXTvXOdJWkyZLvkmOnonlEXayiEZK+qo1abvYlS22uLc6pUkmEVWQG51dalqROVa+5HL3npD6dJ6rS99TrpXe6klRHzXrAHcA0K/RUGccoOc8S02RGx7bCyqbHzIS/auhebA6F4XoSzAzVe86hRTdv3jx17XbAcL3cL1qn/q7MHVX4DkNtYL1JvhT9oPnVnqgqeKX28v2KoWv5FS0jLxeX6ximGw+lpaJJmZO7ZlVXy66YrtogR9RhVXvZPukYd147tVvtqPp7ZOGtxrZSz6u8S5jq+cTExMQK3DGSpqraI+p5da1qjuZVjzfwiKqukidw9pMSLn9KQs7LzlIS58k0ToXi/NU+9iW1NbGUp4p55Pzcf5V0WEmaS3Dxej1nT9U2h2quLEmdVbyny6uSOtPTizOsynV9W3nCda5XUhur05pGHXtuTLV+lnbVdJCovPRK80Wr55p2Le4Ypumw1OjK5pQD4uxJrJKr7YnDgfi5qvQM9fAyQ02wJ57pStVcvZLAaTsm319iJmsYqMuzZB91L6n2r+bX68yn+fMFrvIwnBnBpa+YZqLHACuaXTQC56nMR66sSs3U30tMZklV7dkXe7SpSg6cPeSDbaTKQCvvfSUsjDJNpr3Kw9d3vE2zmnyapmcH4/96PxkTS3qcxjk78j6X4bbq5TPAS6BsR2KmmzSos4kZPx8A0lo7WcnZ+bQt06uYaI+hOqaZtLmXsZJ6FTrxnZSgtFUS20jIldap5fUY/RJT5vGr5pVD9ZL3GN0o0+T55OgYZUyc323VXOtw0jTOrtrTEPm/SsdLTHON1DltmhMTExMrcCUlzYRKk5UEWtnKKukhpUwnqVRlq5oN1J/jrdR2bU8lqVZQepdCgTikKetZkoxGve/qrdbVv5JUeu1cskf1xr1nBhiVQpfsmACs7bj6fRF1un7luVap2moHrqTTSorn+qrf1bkMKWnyb76uJFCVOiv1uichLs2hNRJlhSvNNBWjdoeljnHqeaU2VmEhaptyYS3MDB3D5EnnnEcZvpRquIv71HqYrtxeuNaOOcoMqvCjnk2sYppqq3OTvLJRax6mqVLnlJbKQVCZOvJ6xNww0k9Kc0VXzybJ6TSNU8V7+Xt0qgMq/ytjXFLPeyr4GnOBo3Mkz7YMdKrnExMTEytwR0maqqY5o6977sCe2MqRo2WxFMlSB0uRS1InS4EsgThVX+lh6VIdPNWe8Eyrz/j5iHPH1dlzBPE1P3dSEt/P60rac5Lm0jiPShRLEqn2v6ZZ0oS2ea4SU88pUt2vnGkqaVZSfE91d/n1aLie6aAndappQftJ37u1UL4xiivPNJ09S1/EkTz6XMtjVZ1thcoYKuaozNWl2UaN79lIK7V7LdNU9HbULHnc10xEDZcZsWMmemq3pquYa2WH1XqdGYQZaI9ORsUUteyK/uyjJQbI5WoezVepxy6tlu3qyXsj3u9qzN3YVgx9FNuq4g5TPZ+YmJhYgSsjaW4jHS6px9XqUqnzmafKp5JnpdY6FT7hpInePnDgtMeW04xKmu4Zo1LFXdtY6mQJrJL6RjQCjtcDvHnE5a3GMMtUsPSjNFRjzv2gp+1XtPWciRV03HoqOPebg5NGl1R63RGUGImJ1HTZz67OSqVXb3kFfVb97mkY58WVYZojUMbKv5eu14BV4NH0qgrnfVX1WTVhj7mGJnH+So1PrGGaDksvuVPve6p6r87Kq80hJz1UalplV3Uvcz4fUfGZUfInjJcY4ciOpMrE02Oa3KYe7cpYK0a3xNhcPaPqOadxzKwXMqV1VONepevlqdoyiqmeT0xMTKzAlZM0VQ0fSbOtqs4SnJPO1AlTGesZqsKrqs6SxdKWSuD0SeyVl5zRkzS5nqRV72m+UZOA5u891/pHpb6e6aTysC9JU/zb9ZeaCvjINTVhuPnEcP3E84O1Eocl01F1f8Rjrn3B6at6XNmOzp6kWanTlaTYU88rlbzXb1U7e7hyTBPoq12cxr0ot0pVz7r4t1NPlTHyIPa85Gp64PyVJzcxok6vQS/wvbcP24HVW6B+Idd6wjm9Y8qV3Y6f9wK6R9Vvl37UXKLlVf3E0H6qFsGeWSLR6w+lw/V7xQx7TJPLWJN/9Hr0XtXOEUz1fGJiYmIFRr5G+VIcf9/8Q621/0yefQuA7wLwCa2134vjpfL7ADwHwJ8C+KrW2lvOQ6CTwHrPtpEm19DCkiKv8qxmOUk5JcYlkwDfdyrjWknTPV+DntTZS8/Ok1GMqFAjEqnmWVJHbwVGpP2qb3tmpbVj6UwfzpFUSYP8XNNVfevKqyTAXv7q2vWNU9uXJMwRCdRhRD1/GYDvB/AKvhkRTwbw+QDeR7efjeNvnT8NwGcBeMnm/7lR2ZzyGdFl8/QmYlWPU7tZPXeqOts01R42wigdM1Q7a5UusTbo2mHJJrekmo/YfqvDK0b2pyuqMdU9107N3AauvjV91rvXgztQpQenXlcLR49RLTHNJZV8jRq+pFaPqNhLDHWprB4WmWZr7ecj4inm0fcA+KcAXkP37gXwinZMyRsj4rER8YTW2sOrKevTBKAvfebzXgcv2RT1/ogdc4kxLjHFNc+rPMoQRhabKu2olKT9vqbOXj2j+ddKSWtoWPvycvs1jKqqoxrjSiAAxhZHpbFnk3R5HCNzTHcNk1rDQKvfI1iSLrfFVjbNiPhiAL/dWnubPHoigPfT74c291wZL4iIByLigW1omJiYmLgdWO09j4h7AHwbgL/tHpt7lrW31u4HcP+mzCH231t91kqdS1Jopumt4NtImr3frh1rJZPe7zWr7JL0u6TecnucNLNU5xqsUeuUhiUpfo2UOUL/yHiOopprS1hSm13aNZKmK6Mam17955EUL0JSrbBNyNF/DOCpAN62GagnAXhLRDwDx5LlkyntkwB84LxEXgQqdXxtfjdJeww0oeFDSs+onWrELnaRqvG2NFZ9vY16vIS1Kqarr1f3eW1gPVTzqapf065dbCuMqsc99dqVuZS/qq9X1sj9tXnXjOtq9by19vbW2ie21p7SWnsKjhnl01trvwPgtQC+Mo7x2QD+6KLtmRMTExO3EyMhR68E8EwAj4+IhwC8uLX2g0Xyn8JxuNGDOA45+uoLonMRI+pStWIvqRYurUqU1X0uZ0Q9X8KIpHlejKr+ayXibc0DLv+SeWXUYVPVd5GqYQWt/zx1XsSYbaOec7qR92h0bHoYqWdNnrWIi1Y3tiJi0Ka5Rbmr0ykD1DSj9srRfD06t6U/se3Yjr5029B9HvVcFx59tvaFWbJZj5bTwzZ23G3tcdWCehGqO1+P2kGr/FW6pXp7+S6CkR4cHLy5tfaZXaIwdwRNTExMrMKV3Ht+2Rg1FC9JoXk9Iplt42BhbJNnDc7jcBqlx/Vlr4yeQ2REgnGS6q1Q53qS1lozwEVoC9uMW2W62sapsm17HA3b0LPm2Qgm0xSsneB53w3wkiq+1j65zeQfoc3lH7EDjt5n5rhWPV/K4zCS3pU7oi5uaxNcQ9toWaOmmLUmlSVbq2Niaxhbb7FcgtKz1hx1EYvkVM8nJiYmVuCuljRHJate/lFHgVs9l+rfRgU+r/d8ROocldS2eba2zErSXCNhjHryzyuFXFS6UTrWRBNwOodRc9F5nTzO5FXB0a15LtKMMoq7mmkC57f3rWW8lQq19JJW6UY82eddHLZBT33fZjJWate2jKyyPY/auipGfR4VcE3aizJJaD+sNTFx3qV6z2tfHJm7o/NE053XjsmY6vnExMTECtz1kuZFIVeubWPcRmIQ15a31iQwskqPqrIj9J0H5zURrC1zrbnlIrCNGl5hVI3e1rG2ph8y/UU68LZx7i1J19tqRVeFaf4egD/Z/L9QnGOiPx5Ej/MSXjJO0XNFcNVomvT0cdXoAa4WTf/RSKIrsSMIACLigTYQjX9ZmPQs46rRNOnp46rRA1xNmpYwbZoTExMTKzCZ5sTExMQKXCWmef/tJkAw6VnGVaNp0tPHVaMHuJo0dXFlbJoTExMTdwKukqQ5MTExceUxmebExMTECtx2phkRXxARvxoRD0bEfbeJhidHxM9FxLsi4p0R8U2b+98eEb8dEW/d/D3nEmn6zYh4+6beBzb3Pi4iXhcR79n8f9wl0fJp1AdvjYgPR8Q3X3b/RMRLI+JDEfEOumf7JI7xLzfz6pcj4umXRM93RcS7N3X+REQ8dnP/KRHxZ9RXP3BJ9JRjFBEv2vTPr0bE37kken6YaPnNiHjr5v4t758LQ2vttv0BuAbg1wF8CoDrAN4G4NNvAx1PwPF3jgDgMQB+DcCnA/h2AN9ym/rmNwE8Xu79cwD3ba7vA/Cdt2nMfgfHgcCX2j8APg/A0wG8Y6lPcPzZlZ8GEAA+G8CbLomevw1gd3P9nUTPUzjdJfaPHaPN/H4bgH0AT928h9duNT3y/H8F8M8uq38u6u92S5rPAPBga+29rbUbAF4F4N7LJqK19nBr7S2b648AeBeK77XfZtwL4OWb65cD+JLbQMOzAPx6a+23Lrvi1trPA/h9uV31yb0AXtGO8UYAj42IJ9xqelprP9NaO9z8fCOOv8h6KSj6p8K9AF7VWvuL1tpv4Pi7Xs+4LHrieI/j3wPwyous8zJwu5nmEwG8n34/hNvMrCLiKQA+A8CbNre+fqNqvfSy1OENGoCfiYg3R8QLNvc+qW2+7rn5/4mXSE/iuTg90W9X/ySqPrkKc+sf4FjaTTw1In4pIt4QEZ97iXS4Mbrd/fO5AD7YWnsP3btd/bMKt5tpuhMXblsMVER8NIAfA/DNrbUPA3gJjr/z/tcAPIxjdeKy8DmttacDeDaAr4uIz7vEui0i4jqALwbwI5tbt7N/lnBb51ZEfBuAQwA/tLn1MIC/0lr7DAD/GMC/iYiPuQRSqjG63e/el+P04nu7+mc1bjfTfAjAk+n3kwB84HYQEhF7OGaYP9Ra+3EAaK19sLV21Fq7CeBf44LVlx5aax/Y/P8QgJ/Y1P3BVDE3/z90WfRs8GwAb2mtfXBD223rH0LVrARfXQAAAaxJREFUJ7dtbkXE8wB8EYC/3zYGu40a/B8212/GsQ3xU281LZ0xup39swvgvwLww0TnbemfbXC7meYvAnhaRDx1I8U8F8BrL5uIjX3lBwG8q7X2L+g+28D+SwDv0Ly3iJ6PiojH5DWOnQvvwHHfPG+T7HkAXnMZ9BBOSQe3q38EVZ+8FsBXbrzonw3gj1KNv5WIiC8A8EIAX9xa+1O6/wkRcW1z/SkAngbgvZdATzVGrwXw3IjYj4inbuj597eang3+FoB3t9YeIjpvS/9shdvticKxl/PXcLyyfNttouG/wLFq8ssA3rr5ew6A/xPA2zf3XwvgCZdEz6fg2LP5NgDvzH4B8PEAfhbAezb/P+4S++geAP8BwMfSvUvtHxwz7IcBHOBYUnp+1Sc4Vj//1WZevR3AZ14SPQ/i2FaY8+gHNmn/681Yvg3AWwD83UuipxwjAN+26Z9fBfDsy6Bnc/9lAL5G0t7y/rmov7mNcmJiYmIFbrd6PjExMXFHYTLNiYmJiRWYTHNiYmJiBSbTnJiYmFiByTQnJiYmVmAyzYmJiYkVmExzYmJiYgX+f6jB0VjQqY6IAAAAAElFTkSuQmCC\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 --------------------------------------------------------------------------------