Esempio n. 1
0
class Sensor:

    def __init__(self,camera):
        self.image_width_px = ccfg.image_width_px
        self.image_height_px = ccfg.image_height_px
        self.dark_image = np.zeros((ccfg.image_height_px,ccfg.image_width_px),dtype=np.int16)
        self.dark_subtract = False
        self.n_dark = 10
        self.lenslet_pitch_m = ccfg.lenslet_pitch_m
        self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m
        self.pixel_size_m = ccfg.pixel_size_m
        self.beam_diameter_m = ccfg.beam_diameter_m
        self.wavelength_m = ccfg.wavelength_m
        self.background_correction = ccfg.background_correction
        self.centroiding_iterations = ccfg.centroiding_iterations
        self.iterative_centroiding_step = ccfg.iterative_centroiding_step
        self.filter_lenslets = ccfg.sensor_filter_lenslets
        self.estimate_background = ccfg.estimate_background
        self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront
        self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt

        # calculate diffraction limited spot size on sensor, to determine
        # the centroiding window size
        lenslet_dlss = 1.22*self.wavelength_m*self.lenslet_focal_length_m/self.lenslet_pitch_m
        lenslet_dlss_px = lenslet_dlss/self.pixel_size_m
        # now we need to account for smearing of spots due to axial displacement of retinal layers
        extent = 500e-6 # retinal thickness
        smear = extent*6.75/16.67 # pupil diameter and focal length; use diameter in case beacon is at edge of field
        try:
            magnification = ccfg.retina_sensor_magnification
        except Exception as e:
            magnification = 1.0
        total_size = lenslet_dlss+smear*magnification
        total_size_px = total_size/self.pixel_size_m
        self.centroiding_half_width = int(np.floor(total_size_px/2.0))*2
        
        try:
            xy = np.loadtxt(ccfg.reference_coordinates_filename)
        except Exception as e:
            xy = np.loadtxt(ccfg.reference_coordinates_bootstrap_filename)
            print 'Bootstrapping with %s'%ccfg.reference_coordinates_bootstrap_filename
            
        self.search_boxes = SearchBoxes(xy[:,0],xy[:,1],ccfg.search_box_half_width)
        self.sensor_mask = np.loadtxt(ccfg.reference_mask_filename)
        
        self.x0 = np.zeros(self.search_boxes.x.shape)
        self.y0 = np.zeros(self.search_boxes.y.shape)
        
        self.x0[:] = self.search_boxes.x[:]
        self.y0[:] = self.search_boxes.y[:]
        
        self.n_lenslets = self.search_boxes.n
        n_lenslets = self.n_lenslets
        self.image = np.zeros((ccfg.image_height_px,ccfg.image_width_px))
        self.x_slopes = np.zeros(n_lenslets)
        self.y_slopes = np.zeros(n_lenslets)
        self.x_centroids = np.zeros(n_lenslets)
        self.y_centroids = np.zeros(n_lenslets)
        self.box_maxes = np.zeros(n_lenslets)
        self.box_mins = np.zeros(n_lenslets)
        self.box_means = np.zeros(n_lenslets)
        self.valid_centroids = np.zeros(n_lenslets,dtype=np.int16)

        try:
            self.fast_centroiding = ccfg.fast_centroiding
        except Exception as e:
            self.fast_centroiding = False
        self.box_backgrounds = np.zeros(n_lenslets)
        self.error = 0.0
        self.tip = 0.0
        self.tilt = 0.0
        self.zernikes = np.zeros(ccfg.n_zernike_terms)
        self.wavefront = np.zeros(self.sensor_mask.shape)

        self.image_max = -1
        self.image_min = -1
        self.image_mean = -1
        
        self.cam = camera
        self.frame_timer = FrameTimer('Sensor',verbose=False)
        self.reconstructor = Reconstructor(self.search_boxes.x,
                                           self.search_boxes.y,self.sensor_mask)

        self.n_zernike_orders_corrected=self.reconstructor.N_orders
        self.centroiding_time = -1.0

        self.beeper = Beeper()

        self.logging = False
        self.paused = False
        self.sense_timer = BlockTimer('Sensor sense method')
        
        try:
            self.profile_update_method = ccfg.profile_sensor_update_method
        except:
            self.profile_update_method = False
        
    def update(self):
        if not self.paused:
            try:
                self.sense()
            except Exception as e:
                print 'Sensor update exception:',e
            if self.logging:
                self.log()
                
        self.frame_timer.tick()
    
    def pause(self):
        print 'sensor paused'
        self.paused = True

    def unpause(self):
        print 'sensor unpaused'
        self.paused = False

    def get_average_background(self):
        return np.mean(self.box_backgrounds)

    def get_n_zernike_orders_corrected(self):
        return self.n_zernike_orders_corrected

    def set_n_zernike_orders_corrected(self,n):
        self.n_zernike_orders_corrected = n
        
    def set_dark_subtraction(self,val):
        self.dark_subtract = val

    def set_n_dark(self,val):
        self.n_dark = val

    def set_dark(self):
        self.pause()
        temp = np.zeros(self.dark_image.shape)
        for k in range(self.n_dark):
            temp = temp + self.cam.get_image()
        temp = np.round(temp/float(self.n_dark)).astype(np.int16)
        self.dark_image[...] = temp[...]
        self.unpause()

    def log0(self):
        t_string = now_string(True)

        #seconds = float(datetime.datetime.strptime(t_string,'%Y%m%d%H%M%S.%f').strftime('%s.%f'))
        outfn = os.path.join(ccfg.logging_directory,'sensor_%s.mat'%(t_string))
        d = {}
        #d['time_seconds'] = seconds
        d['x_slopes'] = self.x_slopes
        d['y_slopes'] = self.y_slopes
        d['x_centroids'] = self.x_centroids
        d['y_centroids'] = self.y_centroids
        d['search_box_x1'] = self.search_boxes.x1
        d['search_box_x2'] = self.search_boxes.x2
        d['search_box_y1'] = self.search_boxes.y1
        d['search_box_y2'] = self.search_boxes.y2
        d['ref_x'] = self.search_boxes.x
        d['ref_y'] = self.search_boxes.y
        d['error'] = np.squeeze(self.error)
        d['tip'] = self.tip
        d['tilt'] = self.tilt
        d['wavefront'] = self.wavefront
        d['zernikes'] = np.squeeze(self.zernikes)
        #d['spots_image'] = self.image
        sio.savemat(outfn,d)

    def log(self):
        t_string = now_string(True)

        #seconds = float(datetime.datetime.strptime(t_string,'%Y%m%d%H%M%S.%f').strftime('%s.%f'))
        d = {}
        #d['time_seconds'] = np.array([seconds])
        d['x_slopes'] = self.x_slopes
        d['y_slopes'] = self.y_slopes
        d['x_centroids'] = self.x_centroids
        d['y_centroids'] = self.y_centroids
        d['search_box_x1'] = self.search_boxes.x1
        d['search_box_x2'] = self.search_boxes.x2
        d['search_box_y1'] = self.search_boxes.y1
        d['search_box_y2'] = self.search_boxes.y2
        d['ref_x'] = self.search_boxes.x
        d['ref_y'] = self.search_boxes.y
        d['error'] = np.array([np.squeeze(self.error)])
        #d['tip'] = self.tip
        #d['tilt'] = self.tilt
        d['wavefront'] = self.wavefront
        d['zernikes'] = np.squeeze(self.zernikes)
        d['spots_image'] = self.image.astype(np.uint16)

        for k in d.keys():
            outfn = os.path.join(ccfg.logging_directory,'sensor_%s_%s.txt'%(k,t_string))
            if k=='spots_image':
                np.savetxt(outfn,d[k],fmt='%d')
            else:
                np.savetxt(outfn,d[k])
            
        
        #sio.savemat(outfn,d)

        
    def set_background_correction(self,val):
        #sensor_mutex.lock()
        self.background_correction = val
        #sensor_mutex.unlock()

    def set_fast_centroiding(self,val):
        self.fast_centroiding = val

    def set_logging(self,val):
        self.logging = val


    def set_defocus(self,val):
        self.pause()
        newx = self.search_boxes.x0 + self.reconstructor.defocus_dx*val*ccfg.zernike_dioptric_equivalent
        newy = self.search_boxes.y0 + self.reconstructor.defocus_dy*val*ccfg.zernike_dioptric_equivalent
        self.search_boxes.move(newx,newy)
        
        self.unpause()

    def set_astig0(self,val):
        self.pause()
        
        newx = self.search_boxes.x + self.reconstructor.astig0_dx*val*ccfg.zernike_dioptric_equivalent
        
        newy = self.search_boxes.y + self.reconstructor.astig0_dy*val*ccfg.zernike_dioptric_equivalent
        self.search_boxes.move(newx,newy)
        
        self.unpause()
        
    def set_astig1(self,val):
        self.pause()
        
        newx = self.search_boxes.x + self.reconstructor.astig1_dx*val*ccfg.zernike_dioptric_equivalent
        
        newy = self.search_boxes.y + self.reconstructor.astig1_dy*val*ccfg.zernike_dioptric_equivalent

        self.search_boxes.move(newx,newy)
        
        self.unpause()


    def aberration_reset(self):
        self.pause()
        self.search_boxes.move(self.x0,self.y0)
        self.unpause()
        
    def set_centroiding_half_width(self,val):
        self.centroiding_half_width = val
        
    def sense(self,debug=False):

        if self.profile_update_method:
            self.sense_timer.tick('start')
            
        self.image = self.cam.get_image()

        if self.profile_update_method:
            self.sense_timer.tick('cam.get_image')
        
        if self.dark_subtract:
            self.image = self.image - self.dark_image

        self.image_min = self.image.min()
        self.image_mean = self.image.mean()
        self.image_max = self.image.max()
        
        if self.profile_update_method:
            self.sense_timer.tick('image stats')
            
        
        t0 = time.time()
        if not self.fast_centroiding:
            if self.estimate_background:
                centroid.estimate_backgrounds(spots_image=self.image,
                                              sb_x_vec = self.search_boxes.x,
                                              sb_y_vec = self.search_boxes.y,
                                              sb_bg_vec = self.box_backgrounds,
                                              sb_half_width_p = self.search_boxes.half_width)
                self.box_backgrounds = self.box_backgrounds + self.background_correction
                
            if self.profile_update_method:
                self.sense_timer.tick('estimate background')
            centroid.compute_centroids(spots_image=self.image,
                                       sb_x_vec = self.search_boxes.x,
                                       sb_y_vec = self.search_boxes.y,
                                       sb_bg_vec = self.box_backgrounds,
                                       sb_half_width_p = self.search_boxes.half_width,
                                       iterations_p = self.centroiding_iterations,
                                       iteration_step_px_p = self.iterative_centroiding_step,
                                       x_out = self.x_centroids,
                                       y_out = self.y_centroids,
                                       mean_intensity = self.box_means,
                                       maximum_intensity = self.box_maxes,
                                       minimum_intensity = self.box_mins,
                                       num_threads_p = 1)
            if self.profile_update_method:
                self.sense_timer.tick('centroid')
        else:
            centroid.fast_centroids(spots_image=self.image,
                                    sb_x_vec = self.search_boxes.x,
                                    sb_y_vec = self.search_boxes.y,
                                    sb_half_width_p = self.search_boxes.half_width,
                                    centroiding_half_width_p = self.centroiding_half_width,
                                    x_out = self.x_centroids,
                                    y_out = self.y_centroids,
                                    sb_max_vec = self.box_maxes,
                                    valid_vec = self.valid_centroids,
                                    verbose_p = 0,
                                    num_threads_p = 1)
        self.centroiding_time = time.time()-t0
        self.x_slopes = (self.x_centroids-self.search_boxes.x)*self.pixel_size_m/self.lenslet_focal_length_m
        self.y_slopes = (self.y_centroids-self.search_boxes.y)*self.pixel_size_m/self.lenslet_focal_length_m
        
        self.tilt = np.mean(self.x_slopes)
        self.tip = np.mean(self.y_slopes)
        
        if self.remove_tip_tilt:
            self.x_slopes-=self.tilt
            self.y_slopes-=self.tip

            
        if self.reconstruct_wavefront:
            self.zernikes,self.wavefront,self.error = self.reconstructor.get_wavefront(self.x_slopes,self.y_slopes)
            if self.profile_update_method:
                self.sense_timer.tick('reconstruct wavefront')
            
            
            self.filter_slopes = self.n_zernike_orders_corrected<self.reconstructor.N_orders
            
            if self.filter_slopes:

                # Outline of approach: the basic idea is to filter the residual error
                # slopes by Zernike mode before multiplying by the mirror command
                # matrix.
                # 1. multiply the slopes by a wavefront reconstructor matrix
                #    to get Zernike coefficients; these are already output by
                #    the call to self.reconstructor.get_wavefront above
                # 2. zero the desired modes
                # 3. multiply the modes by the inverse of that matrix, which is stored
                #    in the Reconstructor object as reconstructor.slope_matrix

                # convert the order into a number of terms:
                n_terms = self.reconstructor.Z.nm2j(self.n_zernike_orders_corrected,self.n_zernike_orders_corrected)

                # get the slope matrix (inverse of zernike matrix, which maps slopes onto zernikes)
                slope_matrix = self.reconstructor.slope_matrix

                # create a filtered set of zernike terms
                # not sure if we should zero piston here
                z_filt = np.zeros(len(self.zernikes))
                z_filt[:n_terms+1] = self.zernikes[:n_terms+1]
                
                zero_piston = True
                if zero_piston:
                    z_filt[0] = 0.0
                
                # filter the slopes, and assign them to this sensor object:
                filtered_slopes = np.dot(slope_matrix,z_filt)
                self.x_slopes = filtered_slopes[:self.n_lenslets]
                self.y_slopes = filtered_slopes[self.n_lenslets:]
            
        if self.profile_update_method:
            self.sense_timer.tick('end sense')
            self.sense_timer.tock()
            
        try:
            self.beeper.beep(self.error)
        except Exception as e:
            print e
            print self.error
            sys.exit()
        
    def record_reference(self):
        print 'recording reference'
        self.pause()
        xcent = []
        ycent = []
        for k in range(ccfg.reference_n_measurements):
            print 'measurement %d of %d'%(k+1,ccfg.reference_n_measurements),
            self.sense()
            print '...done'
            xcent.append(self.x_centroids)
            ycent.append(self.y_centroids)

        xcent = np.array(xcent)
        ycent = np.array(ycent)
        
        x_ref = xcent.mean(0)
        y_ref = ycent.mean(0)

        x_var = xcent.var(0)
        y_var = ycent.var(0)
        err = np.sqrt(np.mean([x_var,y_var]))
        print 'reference coordinate error %0.3e px RMS'%err
        
        self.search_boxes = SearchBoxes(x_ref,y_ref,self.search_boxes.half_width)
        refxy = np.array((x_ref,y_ref)).T

        # Record the new reference set to two locations, the
        # filename specified by reference_coordinates_filename
        # in ciao config, and also an archival filename to keep
        # track of the history.
        archive_fn = os.path.join(ccfg.reference_directory,prepend('reference.txt',now_string()))
        
        np.savetxt(archive_fn,refxy,fmt='%0.3f')
        np.savetxt(ccfg.reference_coordinates_filename,refxy,fmt='%0.3f')
        
        self.unpause()
        time.sleep(1)
