def computesys(self,
                   obj,
                   is_zernike=False,
                   is_padding=False,
                   dropout_prob=1):
        """ This computes the FWD-graph of the Q-PHASE microscope;
        1.) Compute the physical dimensions
        2.) Compute the sampling for the waves
        3.) Create the illumination waves depending on System's properties

        ##### IMPORTANT! ##### 
        The ordering of the channels is as follows:
            Nillu, Nz, Nx, Ny
        """
        # define whether we want to pad the experiment
        self.is_padding = is_padding

        if (is_padding):
            print('WARNING: Padding is not yet working correctly!!!!!!!!')
            # add padding in X/Y to avoid wrap-arounds
            self.Nx = self.Nx * 2
            self.Ny = self.Ny * 2
            self.mysize = np.array((self.Nz, self.Nx, self.Ny))
            self.obj = obj
            self.dx = self.dx
            self.dy = self.dy

        else:
            self.mysize = np.array((self.Nz, self.Nx, self.Ny))
            self.obj = obj

        # Decide whether we wan'T to optimize or simply execute the model
        if (self.is_optimization):
            if is_padding:
                # Pad object with zeros along X/Y
                obj_tmp = np.zeros(self.mysize)  # + 1j*np.zeros(muscat.mysize)
                obj_tmp[:, self.Nx // 2 - self.Nx // 4:self.Nx // 2 +
                        self.Nx // 4, self.Ny // 2 -
                        self.Ny // 4:self.Ny // 2 + self.Ny // 4] = self.obj
                self.obj = obj_tmp
            # in case one wants to use this as a fwd-model for an inverse problem
            self.TF_obj_phase = tf.Variable(self.obj,
                                            dtype=tf.float32,
                                            name='Object_Variable')
            self.TF_obj_phase_do = tf.nn.dropout(
                self.TF_obj_phase,
                keep_prob=dropout_prob)  # eventually apply dropout

        else:
            # Variables of the computational graph
            if is_padding:
                # Pad object with zeros along X/Y
                obj_tmp = np.zeros(self.mysize)  # + 1j*np.zeros(muscat.mysize)
                obj_tmp[:, self.Nx // 2 - self.Nx // 4:self.Nx // 2 +
                        self.Nx // 4, self.Ny // 2 -
                        self.Ny // 4:self.Ny // 2 + self.Ny // 4] = self.obj
                self.obj = obj_tmp
            self.TF_obj_phase_do = tf.constant(self.obj,
                                               dtype=tf.float32,
                                               name='Object_const')

        ## Establish normalized coordinates.
        #-----------------------------------------
        vxx = tf_helper.xx(
            (self.mysize[1], self.mysize[2]),
            'freq') * self.lambdaM * self.nEmbb / (self.dx * self.NAo)
        # normalized optical coordinates in X
        vyy = tf_helper.yy(
            (self.mysize[1], self.mysize[2]),
            'freq') * self.lambdaM * self.nEmbb / (self.dy * self.NAo)
        # normalized optical coordinates in Y

        # AbbeLimit=lambda0/NAo;  # Rainer's Method
        # RelFreq = rr(mysize,'freq')*AbbeLimit/dx;  # Is not generally right (dx and dy)
        self.RelFreq = np.sqrt(tf_helper.abssqr(vxx) + tf_helper.abssqr(vyy))
        # spanns the frequency grid of normalized pupil coordinates
        self.Po = self.RelFreq < 1.0
        # Create the pupil of the objective lens

        # Precomputing the first 9 zernike coefficients
        self.myzernikes = np.zeros(
            (self.Po.shape[0], self.Po.shape[1],
             self.nzernikes)) + 1j * np.zeros(
                 (self.Po.shape[0], self.Po.shape[1], self.nzernikes))
        r, theta = zern.cart2pol(vxx, vyy)
        for i in range(0, self.nzernikes):
            self.myzernikes[:, :, i] = zern.zernike(
                r, theta, i + 1, norm=False)  # or 8 in X-direction

        # eventually introduce a phase factor to approximate the experimental data better
        self.Po = self.Po  # Need to shift it before using as a low-pass filter    Po=np.ones((np.shape(Po)))
        if is_zernike:
            print(
                '----------> Be aware: We are taking aberrations into account!'
            )
            # Assuming: System has coma along X-direction
            self.myaberration = np.sum(self.zernikefactors * self.myzernikes,
                                       axis=2)
            self.Po = 1. * self.Po

        # Prepare the normalized spatial-frequency grid.
        self.S = self.NAc / self.NAo
        # Coherence factor
        self.Ic = self.RelFreq <= self.S
        myIntensityFactor = 70
        self.Ic_map = np.cos((myIntensityFactor * tf_helper.xx(
            (self.Nx, self.Ny), mode='freq')**2 +
                              myIntensityFactor * tf_helper.yy(
                                  (self.Nx, self.Ny), mode='freq')**2))**2
        self.Ic = self.Ic * self.Ic_map  # weight the intensity in the condenser aperture, unlikely to be uniform
        print('We are weighing the Intensity int the illu-pupil!')

        if hasattr(self, 'NAci'):
            if self.NAci != None and self.NAci > 0:
                #print('I detected a darkfield illumination aperture!')
                self.S_o = self.NAc / self.NAo
                # Coherence factor
                self.S_i = self.NAci / self.NAo
                # Coherence factor
                self.Ic = (1. * (self.RelFreq < self.S_o) * 1. *
                           (self.RelFreq > self.S_i)
                           ) > 0  # Create the pupil of the condenser plane

        # Shift the pupil in X-direction (optical missalignment)
        if hasattr(self, 'shiftIcX'):
            if self.shiftIcX != None:
                print('Shifting the illumination in X by: ' +
                      str(self.shiftIcX) + ' Pixel')
                self.Ic = np.roll(self.Ic, self.shiftIcX, axis=1)

        # Shift the pupil in Y-direction (optical missalignment)
        if hasattr(self, 'shiftIcY'):
            if self.shiftIcY != None:
                print('Shifting the illumination in Y by: ' +
                      str(self.shiftIcY) + ' Pixel')
                self.Ic = np.roll(self.Ic, self.shiftIcY, axis=0)

        ## Forward propagator  (Ewald sphere based) DO NOT USE NORMALIZED COORDINATES HERE
        self.kxysqr = (tf_helper.abssqr(
            tf_helper.xx((self.mysize[1], self.mysize[2]), 'freq') /
            self.dx) + tf_helper.abssqr(
                tf_helper.yy(
                    (self.mysize[1], self.mysize[2]), 'freq') / self.dy)) + 0j
        self.k0 = 1 / self.lambdaM
        self.kzsqr = tf_helper.abssqr(self.k0) - self.kxysqr
        self.kz = np.sqrt(self.kzsqr)
        self.kz[self.kzsqr < 0] = 0
        self.dphi = 2 * np.pi * self.kz * self.dz
        # exp(1i*kz*dz) would be the propagator for one slice

        ## Get a list of vector coordinates corresponding to the pixels in the mask
        xfreq = tf_helper.xx((self.mysize[1], self.mysize[2]), 'freq')
        yfreq = tf_helper.yy((self.mysize[1], self.mysize[2]), 'freq')
        self.Nc = np.sum(self.Ic > 0)
        print('Number of Illumination Angles / Plane waves: ' + str(self.Nc))

        # Calculate the computatonal grid/sampling
        self.kxcoord = np.reshape(xfreq[self.Ic > 0], [1, 1, 1, self.Nc])
        # NA-positions in condenser aperture plane in x-direction
        self.kycoord = np.reshape(yfreq[self.Ic > 0], [1, 1, 1, self.Nc])
        # NA-positions in condenser aperture plane in y-direction
        self.RefrCos = np.reshape(self.k0 / self.kz[self.Ic > 0],
                                  [1, 1, 1, self.Nc])
        # 1/cosine used for the application of the refractive index steps to acount for longer OPD in medium under an oblique illumination angle

        ## Generate the illumination amplitudes
        self.intensityweights = self.Ic[self.Ic > 0]
        self.A_input = self.intensityweights * np.exp(
            (2 * np.pi * 1j) *
            (self.kxcoord *
             tf_helper.repmat4d(tf_helper.xx(
                 (self.mysize[1], self.mysize[2])), self.Nc) + self.kycoord *
             tf_helper.repmat4d(tf_helper.yy(
                 (self.mysize[1], self.mysize[2])), self.Nc))
        )  # Corresponds to a plane wave under many oblique illumination angles - bfxfun

        ## propagate field to z-stack and sum over all illumination angles
        self.Alldphi = -np.reshape(np.arange(
            0, self.mysize[0], 1), [1, 1, self.mysize[0]]) * np.repeat(
                self.dphi[:, :, np.newaxis], self.mysize[0], axis=2)

        # Ordinary backpropagation. This is NOT what we are interested in:
        self.myAllSlicePropagator = np.transpose(
            np.exp(1j * self.Alldphi) * (np.repeat(
                self.dphi[:, :, np.newaxis], self.mysize[0], axis=2) > 0),
            [2, 0, 1])
예제 #2
0
tf_fwd = muscat.computemodel(is_forcepos=False)

#%%
''' Compute a first guess based on the experimental phase '''
init_guess = np.angle(matlab_val)
init_guess = init_guess - np.min(init_guess)
init_guess = dn * init_guess / np.max(
    init_guess)  #*dn+1j*.01*np.ones(init_guess.shape)
''' Create a 3D Refractive Index Distributaton as a artificial sample'''
#for sphere5
mydiameter = 3
obj = matlab_val
squeezefac = muscat.dx / muscat.dz
obj = (
    ((squeezefac * tf_helper.xx(mysize=obj.shape)**2) +
     (tf_helper.yy(mysize=obj.shape)**2) +
     (squeezefac * tf_helper.zz(mysize=obj.shape)**2)) < (mydiameter**2)
) * dn  #tf_go.generateObject(mysize=obj.shape, obj_dim=muscat.dx, obj_type ='sphere', diameter = mydiameter, dn = dn)
obj_absorption = tf_go.generateObject(mysize=obj.shape,
                                      obj_dim=muscat.dx,
                                      obj_type='sphere',
                                      diameter=mydiameter,
                                      dn=.01)
obj = obj + 1j * obj_absorption
obj = np.roll(obj, 5, 0)  # z
obj = np.roll(obj, -3, 1)  # y
obj = np.roll(obj, 1, 2)  # x

init_guess = obj
if (False):
    init_guess = matlab_val
예제 #3
0
                  dropout_prob=my_dropout_prob,
                  mysubsamplingIC=mysubsamplingIC)

# Generate Computational Graph (fwd model)
tf_fwd = muscat.computemodel(is_forcepos=False)

#%%
''' Compute a first guess based on the experimental phase '''
init_guess = np.angle(matlab_val)
init_guess = init_guess - np.min(init_guess)
init_guess = dn * init_guess / np.max(
    init_guess)  #*dn+1j*.01*np.ones(init_guess.shape)

#% try to damp along Z
if (nboundaryz > 0):
    mymask = abs(tf_helper.yy(
        init_guess.shape)) - init_guess.shape[0] // 2 + nboundaryz
    mymask[mymask < 0] = 0
    mymask = -mymask
    mymask = np.exp(mymask / nboundaryz * 2)
    plt.imshow(mymask[:, 16, :]), plt.colorbar(), plt.title(
        'Mask to confine the initial object in the center only')
    init_guess = mymask * init_guess

#%%
'''# Estimate the Phase difference between Measurement and Simulation'''
# This is actually a crucial step and needs to be used with care. We don't want any phase wrappings !
'''Numpy to Tensorflow'''
np_meas = matlab_val
np_mean = np.mean((np_meas))
print("Mean of the MEasurement is: " + str(np_mean))
'''Define Cost-function'''
    def computesys(self, obj, is_padding=False, is_tomo=False, dropout_prob=1):
        """ This computes the FWD-graph of the Q-PHASE microscope;
        1.) Compute the physical dimensions
        2.) Compute the sampling for the waves
        3.) Create the illumination waves depending on System's properties
 
        ##### IMPORTANT! ##### 
        The ordering of the channels is as follows:
            Nillu, Nz, Nx, Ny
        """
        # define whether we want to pad the experiment
        self.is_padding = is_padding
        self.is_tomo = is_tomo

        self.obj = obj
        if (is_padding):
            print(
                '--------->WARNING: Padding is not yet working correctly!!!!!!!!'
            )
            # add padding in X/Y to avoid wrap-arounds
            self.mysize_old = np.array((self.Nz, self.Nx, self.Ny))
            self.Nx = self.Nx * 2
            self.Ny = self.Ny * 2
            self.mysize = np.array((self.Nz, self.Nx, self.Ny))
            self.obj = obj
            self.dx = self.dx
            self.dy = self.dy
        else:
            self.mysize = np.array((self.Nz, self.Nx, self.Ny))
            self.mysize_old = self.mysize

        # Decide whether we wan'T to optimize or simply execute the model
        if (self.is_optimization == 1):
            #self.TF_obj = tf.Variable(np.real(self.obj), dtype=tf.float32, name='Object_Variable')
            #self.TF_obj_absorption = tf.Variable(np.imag(self.obj), dtype=tf.float32, name='Object_Variable')
            with tf.variable_scope("Complex_Object"):
                self.TF_obj = tf.get_variable('Object_Variable_Real',
                                              dtype=tf.float32,
                                              initializer=np.float32(
                                                  np.real(self.obj)))
                self.TF_obj_absorption = tf.get_variable(
                    'Object_Variable_Imag',
                    dtype=tf.float32,
                    initializer=np.float32(np.imag(self.obj)))
                #set reuse flag to True
                tf.get_variable_scope().reuse_variables()
                #just an assertion!
                assert tf.get_variable_scope().reuse == True

            # assign training variables
            self.tf_lambda_tv = tf.placeholder(tf.float32, [])
            self.tf_eps = tf.placeholder(tf.float32, [])
            self.tf_meas = tf.placeholder(dtype=tf.complex64,
                                          shape=self.mysize_old)
            self.tf_learningrate = tf.placeholder(tf.float32, [])

        elif (self.is_optimization == 0):
            # Variables of the computational graph
            self.TF_obj = tf.constant(np.real(self.obj),
                                      dtype=tf.float32,
                                      name='Object_const')
            self.TF_obj_absorption = tf.constant(np.imag(self.obj),
                                                 dtype=tf.float32,
                                                 name='Object_const')

        elif (self.is_optimization == -1):
            # THis is for the case that we want to train the resnet
            self.tf_meas = tf.placeholder(dtype=tf.complex64,
                                          shape=self.mysize_old)
            # in case one wants to use this as a fwd-model for an inverse problem

            #self.TF_obj = tf.Variable(np.real(self.obj), dtype=tf.float32, name='Object_Variable')
            #self.TF_obj_absorption = tf.Variable(np.imag(self.obj), dtype=tf.float32, name='Object_Variable')
            self.TF_obj = tf.placeholder(dtype=tf.float32,
                                         shape=self.obj.shape,
                                         name='Object_Variable_Real')
            self.TF_obj_absorption = tf.placeholder(
                dtype=tf.float32,
                shape=self.obj.shape,
                name='Object_Variable_Imag')

            # assign training variables
            self.tf_lambda_tv = tf.placeholder(tf.float32, [])
            self.tf_eps = tf.placeholder(tf.float32, [])

            self.tf_learningrate = tf.placeholder(tf.float32, [])

        ## Establish normalized coordinates.
        #-----------------------------------------
        vxx = tf_helper.xx(
            (self.mysize[1], self.mysize[2]),
            'freq') * self.lambdaM * self.nEmbb / (self.dx * self.NAo)
        # normalized optical coordinates in X
        vyy = tf_helper.yy(
            (self.mysize[1], self.mysize[2]),
            'freq') * self.lambdaM * self.nEmbb / (self.dy * self.NAo)
        # normalized optical coordinates in Y

        # AbbeLimit=lambda0/NAo;  # Rainer's Method
        # RelFreq = rr(mysize,'freq')*AbbeLimit/dx;  # Is not generally right (dx and dy)
        self.RelFreq = np.sqrt(tf_helper.abssqr(vxx) + tf_helper.abssqr(vyy))
        # spanns the frequency grid of normalized pupil coordinates
        self.Po = self.RelFreq < 1.0
        # Create the pupil of the objective lens

        # Precomputing the first 9 zernike coefficients
        self.nzernikes = np.squeeze(self.zernikefactors.shape)
        self.myzernikes = np.zeros(
            (self.Po.shape[0], self.Po.shape[1],
             self.nzernikes)) + 1j * np.zeros(
                 (self.Po.shape[0], self.Po.shape[1], self.nzernikes))
        r, theta = zern.cart2pol(vxx, vyy)
        for i in range(0, self.nzernikes):
            self.myzernikes[:, :, i] = np.fft.fftshift(
                zern.zernike(r, theta, i + 1,
                             norm=False))  # or 8 in X-direction

        # eventually introduce a phase factor to approximate the experimental data better
        self.Po = np.fft.fftshift(
            self.Po
        )  # Need to shift it before using as a low-pass filter    Po=np.ones((np.shape(Po)))
        print('----------> Be aware: We are taking aberrations into account!')
        # Assuming: System has coma along X-direction
        self.myaberration = np.sum(self.zernikefactors * self.myzernikes,
                                   axis=2)
        self.Po = 1. * self.Po  #*np.exp(1j*self.myaberration)

        # Prepare the normalized spatial-frequency grid.
        self.S = self.NAc / self.NAo
        # Coherence factor
        self.Ic = self.RelFreq <= self.S

        # Take Darkfield into account
        if hasattr(self, 'NAci'):
            if self.NAci != None and self.NAci > 0:
                #print('I detected a darkfield illumination aperture!')
                self.S_o = self.NAc / self.NAo
                # Coherence factor
                self.S_i = self.NAci / self.NAo
                # Coherence factor
                self.Ic = (1. * (self.RelFreq < self.S_o) * 1. *
                           (self.RelFreq > self.S_i)
                           ) > 0  # Create the pupil of the condenser plane

        # weigh the illumination source with some cos^2 intensity weight?!
        myIntensityFactor = 70
        self.Ic_map = np.cos((myIntensityFactor * tf_helper.xx(
            (self.Nx, self.Ny), mode='freq')**2 +
                              myIntensityFactor * tf_helper.yy(
                                  (self.Nx, self.Ny), mode='freq')**2))**2
        self.Ic = self.Ic * np.sqrt(
            self.Ic_map
        )  # weight the intensity in the condenser aperture, unlikely to be uniform
        # print('--------> ATTENTION! - We are not weighing the Intensity int the illu-pupil!')

        # Shift the pupil in X-direction (optical missalignment)
        if hasattr(self, 'shiftIcX'):
            if self.shiftIcX != None:
                if (is_padding): self.shiftIcX = self.shiftIcX * 2
                print('Shifting the illumination in X by: ' +
                      str(self.shiftIcX) + ' Pixel')
                if (0):
                    self.Ic = np.roll(self.Ic, self.shiftIcX, axis=1)
                elif (1):
                    tform = AffineTransform(scale=(1, 1),
                                            rotation=0,
                                            shear=0,
                                            translation=(self.shiftIcX, 0))
                    self.Ic = warp(self.Ic,
                                   tform.inverse,
                                   output_shape=self.Ic.shape)
                elif (0):
                    # We apply a phase-factor to shift the source in realspace - so make it trainable
                    self.shift_xx = tf_helper.xx(
                        (self.mysize[1], self.mysize[2]), 'freq')
                    self.Ic = np.abs(
                        np.fft.ifft2(
                            np.fft.fft2(self.Ic) *
                            np.exp(1j * 2 * np.pi * self.shift_xx *
                                   self.shiftIcX)))

        # Shift the pupil in Y-direction (optical missalignment)
        if hasattr(self, 'shiftIcY'):
            if self.shiftIcY != None:
                if (is_padding): self.shiftIcY = self.shiftIcY * 2
                print('Shifting the illumination in Y by: ' +
                      str(self.shiftIcY) + ' Pixel')
                if (0):
                    self.Ic = np.roll(self.Ic, self.shiftIcY, axis=0)
                elif (1):
                    tform = AffineTransform(scale=(1, 1),
                                            rotation=0,
                                            shear=0,
                                            translation=(0, self.shiftIcY))
                    self.Ic = warp(self.Ic,
                                   tform.inverse,
                                   output_shape=self.Ic.shape)
                elif (0):
                    # We apply a phase-factor to shift the source in realspace - so make it trainable
                    self.shift_yy = tf_helper.yy(
                        (self.mysize[1], self.mysize[2]), 'freq')
                    self.Ic = np.abs(
                        np.fft.ifft2(
                            np.fft.fft2(self.Ic) *
                            np.exp(1j * self.shift_yy * self.shiftIcY)))

        ## Forward propagator  (Ewald sphere based) DO NOT USE NORMALIZED COORDINATES HERE
        self.kxysqr = (tf_helper.abssqr(
            tf_helper.xx((self.mysize[1], self.mysize[2]), 'freq') /
            self.dx) + tf_helper.abssqr(
                tf_helper.yy(
                    (self.mysize[1], self.mysize[2]), 'freq') / self.dy)) + 0j
        self.k0 = 1 / self.lambdaM
        self.kzsqr = tf_helper.abssqr(self.k0) - self.kxysqr
        self.kz = np.sqrt(self.kzsqr)
        self.kz[self.kzsqr < 0] = 0
        self.dphi = 2 * np.pi * self.kz * self.dz
        # exp(1i*kz*dz) would be the propagator for one slice

        ## Get a list of vector coordinates corresponding to the pixels in the mask
        xfreq = tf_helper.xx((self.mysize[1], self.mysize[2]), 'freq')
        yfreq = tf_helper.yy((self.mysize[1], self.mysize[2]), 'freq')
        self.Nc = np.sum(self.Ic > 0)
        print('Number of Illumination Angles / Plane waves: ' + str(self.Nc))

        # Calculate the computatonal grid/sampling
        self.kxcoord = np.reshape(xfreq[self.Ic > 0], [1, 1, 1, self.Nc])
        # NA-positions in condenser aperture plane in x-direction
        self.kycoord = np.reshape(yfreq[self.Ic > 0], [1, 1, 1, self.Nc])
        # NA-positions in condenser aperture plane in y-direction
        self.RefrCos = np.reshape(self.k0 / self.kz[self.Ic > 0],
                                  [1, 1, 1, self.Nc])
        # 1/cosine used for the application of the refractive index steps to acount for longer OPD in medium under an oblique illumination angle

        ## Generate the illumination amplitudes
        self.intensityweights = self.Ic[self.Ic > 0]
        self.A_input = self.intensityweights * np.exp(
            (2 * np.pi * 1j) *
            (self.kxcoord *
             tf_helper.repmat4d(tf_helper.xx(
                 (self.mysize[1], self.mysize[2])), self.Nc) + self.kycoord *
             tf_helper.repmat4d(tf_helper.yy(
                 (self.mysize[1], self.mysize[2])), self.Nc))
        )  # Corresponds to a plane wave under many oblique illumination angles - bfxfun

        ## propagate field to z-stack and sum over all illumination angles
        self.Alldphi = -np.reshape(np.arange(
            0, self.mysize[0], 1), [1, 1, self.mysize[0]]) * np.repeat(
                np.fft.fftshift(self.dphi)[:, :, np.newaxis],
                self.mysize[0],
                axis=2)

        # Ordinary backpropagation. This is NOT what we are interested in:
        self.myAllSlicePropagator = np.transpose(
            np.exp(1j * self.Alldphi) *
            (np.repeat(np.fft.fftshift(self.dphi)[:, :, np.newaxis],
                       self.mysize[0],
                       axis=2) > 0), [2, 0, 1])