Esempio n. 2
0
class Sensor(QObject):

    finished = pyqtSignal()

    def __init__(self, camera):
        super(Sensor, self).__init__()
        self.image_width_px = ccfg.image_width_px
        self.image_height_px = ccfg.image_height_px
        self.lenslet_pitch_m = ccfg.lenslet_pitch_m
        self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m
        self.pixel_size_m = ccfg.pixel_size_m
        self.beam_diameter_m = ccfg.beam_diameter_m
        self.wavelength_m = ccfg.wavelength_m
        self.background_correction = ccfg.background_correction
        self.centroiding_iterations = ccfg.centroiding_iterations
        self.iterative_centroiding_step = ccfg.iterative_centroiding_step
        self.filter_lenslets = ccfg.sensor_filter_lenslets
        self.estimate_background = ccfg.estimate_background
        self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront
        self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt
        try:
            # check to see if the camera object produced its own
            # search boxes, and if not, use reference coordinates
            self.search_boxes = camera.search_boxes
            self.mask = camera.lenslet_mask
        except Exception as e:
            xy = np.loadtxt(ccfg.reference_coordinates_filename)
            self.search_boxes = SearchBoxes(xy[:, 0], xy[:, 1],
                                            ccfg.search_box_half_width)
            self.mask = np.loadtxt(ccfg.reference_mask_filename)

        self.x0 = np.zeros(self.search_boxes.x.shape)
        self.y0 = np.zeros(self.search_boxes.y.shape)

        self.x0[:] = self.search_boxes.x[:]
        self.y0[:] = self.search_boxes.y[:]

        self.n_lenslets = self.search_boxes.n
        n_lenslets = self.n_lenslets
        self.image = np.zeros((ccfg.image_height_px, ccfg.image_width_px))
        self.x_slopes = np.zeros(n_lenslets)
        self.y_slopes = np.zeros(n_lenslets)
        self.x_centroids = np.zeros(n_lenslets)
        self.y_centroids = np.zeros(n_lenslets)
        self.box_maxes = np.zeros(n_lenslets)
        self.box_mins = np.zeros(n_lenslets)
        self.box_means = np.zeros(n_lenslets)
        self.box_backgrounds = np.zeros(n_lenslets)
        self.error = 0.0
        self.tip = 0.0
        self.tilt = 0.0
        self.zernikes = None
        self.wavefront = None

        self.cam = camera
        self.frame_timer = FrameTimer('Sensor', verbose=False)
        self.reconstructor = Reconstructor(self.search_boxes.x,
                                           self.search_boxes.y, self.mask)
        self.logging = False
        self.paused = False

    @pyqtSlot()
    def update(self):
        if not self.paused:
            try:
                self.sense()
            except Exception as e:
                print e
            if self.logging:
                self.log()

        self.finished.emit()
        self.frame_timer.tick()

    @pyqtSlot()
    def pause(self):
        print 'sensor paused'
        self.paused = True

    @pyqtSlot()
    def unpause(self):
        print 'sensor unpaused'
        self.paused = False
        #self.sense()

    def log(self):
        outfn = os.path.join(ccfg.logging_directory,
                             'sensor_%s.mat' % (now_string(True)))
        d = {}
        d['x_slopes'] = self.x_slopes
        d['y_slopes'] = self.y_slopes
        d['x_centroids'] = self.x_centroids
        d['y_centroids'] = self.y_centroids
        d['search_box_x1'] = self.search_boxes.x1
        d['search_box_x2'] = self.search_boxes.x2
        d['search_box_y1'] = self.search_boxes.y1
        d['search_box_y2'] = self.search_boxes.y2
        d['ref_x'] = self.search_boxes.x
        d['ref_y'] = self.search_boxes.y
        d['error'] = self.error
        d['tip'] = self.tip
        d['tilt'] = self.tilt
        d['wavefront'] = self.wavefront
        d['zernikes'] = self.zernikes

        sio.savemat(outfn, d)

    def set_background_correction(self, val):
        #sensor_mutex.lock()
        self.background_correction = val
        #sensor_mutex.unlock()

    def set_logging(self, val):
        self.logging = val

    def set_defocus(self, val):
        self.pause()

        newx = self.x0 + self.reconstructor.defocus_dx * val * ccfg.zernike_dioptric_equivalent

        newy = self.y0 + self.reconstructor.defocus_dy * val * ccfg.zernike_dioptric_equivalent
        self.search_boxes.move(newx, newy)

        self.unpause()

    def sense(self):
        image = self.cam.get_image()
        sb = self.search_boxes
        xr = np.zeros(self.search_boxes.x.shape)
        xr[:] = self.search_boxes.x[:]
        yr = np.zeros(self.search_boxes.y.shape)
        yr[:] = self.search_boxes.y[:]
        half_width = sb.half_width
        for iteration in range(self.centroiding_iterations):
            #QApplication.processEvents()
            msi = iteration == self.centroiding_iterations - 1
            centroid.compute_centroids(
                spots_image=image,
                sb_x1_vec=sb.x1,
                sb_x2_vec=sb.x2,
                sb_y1_vec=sb.y1,
                sb_y2_vec=sb.y2,
                x_out=xr,
                y_out=yr,
                mean_intensity=self.box_means,
                maximum_intensity=self.box_maxes,
                minimum_intensity=self.box_mins,
                background_intensity=self.box_backgrounds,
                estimate_background=self.estimate_background,
                background_correction=self.background_correction,
                num_threads=1,
                modify_spots_image=msi)
            half_width -= self.iterative_centroiding_step
            sb = SearchBoxes(xr, yr, half_width)

        self.x_centroids[:] = xr[:]
        self.y_centroids[:] = yr[:]
        self.x_slopes = (self.x_centroids - self.search_boxes.x
                         ) * self.pixel_size_m / self.lenslet_focal_length_m
        self.y_slopes = (self.y_centroids - self.search_boxes.y
                         ) * self.pixel_size_m / self.lenslet_focal_length_m
        self.tilt = np.mean(self.x_slopes)
        self.tip = np.mean(self.y_slopes)
        if self.remove_tip_tilt:
            self.x_slopes -= self.tilt
            self.y_slopes -= self.tip
        self.image = image
        if self.reconstruct_wavefront:
            self.zernikes, self.wavefront, self.error = self.reconstructor.get_wavefront(
                self.x_slopes, self.y_slopes)

    def record_reference(self):
        print 'recording reference'
        self.pause()
        xcent = []
        ycent = []
        for k in range(ccfg.reference_n_measurements):
            print 'measurement %d of %d' % (k + 1,
                                            ccfg.reference_n_measurements),
            self.sense()
            print '...done'
            xcent.append(self.x_centroids)
            ycent.append(self.y_centroids)

        x_ref = np.array(xcent).mean(0)
        y_ref = np.array(ycent).mean(0)
        self.search_boxes = SearchBoxes(x_ref, y_ref,
                                        self.search_boxes.half_width)
        outfn = os.path.join(ccfg.reference_directory,
                             prepend('coords.txt', now_string()))
        refxy = np.array((x_ref, y_ref)).T
        np.savetxt(outfn, refxy, fmt='%0.2f')
        self.unpause()
        time.sleep(1)
Esempio n. 3
0
class Sensor(QObject):

    finished = pyqtSignal()

    def __init__(self, camera):
        super(Sensor, self).__init__()
        self.image_width_px = ccfg.image_width_px
        self.image_height_px = ccfg.image_height_px
        self.lenslet_pitch_m = ccfg.lenslet_pitch_m
        self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m
        self.pixel_size_m = ccfg.pixel_size_m
        self.beam_diameter_m = ccfg.beam_diameter_m
        self.wavelength_m = ccfg.wavelength_m
        self.background_correction = ccfg.background_correction
        self.centroiding_iterations = ccfg.centroiding_iterations
        self.iterative_centroiding_step = ccfg.iterative_centroiding_step
        self.filter_lenslets = ccfg.sensor_filter_lenslets
        self.estimate_background = ccfg.estimate_background
        self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront
        self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt

        try:
            xy = np.loadtxt(ccfg.reference_coordinates_filename)
        except Exception as e:
            xy = np.loadtxt(ccfg.reference_coordinates_bootstrap_filename)
            print 'Bootstrapping with %s' % ccfg.reference_coordinates_bootstrap_filename

        self.search_boxes = SearchBoxes(xy[:, 0], xy[:, 1],
                                        ccfg.search_box_half_width)
        self.sensor_mask = np.loadtxt(ccfg.reference_mask_filename)

        self.x0 = np.zeros(self.search_boxes.x.shape)
        self.y0 = np.zeros(self.search_boxes.y.shape)

        self.x0[:] = self.search_boxes.x[:]
        self.y0[:] = self.search_boxes.y[:]

        self.n_lenslets = self.search_boxes.n
        n_lenslets = self.n_lenslets
        self.image = np.zeros((ccfg.image_height_px, ccfg.image_width_px))
        self.x_slopes = np.zeros(n_lenslets)
        self.y_slopes = np.zeros(n_lenslets)
        self.x_centroids = np.zeros(n_lenslets)
        self.y_centroids = np.zeros(n_lenslets)
        self.box_maxes = np.zeros(n_lenslets)
        self.box_mins = np.zeros(n_lenslets)
        self.box_means = np.zeros(n_lenslets)
        self.box_backgrounds = np.zeros(n_lenslets)
        self.error = 0.0
        self.tip = 0.0
        self.tilt = 0.0
        self.zernikes = None
        self.wavefront = np.zeros(self.sensor_mask.shape)

        self.cam = camera
        self.frame_timer = FrameTimer('Sensor', verbose=False)
        self.reconstructor = Reconstructor(self.search_boxes.x,
                                           self.search_boxes.y,
                                           self.sensor_mask)
        self.logging = False
        self.paused = False

    @pyqtSlot()
    def update(self):
        if not self.paused:
            try:
                self.sense()
            except Exception as e:
                print 'Sensor update exception:', e
            if self.logging:
                self.log()

        self.finished.emit()
        self.frame_timer.tick()

    @pyqtSlot()
    def pause(self):
        print 'sensor paused'
        self.paused = True

    @pyqtSlot()
    def unpause(self):
        print 'sensor unpaused'
        self.paused = False
        #self.sense()

    def log(self):
        outfn = os.path.join(ccfg.logging_directory,
                             'sensor_%s.mat' % (now_string(True)))
        d = {}
        d['x_slopes'] = self.x_slopes
        d['y_slopes'] = self.y_slopes
        d['x_centroids'] = self.x_centroids
        d['y_centroids'] = self.y_centroids
        d['search_box_x1'] = self.search_boxes.x1
        d['search_box_x2'] = self.search_boxes.x2
        d['search_box_y1'] = self.search_boxes.y1
        d['search_box_y2'] = self.search_boxes.y2
        d['ref_x'] = self.search_boxes.x
        d['ref_y'] = self.search_boxes.y
        d['error'] = self.error
        d['tip'] = self.tip
        d['tilt'] = self.tilt
        d['wavefront'] = self.wavefront
        d['zernikes'] = self.zernikes

        sio.savemat(outfn, d)

    def set_background_correction(self, val):
        #sensor_mutex.lock()
        self.background_correction = val
        #sensor_mutex.unlock()

    def set_logging(self, val):
        self.logging = val

    def set_defocus(self, val):
        self.pause()

        newx = self.x0 + self.reconstructor.defocus_dx * val * ccfg.zernike_dioptric_equivalent

        newy = self.y0 + self.reconstructor.defocus_dy * val * ccfg.zernike_dioptric_equivalent
        self.search_boxes.move(newx, newy)

        self.unpause()

    def sense(self, debug=False):
        self.image = self.cam.get_image()

        centroid.estimate_backgrounds(
            spots_image=self.image,
            sb_x_vec=self.search_boxes.x,
            sb_y_vec=self.search_boxes.y,
            sb_bg_vec=self.box_backgrounds,
            sb_half_width_p=self.search_boxes.half_width)
        centroid.compute_centroids(
            spots_image=self.image,
            sb_x_vec=self.search_boxes.x,
            sb_y_vec=self.search_boxes.y,
            sb_bg_vec=self.box_backgrounds,
            sb_half_width_p=self.search_boxes.half_width,
            iterations_p=self.centroiding_iterations,
            iteration_step_px_p=self.iterative_centroiding_step,
            x_out=self.x_centroids,
            y_out=self.y_centroids,
            mean_intensity=self.box_means,
            maximum_intensity=self.box_maxes,
            minimum_intensity=self.box_mins,
            num_threads_p=1)

        self.x_slopes = (self.x_centroids - self.search_boxes.x
                         ) * self.pixel_size_m / self.lenslet_focal_length_m
        self.y_slopes = (self.y_centroids - self.search_boxes.y
                         ) * self.pixel_size_m / self.lenslet_focal_length_m
        self.tilt = np.mean(self.x_slopes)
        self.tip = np.mean(self.y_slopes)
        if self.remove_tip_tilt:
            self.x_slopes -= self.tilt
            self.y_slopes -= self.tip
        if self.reconstruct_wavefront:
            self.zernikes, self.wavefront, self.error = self.reconstructor.get_wavefront(
                self.x_slopes, self.y_slopes)

    def sense0(self, debug=False):
        image = self.cam.get_image()
        sb = self.search_boxes
        xr = np.zeros(self.search_boxes.x.shape)
        xr[:] = self.search_boxes.x[:]
        yr = np.zeros(self.search_boxes.y.shape)
        yr[:] = self.search_boxes.y[:]
        half_width = sb.half_width

        for iteration in range(self.centroiding_iterations):
            #QApplication.processEvents()
            msi = iteration == self.centroiding_iterations - 1
            if debug:
                plt.figure()
                plt.imshow(image)
                plt.title('iteration %d' % iteration)
            centroid.compute_centroids(
                spots_image=image,
                sb_x1_vec=sb.x1,
                sb_x2_vec=sb.x2,
                sb_y1_vec=sb.y1,
                sb_y2_vec=sb.y2,
                x_out=xr,
                y_out=yr,
                mean_intensity=self.box_means,
                maximum_intensity=self.box_maxes,
                minimum_intensity=self.box_mins,
                background_intensity=self.box_backgrounds,
                estimate_background=self.estimate_background,
                background_correction=self.background_correction,
                num_threads=1,
                modify_spots_image=msi)
            half_width -= self.iterative_centroiding_step
            sb = SearchBoxes(xr, yr, half_width)
        if debug:
            plt.figure()
            plt.imshow(image)
            plt.show()
            sys.exit()
        self.x_centroids[:] = xr[:]
        self.y_centroids[:] = yr[:]
        self.x_slopes = (self.x_centroids - self.search_boxes.x
                         ) * self.pixel_size_m / self.lenslet_focal_length_m
        self.y_slopes = (self.y_centroids - self.search_boxes.y
                         ) * self.pixel_size_m / self.lenslet_focal_length_m
        self.tilt = np.mean(self.x_slopes)
        self.tip = np.mean(self.y_slopes)
        if self.remove_tip_tilt:
            self.x_slopes -= self.tilt
            self.y_slopes -= self.tip
        self.image = image
        if self.reconstruct_wavefront:
            self.zernikes, self.wavefront, self.error = self.reconstructor.get_wavefront(
                self.x_slopes, self.y_slopes)

    def record_reference(self):
        print 'recording reference'
        self.pause()
        xcent = []
        ycent = []
        for k in range(ccfg.reference_n_measurements):
            print 'measurement %d of %d' % (k + 1,
                                            ccfg.reference_n_measurements),
            self.sense()
            print '...done'
            xcent.append(self.x_centroids)
            ycent.append(self.y_centroids)

        xcent = np.array(xcent)
        ycent = np.array(ycent)
        x_ref = xcent.mean(0)
        y_ref = ycent.mean(0)

        x_var = xcent.var(0)
        y_var = ycent.var(0)
        err = np.sqrt(np.mean([x_var, y_var]))
        print 'reference coordinate error %0.3e px RMS' % err

        self.search_boxes = SearchBoxes(x_ref, y_ref,
                                        self.search_boxes.half_width)
        refxy = np.array((x_ref, y_ref)).T

        # Record the new reference set to two locations, the
        # filename specified by reference_coordinates_filename
        # in ciao config, and also an archival filename to keep
        # track of the history.
        archive_fn = os.path.join(ccfg.reference_directory,
                                  prepend('reference.txt', now_string()))

        np.savetxt(archive_fn, refxy, fmt='%0.3f')
        np.savetxt(ccfg.reference_coordinates_filename, refxy, fmt='%0.3f')

        self.unpause()
        time.sleep(1)
Esempio n. 4
0
class Sensor(QObject):

    finished = pyqtSignal()
    
    def __init__(self,camera):
        super(Sensor,self).__init__()
        self.image_width_px = kcfg.image_width_px
        self.image_height_px = kcfg.image_height_px
        self.lenslet_pitch_m = kcfg.lenslet_pitch_m
        self.lenslet_focal_length_m = kcfg.lenslet_focal_length_m
        self.pixel_size_m = kcfg.pixel_size_m
        self.beam_diameter_m = kcfg.beam_diameter_m
        self.wavelength_m = kcfg.wavelength_m
        self.background_correction = kcfg.background_correction
        self.centroiding_iterations = kcfg.centroiding_iterations
        self.iterative_centroiding_step = kcfg.iterative_centroiding_step
        self.filter_lenslets = kcfg.sensor_filter_lenslets
        self.estimate_background = kcfg.estimate_background
        self.reconstruct_wavefront = kcfg.sensor_reconstruct_wavefront
        self.remove_tip_tilt = kcfg.sensor_remove_tip_tilt
        try:
            # check to see if the camera object produced its own
            # search boxes, and if not, use reference coordinates
            self.search_boxes = camera.search_boxes
            self.mask = camera.lenslet_mask
        except Exception as e:
            xy = np.loadtxt(kcfg.reference_coordinates_filename)
            self.search_boxes = SearchBoxes(xy[:,0],xy[:,1],kcfg.search_box_half_width)
            self.mask = np.loadtxt(kcfg.reference_mask_filename)
        
        self.x0 = np.zeros(self.search_boxes.x.shape)
        self.y0 = np.zeros(self.search_boxes.y.shape)
        
        self.x0[:] = self.search_boxes.x[:]
        self.y0[:] = self.search_boxes.y[:]
        
        self.n_lenslets = self.search_boxes.n
        n_lenslets = self.n_lenslets
        self.image = np.zeros((kcfg.image_height_px,kcfg.image_width_px))
        self.x_slopes = np.zeros(n_lenslets)
        self.y_slopes = np.zeros(n_lenslets)
        self.x_centroids = np.zeros(n_lenslets)
        self.y_centroids = np.zeros(n_lenslets)
        self.box_maxes = np.zeros(n_lenslets)
        self.box_mins = np.zeros(n_lenslets)
        self.box_means = np.zeros(n_lenslets)
        self.box_backgrounds = np.zeros(n_lenslets)
        self.error = 0.0
        self.tip = 0.0
        self.tilt = 0.0
        self.zernikes = None
        self.wavefront = None

        self.cam = camera
        self.frame_timer = FrameTimer('Sensor',verbose=False)
        self.reconstructor = Reconstructor(self.search_boxes.x,
                                           self.search_boxes.y,self.mask)
        self.logging = False
        self.paused = False
        
    @pyqtSlot()
    def update(self):
        if not self.paused:
            try:
                self.sense()
            except Exception as e:
                print e
            if self.logging:
                self.log()
                
        self.finished.emit()
        self.frame_timer.tick()
    
    @pyqtSlot()
    def pause(self):
        print 'sensor paused'
        self.paused = True

    @pyqtSlot()
    def unpause(self):
        print 'sensor unpaused'
        self.paused = False
        #self.sense()

    def log(self):
        outfn = os.path.join(kcfg.logging_directory,'sensor_%s.mat'%(now_string(True)))
        d = {}
        d['x_slopes'] = self.x_slopes
        d['y_slopes'] = self.y_slopes
        d['x_centroids'] = self.x_centroids
        d['y_centroids'] = self.y_centroids
        d['search_box_x1'] = self.search_boxes.x1
        d['search_box_x2'] = self.search_boxes.x2
        d['search_box_y1'] = self.search_boxes.y1
        d['search_box_y2'] = self.search_boxes.y2
        d['ref_x'] = self.search_boxes.x
        d['ref_y'] = self.search_boxes.y
        d['error'] = self.error
        d['tip'] = self.tip
        d['tilt'] = self.tilt
        d['wavefront'] = self.wavefront
        d['zernikes'] = self.zernikes
        
        sio.savemat(outfn,d)

    def set_background_correction(self,val):
        sensor_mutex.lock()
        self.background_correction = val
        sensor_mutex.unlock()


    def set_logging(self,val):
        self.logging = val


    def set_defocus(self,val):
        self.pause()
        
        newx = self.x0 + self.reconstructor.defocus_dx*val*kcfg.zernike_dioptric_equivalent
        
        newy = self.y0 + self.reconstructor.defocus_dy*val*kcfg.zernike_dioptric_equivalent
        self.search_boxes.move(newx,newy)
        
        self.unpause()
        
    def sense(self):
        image = cam.get_image()
        sensor_mutex.lock()
        sb = self.search_boxes
        xr = np.zeros(self.search_boxes.x.shape)
        xr[:] = self.search_boxes.x[:]
        yr = np.zeros(self.search_boxes.y.shape)
        yr[:] = self.search_boxes.y[:]
        half_width = sb.half_width
        for iteration in range(self.centroiding_iterations):
            #QApplication.processEvents()
            msi = iteration==self.centroiding_iterations-1
            centroid.compute_centroids(spots_image=image,
                                       sb_x1_vec=sb.x1,
                                       sb_x2_vec=sb.x2,
                                       sb_y1_vec=sb.y1,
                                       sb_y2_vec=sb.y2,
                                       x_out=xr,
                                       y_out=yr,
                                       mean_intensity = self.box_means,
                                       maximum_intensity = self.box_maxes,
                                       minimum_intensity = self.box_mins,
                                       background_intensity = self.box_backgrounds,
                                       estimate_background = self.estimate_background,
                                       background_correction = self.background_correction,
                                       num_threads = 1,
                                       modify_spots_image = msi)
            half_width-=self.iterative_centroiding_step
            sb = SearchBoxes(xr,yr,half_width)
            
        self.x_centroids[:] = xr[:]
        self.y_centroids[:] = yr[:]
        self.x_slopes = (self.x_centroids-self.search_boxes.x)*self.pixel_size_m/self.lenslet_focal_length_m
        self.y_slopes = (self.y_centroids-self.search_boxes.y)*self.pixel_size_m/self.lenslet_focal_length_m
        self.tilt = np.mean(self.x_slopes)
        self.tip = np.mean(self.y_slopes)
        if self.remove_tip_tilt:
            self.x_slopes-=self.tilt
            self.y_slopes-=self.tip
        self.image = image
        if self.reconstruct_wavefront:
            self.zernikes,self.wavefront,self.error = self.reconstructor.get_wavefront(self.x_slopes,self.y_slopes)
        sensor_mutex.unlock()

    
    def record_reference(self):
        print 'recording reference'
        self.pause()
        xcent = []
        ycent = []
        for k in range(kcfg.reference_n_measurements):
            print 'measurement %d of %d'%(k+1,kcfg.reference_n_measurements),
            self.sense()
            print '...done'
            xcent.append(self.x_centroids)
            ycent.append(self.y_centroids)
            
        x_ref = np.array(xcent).mean(0)
        y_ref = np.array(ycent).mean(0)
        self.search_boxes = SearchBoxes(x_ref,y_ref,self.search_boxes.half_width)
        outfn = os.path.join(kcfg.reference_directory,prepend('coords.txt',now_string()))
        refxy = np.array((x_ref,y_ref)).T
        np.savetxt(outfn,refxy,fmt='%0.2f')
        self.unpause()
        time.sleep(1)