def motion_correct_file(args, n_iter=0, max_iter=10): try: in_fn, file_index, template, mc_args, \ subidx, apply_subidx, apply_ofn = args max_shifts, strides, overlaps, \ max_deviation_rigid, shifts_opencv, border_nan = mc_args mc = MotionCorrect(in_fn, dview=None, max_shifts=max_shifts, strides=strides, overlaps=overlaps, max_deviation_rigid=max_deviation_rigid, shifts_opencv=shifts_opencv, nonneg_movie=True, splits_els=1, splits_rig=1, border_nan=border_nan, subidx=subidx) mc.motion_correct(template=template, save_movie=False) if apply_subidx is not None: applied_mov = mc.apply_shifts_movie(in_fn, apply_subidx) applied_mov.save(apply_ofn) return (file_index, np.mean(mc.templates_rig, axis=0)) except Exception as e: if n_iter < max_iter: print("Retrying %s due to %s" % (in_fn, e)) return motion_correct_file(args, n_iter=n_iter + 1) else: return Exception("Failed max_iter: %s times" % max_iter)
def caiman_motion_correct(fnames, opts): '''do the motion correction of the Caiman pipeline and save results. Parameters ---------- fnames : string name of tiff movie opts : caiman object with the options for motion correction''' #%% start a cluster for parallel processing (if a cluster already exists it will be closed and a new session will be opened) if 'dview' in locals(): cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # first we create a motion correction object with the parameters specified mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) mc.motion_correct(save_movie=True) border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # memory map the file in order 'C' fname_new = cm.save_memmap(mc.mmap_file, base_name='memmap_', order='C', border_to_0=border_to_0, dview=dview) # exclude borders cm.stop_server(dview=dview)
def motion_correct_file(folder, dview): import caiman as cm from caiman.motion_correction import MotionCorrect from caiman.source_extraction.cnmf import params as params print(folder) mc_dict = { 'fnames': [os.path.join(folder, 'movie_total.hdf5')], 'fr': 7, 'decay_time': 1.5, 'dxy': [1.15, 1.15], 'pw_rigid': False, 'max_shifts': [5,5], 'strides': None, 'overlaps': None, 'max_deviation_rigid': None, 'border_nan': 'copy' } opts = params.CNMFParams(params_dict=mc_dict) mc = MotionCorrect(mc_dict['fnames'], dview=dview, **opts.get_group('motion')) mc.motion_correct(save_movie=True)
def motion_correct(self): """ Do motion correction. """ # Set up motion correction object and load parameters. mc = MotionCorrect(self.fnames, dview=self.dview, **self.opts.get_group('motion')) # Do motion correction. mc.motion_correct(save_movie=True) # Plot motion correction statistics. fname_mc = mc.fname_tot_els if self.opts.motion[ 'pw_rigid'] else mc.fname_tot_rig if self.opts.motion['pw_rigid']: self.bord_px = np.ceil( np.maximum(np.max(np.abs(mc.x_shifts_els)), np.max(np.abs(mc.y_shifts_els)))).astype(np.int) else: self.bord_px = np.ceil(np.max(np.abs(mc.shifts_rig))).astype( np.int) plt.subplot(1, 2, 1) plt.imshow(mc.total_template_rig) # % plot template plt.subplot(1, 2, 2) plt.plot(mc.shifts_rig) # % plot rigid shifts plt.legend(['x shifts', 'y shifts']) plt.xlabel('frames') plt.ylabel('pixels') # Save memory map. self.bord_px = 0 if self.opts.motion[ 'border_nan'] is 'copy' else self.bord_px self.fname_new = cm.save_memmap(fname_mc, base_name='full', order='C', border_to_0=self.bord_px)
def motion_corr(fnames, dview, opts, disp_movie, is_3d=False): """Perform motion correction""" # Create a motion correction object with the parameters specified. Note # that the file is not loaded in memory mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run piecewise-rigid motion correction using NoRMCorre mc.motion_correct(save_movie=True) # Determine maximum shift to be used for trimming against NaNs border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # Compare with original movie if disp_movie and not is_3d: m_els = cm.load(mc.fname_tot_els) m_orig = cm.load_movie_chain(fnames) ds_ratio = 0.2 cm.concatenate([ m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_els.resize(1, 1, ds_ratio) ], axis=2).play(fr=60, gain=15, magnification=2, offset=0) # press q to exit return mc, border_to_0
def main(): pass # For compatibility between running under Spyder and the CLI #%% Select file(s) to be processed (download if not present) # fnames = [os.path.join(caiman_datadir(), 'example_movies/sampled3dMovieRigid.nwb')] fnames = [ os.path.join(caiman_datadir(), 'example_movies/sampled3dMovie2.nwb') ] # filename to be created or processed # dataset dependent parameters fr = 5 # imaging rate in frames per second decay_time = 0.4 # length of a typical transient in seconds starting_time = 0. #%% load the file and save it in the NWB format (if it doesn't exist already) if not os.path.exists(fnames[0]): # fnames_orig = [os.path.join(caiman_datadir(), 'example_movies/sampled3dMovieRigid.h5')] # filename to be processed fnames_orig = [ os.path.join(caiman_datadir(), 'example_movies/sampled3dMovie2.h5') ] # filename to be processed orig_movie = cm.load(fnames_orig, fr=fr, is3D=True) # orig_movie = cm.load_movie_chain(fnames_orig,fr=fr,is3D=True) # save file in NWB format with various additional info orig_movie.save(fnames[0], sess_desc='test', identifier='demo 3d', exp_desc='demo movie', imaging_plane_description='multi plane', emission_lambda=520.0, indicator='none', location='visual cortex', starting_time=starting_time, experimenter='NAOMi', lab_name='Tank Lab', institution='Princeton U', experiment_description='Experiment Description', session_id='Session 1', var_name_hdf5='TwoPhotonSeries') #%% First setup some parameters for data and motion correction # motion correction parameters dxy = (1., 1., 5.) # spatial resolution in x, y, and z in (um per pixel) # note the lower than usual spatial resolution here max_shift_um = (10., 10., 10.) # maximum shift in um patch_motion_um = (50., 50., 30. ) # patch size for non-rigid correction in um # pw_rigid = False # flag to select rigid vs pw_rigid motion correction niter_rig = 1 pw_rigid = True # flag to select rigid vs pw_rigid motion correction # maximum allowed rigid shift in pixels max_shifts = [int(a / b) for a, b in zip(max_shift_um, dxy)] # start a new patch for pw-rigid motion correction every x pixels strides = tuple([int(a / b) for a, b in zip(patch_motion_um, dxy)]) # overlap between pathes (size of patch in pixels: strides+overlaps) overlaps = (24, 24, 4) # maximum deviation allowed for patch with respect to rigid shifts max_deviation_rigid = 3 is3D = True mc_dict = { 'fnames': fnames, 'fr': fr, 'decay_time': decay_time, 'dxy': dxy, 'pw_rigid': pw_rigid, 'niter_rig': niter_rig, 'max_shifts': max_shifts, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': 'copy', 'var_name_hdf5': 'acquisition/TwoPhotonSeries', 'is3D': is3D, 'splits_els': 12, 'splits_rig': 12 } opts = params.CNMFParams( params_dict=mc_dict ) #NOTE: default adjustments of parameters are not set yet, manually setting them now # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = True if display_images: m_orig = cm.load_movie_chain(fnames, var_name_hdf5=opts.data['var_name_hdf5'], is3D=True) T, h, w, z = m_orig.shape # Time, plane, height, weight m_orig = np.reshape(np.transpose(m_orig, (3, 0, 1, 2)), (T * z, h, w)) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing # NOTE: ignore dview right now for debugging purposes # c, dview, n_processes = cm.cluster.setup_cluster( # backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=None, var_name_hdf5=opts.data['var_name_hdf5'], **opts.get_group('motion')) # mc = MotionCorrect(fnames, dview=dview, var_name_hdf5=opts.data['var_name_hdf5'], **opts.get_group('motion')) # note that the file is not loaded in memory # %% Run (piecewise-rigid motion) correction using NoRMCorre mc.motion_correct(save_movie=True) # %% compare with original movie if display_images: m_orig = cm.load_movie_chain(fnames, var_name_hdf5=opts.data['var_name_hdf5'], is3D=True) T, h, w, z = m_orig.shape # Time, plane, height, weight m_orig = np.reshape(np.transpose(m_orig, (3, 0, 1, 2)), (T * z, h, w)) m_els = cm.load(mc.mmap_file, is3D=True) m_els = np.reshape(np.transpose(m_els, (3, 0, 1, 2)), (T * z, h, w)) ds_ratio = 0.2 moviehandle = cm.concatenate([ m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_els.resize(1, 1, ds_ratio) ], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit
def run_volpy(fnames, options=None, do_motion_correction=True, do_memory_mapping=True, fr=400): #pass # For compatibility between running under Spyder and the CLI # %% Load demo movie and ROIs file_dir = os.path.split(fnames)[0] path_ROIs = [file for file in os.listdir(file_dir) if 'ROIs_gt' in file] if len(path_ROIs) > 0: path_ROIs = path_ROIs[0] #path_ROIs = '/home/nel/NEL-LAB Dropbox/NEL/Datasets/voltage_lin/peyman_golshani/ROIs.hdf5' #%% dataset dependent parameters # dataset dependent parameters fr = fr # sample rate of the movie # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = ( 48, 48 ) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24 ) # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = 3 # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run correction do_motion_correction = do_motion_correction if do_motion_correction: mc.motion_correct(save_movie=True) else: mc_list = [ file for file in os.listdir(file_dir) if (os.path.splitext(os.path.split(fnames)[-1])[0] in file and '.mmap' in file) ] mc.mmap_file = [os.path.join(file_dir, mc_list[0])] print(f'reuse previously saved motion corrected file:{mc.mmap_file}') # %% MEMORY MAPPING do_memory_mapping = do_memory_mapping if do_memory_mapping: border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap_join( mc.mmap_file, base_name='memmap_' + os.path.splitext(os.path.split(fnames)[-1])[0], add_to_mov=border_to_0, dview=dview) # exclude border else: mmap_list = [ file for file in os.listdir(file_dir) if ('memmap_' + os.path.splitext(os.path.split(fnames)[-1])[0]) in file ] fname_new = os.path.join(file_dir, mmap_list[0]) print(f'reuse previously saved memory mapping file:{fname_new}') # %% SEGMENTATION # create summary images img = mean_image(mc.mmap_file[0], window=1000, dview=dview) img = (img - np.mean(img)) / np.std(img) gaussian_blur = False # Use gaussian blur when there is too much noise in the video Cn = local_correlations_movie_offline(mc.mmap_file[0], fr=fr, window=fr * 4, stride=fr * 4, winSize_baseline=fr, remove_baseline=True, gaussian_blur=gaussian_blur, dview=dview).max(axis=0) img_corr = (Cn - np.mean(Cn)) / np.std(Cn) summary_images = np.stack([img, img, img_corr], axis=0).astype(np.float32) # ! save summary image, it is used in GUI cm.movie(summary_images).save(fnames[:-5] + '_summary_images.tif') #plt.imshow(summary_images[0]) #%% three methods for segmentation methods_list = [ 'manual_annotation', # manual annotation needs user to prepare annotated datasets same format as demo ROIs 'gui_annotation', # use gui to manually annotate neurons, but this is still under developing 'maskrcnn' ] # maskrcnn is a convolutional network trained for finding neurons using summary images method = methods_list[0] if method == 'manual_annotation': #with h5py.File(path_ROIs, 'r') as fl: # ROIs = fl['mov'][()] ROIs = np.load(os.path.join(file_dir, path_ROIs)) elif method == 'gui_annotation': # run volpy_gui file in the caiman/source_extraction/volpy folder # load the summary images you have just saved # save the ROIs to the video folder path_ROIs = caiman_datadir() + '/example_movies/volpy/gui_roi.hdf5' with h5py.File(path_ROIs, 'r') as fl: ROIs = fl['mov'][()] elif method == 'maskrcnn': # Important!! make sure install keras before using mask rcnn weights_path = download_model('mask_rcnn') weights_path = '/home/nel/Code/NEL_LAB/Mask_RCNN/logs/neurons20200824T1032/mask_rcnn_neurons_0040.h5' ROIs = utils.mrcnn_inference( img=summary_images.transpose([1, 2, 0]), size_range=[5, 100], weights_path=weights_path, display_result=True ) # size parameter decides size range of masks to be selected #np.save(os.path.join(file_dir, 'ROIs'), ROIs) # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False, maxtasksperchild=1) # %% parameters for trace denoising and spike extraction ROIs = ROIs # region of interests index = list(range(len(ROIs))) # index of neurons weights = None # reuse spatial weights context_size = 35 # number of pixels surrounding the ROI to censor from the background PCA flip_signal = True # Important!! Flip signal or not, True for Voltron indicator, False for others hp_freq_pb = 1 / 3 # parameter for high-pass filter to remove photobleaching threshold_method = 'adaptive_threshold' # 'simple' or 'adaptive_threshold' min_spikes = 30 # minimal spikes to be found threshold = 4 # threshold for finding spikes, increase threshold to find less spikes do_plot = False # plot detail of spikes, template for the last iteration ridge_bg = 0.01 # ridge regression regularizer strength for background removement, larger value specifies stronger regularization sub_freq = 20 # frequency for subthreshold extraction weight_update = 'ridge' # 'ridge' or 'NMF' for weight update n_iter = 2 opts_dict = { 'fnames': fname_new, 'ROIs': ROIs, 'index': index, 'weights': weights, 'context_size': context_size, 'flip_signal': flip_signal, 'hp_freq_pb': hp_freq_pb, 'threshold_method': threshold_method, 'min_spikes': min_spikes, 'threshold': threshold, 'do_plot': do_plot, 'ridge_bg': ridge_bg, 'sub_freq': sub_freq, 'weight_update': weight_update, 'n_iter': n_iter } opts.change_params(params_dict=opts_dict) if options is not None: print('using external options') opts.change_params(params_dict=options) else: print('not using external options') #%% TRACE DENOISING AND SPIKE DETECTION vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) #%% visualization display_images = False if display_images: print(np.where( vpy.estimates['locality'])[0]) # neurons that pass locality test idx = np.where(vpy.estimates['locality'] > 0)[0] utils.view_components(vpy.estimates, img_corr, idx) #%% reconstructed movie # note the negative spatial weights is cutoff if display_images: mv_all = utils.reconstructed_movie(vpy.estimates, fnames=mc.mmap_file, idx=idx, scope=(0, 1000), flip_signal=flip_signal) mv_all.play(fr=40) #%% save the result in .npy format save_result = True if save_result: vpy.estimates['ROIs'] = ROIs save_name = f'volpy_{os.path.split(fnames)[1][:-5]}_{opts.volspike["threshold_method"]}_{opts.volspike["threshold"]}_{opts.volspike["weight_update"]}_bg_{opts.volspike["ridge_bg"]}' np.save(os.path.join(file_dir, save_name), vpy.estimates) # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
def run_alignment(mouse, sessions, motion_correction_v, cropping_v, dview): """ This is the main function for the alignment step. It applies methods from the CaImAn package used originally in motion correction to do alignment. """ for session in sessions: # Update the database file_name = f"mouse_{mouse}_session_{session}_alignment" sql1 = "UPDATE Analysis SET alignment_main=? WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=? " val1 = [file_name, mouse, session, motion_correction_v, cropping_v] cursor.execute(sql1, val1) # Determine the output .mmap file name output_mmap_file_path = os.environ[ 'DATA_DIR_LOCAL'] + f'data/interim/alignment/main/{file_name}.mmap' sql = "SELECT motion_correction_main FROM Analysis WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=? " val = [mouse, session, motion_correction_v, cropping_v] cursor.execute(sql, val) result = cursor.fetchall() input_mmap_file_list = [] inter = [] for x in result: inter += x for y in inter: input_mmap_file_list.append(y) sql = "SELECT motion_correction_cropping_points_x1 FROM Analysis WHERE mouse = ? AND session=?AND motion_correction_v =? AND cropping_v=? " val = [mouse, session, motion_correction_v, cropping_v] cursor.execute(sql, val) result = cursor.fetchall() x_ = [] inter = [] for i in result: inter += i for j in range(0, len(inter)): x_.append(inter[j]) sql = "SELECT motion_correction_cropping_points_x2 FROM Analysis WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=? " val = [mouse, session, motion_correction_v, cropping_v] cursor.execute(sql, val) result = cursor.fetchall() _x = [] inter = [] for i in result: inter += i for j in range(0, len(inter)): _x.append(inter[j]) sql = "SELECT motion_correction_cropping_points_y1 FROM Analysis WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=?" val = [mouse, session, motion_correction_v, cropping_v] cursor.execute(sql, val) result = cursor.fetchall() _y = [] inter = [] for i in result: inter += i for j in range(0, len(inter)): _y.append(inter[j]) sql = "SELECT motion_correction_cropping_points_y2 FROM Analysis WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=?" val = [mouse, session, motion_correction_v, cropping_v] cursor.execute(sql, val) result = cursor.fetchall() y_ = [] inter = [] for i in result: inter += i for j in range(0, len(inter)): y_.append(inter[j]) new_x1 = max(x_) new_x2 = max(_x) new_y1 = max(y_) new_y2 = max(_y) m_list = [] for i in range(len(input_mmap_file_list)): m = cm.load(input_mmap_file_list[i]) m = m.crop(new_x1 - x_[i], new_x2 - _x[i], new_y1 - y_[i], new_y2 - _y[i], 0, 0) m_list.append(m) # Concatenate them using the concat function m_concat = cm.concatenate(m_list, axis=0) fname = m_concat.save(output_mmap_file_path, order='C') # MOTION CORRECTING EACH INDIVIDUAL MOVIE WITH RESPECT TO A TEMPLATE MADE OF THE FIRST MOVIE logging.info( 'Performing motion correction on all movies with respect to a template made of the first movie.' ) t0 = datetime.datetime.today() # parameters alignment sql5 = "SELECT make_template_from_trial,gSig_filt,max_shifts,niter_rig,strides,overlaps,upsample_factor_grid,num_frames_split,max_deviation_rigid,shifts_opencv,use_conda,nonneg_movie, border_nan FROM Analysis WHERE alignment_main=? " val5 = [ file_name, ] cursor.execute(sql5, val5) myresult = cursor.fetchall() para = [] aux = [] for x in myresult: aux = x for y in aux: para.append(y) parameters = { 'make_template_from_trial': para[0], 'gSig_filt': (para[1], para[1]), 'max_shifts': (para[2], para[2]), 'niter_rig': para[3], 'strides': (para[4], para[4]), 'overlaps': (para[5], para[5]), 'upsample_factor_grid': para[6], 'num_frames_split': para[7], 'max_deviation_rigid': para[8], 'shifts_opencv': para[9], 'use_cuda': para[10], 'nonneg_movie': para[11], 'border_nan': para[12] } # Create a template of the first movie template_index = parameters['make_template_from_trial'] m0 = cm.load(input_mmap_file_list[1]) [x1, x2, y1, y2] = [x_, _x, y_, _y] for i in range(len(input_mmap_file_list)): m0 = m0.crop(new_x1 - x_[i], new_x2 - _x[i], new_y1 - y_[i], new_y2 - _y[i], 0, 0) m0_filt = cm.movie( np.array([ high_pass_filter_space(m_, parameters['gSig_filt']) for m_ in m0 ])) template0 = cm.motion_correction.bin_median( m0_filt.motion_correct( 5, 5, template=None)[0]) # may be improved in the future # Setting the parameters opts = params.CNMFParams(params_dict=parameters) # Create a motion correction object mc = MotionCorrect(fname, dview=dview, **opts.get_group('motion')) # Perform non-rigid motion correction mc.motion_correct(template=template0, save_movie=True) # Cropping borders x_ = math.ceil( abs(np.array(mc.shifts_rig)[:, 1].max() ) if np.array(mc.shifts_rig)[:, 1].max() > 0 else 0) _x = math.ceil( abs(np.array(mc.shifts_rig)[:, 1].min() ) if np.array(mc.shifts_rig)[:, 1].min() < 0 else 0) y_ = math.ceil( abs(np.array(mc.shifts_rig)[:, 0].max() ) if np.array(mc.shifts_rig)[:, 0].max() > 0 else 0) _y = math.ceil( abs(np.array(mc.shifts_rig)[:, 0].min() ) if np.array(mc.shifts_rig)[:, 0].min() < 0 else 0) # Load the motion corrected movie into memory movie = cm.load(mc.fname_tot_rig[0]) # Crop all movies to those border pixels movie.crop(x_, _x, y_, _y, 0, 0) sql1 = "UPDATE Analysis SET alignment_x1=?, alignment_x2 =?, alignment_y1=?, alignment_y2=? WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=?" val1 = [ x_, _x, y_, _y, mouse, session, motion_correction_v, cropping_v ] cursor.execute(sql1, val1) # save motion corrected and cropped movie output_mmap_file_path_tot = movie.save( os.environ['DATA_DIR_LOCAL'] + f'data/interim/alignment/main/{file_name}.mmap', order='C') logging.info( f' Cropped and saved rigid movie as {output_mmap_file_path_tot}') # Remove the remaining non-cropped movie os.remove(mc.fname_tot_rig[0]) # Create a timeline and store it sql = "SELECT trial FROM Analysis WHERE mouse = ? AND session=? AND motion_correction_v =? AND cropping_v=?" val = [mouse, session, motion_correction_v, cropping_v] cursor.execute(sql, val) result = cursor.fetchall() trial_index_list = [] inter = [] for i in result: inter += i for j in range(0, len(inter)): trial_index_list.append(inter[j]) timeline = [[trial_index_list[0], 0]] timepoints = [0] for i in range(1, len(m_list)): m = m_list[i] timeline.append( [trial_index_list[i], timeline[i - 1][1] + m.shape[0]]) timepoints.append(timepoints[i - 1] + m.shape[0]) timeline_pkl_file_path = os.environ[ 'DATA_DIR'] + f'data/interim/alignment/meta/timeline/{file_name}.pkl' with open(timeline_pkl_file_path, 'wb') as f: pickle.dump(timeline, f) sql1 = "UPDATE Analysis SET alignment_timeline=? WHERE mouse = ? AND session=?AND motion_correction_v =? AND cropping_v=? " val1 = [ timeline_pkl_file_path, mouse, session, motion_correction_v, cropping_v ] cursor.execute(sql1, val1) timepoints.append(movie.shape[0]) dt = int((datetime.datetime.today() - t0).seconds / 60) # timedelta in minutes sql1 = "UPDATE Analysis SET alignment_duration_concatenation=? WHERE mouse = ? AND session=?AND motion_correction_v =? AND cropping_v=? " val1 = [dt, mouse, session, motion_correction_v, cropping_v] cursor.execute(sql1, val1) logging.info(f' Performed concatenation. dt = {dt} min.') ## modify all motion correction file to the aligned version data_dir = os.environ[ 'DATA_DIR'] + 'data/interim/motion_correction/main/' for i in range(len(input_mmap_file_list)): aligned_movie = movie[timepoints[i]:timepoints[i + 1]] motion_correction_output_aligned = aligned_movie.save( data_dir + file_name + '_els' + '.mmap', order='C') sql1 = "UPDATE Analysis SET motion_correct_align=? WHERE motion_correction_meta=? AND motion_correction_v" val1 = [ motion_correction_output_aligned, input_mmap_file_list[i], motion_correction_v ] cursor.execute(sql1, val1) database.commit() return
def caimanAlign(fnames, frameRate=20): """ fnames: list of file path """ startSeconds = time.time() opts = caimanOptions.createParams(fnames, frameRate=frameRate) #start a cluster for parallel processing (if a cluster already exists it will be closed and a new session will be opened) if 'dview' in locals(): cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # # create a motion correction object with the parameters specified. #Note that the file is not loaded in memory mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # set mmap_file ''' tmpPath, tmpExt = os.path.splitext(fnames[0]) tmpPath += '.mmap' print('setting mc.mmap_file to tmpPath:', tmpPath) mc.mmap_file = tmpPath ''' #print('mc.mmap_file:', mc.mmap_file) # # perform motion correction # We will perform piecewise rigid motion correction using the NoRMCorre algorithm. # This has already been selected by setting pw_rigid=True when defining the parameters object. print(' performing motion correction ... please wait ...', fnames[0]) mc.motion_correct(save_movie=True) m_els = cm.load(mc.fname_tot_els) border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 print(' border_to_0:', border_to_0) # maximum shift to be used for trimming against NaNs # # memory mapping print(' memory mapping') print(' save_memmap mc.mmap_file:', mc.mmap_file) fname_new = cm.save_memmap(mc.mmap_file, base_name='memmap_', order='C', border_to_0=border_to_0, dview=dview) # exclude borders print(' mc.mmap_file:', mc.mmap_file) print(' fname_new:', fname_new) # make a copy of mmap file with a sane name # does not work, seems you can not 'copy' a mmap file like a normal file ''' tmpSavePath, tmpExt = os.path.splitext(fnames[0]) tmpSavePath += '.mmap' # need to be _aligned_ch1.tif shutil.copyfile(fname_new, tmpSavePath) ''' # save a _mmap.txt file with the name of the memory map file ''' tmpFile, tmpFilename = os.path.splitext(fnames[0]) tmpFile += '_mmap.txt' with open(tmpFile, 'w') as myTmpFile: myTmpFile.write(fname_new) ''' # now load the file Yr, dims, T = cm.load_memmap(fname_new) images = np.reshape(Yr.T, [T] + list(dims), order='F') #load frames in python format (T x X x Y) # save as .tif images_8bit = ((images - images.min()) / (images.ptp() / 255.0)).astype( np.uint8) # map the data range to 0 - 255 tmpSavePath, tmpExt = os.path.splitext(fnames[0]) tmpSavePath += '_aligned.tif' # need to be _aligned_ch1.tif print(' saving aligned .tif', images_8bit.shape, images_8bit.dtype, 'tmpSavePath:', tmpSavePath) tifffile.imsave(tmpSavePath, images_8bit, bigtiff=True) # shut down the cluster if 'dview' in locals(): cm.stop_server(dview=dview) # remove mmap file fname_new if os.path.isfile(fname_new): print(' removing mmap file:', fname_new) os.remove(fname_new) oneFile = mc.mmap_file[0] if os.path.isfile(oneFile): print(' removing mmap file mc.mmap_file[0]:', oneFile) os.remove(oneFile) # done stopSeconds = time.time() elapsedSeconds = round(stopSeconds - startSeconds, 3) elapsedMinutes = round(elapsedSeconds / 60, 3) print(f' caimanAlign() done in {elapsedMinutes} minutes')
def run_alignmnet(states_df, parameters, dview): ''' This is the main function for the alignment step. It applies methods from the CaImAn package used originally in motion correction to do alignment. Args: df: pd.DataFrame A dataframe containing the analysis states you want to have aligned. parameters: dict The alignment parameters. dview: object The dview object Returns: df: pd.DataFrame A dataframe containing the aligned analysis states. ''' # Sort the dataframe correctly df = states_df.copy() df = df.sort_values(by=paths.multi_index_structure) # Determine the mouse and session of the dataset index = df.iloc[0].name mouse, session, *r = index #alignment_v = index[len(paths.data_structure) + step_index] alignment_v = len(df) alignment_index = (mouse, session, alignment_v) # Determine the output .mmap file name file_name = f'mouse_{mouse}_session_{session}_v{alignment_v}' output_mmap_file_path = f'data/interim/alignment/main/{file_name}.mmap' try: df.reset_index()[['trial', 'is_rest']].set_index(['trial', 'is_rest'], verify_integrity=True) except ValueError: logging.error( 'You passed multiple of the same trial in the dataframe df') return df output = { 'meta': { 'analysis': { 'analyst': os.environ['ANALYST'], 'date': datetime.datetime.today().strftime("%m-%d-%Y"), 'time': datetime.datetime.today().strftime("%H:%M:%S") }, 'duration': {} } } # Get necessary parameters motion_correction_parameters_list = [] motion_correction_output_list = [] input_mmap_file_list = [] trial_index_list = [] for idx, row in df.iterrows(): motion_correction_parameters_list.append( eval(row.loc['motion_correction_parameters'])) motion_correction_output = eval(row.loc['motion_correction_output']) motion_correction_output_list.append(motion_correction_output) input_mmap_file_list.append(motion_correction_output['main']) trial_index_list.append(db.get_trial_name(idx[2], idx[3])) # MOTION CORRECTING EACH INDIVIDUAL MOVIE WITH RESPECT TO A TEMPLATE MADE OF THE FIRST MOVIE logging.info( f'{alignment_index} Performing motion correction on all movies with respect to a template made of \ the first movie.') t0 = datetime.datetime.today() # Create a template of the first movie template_index = trial_index_list.index( parameters['make_template_from_trial']) m0 = cm.load(input_mmap_file_list[template_index]) m0_filt = cm.movie( np.array([ high_pass_filter_space(m_, parameters['gSig_filt']) for m_ in m0 ])) template0 = cm.motion_correction.bin_median( m0_filt.motion_correct( 5, 5, template=None)[0]) # may be improved in the future # Setting the parameters opts = params.CNMFParams(params_dict=parameters) # Create a motion correction object mc = MotionCorrect(input_mmap_file_list, dview=dview, **opts.get_group('motion')) # Perform non-rigid motion correction mc.motion_correct(template=template0, save_movie=True) # Cropping borders x_ = math.ceil( abs(np.array(mc.shifts_rig)[:, 1].max() ) if np.array(mc.shifts_rig)[:, 1].max() > 0 else 0) _x = math.ceil( abs(np.array(mc.shifts_rig)[:, 1].min() ) if np.array(mc.shifts_rig)[:, 1].min() < 0 else 0) y_ = math.ceil( abs(np.array(mc.shifts_rig)[:, 0].max() ) if np.array(mc.shifts_rig)[:, 0].max() > 0 else 0) _y = math.ceil( abs(np.array(mc.shifts_rig)[:, 0].min() ) if np.array(mc.shifts_rig)[:, 0].min() < 0 else 0) dt = int( (datetime.datetime.today() - t0).seconds / 60) # timedelta in minutes output['meta']['duration']['motion_correction'] = dt logging.info( f'{alignment_index} Performed motion correction. dt = {dt} min.') # CONCATENATING ALL MOTION CORRECTED MOVIES logging.info( f'{alignment_index} Concatenating all motion corrected movies.') # Load all movies into memory m_list = [cm.load(fname) for fname in mc.fname_tot_rig] # Crop all movies to those border pixels for idx, m in enumerate(m_list): m_list[idx] = m.crop(x_, _x, y_, _y, 0, 0) output['meta']['cropping_points'] = [x_, _x, y_, _y] # Concatenate them using the concat function m_concat = cm.concatenate(m_list, axis=0) # Create a timeline and store it timeline = [[trial_index_list[0], 0]] for i in range(1, len(m_list)): m = m_list[i] timeline.append([trial_index_list[i], timeline[i - 1][1] + m.shape[0]]) # timeline_pkl_file_path = f'data/interim/alignment/meta/timeline/{file_name}.pkl' # with open(timeline_pkl_file_path,'wb') as f: # pickle.dump(timeline,f) # output['meta']['timeline'] = timeline_pkl_file_path output['meta']['timeline'] = timeline # Save the concatenated movie output_mmap_file_path_tot = m_concat.save(output_mmap_file_path) output['main'] = output_mmap_file_path_tot # # Delete the motion corrected movies # for fname in mc.fname_tot_rig: # os.remove(fname) dt = int( (datetime.datetime.today() - t0).seconds / 60) # timedelta in minutes output['meta']['duration']['concatenation'] = dt logging.info(f'{alignment_index} Performed concatenation. dt = {dt} min.') for idx, row in df.iterrows(): df.loc[idx, 'alignment_output'] = str(output) df.loc[idx, 'alignment_parameters'] = str(parameters) return df
def main(): pass # For compatibility between running under Spyder and the CLI #%% Select file(s) to be processed (download if not present) fnames = ['Sue_2x_3000_40_-46.tif'] # filename to be processed if fnames[0] in ['Sue_2x_3000_40_-46.tif', 'demoMovie.tif']: fnames = [download_demo(fnames[0])] #%% First setup some parameters for data and motion correction # dataset dependent parameters fr = 30 # imaging rate in frames per second decay_time = 0.4 # length of a typical transient in seconds dxy = (2., 2.) # spatial resolution in x and y in (um per pixel) # note the lower than usual spatial resolution here max_shift_um = (12., 12.) # maximum shift in um patch_motion_um = (100., 100.) # patch size for non-rigid correction in um # motion correction parameters pw_rigid = True # flag to select rigid vs pw_rigid motion correction # maximum allowed rigid shift in pixels max_shifts = [int(a/b) for a, b in zip(max_shift_um, dxy)] # start a new patch for pw-rigid motion correction every x pixels strides = tuple([int(a/b) for a, b in zip(patch_motion_um, dxy)]) # overlap between pathes (size of patch in pixels: strides+overlaps) overlaps = (24, 24) # maximum deviation allowed for patch with respect to rigid shifts max_deviation_rigid = 3 mc_dict = { 'fnames': fnames, 'fr': fr, 'decay_time': decay_time, 'dxy': dxy, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': 'copy' } opts = params.CNMFParams(params_dict=mc_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = True if display_images: m_orig = cm.load_movie_chain(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # note that the file is not loaded in memory # %% Run (piecewise-rigid motion) correction using NoRMCorre mc.motion_correct(save_movie=True) # %% compare with original movie if display_images: m_orig = cm.load_movie_chain(fnames) m_els = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([m_orig.resize(1, 1, ds_ratio) - mc.min_mov*mc.nonneg_movie, m_els.resize(1, 1, ds_ratio)], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit # %% MEMORY MAPPING border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap(mc.mmap_file, base_name='memmap_', order='C', border_to_0=border_to_0) # exclude borders # now load the file Yr, dims, T = cm.load_memmap(fname_new) images = np.reshape(Yr.T, [T] + list(dims), order='F') # load frames in python format (T x X x Y) # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) # %% parameters for source extraction and deconvolution p = 1 # order of the autoregressive system gnb = 2 # number of global background components merge_thr = 0.85 # merging threshold, max correlation allowed rf = 15 # half-size of the patches in pixels. e.g., if rf=25, patches are 50x50 stride_cnmf = 6 # amount of overlap between the patches in pixels K = 4 # number of components per patch gSig = [4, 4] # expected half size of neurons in pixels # initialization method (if analyzing dendritic data using 'sparse_nmf') method_init = 'greedy_roi' ssub = 2 # spatial subsampling during initialization tsub = 2 # temporal subsampling during intialization # parameters for component evaluation opts_dict = {'fnames': fnames, 'p': p, 'fr': fr, 'nb': gnb, 'rf': rf, 'K': K, 'gSig': gSig, 'stride': stride_cnmf, 'method_init': method_init, 'rolling_sum': True, 'merge_thr': merge_thr, 'n_processes': n_processes, 'only_init': True, 'ssub': ssub, 'tsub': tsub} opts.change_params(params_dict=opts_dict); # %% RUN CNMF ON PATCHES # First extract spatial and temporal components on patches and combine them # for this step deconvolution is turned off (p=0). If you want to have # deconvolution within each patch change params.patch['p_patch'] to a # nonzero value #opts.change_params({'p': 0}) cnm = cnmf.CNMF(n_processes, params=opts, dview=dview) cnm = cnm.fit(images) # %% ALTERNATE WAY TO RUN THE PIPELINE AT ONCE # you can also perform the motion correction plus cnmf fitting steps # simultaneously after defining your parameters object using # cnm1 = cnmf.CNMF(n_processes, params=opts, dview=dview) # cnm1.fit_file(motion_correct=True) # %% plot contours of found components Cns = local_correlations_movie_offline(mc.mmap_file[0], remove_baseline=True, window=1000, stride=1000, winSize_baseline=100, quantil_min_baseline=10, dview=dview) Cn = Cns.max(axis=0) Cn[np.isnan(Cn)] = 0 cnm.estimates.plot_contours(img=Cn) plt.title('Contour plots of found components') #%% save results cnm.estimates.Cn = Cn cnm.save(fname_new[:-5]+'_init.hdf5') # %% RE-RUN seeded CNMF on accepted patches to refine and perform deconvolution cnm2 = cnm.refit(images, dview=dview) # %% COMPONENT EVALUATION # the components are evaluated in three ways: # a) the shape of each component must be correlated with the data # b) a minimum peak SNR is required over the length of a transient # c) each shape passes a CNN based classifier min_SNR = 2 # signal to noise ratio for accepting a component rval_thr = 0.85 # space correlation threshold for accepting a component cnn_thr = 0.99 # threshold for CNN based classifier cnn_lowest = 0.1 # neurons with cnn probability lower than this value are rejected cnm2.params.set('quality', {'decay_time': decay_time, 'min_SNR': min_SNR, 'rval_thr': rval_thr, 'use_cnn': True, 'min_cnn_thr': cnn_thr, 'cnn_lowest': cnn_lowest}) cnm2.estimates.evaluate_components(images, cnm2.params, dview=dview) # %% PLOT COMPONENTS cnm2.estimates.plot_contours(img=Cn, idx=cnm2.estimates.idx_components) # %% VIEW TRACES (accepted and rejected) if display_images: cnm2.estimates.view_components(images, img=Cn, idx=cnm2.estimates.idx_components) cnm2.estimates.view_components(images, img=Cn, idx=cnm2.estimates.idx_components_bad) #%% update object with selected components cnm2.estimates.select_components(use_object=True) #%% Extract DF/F values cnm2.estimates.detrend_df_f(quantileMin=8, frames_window=250) #%% Show final traces cnm2.estimates.view_components(img=Cn) #%% cnm2.estimates.Cn = Cn cnm2.save(cnm2.mmap_file[:-4] + 'hdf5') #%% reconstruct denoised movie (press q to exit) if display_images: cnm2.estimates.play_movie(images, q_max=99.9, gain_res=2, magnification=2, bpx=border_to_0, include_bck=False) # background not shown #%% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
class MakeMasks3D: """Not yet fully working so dont use!""" def __init__(self, tiff, channels, planes, x_start, x_end, mc_opts, use_green_ch=False,): self.tiff = tiff self.channels = channels self.planes = planes self.x_start = x_start self.x_end = x_end self.xslice = slice(x_start, x_end) self.mc_opts = mc_opts self.use_green_ch = use_green_ch if self.use_green_ch == True: self.channel2use = 0 else: self.channel2use = 1 if self.mc_opts: self.opts = params.CNMFParams(params_dict=mc_opts) self.file_list = [] self.images = [] self.motion_corrected_images = [] self.masks = [] self.coords = None self.corr_images = [] def crop_tiffs(self): self.images = [] self.file_list = [] for plane in list(range(self.planes)): time_slice = slice(plane*self.channels+self.channel2use, -1, self.channels*self.planes) with ScanImageTiffReader(self.tiff) as reader: data = reader.data() data = data[time_slice, : , self.xslice] self.images.append(data) tif_name = self.tiff.split('.')[0] + '_template_plane' + str(plane) + '.tif' self.file_list.append(tif_name) tifffile.imsave(tif_name, data) def view_planes(self): fig, axes = plt.subplots(1, self.planes, constrained_layout=True) for i,ax in enumerate(axes): image = self.images[i].mean(axis=0) ax.imshow(image) ax.set_aspect('equal', 'box') ax.axis('off') ax.set_title(f'Plane {i}') fig.suptitle('Original') def view_corrected(self): fig, axes = plt.subplots(1, self.planes, constrained_layout=True) for i,ax in enumerate(axes): image = self.motion_corrected_images[i] ax.imshow(image) ax.set_aspect('equal', 'box') ax.axis('off') ax.set_title(f'Plane {i}') fig.suptitle('Corrected') def view_corr(self): self.corr_images = [] fig, axes = plt.subplots(1, self.planes, constrained_layout=True) for i,ax in enumerate(axes): image = self.motion_corrected_images[i] corr_im = cm.local_correlations(image, swap_dim=False) self.corr_images.append(corr_im) ax.imshow(image) ax.set_aspect('equal', 'box') ax.axis('off') ax.set_title(f'Plane {i}') fig.suptitle('Correlation Image') def motion_correct_red(self): c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) self.motion_corrected_images = [] for plane in list(range(self.planes)): print(f'Starting motion correction plane {plane}') self.mc = MotionCorrect(self.file_list[plane], dview=dview, **self.opts.get_group('motion')) self.mc.motion_correct() self.motion_corrected_images.append(self.mc.total_template_els) cm.stop_server(dview=dview) def extract_masks(self, radius=7): self.masks = [] self.coords = [] if len(self.motion_corrected_images) > 0: image_source = self.motion_corrected_images else: image_source = self.images for plane in range(self.planes): self.masks.append(cm.base.rois.extract_binary_masks_from_structural_channel(image_source[plane])[0]) self.coords.append(cm.utils.visualization.get_contours(self.masks[plane], image_source[plane].shape, thr=0.99, thr_method='max')) def run(self): self.crop_tiffs() self.motion_correct_red() self.extract_masks()
def main(): pass # For compatibility between running under Spyder and the CLI # %% start the cluster try: cm.stop_server() # stop it if it was running except (): pass c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes= 24, # number of process to use, if you go out of memory try to reduce this one single_thread=False) # %% First setup some parameters for motion correction # dataset dependent parameters fnames = ['data_endoscope.tif'] # filename to be processed fnames = [download_demo(fnames[0])] # download file if not already present filename_reorder = fnames fr = 10 # movie frame rate decay_time = 0.4 # length of a typical transient in seconds # motion correction parameters motion_correct = True # flag for motion correction pw_rigid = False # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = ( 48, 48 ) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24 ) # overlap between pathes (size of patch strides+overlaps) # maximum deviation allowed for patch with respect to rigid shifts max_deviation_rigid = 3 border_nan = 'copy' mc_dict = { 'fnames': fnames, 'fr': fr, 'decay_time': decay_time, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = params.CNMFParams(params_dict=mc_dict) # %% MOTION CORRECTION # The pw_rigid flag set above, determines where to use rigid or pw-rigid # motion correction if motion_correct: # do motion correction rigid mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) mc.motion_correct(save_movie=True) fname_mc = mc.fname_tot_els if pw_rigid else mc.fname_tot_rig if pw_rigid: bord_px = np.ceil( np.maximum(np.max(np.abs(mc.x_shifts_els)), np.max(np.abs(mc.y_shifts_els)))).astype(np.int) else: bord_px = np.ceil(np.max(np.abs(mc.shifts_rig))).astype(np.int) plt.subplot(1, 2, 1) plt.imshow(mc.total_template_rig) # % plot template plt.subplot(1, 2, 2) plt.plot(mc.shifts_rig) # % plot rigid shifts plt.legend(['x shifts', 'y shifts']) plt.xlabel('frames') plt.ylabel('pixels') bord_px = 0 if border_nan == 'copy' else bord_px fname_new = cm.save_memmap(fname_mc, base_name='memmap_', order='C', border_to_0=bord_px) else: # if no motion correction just memory map the file fname_new = cm.save_memmap(filename_reorder, base_name='memmap_', order='C', border_to_0=0, dview=dview) # load memory mappable file Yr, dims, T = cm.load_memmap(fname_new) images = Yr.T.reshape((T, ) + dims, order='F') # %% Parameters for source extraction and deconvolution (CNMF-E algorithm) p = 1 # order of the autoregressive system K = None # upper bound on number of components per patch, in general None for 1p data gSig = ( 3, 3 ) # gaussian width of a 2D gaussian kernel, which approximates a neuron gSiz = (13, 13) # average diameter of a neuron, in general 4*gSig+1 Ain = None # possibility to seed with predetermined binary masks merge_thr = .7 # merging threshold, max correlation allowed rf = 40 # half-size of the patches in pixels. e.g., if rf=40, patches are 80x80 stride_cnmf = 20 # amount of overlap between the patches in pixels # (keep it at least large as gSiz, i.e 4 times the neuron size gSig) tsub = 2 # downsampling factor in time for initialization, # increase if you have memory problems ssub = 1 # downsampling factor in space for initialization, # increase if you have memory problems # you can pass them here as boolean vectors low_rank_background = None # None leaves background of each patch intact, # True performs global low-rank approximation if gnb>0 gnb = 0 # number of background components (rank) if positive, # else exact ring model with following settings # gnb= 0: Return background as b and W # gnb=-1: Return full rank background B # gnb<-1: Don't return background nb_patch = 0 # number of background components (rank) per patch if gnb>0, # else it is set automatically min_corr = .8 # min peak value from correlation image min_pnr = 10 # min peak to noise ration from PNR image ssub_B = 2 # additional downsampling factor in space for background ring_size_factor = 1.4 # radius of ring is gSiz*ring_size_factor opts.change_params( params_dict={ 'dims': dims, 'method_init': 'corr_pnr', # use this for 1 photon 'K': K, 'gSig': gSig, 'gSiz': gSiz, 'merge_thr': merge_thr, 'p': p, 'tsub': tsub, 'ssub': ssub, 'rf': rf, 'stride': stride_cnmf, 'only_init': True, # set it to True to run CNMF-E 'nb': gnb, 'nb_patch': nb_patch, 'method_deconvolution': 'oasis', # could use 'cvxpy' alternatively 'low_rank_background': low_rank_background, 'update_background_components': True, # sometimes setting to False improve the results 'min_corr': min_corr, 'min_pnr': min_pnr, 'normalize_init': False, # just leave as is 'center_psf': True, # leave as is for 1 photon 'ssub_B': ssub_B, 'ring_size_factor': ring_size_factor, 'del_duplicates': True, # whether to remove duplicates from initialization 'border_pix': bord_px }) # number of pixels to not consider in the borders) # %% compute some summary images (correlation and peak to noise) # change swap dim if output looks weird, it is a problem with tiffile cn_filter, pnr = cm.summary_images.correlation_pnr(images[::1], gSig=gSig[0], swap_dim=False) # if your images file is too long this computation will take unnecessarily # long time and consume a lot of memory. Consider changing images[::1] to # images[::5] or something similar to compute on a subset of the data # inspect the summary images and set the parameters inspect_correlation_pnr(cn_filter, pnr) # print parameters set above, modify them if necessary based on summary images print(min_corr) # min correlation of peak (from correlation image) print(min_pnr) # min peak to noise ratio # %% RUN CNMF ON PATCHES cnm = cnmf.CNMF(n_processes=n_processes, dview=dview, Ain=Ain, params=opts) cnm.fit(images) # %% ALTERNATE WAY TO RUN THE PIPELINE AT ONCE # you can also perform the motion correction plus cnmf fitting steps # simultaneously after defining your parameters object using # cnm1 = cnmf.CNMF(n_processes, params=opts, dview=dview) # cnm1.fit_file(motion_correct=True) # %% DISCARD LOW QUALITY COMPONENTS min_SNR = 2.5 # adaptive way to set threshold on the transient size r_values_min = 0.85 # threshold on space consistency (if you lower more components # will be accepted, potentially with worst quality) cnm.params.set('quality', { 'min_SNR': min_SNR, 'rval_thr': r_values_min, 'use_cnn': False }) cnm.estimates.evaluate_components(images, cnm.params, dview=dview) print(' ***** ') print('Number of total components: ', len(cnm.estimates.C)) print('Number of accepted components: ', len(cnm.estimates.idx_components)) # %% PLOT COMPONENTS cnm.dims = dims display_images = True # Set to true to show movies and images if display_images: cnm.estimates.plot_contours(img=cn_filter, idx=cnm.estimates.idx_components) cnm.estimates.view_components(images, idx=cnm.estimates.idx_components) # %% MOVIES display_images = False # Set to true to show movies and images if display_images: # fully reconstructed movie cnm.estimates.play_movie(images, q_max=99.5, magnification=2, include_bck=True, gain_res=10, bpx=bord_px) # movie without background cnm.estimates.play_movie(images, q_max=99.9, magnification=2, include_bck=False, gain_res=4, bpx=bord_px) # %% STOP SERVER cm.stop_server(dview=dview)
def run( file_path, n_cpus, motion_correct: bool = True, mc_settings: dict = {}, job_name: str = "job", output_directory: str = "", ): mkl = os.environ.get("MKL_NUM_THREADS") blas = os.environ.get("OPENBLAS_NUM_THREADS") vec = os.environ.get("VECLIB_MAXIMUM_THREADS") print(f"MKL: {mkl}") print(f"blas: {blas}") print(f"vec: {vec}") # we import the pipeline upon running so they aren't required for all installs import caiman as cm from caiman.motion_correction import MotionCorrect from caiman.source_extraction.cnmf import params as params # print the directory caiman is imported from caiman_path = os.path.abspath(cm.__file__) print(f"caiman path: {caiman_path}") sys.stdout.flush() # setup the logger logger_file = os.path.join(output_directory, "caiman.log") logging.basicConfig( format=LOGGER_FORMAT, filename=logger_file, filemode="w", level=logging.DEBUG, ) # if indices to perform mcorr are set, format them if "indices" in mc_settings: indices = mc_settings["indices"] indices_formatted = () for axis_slice in indices: start = axis_slice[0] stop = axis_slice[1] if len(axis_slice) == 3: step = axis_slice[2] else: step = 1 indices_formatted += (slice(start, stop, step), ) mc_settings["indices"] = indices_formatted # load and update the pipeline settings mc_parameters = DEFAULT_MCORR_SETTINGS for k, v in mc_settings.items(): mc_parameters[k] = v opts = params.CNMFParams(params_dict=mc_parameters) # get the filenames if os.path.isfile(file_path): print(file_path) fnames = [file_path] else: file_pattern = os.path.join(file_path, "*.tif*") fnames = sorted(glob.glob(file_pattern)) print(fnames) opts.set("data", {"fnames": fnames}) if n_cpus > 1: print("starting server") # start the server n_proc = np.max([(n_cpus - 1), 1]) c, dview, n_processes = cm.cluster.setup_cluster(backend="local", n_processes=n_proc, single_thread=False) sleep(30) else: print("multiprocessing disabled") dview = None n_processes = 1 print(n_processes) print("starting motion correction") sys.stdout.flush() mc = MotionCorrect(fnames, dview=dview, **opts.get_group("motion")) mc.motion_correct(save_movie=True) pw_rigid = mc_parameters["pw_rigid"] fname_mc = mc.fname_tot_els if pw_rigid else mc.fname_tot_rig if pw_rigid: bord_px = np.ceil( np.maximum(np.max(np.abs(mc.x_shifts_els)), np.max(np.abs(mc.y_shifts_els)))).astype(np.int) else: bord_px = np.ceil(np.max(np.abs(mc.shifts_rig))).astype(np.int) border_nan = mc_parameters["border_nan"] bord_px = 0 if border_nan == "copy" else bord_px _ = cm.save_memmap(fname_mc, base_name="memmap_", order="C", border_to_0=bord_px) # if motion correction was performed, save the file # we save as hdf5 for better reading performance # downstream if motion_correct: print("saving motion corrected file") results_filebase = os.path.join(output_directory, job_name) mcorr_fname = results_filebase + "_mcorr.hdf5" dataset_name = opts.data["var_name_hdf5"] # fnames = opts.data["fnames"] # memmap_files = [] # for f in fnames: # if isinstance(f, bytes): # f = f.decode() # base_file = os.path.splitext(f)[0] # if pw_rigid: # memmap_pattern = base_file + "*_els_*" # else: # memmap_pattern = base_file + "*_rig_*" # memmap_files += sorted(glob.glob(memmap_pattern)) if pw_rigid: memmap_files = mc.fname_tot_els else: memmap_files = mc.fname_tot_rig # get the frame shape mov = cm.load(memmap_files[0]) frame_shape = mov.shape[-2::] write_hdf5_movie( movie_name=mcorr_fname, memmap_files=memmap_files, frame_shape=frame_shape, dataset_name=dataset_name, compression="gzip", ) # save the parameters in the same dir as the results final_params = opts.to_dict() params_file = os.path.join(output_directory, "all_mcorr_parameters.pkl") with open(params_file, "wb") as fp: pickle.dump(final_params, fp) # deleting mcorr unused memmap files if pw_rigid: memmap_files = mc.fname_tot_els else: memmap_files = mc.fname_tot_rig print(f"deleting {memmap_files}") for f in memmap_files: os.remove(f) print("stopping server") cm.stop_server(dview=dview)
def main(): pass # For compatibility between running under Spyder and the CLI # %% Please download the .npz file manually to your file path. url = 'https://www.dropbox.com/s/tuv1bx9w6wdywnm/demo_voltage_imaging.npz?dl=0' # %% Load demo movie and ROIs file_path = '/home/nel/Code/Voltage_imaging/exampledata/403106_3min/demo_voltage_imaging.npz' m = np.load(file_path) mv = cm.movie(m.f.arr_0) ROIs = m.f.arr_1 # %% Save the movie fnames = '/home/nel/Code/Voltage_imaging/exampledata/403106_3min/demomovie_voltage_imaging.hdf5' mv.save(fnames) # neglect the warning # %% Setup some parameters for data and motion correction # dataset parameters fr = 400 # sample rate of the movie index = list(range(ROIs.shape[0])) # index of neurons weights = None # reuse spatial weights by # opts.change_params(params_dict={'weights':vpy.estimates['weights']}) # motion correction parameters motion_correct = True # flag for motion correction pw_rigid = True # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = (48, 48) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24) # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = 3 # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' mc_dict = { 'fnames': fnames, 'fr': fr, 'index': index, 'ROIs':ROIs, 'weights':weights, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=mc_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = True if display_images: m_orig = cm.load(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=12, single_thread=False) # %%% MOTION CORRECTION # Create a motion correction object with the specified parameters mc_pw = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run piecewise rigid motion correction mc_pw.motion_correct(save_movie=True) # %% motion correction compared with original movie display_images = True if display_images: m_orig = cm.load(fnames) m_rig = cm.load(mc_pw.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([m_orig.resize(1, 1, ds_ratio) - mc_pw.min_mov * mc_pw.nonneg_movie, m_rig.resize(1, 1, ds_ratio)], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit # %% movie subtracted from the mean m_orig2 = (m_orig - np.mean(m_orig, axis=0)) m_rig2 = (m_rig - np.mean(m_rig, axis=0)) moviehandle1 = cm.concatenate([m_orig2.resize(1, 1, ds_ratio), m_rig2.resize(1, 1, ds_ratio)], axis=2) moviehandle1.play(fr=60, q_max=99.5, magnification=2) # %% change fnames to the new motion corrected one fname_new = mc_pw.mmap_file[0] # memory map file name opts.change_params(params_dict={'fnames':fname_new}) # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=12, single_thread=False) # %% process cells using volspike function vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit() # %% some visualization vpy.estimates['cellN'] n = 0 # cell you are interested in plt.figure() plt.plot(vpy.estimates['trace'][n]) plt.plot(vpy.estimates['spikeTimes'][n], np.max(vpy.estimates['trace'][n]) * 1 * np.ones(vpy.estimates['spikeTimes'][n].shape), color='g', marker='o', fillstyle='none', linestyle='none') plt.title('signal and spike times') plt.show() plt.figure() plt.imshow(vpy.estimates['spatialFilter'][n]) plt.colorbar() plt.title('spatial filter') plt.show() # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
def piecewise_rigid_registration(fnames, max_shifts=(6, 6), strides=(48, 48), overlaps=(24, 24), num_frames_split=100, max_deviation_rigid=3, pw_rigid=False, shifts_opencv=True, border_nan='copy', highPassFilter=False, sigma=7): '''Apply CaImAn piecewise rigid registration on raw imaging data :param fnames: full path filename for motion correction, possible extensions are tif, avi, npy :param max_shifts: maximum allowed rigid shift in pixels (view the movie to get a sense of motion) :param strides: create a new patch every x pixels for pw-rigid correction :param overlaps: overlap between pathes (size of patch strides+overlaps) :param num_frames_split: length in frames of each chunk of the movie (to be processed in parallel) :param max_deviation_rigid: maximum deviation allowed for patch with respect to rigid shifts :param pw_rigid: flag for performing rigid or piecewise rigid motion correction :param shifts_opencv: flag for correcting motion using bicubic interpolation (otherwise FFT interpolation is used) :param border_nan: replicate values along the boundary (if True, fill in with NaN) :param highPassFilter: whether applying high pass filter :param sigma: lowpass gaussian filter sigma value :return: motion corrected image in numpy ''' fnames = [fnames] m_orig = cm.load_movie_chain(fnames) if 'dview' in locals(): cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # create a motion correction object mc = MotionCorrect(fnames, dview=dview, max_shifts=max_shifts, strides=strides, overlaps=overlaps, max_deviation_rigid=max_deviation_rigid, shifts_opencv=shifts_opencv, nonneg_movie=True, border_nan=border_nan) # correct for rigid motion correction and save the file (in memory mapped form) mc.motion_correct(save_movie=True) # load motion corrected movie and apply piece-wise rigid registration m_rig = cm.load(mc.mmap_file) mc.pw_rigid = True # turn the flag to True for pw-rigid motion correction mc.template = mc.mmap_file # use the template obtained before to save in computation (optional) mc.motion_correct(save_movie=True, template=mc.total_template_rig) cm.stop_server(dview=dview) # stop the server m_els = cm.load(mc.fname_tot_els) Y = np.array(m_els.tolist()) if highPassFilter: Y = high_pass_filtering(Y, sigma) return Y
def main(): pass # For compatibility between running under Spyder and the CLI # %% Load demo movie and ROIs fnames = download_demo( 'demo_voltage_imaging.hdf5', 'volpy') # file path to movie file (will download if not present) path_ROIs = download_demo( 'demo_voltage_imaging_ROIs.hdf5', 'volpy') # file path to ROIs file (will download if not present) file_dir = os.path.split(fnames)[0] #%% dataset dependent parameters # dataset dependent parameters fr = 400 # sample rate of the movie # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = ( 48, 48 ) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24 ) # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = 3 # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the movie press q display_images = False if display_images: m_orig = cm.load(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=40, magnification=4) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run correction do_motion_correction = True if do_motion_correction: mc.motion_correct(save_movie=True) else: mc_list = [ file for file in os.listdir(file_dir) if (os.path.splitext(os.path.split(fnames)[-1])[0] in file and '.mmap' in file) ] mc.mmap_file = [os.path.join(file_dir, mc_list[0])] print(f'reuse previously saved motion corrected file:{mc.mmap_file}') # %% compare with original movie if display_images: m_orig = cm.load(fnames) m_rig = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate( [m_orig.resize(1, 1, ds_ratio), m_rig.resize(1, 1, ds_ratio)], axis=2) moviehandle.play(fr=40, q_max=99.5, magnification=4) # press q to exit # %% MEMORY MAPPING do_memory_mapping = True if do_memory_mapping: border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap_join( mc.mmap_file, base_name='memmap_' + os.path.splitext(os.path.split(fnames)[-1])[0], add_to_mov=border_to_0, dview=dview) # exclude border else: mmap_list = [ file for file in os.listdir(file_dir) if ('memmap_' + os.path.splitext(os.path.split(fnames)[-1])[0]) in file ] fname_new = os.path.join(file_dir, mmap_list[0]) print(f'reuse previously saved memory mapping file:{fname_new}') # %% SEGMENTATION # create summary images img = mean_image(mc.mmap_file[0], window=1000, dview=dview) img = (img - np.mean(img)) / np.std(img) gaussian_blur = False # Use gaussian blur when there is too much noise in the video Cn = local_correlations_movie_offline(mc.mmap_file[0], fr=fr, window=fr * 4, stride=fr * 4, winSize_baseline=fr, remove_baseline=True, gaussian_blur=gaussian_blur, dview=dview).max(axis=0) img_corr = (Cn - np.mean(Cn)) / np.std(Cn) summary_images = np.stack([img, img, img_corr], axis=0).astype(np.float32) # save summary images which are used in the VolPy GUI cm.movie(summary_images).save(fnames[:-5] + '_summary_images.tif') fig, axs = plt.subplots(1, 2) axs[0].imshow(summary_images[0]) axs[1].imshow(summary_images[2]) axs[0].set_title('mean image') axs[1].set_title('corr image') #%% methods for segmentation methods_list = [ 'manual_annotation', # manual annotations need prepared annotated datasets in the same format as demo_voltage_imaging_ROIs.hdf5 'maskrcnn', # Mask R-CNN is a convolutional neural network trained for detecting neurons in summary images 'gui_annotation' ] # use VolPy GUI to correct outputs of Mask R-CNN or annotate new datasets method = methods_list[0] if method == 'manual_annotation': with h5py.File(path_ROIs, 'r') as fl: ROIs = fl['mov'][()] elif method == 'maskrcnn': # Important!! Make sure install keras before using mask rcnn. weights_path = download_model( 'mask_rcnn' ) # also make sure you have downloaded the new weight. The weight was updated on Dec 1st 2020. ROIs = utils.mrcnn_inference( img=summary_images.transpose([1, 2, 0]), size_range=[5, 22], weights_path=weights_path, display_result=True ) # size parameter decides size range of masks to be selected cm.movie(ROIs).save(fnames[:-5] + 'mrcnn_ROIs.hdf5') elif method == 'gui_annotation': # run volpy_gui.py file in the caiman/source_extraction/volpy folder gui_ROIs = caiman_datadir() + '/example_movies/volpy/gui_roi.hdf5' with h5py.File(gui_ROIs, 'r') as fl: ROIs = fl['mov'][()] fig, axs = plt.subplots(1, 2) axs[0].imshow(summary_images[0]) axs[1].imshow(ROIs.sum(0)) axs[0].set_title('mean image') axs[1].set_title('masks') # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False, maxtasksperchild=1) # %% parameters for trace denoising and spike extraction ROIs = ROIs # region of interests index = list(range(len(ROIs))) # index of neurons weights = None # reuse spatial weights context_size = 35 # number of pixels surrounding the ROI to censor from the background PCA visualize_ROI = False # whether to visualize the region of interest inside the context region flip_signal = True # Important!! Flip signal or not, True for Voltron indicator, False for others hp_freq_pb = 1 / 3 # parameter for high-pass filter to remove photobleaching clip = 100 # maximum number of spikes to form spike template threshold_method = 'adaptive_threshold' # adaptive_threshold or simple min_spikes = 10 # minimal spikes to be found pnorm = 0.5 # a variable deciding the amount of spikes chosen for adaptive threshold method threshold = 3 # threshold for finding spikes only used in simple threshold method, Increase the threshold to find less spikes do_plot = False # plot detail of spikes, template for the last iteration ridge_bg = 0.01 # ridge regression regularizer strength for background removement, larger value specifies stronger regularization sub_freq = 20 # frequency for subthreshold extraction weight_update = 'ridge' # ridge or NMF for weight update n_iter = 2 # number of iterations alternating between estimating spike times and spatial filters opts_dict = { 'fnames': fname_new, 'ROIs': ROIs, 'index': index, 'weights': weights, 'context_size': context_size, 'visualize_ROI': visualize_ROI, 'flip_signal': flip_signal, 'hp_freq_pb': hp_freq_pb, 'clip': clip, 'threshold_method': threshold_method, 'min_spikes': min_spikes, 'pnorm': pnorm, 'threshold': threshold, 'do_plot': do_plot, 'ridge_bg': ridge_bg, 'sub_freq': sub_freq, 'weight_update': weight_update, 'n_iter': n_iter } opts.change_params(params_dict=opts_dict) #%% TRACE DENOISING AND SPIKE DETECTION vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) #%% visualization display_images = True if display_images: print(np.where( vpy.estimates['locality'])[0]) # neurons that pass locality test idx = np.where(vpy.estimates['locality'] > 0)[0] utils.view_components(vpy.estimates, img_corr, idx) #%% reconstructed movie # note the negative spatial weights is cutoff if display_images: mv_all = utils.reconstructed_movie(vpy.estimates.copy(), fnames=mc.mmap_file, idx=idx, scope=(0, 1000), flip_signal=flip_signal) mv_all.play(fr=40) #%% save the result in .npy format save_result = True if save_result: vpy.estimates['ROIs'] = ROIs vpy.estimates['params'] = opts save_name = f'volpy_{os.path.split(fnames)[1][:-5]}_{threshold_method}' np.save(os.path.join(file_dir, save_name), vpy.estimates) # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
def main(): #%% First setup some parameters for data and motion correction # dataset dependent parameters fr = 15.49 # imaging rate in frames per second decay_time = 0.9 # length of a typical transient in seconds dxy = (1.4, 1.4) # spatial resolution in x and y in (um per pixel) # note the lower than usual spatial resolution here max_shift_um = (12., 12.) # maximum shift in um patch_motion_um = (100., 100.) # patch size for non-rigid correction in um # motion correction parameters pw_rigid = True # flag to select rigid vs pw_rigid motion correction # maximum allowed rigid shift in pixels max_shifts = [int(a/b) for a, b in zip(max_shift_um, dxy)] # start a new patch for pw-rigid motion correction every x pixels strides = tuple([int(a/b) for a, b in zip(patch_motion_um, dxy)]) # overlap between pathes (size of patch in pixels: strides+overlaps) overlaps = (24, 24) # maximum deviation allowed for patch with respect to rigid shifts max_deviation_rigid = 3 mc_dict = { 'fnames': fnames, 'fr': fr, 'decay_time': decay_time, 'dxy': dxy, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': 'copy' } opts = params.CNMFParams(params_dict=mc_dict) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # note that the file is not loaded in memory # %% Run (piecewise-rigid motion) correction using NoRMCorre mc.motion_correct(save_movie=True) # %% MEMORY MAPPING border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap(mc.mmap_file, base_name='_memmap_', order='C', border_to_0=border_to_0) # exclude borders # now load the file Yr, dims, T = cm.load_memmap(fname_new) images = np.reshape(Yr.T, [T] + list(dims), order='F') # load frames in python format (T x X x Y) # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) # %% parameters for source extraction and deconvolution p = 1 # order of the autoregressive system gnb = 3 # number of global background components merge_thr = 0.85 # merging threshold, max correlation allowed rf = 20 # half-size of the patches in pixels. e.g., if rf=25, patches are 50x50 stride_cnmf = 6 # amount of overlap between the patches in pixels K = 3 # number of components per patch gSig = [7, 7] # expected half size of neurons in pixels method_init = 'greedy_roi' # initialization method (if analyzing dendritic data using 'sparse_nmf') ssub = 2 # spatial subsampling during initialization tsub = 2 # temporal subsampling during intialization s_min = -20 # minimum signal amplitude needed in order for a transient to be considered as activity # parameters for component evaluation opts_dict = {'fnames': fnames, 'fr': fr, 'nb': gnb, 'rf': rf, 'K': K, 'gSig': gSig, 'stride': stride_cnmf, 'method_init': method_init, 'rolling_sum': True, 'merge_thr': merge_thr, 'n_processes': n_processes, 'only_init': True, 'ssub': ssub, 'tsub': tsub, 's_min': s_min} opts.change_params(params_dict=opts_dict) # %% RUN CNMF ON PATCHES # First extract spatial and temporal components on patches and combine them # for this step deconvolution is turned off (p=0) opts.change_params({'p': 0}) cnm = cnmf.CNMF(n_processes, params=opts, dview=dview) cnm = cnm.fit(images) # %% ALTERNATE WAY TO RUN THE PIPELINE AT ONCE # you can also perform the motion correction plus cnmf fitting steps # simultaneously after defining your parameters object using # cnm1 = cnmf.CNMF(n_processes, params=opts, dview=dview) # cnm1.fit_file(motion_correct=True) # %% RE-RUN seeded CNMF on accepted patches to refine and perform deconvolution cnm.params.change_params({'p': p}) cnm2 = cnm.refit(images, dview=dview) # %% COMPONENT EVALUATION # the components are evaluated in three ways: # a) the shape of each component must be correlated with the data # b) a minimum peak SNR is required over the length of a transient # c) each shape passes a CNN based classifier min_SNR = 2 # Overall minimum signal to noise ratio for accepting a component rval_thr = 0.85 # space correlation threshold for accepting a component cnn_thr = 0.99 # threshold for CNN based classifier cnn_lowest = 0.15 # neurons with cnn probability lower than this value are rejected min_size_neuro = 0.1*gSig[0]*np.pi**2 max_size_neuro = 2.5*gSig[0]*np.pi**2 cnm2.params.set('quality', {'decay_time': decay_time, 'min_SNR': min_SNR, 'rval_thr': rval_thr, 'use_cnn': True, 'min_cnn_thr': cnn_thr, 'cnn_lowest': cnn_lowest, 'min_size_neuro': min_size_neuro, 'max_size_neuro': max_size_neuro,}) cnm2.estimates.evaluate_components(images, cnm2.params, dview=dview) #%% update object with selected components cnm2.estimates.select_components(use_object=True) #%% Extract DF/F values cnm2.estimates.detrend_df_f(quantileMin=8, frames_window=250) #cnm2.estimates.threshold_spatial_components(maxthr=0.85) #cnm2.estimates.remove_small_large_neurons(min_size_neuro=min_size_neuro, max_size_neuro=max_size_neuro) # %% Generate heat image of video and save data Cn = cm.local_correlations(images, swap_dim=False) Cn[np.isnan(Cn)] = 0 cnm2.estimates.Cn = Cn cnm2.save(cnm2.mmap_file[:-4] + 'hdf5') #%% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) #Create denoised video as matrix denoised = cm.movie(cnm2.estimates.A.dot(cnm2.estimates.C) + \ cnm2.estimates.b.dot(cnm2.estimates.f)).reshape(dims + (-1,), order='F').transpose([2, 0, 1]) #Normalizing denoised matrix to the [0,255] range prior to type conversion max_pixel = np.nanmax(denoised) norm_denoised = (denoised/max_pixel)*255 #Type conversion so imageio doesn't get mad norm_denoised = np.uint8(norm_denoised) #Saving a denoised avi of the analyzed video sname = Path(args.in_file).stem + '.avi' imageio.mimwrite(sname, norm_denoised, fps=15.49)
def main(): pass # For compatibility between running under Spyder and the CLI # %% Load demo movie and ROIs fnames = download_demo( 'demo_voltage_imaging.hdf5', 'volpy') # file path to movie file (will download if not present) path_ROIs = download_demo( 'demo_voltage_imaging_ROIs.hdf5', 'volpy') # file path to ROIs file (will download if not present) #%% dataset dependent parameters # dataset dependent parameters fr = 400 # sample rate of the movie # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = ( 48, 48 ) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24 ) # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = 3 # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the movie press q display_images = False if display_images: m_orig = cm.load(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=40, magnification=6) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run correction mc.motion_correct(save_movie=True) # %% compare with original movie if display_images: m_orig = cm.load(fnames) m_rig = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([ m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_rig.resize(1, 1, ds_ratio) ], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=4) # press q to exit # %% MEMORY MAPPING border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap_join(mc.mmap_file, base_name='memmap_', add_to_mov=border_to_0, dview=dview) # exclude border # %% SEGMENTATION # create summary images img = mean_image(mc.mmap_file[0], window=1000, dview=dview) img = (img - np.mean(img)) / np.std(img) gaussian_blur = False # Use gaussian blur when the quality of corr image(Cn) is bad Cn = local_correlations_movie_offline(mc.mmap_file[0], fr=fr, window=fr * 4, stride=fr * 4, winSize_baseline=fr, remove_baseline=True, gaussian_blur=gaussian_blur, dview=dview).max(axis=0) img_corr = (Cn - np.mean(Cn)) / np.std(Cn) summary_image = np.stack([img, img, img_corr], axis=2).astype(np.float32) #%% three methods for segmentation methods_list = [ 'manual_annotation', # manual annotation needs user to prepare annotated datasets same format as demo ROIs 'quick_annotation', # quick annotation annotates data with simple interface in python 'maskrcnn' ] # maskrcnn is a convolutional network trained for finding neurons using summary images method = methods_list[0] if method == 'manual_annotation': with h5py.File(path_ROIs, 'r') as fl: ROIs = fl['mov'][()] elif method == 'quick_annotation': ROIs = utils.quick_annotation(img, min_radius=4, max_radius=8) elif method == 'maskrcnn': # Important!! make sure install keras before using mask rcnn weights_path = download_model('mask_rcnn') ROIs = utils.mrcnn_inference(img=summary_image, weights_path=weights_path, display_result=True) # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False, maxtasksperchild=1) # %% parameters for trace denoising and spike extraction ROIs = ROIs # region of interests index = list(range(len(ROIs))) # index of neurons weights = None # reuse spatial weights context_size = 35 # number of pixels surrounding the ROI to censor from the background PCA flip_signal = True # Important!! Flip signal or not, True for Voltron indicator, False for others hp_freq_pb = 1 / 3 # parameter for high-pass filter to remove photobleaching threshold_method = 'simple' # 'simple' or 'adaptive_threshold' min_spikes = 10 # minimal spikes to be found threshold = 3.5 # threshold for finding spikes, increase threshold to find less spikes do_plot = False # plot detail of spikes, template for the last iteration ridge_bg = 0.001 # ridge regression regularizer strength for background removement sub_freq = 20 # frequency for subthreshold extraction weight_update = 'ridge' # 'ridge' or 'NMF' for weight update opts_dict = { 'fnames': fname_new, 'ROIs': ROIs, 'index': index, 'weights': weights, 'context_size': context_size, 'flip_signal': flip_signal, 'hp_freq_pb': hp_freq_pb, 'threshold_method': threshold_method, 'min_spikes': min_spikes, 'threshold': threshold, 'do_plot': do_plot, 'ridge_bg': ridge_bg, 'sub_freq': sub_freq, 'weight_update': weight_update } opts.change_params(params_dict=opts_dict) #%% TRACE DENOISING AND SPIKE DETECTION vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) #%% visualization if display_images: print(np.where( vpy.estimates['locality'])[0]) # neurons that pass locality test idx = np.where(vpy.estimates['locality'] > 0)[0] utils.view_components(vpy.estimates, img_corr, idx) #%% reconstructed movie # note the negative spatial weights is cutoff if display_images: mv_all = utils.reconstructed_movie(vpy.estimates, fnames=mc.mmap_file, idx=idx, scope=(0, 1000), flip_signal=flip_signal) mv_all.play(fr=40) # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
def run_caiman_pipeline(movie, fr, fnames, savedir, usematlabroi): #%% cpu_num = 7 cpu_num_spikepursuit = 2 #gsig_filt_micron = (4, 4) #max_shifts_micron = (6,6) #strides_micron = (60,60) #overlaps_micron = (30, 30) gsig_filt_micron = (4, 4) max_shifts_micron = (6, 6) strides_micron = (30, 30) overlaps_micron = (15, 15) max_deviation_rigid_micron = 4 pixel_size = movie['movie_pixel_size'] ROIs = None # Region of interests index = None # index of neurons weights = None # reuse spatial weights by # opts.change_params(params_dict={'weights':vpy.estimates['weights']}) # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = tuple( np.asarray(np.round(np.asarray(gsig_filt_micron) / float(pixel_size)), int)) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = tuple( np.asarray(np.round(np.asarray(max_shifts_micron) / float(pixel_size)), int)) strides = tuple( np.asarray(np.round(np.asarray(strides_micron) / float(pixel_size)), int) ) # start a new patch for pw-rigid motion correction every x pixels overlaps = tuple( np.asarray(np.round(np.asarray(overlaps_micron) / float(pixel_size)), int) ) # start a new patch for pw-rigid motion correction every x pixels # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = int( round(max_deviation_rigid_micron / pixel_size) ) # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'index': index, 'ROIs': ROIs, 'weights': weights, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = False if display_images: m_orig = cm.load(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=cpu_num, single_thread=False) # % MOTION CORRECTION # Create a motion correction object with the specified parameters mcrig = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run piecewise rigid motion correction #% mcrig.motion_correct(save_movie=True) dview.terminate() # % MOTION CORRECTION2 opts.change_params({'pw_rigid': True}) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=cpu_num, single_thread=False) # Create a motion correction object with the specified parameters mc = MotionCorrect(mcrig.mmap_file, dview=dview, **opts.get_group('motion')) # Run piecewise rigid motion correction mc.motion_correct(save_movie=True) dview.terminate() # %% motion correction compared with original movie display_images = False if display_images: m_orig = cm.load(fnames) m_rig = cm.load(mcrig.mmap_file) m_pwrig = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([ m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_rig.resize(1, 1, ds_ratio), m_pwrig.resize(1, 1, ds_ratio) ], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit # % movie subtracted from the mean m_orig2 = (m_orig - np.mean(m_orig, axis=0)) m_rig2 = (m_rig - np.mean(m_rig, axis=0)) m_pwrig2 = (m_pwrig - np.mean(m_pwrig, axis=0)) moviehandle1 = cm.concatenate([ m_orig2.resize(1, 1, ds_ratio), m_rig2.resize(1, 1, ds_ratio), m_pwrig2.resize(1, 1, ds_ratio) ], axis=2) moviehandle1.play(fr=60, q_max=99.5, magnification=2) # %% Memory Mapping c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=cpu_num, single_thread=False) border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 fname_new = cm.save_memmap_join(mc.mmap_file, base_name='memmap_', add_to_mov=border_to_0, dview=dview, n_chunks=10) dview.terminate() # %% change fnames to the new motion corrected one opts.change_params(params_dict={'fnames': fname_new}) # %% SEGMENTATION roidir = savedir[:savedir.find('VolPy')] + 'Spikepursuit' + savedir[ savedir.find('VolPy') + len('Volpy'):] try: files = os.listdir(roidir) except: files = [] if usematlabroi and 'ROIs.mat' in files: ROIs = loadmat(os.path.join(roidir, 'ROIs.mat'))['ROIs'] if len(np.shape(ROIs)) == 3: ROIs = np.moveaxis(np.asarray(ROIs, bool), 2, 0) else: ROIs = np.asarray([ROIs]) all_rois = ROIs opts.change_params( params_dict={ 'ROIs': ROIs, 'index': list(range(ROIs.shape[0])), 'method': 'SpikePursuit' }) else: #% print('WTF') # Create mean and correlation image use_maskrcnn = True # set to True to predict the ROIs using the mask R-CNN if not use_maskrcnn: # use manual annotations with h5py.File(path_ROIs, 'r') as fl: ROIs = fl['mov'][()] # load ROIs opts.change_params( params_dict={ 'ROIs': ROIs, 'index': list(range(ROIs.shape[0])), 'method': 'SpikePursuit' }) else: try: m = cm.load(mc.mmap_file[0], subindices=slice(0, 20000)) except: m = cm.load( '/home/rozmar/Data/Voltage_imaging/Voltage_rig_1P/rozsam/20200120/40x_1xtube_10A_7_000_rig__d1_128_d2_512_d3_1_order_F_frames_2273_._els__d1_128_d2_512_d3_1_order_F_frames_2273_.mmap', subindices=slice(0, 20000)) m.fr = fr img = m.mean(axis=0) img = (img - np.mean(img)) / np.std(img) m1 = m.computeDFF(secsWindow=1, in_place=True)[0] m = m - m1 Cn = m.local_correlations(swap_dim=False, eight_neighbours=True) img_corr = (Cn - np.mean(Cn)) / np.std(Cn) summary_image = np.stack([img, img, img_corr], axis=2).astype(np.float32) del m del m1 # % # Mask R-CNN config = neurons.NeuronsConfig() class InferenceConfig(config.__class__): # Run detection on one image at a time GPU_COUNT = 1 IMAGES_PER_GPU = 1 DETECTION_MIN_CONFIDENCE = 0.7 IMAGE_RESIZE_MODE = "pad64" IMAGE_MAX_DIM = 512 RPN_NMS_THRESHOLD = 0.7 POST_NMS_ROIS_INFERENCE = 1000 config = InferenceConfig() config.display() model_dir = os.path.join(caiman_datadir(), 'model') DEVICE = "/cpu:0" # /cpu:0 or /gpu:0 with tf.device(DEVICE): model = modellib.MaskRCNN(mode="inference", model_dir=model_dir, config=config) weights_path = download_model('mask_rcnn') model.load_weights(weights_path, by_name=True) results = model.detect([summary_image], verbose=1) r = results[0] ROIs_mrcnn = r['masks'].transpose([2, 0, 1]) # %% visualize the result display_result = False if display_result: _, ax = plt.subplots(1, 1, figsize=(16, 16)) visualize.display_instances(summary_image, r['rois'], r['masks'], r['class_ids'], ['BG', 'neurons'], r['scores'], ax=ax, title="Predictions") # %% set rois opts.change_params( params_dict={ 'ROIs': ROIs_mrcnn, 'index': list(range(ROIs_mrcnn.shape[0])), 'method': 'SpikePursuit' }) #all_rois = ROIs_mrcnn # %% Trace Denoising and Spike Extraction c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=cpu_num_spikepursuit, single_thread=False, maxtasksperchild=1) #dview=None vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) #%% print('saving parameters') parameters = dict() parameters['motion'] = opts.motion parameters['data'] = opts.data parameters['volspike'] = opts.volspike with open(os.path.join(savedir, 'parameters.pickle'), 'wb') as outfile: pickle.dump(parameters, outfile) #%% volspikedata = dict() volspikedata['estimates'] = vpy.estimates volspikedata['params'] = vpy.params.data with open(os.path.join(savedir, 'spikepursuit.pickle'), 'wb') as outfile: pickle.dump(volspikedata, outfile) #%% for mcidx, mc_now in enumerate([mcrig, mc]): motioncorr = dict() motioncorr['fname'] = mc_now.fname motioncorr['fname_tot_rig'] = mc_now.fname_tot_rig motioncorr['mmap_file'] = mc_now.mmap_file motioncorr['min_mov'] = mc_now.min_mov motioncorr['shifts_rig'] = mc_now.shifts_rig motioncorr['shifts_opencv'] = mc_now.shifts_opencv motioncorr['niter_rig'] = mc_now.niter_rig motioncorr['min_mov'] = mc_now.min_mov motioncorr['templates_rig'] = mc_now.templates_rig motioncorr['total_template_rig'] = mc_now.total_template_rig try: motioncorr['x_shifts_els'] = mc_now.x_shifts_els motioncorr['y_shifts_els'] = mc_now.y_shifts_els except: pass with open( os.path.join(savedir, 'motion_corr_' + str(mcidx) + '.pickle'), 'wb') as outfile: pickle.dump(motioncorr, outfile) #%% saving stuff print('moving files') for mmap_file in mcrig.mmap_file: fname = pathlib.Path(mmap_file).name os.remove(mmap_file) #shutil.move(mmap_file, os.path.join(savedir,fname)) for mmap_file in mc.mmap_file: fname = pathlib.Path(mmap_file).name os.remove(mmap_file) #shutil.move(mmap_file, os.path.join(savedir,fname)) fname = pathlib.Path(fname_new).name shutil.move(fname_new, os.path.join(savedir, fname)) #print('waiting') #time.sleep(1000) # %% some visualization plotstuff = False if plotstuff: print(np.where(vpy.estimates['passedLocalityTest']) [0]) # neurons that pass locality test n = 0 # Processed signal and spikes of neurons plt.figure() plt.plot(vpy.estimates['trace'][n]) plt.plot(vpy.estimates['spikeTimes'][n], np.max(vpy.estimates['trace'][n]) * np.ones(vpy.estimates['spikeTimes'][n].shape), color='g', marker='o', fillstyle='none', linestyle='none') plt.title('signal and spike times') plt.show() # Location of neurons by Mask R-CNN or manual annotation plt.figure() if use_maskrcnn: plt.imshow(ROIs_mrcnn[n]) else: plt.imshow(ROIs[n]) mv = cm.load(fname_new) plt.imshow(mv.mean(axis=0), alpha=0.5) # Spatial filter created by algorithm plt.figure() plt.imshow(vpy.estimates['spatialFilter'][n]) plt.colorbar() plt.title('spatial filter') plt.show() # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
print('checkpoint 1: mcorrect', flush=True) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters if nomc: print('Skipping motion correction due to -nomc flag', flush=True) print('saving movies as mmap file', flush=True) fname_new = cm.save_memmap(fname, base_name='memmap_{}_full_'.format(slurmid), order='C', border_to_0=0) else: mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # note that the file is not loaded in memory # %% Run (piecewise-rigid motion) correction using NoRMCorre mc.motion_correct(save_movie=True, template=mc_temp) # %% MEMORY MAPPING border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' save_name = mc.fname_tot_els if opts.get('motion','pw_rigid') else mc.fname_tot_rig print('saving movies as mmap file', flush=True) fname_new = cm.save_memmap(save_name, base_name='memmap_{}_full_'.format(slurmid), order='C', border_to_0=border_to_0) # exclude borders
def main(): pass # For compatibility between running under Spyder and the CLI #%% """ General parameters """ play_movie = 1 plot_extras = 1 plot_extras_cell = 1 compute_mc_metrics = 1 #%% Select file(s) to be processed (download if not present) """ Load file """ #fnames = ['Sue_2x_3000_40_-46.tif'] # filename to be processed #if fnames[0] in ['Sue_2x_3000_40_-46.tif', 'demoMovie.tif']: # fnames = [download_demo(fnames[0])] #fnames = ['/home/yuriy/Desktop/Data/rest1_5_9_19_cut.tif'] #f_dir = 'C:\\Users\\rylab_dataPC\\Desktop\\Yuriy\\caiman_data\\short\\' f_dir = 'G:\\analysis\\190828-calcium_voltage\\soma_dendrites\\pCAG_jREGECO1a_ASAP3_anesth_001\\' f_name = 'Ch1' f_ext = 'tif' fnames = [f_dir + f_name + '.' + f_ext] #fnames = ['C:/Users/rylab_dataPC/Desktop/Yuriy/caiman_data/rest1_5_9_19_2_cut_ca.hdf5'] #%% First setup some parameters for data and motion correction """ Parameters """ # dataset dependent parameters fr = 30 # imaging rate in frames per second decay_time = 1 #0.4 # length of a typical transient in seconds dxy = (2., 2.) # spatial resolution in x and y in (um per pixel) # note the lower than usual spatial resolution here max_shift_um = (12., 12.) # maximum shift in um patch_motion_um = (100., 100.) # patch size for non-rigid correction in um # motion correction parameters pw_rigid = True # flag to select rigid vs pw_rigid motion correction # maximum allowed rigid shift in pixels #max_shifts = [int(a/b) for a, b in zip(max_shift_um, dxy)] max_shifts = [6, 6] # start a new patch for pw-rigid motion correction every x pixels #strides = tuple([int(a/b) for a, b in zip(patch_motion_um, dxy)]) strides = [48, 48] # overlap between pathes (size of patch in pixels: strides+overlaps) overlaps = (24, 24) # maximum deviation allowed for patch with respect to rigid shifts max_deviation_rigid = 3 mc_dict = { 'fnames': fnames, 'fr': fr, 'decay_time': decay_time, 'dxy': dxy, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': 'copy' } opts = params.CNMFParams(params_dict=mc_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q if play_movie: m_orig = cm.load_movie_chain(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # note that the file is not loaded in memory # %% Run (piecewise-rigid motion) correction using NoRMCorre mc.motion_correct(save_movie=True) # type "mc."and press TAB to see all interesting associated variables and self. outputs # interesting outputs # saved file is mc.fname_tot_els / mc.fname_tot_rig # mc.x_shifts_els / mc.y_shifts_els: shifts in x/y per frame per patch # mc.coord_shifts_els: coordinates associated to patches with shifts # mc.total_template_els: updated template for pw # mc.total_template_rig: updated template for rigid # mc.templates_rig: templates for each iteration in rig #%% # compute metrics for the results (TAKES TIME!!) if compute_mc_metrics: # not finished bord_px_els = np.ceil( np.maximum(np.max(np.abs(mc.x_shifts_els)), np.max(np.abs(mc.y_shifts_els)))).astype(np.int) final_size = np.subtract( mc.total_template_els.shape, 2 * bord_px_els) # remove pixels in the boundaries winsize = 100 swap_dim = False resize_fact_flow = .2 # downsample for computing ROF tmpl_rig, correlations_orig, flows_orig, norms_orig, crispness_orig = cm.motion_correction.compute_metrics_motion_correction( fnames[0], final_size[0], final_size[1], swap_dim, winsize=winsize, play_flow=False, resize_fact_flow=resize_fact_flow) plt.figure() plt.plot(correlations_orig) # %% compare with original movie if play_movie: m_orig = cm.load_movie_chain(fnames) m_els = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([ m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_els.resize(1, 1, ds_ratio) ], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit del m_orig del m_els if plot_extras: # plot total template plt.figure() plt.imshow(mc.total_template_els) plt.title('Template after iteration') # plot x and y corrections plt.figure() plt.plot(mc.shifts_rig) plt.title('Rigid motion correction xy movement') plt.legend(['x shift', 'y shift']) plt.xlabel('frames') # %% MEMORY MAPPING border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap(mc.mmap_file, base_name='memmap_', order='C', border_to_0=border_to_0) # exclude borders # now load the file Yr, dims, T = cm.load_memmap(fname_new) images = np.reshape(Yr.T, [T] + list(dims), order='F') # load frames in python format (T x X x Y) # %% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) # %% parameters for source extraction and deconvolution p = 2 # order of the autoregressive system gnb = 2 # number of global background components merge_thr = 0.85 # merging threshold, max correlation allowed rf = 15 # half-size of the patches in pixels. e.g., if rf=25, patches are 50x50 stride_cnmf = 6 # amount of overlap between the patches in pixels K = 2 # number of components per patch gSig = [15, 15] # expected half size of neurons in pixels # initialization method (if analyzing dendritic data using 'sparse_nmf') method_init = 'greedy_roi' ssub = 1 # spatial subsampling during initialization tsub = 1 # temporal subsampling during intialization # parameters for component evaluation opts_dict = { 'fnames': fnames, 'fr': fr, 'nb': gnb, 'rf': rf, 'K': K, 'gSig': gSig, 'stride': stride_cnmf, 'method_init': method_init, 'rolling_sum': True, 'merge_thr': merge_thr, 'n_processes': n_processes, 'only_init': True, 'ssub': ssub, 'tsub': tsub } opts.change_params(params_dict=opts_dict) # %% RUN CNMF ON PATCHES # First extract spatial and temporal components on patches and combine them # for this step deconvolution is turned off (p=0) opts.change_params({'p': 0}) cnm = cnmf.CNMF(n_processes, params=opts, dview=dview) cnm = cnm.fit(images) if plot_extras_cell: num_cell_plot = 51 plt.figure() plt.plot(cnm.estimates.C[num_cell_plot, :]) plt.title('Temporal component') plt.legend(['Cell ' + str(num_cell_plot)]) # plot component sptial profile A # first convert back to dense components plot_spat_A = cnm.estimates.A[:, num_cell_plot].toarray().reshape( list(dims)) plt.figure() plt.imshow(plot_spat_A) plt.title('Spatial component cell ' + str(num_cell_plot)) # %% ALTERNATE WAY TO RUN THE PIPELINE AT ONCE # you can also perform the motion correction plus cnmf fitting steps # simultaneously after defining your parameters object using # cnm1 = cnmf.CNMF(n_processes, params=opts, dview=dview) # cnm1.fit_file(motion_correct=True) # %% plot contours of found components Cn = cm.local_correlations(images, swap_dim=False) Cn[np.isnan(Cn)] = 0 cnm.estimates.plot_contours(img=Cn) plt.title('Contour plots of found components') if plot_extras: plt.figure() plt.imshow(Cn) plt.title('Local correlations') # %% RE-RUN seeded CNMF on accepted patches to refine and perform deconvolution cnm.params.change_params({'p': p}) cnm2 = cnm.refit(images, dview=dview) # %% COMPONENT EVALUATION # the components are evaluated in three ways: # a) the shape of each component must be correlated with the data # b) a minimum peak SNR is required over the length of a transient # c) each shape passes a CNN based classifier min_SNR = 2 # signal to noise ratio for accepting a component rval_thr = 0.90 # space correlation threshold for accepting a component cnn_thr = 0.99 # threshold for CNN based classifier cnn_lowest = 0.1 # neurons with cnn probability lower than this value are rejected cnm2.params.set( 'quality', { 'decay_time': decay_time, 'min_SNR': min_SNR, 'rval_thr': rval_thr, 'use_cnn': True, 'min_cnn_thr': cnn_thr, 'cnn_lowest': cnn_lowest }) cnm2.estimates.evaluate_components(images, cnm2.params, dview=dview) # %% PLOT COMPONENTS cnm2.estimates.plot_contours(img=Cn, idx=cnm2.estimates.idx_components) plt.suptitle('Component selection: min_SNR=' + str(min_SNR) + '; rval_thr=' + str(rval_thr) + '; cnn prob range=[' + str(cnn_lowest) + ' ' + str(cnn_thr) + ']') # %% VIEW TRACES (accepted and rejected) if plot_extras: cnm2.estimates.view_components(images, img=Cn, idx=cnm2.estimates.idx_components) plt.suptitle('Accepted') cnm2.estimates.view_components(images, img=Cn, idx=cnm2.estimates.idx_components_bad) plt.suptitle('Rejected') #plt.figure(); #plt.plot(cnm2.estimates.YrA[0,:]+cnm2.estimates.C[0,:]) # # # # #plt.figure(); #plt.plot(cnm2.estimates.R[0,:]-cnm2.estimates.YrA[0,:]); #plt.plot(); #plt.show(); # # #plt.figure(); #plt.plot(cnm2.estimates.detrend_df_f[1,:]) # these store the good and bad components, and next step sorts them # cnm2.estimates.idx_components # cnm2.estimates.idx_components_bad #%% update object with selected components #cnm2.estimates.select_components(use_object=True) #%% Extract DF/F values cnm2.estimates.detrend_df_f(quantileMin=8, frames_window=250) #%% Show final traces cnm2.estimates.view_components(img=Cn) plt.suptitle("Final results") #%% Save the mc data as in cmn struct as well ## #mc_out = dict( # pw_rigid = mc.pw_rigid, # fname = mc.fname, # mmap_file = mc.mmap_file, # total_template_els = mc.total_template_els, # total_template_rig = mc.total_template_rig, # border_nan = mc.border_nan, # border_to_0 = mc.border_to_0, # x_shifts_els = mc.x_shifts_els, # y_shifts_els = mc.y_shifts_els, # Cn = Cn # ) # # #deepdish.io.save(fnames[0] + '_mc_data.hdf5', mc_out) #%% reconstruct denoised movie (press q to exit) if play_movie: cnm2.estimates.play_movie(images, q_max=99.9, gain_res=2, magnification=2, bpx=border_to_0, include_bck=False) # background not shown #%% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file) save_results = True if save_results: cnm2.save(fnames[0][:-4] + '_results.hdf5')
def main(): pass # For compatibility between running under Spyder and the CLI # %% Load demo movie and ROIs fnames = download_demo('demo_voltage_imaging.hdf5', 'volpy') # file path to movie file (will download if not present) path_ROIs = download_demo('demo_voltage_imaging_ROIs.hdf5', 'volpy') # file path to ROIs file (will download if not present) # %% Setup some parameters for data and motion correction # dataset parameters fr = 400 # sample rate of the movie ROIs = None # Region of interests index = None # index of neurons weights = None # reuse spatial weights by # opts.change_params(params_dict={'weights':vpy.estimates['weights']}) # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = (48, 48) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24) # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = 3 # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'index': index, 'ROIs': ROIs, 'weights': weights, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = False if display_images: m_orig = cm.load(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) # %%% MOTION CORRECTION # Create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run piecewise rigid motion correction mc.motion_correct(save_movie=True) dview.terminate() # %% motion correction compared with original movie display_images = False if display_images: m_orig = cm.load(fnames) m_rig = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_rig.resize(1, 1, ds_ratio)], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit # % movie subtracted from the mean m_orig2 = (m_orig - np.mean(m_orig, axis=0)) m_rig2 = (m_rig - np.mean(m_rig, axis=0)) moviehandle1 = cm.concatenate([m_orig2.resize(1, 1, ds_ratio), m_rig2.resize(1, 1, ds_ratio)], axis=2) moviehandle1.play(fr=60, q_max=99.5, magnification=2) # %% Memory Mapping c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 fname_new = cm.save_memmap_join(mc.mmap_file, base_name='memmap_', add_to_mov=border_to_0, dview=dview, n_chunks=10) dview.terminate() # %% change fnames to the new motion corrected one opts.change_params(params_dict={'fnames': fname_new}) # %% SEGMENTATION # Create mean and correlation image use_maskrcnn = True # set to True to predict the ROIs using the mask R-CNN if not use_maskrcnn: # use manual annotations with h5py.File(path_ROIs, 'r') as fl: ROIs = fl['mov'][()] # load ROIs opts.change_params(params_dict={'ROIs': ROIs, 'index': list(range(ROIs.shape[0])), 'method': 'SpikePursuit'}) else: m = cm.load(mc.mmap_file[0], subindices=slice(0, 20000)) m.fr = fr img = m.mean(axis=0) img = (img-np.mean(img))/np.std(img) m1 = m.computeDFF(secsWindow=1, in_place=True)[0] m = m - m1 Cn = m.local_correlations(swap_dim=False, eight_neighbours=True) img_corr = (Cn-np.mean(Cn))/np.std(Cn) summary_image = np.stack([img, img, img_corr], axis=2).astype(np.float32) del m del m1 # %% # Mask R-CNN config = neurons.NeuronsConfig() class InferenceConfig(config.__class__): # Run detection on one image at a time GPU_COUNT = 1 IMAGES_PER_GPU = 1 DETECTION_MIN_CONFIDENCE = 0.7 IMAGE_RESIZE_MODE = "pad64" IMAGE_MAX_DIM = 512 RPN_NMS_THRESHOLD = 0.7 POST_NMS_ROIS_INFERENCE = 1000 config = InferenceConfig() config.display() model_dir = os.path.join(caiman_datadir(), 'model') DEVICE = "/cpu:0" # /cpu:0 or /gpu:0 with tf.device(DEVICE): model = modellib.MaskRCNN(mode="inference", model_dir=model_dir, config=config) weights_path = download_model('mask_rcnn') model.load_weights(weights_path, by_name=True) results = model.detect([summary_image], verbose=1) r = results[0] ROIs_mrcnn = r['masks'].transpose([2, 0, 1]) # %% visualize the result display_result = False if display_result: _, ax = plt.subplots(1,1, figsize=(16,16)) visualize.display_instances(summary_image, r['rois'], r['masks'], r['class_ids'], ['BG', 'neurons'], r['scores'], ax=ax, title="Predictions") # %% set rois opts.change_params(params_dict={'ROIs':ROIs_mrcnn, 'index':list(range(ROIs_mrcnn.shape[0])), 'method':'SpikePursuit'}) # %% Trace Denoising and Spike Extraction c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False, maxtasksperchild=1) vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) # %% some visualization print(np.where(vpy.estimates['passedLocalityTest'])[0]) # neurons that pass locality test n = 0 # Processed signal and spikes of neurons plt.figure() plt.plot(vpy.estimates['trace'][n]) plt.plot(vpy.estimates['spikeTimes'][n], np.max(vpy.estimates['trace'][n]) * np.ones(vpy.estimates['spikeTimes'][n].shape), color='g', marker='o', fillstyle='none', linestyle='none') plt.title('signal and spike times') plt.show() # Location of neurons by Mask R-CNN or manual annotation plt.figure() if use_maskrcnn: plt.imshow(ROIs_mrcnn[n]) else: plt.imshow(ROIs[n]) mv = cm.load(fname_new) plt.imshow(mv.mean(axis=0),alpha=0.5) # Spatial filter created by algorithm plt.figure() plt.imshow(vpy.estimates['spatialFilter'][n]) plt.colorbar() plt.title('spatial filter') plt.show() # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
def run_caiman_pipeline(movie, fr, fnames, savedir, caiman_parameters): #%% usematlabroi = caiman_parameters['usematlabroi'] cpu_num = 16 cpu_num_spikepursuit = 3 #gsig_filt_micron = (4, 4) #max_shifts_micron = (6,6) #strides_micron = (60,60) #overlaps_micron = (30, 30) gsig_filt_micron = (4, 4) max_shifts_micron = (6, 6) strides_micron = (30, 30) overlaps_micron = (15, 15) max_deviation_rigid_micron = 4 pixel_size = movie['movie_pixel_size'] ROIs = None # Region of interests index = None # index of neurons weights = None # reuse spatial weights by # opts.change_params(params_dict={'weights':vpy.estimates['weights']}) # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = tuple( np.asarray(np.round(np.asarray(gsig_filt_micron) / float(pixel_size)), int)) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = tuple( np.asarray(np.round(np.asarray(max_shifts_micron) / float(pixel_size)), int)) strides = tuple( np.asarray(np.round(np.asarray(strides_micron) / float(pixel_size)), int) ) # start a new patch for pw-rigid motion correction every x pixels overlaps = tuple( np.asarray(np.round(np.asarray(overlaps_micron) / float(pixel_size)), int) ) # start a new patch for pw-rigid motion correction every x pixels # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = int( round(max_deviation_rigid_micron / pixel_size) ) # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'index': index, 'ROIs': ROIs, 'weights': weights, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) #%% if not caiman_parameters['motion_correction_already_done']: # %% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = False if display_images: m_orig = cm.load(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=60, magnification=2) # %% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=cpu_num, single_thread=False) # % MOTION CORRECTION # Create a motion correction object with the specified parameters mcrig = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run piecewise rigid motion correction #% mcrig.motion_correct(save_movie=True) dview.terminate() # % MOTION CORRECTION2 opts.change_params({'pw_rigid': True}) c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=cpu_num, single_thread=False) # Create a motion correction object with the specified parameters mc = MotionCorrect(mcrig.mmap_file, dview=dview, **opts.get_group('motion')) # Run piecewise rigid motion correction mc.motion_correct(save_movie=True) dview.terminate() # %% motion correction compared with original movie display_images = False if display_images: m_orig = cm.load(fnames) m_rig = cm.load(mcrig.mmap_file) m_pwrig = cm.load(mc.mmap_file) ds_ratio = 0.2 moviehandle = cm.concatenate([ m_orig.resize(1, 1, ds_ratio) - mc.min_mov * mc.nonneg_movie, m_rig.resize(1, 1, ds_ratio), m_pwrig.resize(1, 1, ds_ratio) ], axis=2) moviehandle.play(fr=60, q_max=99.5, magnification=2) # press q to exit # % movie subtracted from the mean m_orig2 = (m_orig - np.mean(m_orig, axis=0)) m_rig2 = (m_rig - np.mean(m_rig, axis=0)) m_pwrig2 = (m_pwrig - np.mean(m_pwrig, axis=0)) moviehandle1 = cm.concatenate([ m_orig2.resize(1, 1, ds_ratio), m_rig2.resize(1, 1, ds_ratio), m_pwrig2.resize(1, 1, ds_ratio) ], axis=2) moviehandle1.play(fr=60, q_max=99.5, magnification=2) # %% Memory Mapping c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=cpu_num, single_thread=False) border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 fname_new = cm.save_memmap_join(mc.mmap_file, base_name='memmap_', add_to_mov=border_to_0, dview=dview, n_chunks=10) dview.terminate() # %% change fnames to the new motion corrected one opts.change_params(params_dict={'fnames': fname_new}) else: #%% files = os.listdir(savedir) for file in files: if '.mmap' in file: break fname_new = os.path.join(savedir, file) opts.change_params(params_dict={'fnames': fname_new}) # %% SEGMENTATION if caiman_parameters['dospikepursuit']: roidir_matlab = savedir[:savedir.find( 'VolPy')] + 'Spikepursuit' + savedir[savedir.find('VolPy') + len('Volpy'):] try: files_matlab = os.listdir(roidir) except: files_matlab = [] roidir_volpy = savedir[:savedir.find('VolPy')] + 'ROI' + savedir[ savedir.find('VolPy') + len('Volpy'):] try: files_volpy = os.listdir(roidir_volpy) except: files_volpy = [] if usematlabroi and 'ROIs.mat' in files_matlab: ROIs = loadmat(os.path.join(roidir_matlab, 'ROIs.mat'))['ROIs'] if len(np.shape(ROIs)) == 3: ROIs = np.moveaxis(np.asarray(ROIs, bool), 2, 0) else: ROIs = np.asarray([ROIs]) all_rois = ROIs opts.change_params( params_dict={ 'ROIs': ROIs, 'index': list(range(ROIs.shape[0])), 'method': 'SpikePursuit' }) elif caiman_parameters['usevolpyroi'] and 'VolPy.npy' in files_volpy: ROIs_original = np.load(os.path.join(roidir_volpy, 'VolPy.npy')) roinum = int(np.max(np.unique(ROIs_original))) ROIs = np.asarray( np.zeros([ int(roinum), ROIs_original.shape[0], ROIs_original.shape[1] ]), bool) for i in range(1, roinum + 1): ROIs[i - 1, ROIs_original == i] = True all_rois = ROIs opts.change_params( params_dict={ 'ROIs': ROIs, 'index': list(range(ROIs.shape[0])), 'method': 'SpikePursuit' }) else: #% print('WTF') # %% Trace Denoising and Spike Extraction c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=cpu_num_spikepursuit, single_thread=False, maxtasksperchild=1) #dview=None vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) #%% if caiman_parameters['dospikepursuit']: volspikedata = dict() volspikedata['estimates'] = vpy.estimates volspikedata['params'] = vpy.params.data with open(os.path.join(savedir, 'spikepursuit.pickle'), 'wb') as outfile: pickle.dump(volspikedata, outfile) if not caiman_parameters['motion_correction_already_done']: print('saving parameters') parameters = dict() parameters['motion'] = opts.motion parameters['data'] = opts.data if caiman_parameters['dospikepursuit']: parameters['volspike'] = opts.volspike with open(os.path.join(savedir, 'parameters.pickle'), 'wb') as outfile: pickle.dump(parameters, outfile) #% #% for mcidx, mc_now in enumerate([mcrig, mc]): motioncorr = dict() motioncorr['fname'] = mc_now.fname motioncorr['fname_tot_rig'] = mc_now.fname_tot_rig motioncorr['mmap_file'] = mc_now.mmap_file motioncorr['min_mov'] = mc_now.min_mov motioncorr['shifts_rig'] = mc_now.shifts_rig motioncorr['shifts_opencv'] = mc_now.shifts_opencv motioncorr['niter_rig'] = mc_now.niter_rig motioncorr['min_mov'] = mc_now.min_mov motioncorr['templates_rig'] = mc_now.templates_rig motioncorr['total_template_rig'] = mc_now.total_template_rig try: motioncorr['x_shifts_els'] = mc_now.x_shifts_els motioncorr['y_shifts_els'] = mc_now.y_shifts_els except: pass with open( os.path.join(savedir, 'motion_corr_' + str(mcidx) + '.pickle'), 'wb') as outfile: pickle.dump(motioncorr, outfile) #%saving stuff print('moving files') for mmap_file in mcrig.mmap_file: fname = pathlib.Path(mmap_file).name os.remove(mmap_file) #shutil.move(mmap_file, os.path.join(savedir,fname)) for mmap_file in mc.mmap_file: fname = pathlib.Path(mmap_file).name os.remove(mmap_file) #shutil.move(mmap_file, os.path.join(savedir,fname)) fname = pathlib.Path(fname_new).name #Thread(target=shutil.copy, args=[fname_new, os.path.join(savedir,fname)]).start() shutil.move(fname_new, os.path.join(savedir, fname)) #print('waiting') #time.sleep(1000) # %% some visualization plotstuff = False if plotstuff: print(np.where(vpy.estimates['passedLocalityTest']) [0]) # neurons that pass locality test n = 0 # Processed signal and spikes of neurons plt.figure() plt.plot(vpy.estimates['trace'][n]) plt.plot(vpy.estimates['spikeTimes'][n], np.max(vpy.estimates['trace'][n]) * np.ones(vpy.estimates['spikeTimes'][n].shape), color='g', marker='o', fillstyle='none', linestyle='none') plt.title('signal and spike times') plt.show() # Location of neurons by Mask R-CNN or manual annotation plt.figure() if use_maskrcnn: plt.imshow(ROIs_mrcnn[n]) else: plt.imshow(ROIs[n]) mv = cm.load(fname_new) plt.imshow(mv.mean(axis=0), alpha=0.5) # Spatial filter created by algorithm plt.figure() plt.imshow(vpy.estimates['spatialFilter'][n]) plt.colorbar() plt.title('spatial filter') plt.show() # %% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file)
def run_alignmnet(selected_rows, parameters, dview): ''' This is the main function for the alignment step. It applies methods from the CaImAn package used originally in motion correction to do alignment. Args: df: pd.DataFrame A dataframe containing the analysis states you want to have aligned. parameters: dict The alignment parameters. dview: object The dview object Returns: df: pd.DataFrame A dataframe containing the aligned analysis states. ''' # Sort the dataframe correctly df = selected_rows.copy() df = df.sort_values(by=paths.multi_index_structure) # Determine the mouse and session of the dataset index = df.iloc[0].name mouse, session, *r = index # alignment_v = index[len(paths.data_structure) + step_index] alignment_v = len(df) alignment_index = (mouse, session, alignment_v) # Determine the output .mmap file name file_name = f'mouse_{mouse}_session_{session}_v{alignment_v}' output_mmap_file_path = os.environ['DATA_DIR'] + f'data/interim/alignment/main/{file_name}.mmap' try: df.reset_index()[['session','trial', 'is_rest']].set_index(['session','trial', 'is_rest'], verify_integrity=True) except ValueError: logging.error('You passed multiple of the same trial in the dataframe df') return df output = { 'meta': { 'analysis': { 'analyst': os.environ['ANALYST'], 'date': datetime.datetime.today().strftime("%m-%d-%Y"), 'time': datetime.datetime.today().strftime("%H:%M:%S") }, 'duration': {} } } # Get necessary parameters motion_correction_parameters_list = [] motion_correction_output_list = [] input_mmap_file_list = [] trial_index_list = [] x_ = [] _x = [] y_ = [] _y = [] for idx, row in df.iterrows(): motion_correction_parameters_list.append(eval(row.loc['motion_correction_parameters'])) motion_correction_output = eval(row.loc['motion_correction_output']) motion_correction_output_list.append(motion_correction_output) input_mmap_file_list.append(motion_correction_output['main']) trial_index_list.append(db.get_trial_name(idx[2], idx[3])) [x1,x2,y1,y2] = motion_correction_output['meta']['cropping_points'] x_.append(x1) _x.append(x2) y_.append(y1) _y.append(y2) new_x1 = max(x_) new_x2 = max(_x) new_y1 = max(y_) new_y2 = max(_y) m_list = [] for i in range(len(input_mmap_file_list)): m = cm.load(input_mmap_file_list[i]) motion_correction_output = eval(df.iloc[i].loc['motion_correction_output']) [x1,x2,y1,y2] = motion_correction_output['meta']['cropping_points'] m = m.crop(new_x1 - x1, new_x2 - x2, new_y1 - y1, new_y2 - y2, 0, 0) m_list.append(m) # Concatenate them using the concat function m_concat = cm.concatenate(m_list, axis=0) data_dir = os.environ['DATA_DIR'] + 'data/interim/alignment/main/' file_name = db.create_file_name(step_index, index) fname= m_concat.save(data_dir + file_name + '.mmap', order='C') #meta_pkl_dict['pw_rigid']['cropping_points'] = [x_, _x, y_, _y] #output['meta']['cropping_points'] = [x_, _x, y_, _y] # Save the movie #fname_tot_els = m_els.save(data_dir + 'main/' + file_name + '_els' + '.mmap', order='C') #logging.info(f'{index} Cropped and saved rigid movie as {fname_tot_els}') # MOTION CORRECTING EACH INDIVIDUAL MOVIE WITH RESPECT TO A TEMPLATE MADE OF THE FIRST MOVIE logging.info(f'{alignment_index} Performing motion correction on all movies with respect to a template made of \ the first movie.') t0 = datetime.datetime.today() # Create a template of the first movie template_index = trial_index_list.index(parameters['make_template_from_trial']) m0 = cm.load(input_mmap_file_list[template_index ]) [x1, x2, y1, y2] = motion_correction_output_list[template_index]['meta']['cropping_points'] m0 = m0.crop(new_x1 - x1, new_x2 - x2, new_y1 - y1, new_y2 - y2, 0, 0) m0_filt = cm.movie( np.array([high_pass_filter_space(m_, parameters['gSig_filt']) for m_ in m0])) template0 = cm.motion_correction.bin_median( m0_filt.motion_correct(5, 5, template=None)[0]) # may be improved in the future # Setting the parameters opts = params.CNMFParams(params_dict=parameters) # Create a motion correction object mc = MotionCorrect(fname, dview=dview, **opts.get_group('motion')) # Perform non-rigid motion correction mc.motion_correct(template=template0, save_movie=True) # Cropping borders x_ = math.ceil(abs(np.array(mc.shifts_rig)[:, 1].max()) if np.array(mc.shifts_rig)[:, 1].max() > 0 else 0) _x = math.ceil(abs(np.array(mc.shifts_rig)[:, 1].min()) if np.array(mc.shifts_rig)[:, 1].min() < 0 else 0) y_ = math.ceil(abs(np.array(mc.shifts_rig)[:, 0].max()) if np.array(mc.shifts_rig)[:, 0].max() > 0 else 0) _y = math.ceil(abs(np.array(mc.shifts_rig)[:, 0].min()) if np.array(mc.shifts_rig)[:, 0].min() < 0 else 0) # Load the motion corrected movie into memory movie= cm.load(mc.fname_tot_rig[0]) # Crop all movies to those border pixels movie.crop(x_, _x, y_, _y, 0, 0) output['meta']['cropping_points'] = [x_, _x, y_, _y] #save motion corrected and cropped movie output_mmap_file_path_tot = movie.save(data_dir + file_name + '.mmap', order='C') logging.info(f'{index} Cropped and saved rigid movie as {output_mmap_file_path_tot}') # Save the path in teh output dictionary output['main'] = output_mmap_file_path_tot # Remove the remaining non-cropped movie os.remove(mc.fname_tot_rig[0]) # Create a timeline and store it timeline = [[trial_index_list[0], 0]] timepoints = [0] for i in range(1, len(m_list)): m = m_list[i] timeline.append([trial_index_list[i], timeline[i - 1][1] + m.shape[0]]) timepoints.append(timepoints[i-1]+ m.shape[0]) timeline_pkl_file_path = os.environ['DATA_DIR'] + f'data/interim/alignment/meta/timeline/{file_name}.pkl' with open(timeline_pkl_file_path,'wb') as f: pickle.dump(timeline,f) output['meta']['timeline'] = timeline_pkl_file_path timepoints.append(movie.shape[0]) dt = int((datetime.datetime.today() - t0).seconds / 60) # timedelta in minutes output['meta']['duration']['concatenation'] = dt logging.info(f'{alignment_index} Performed concatenation. dt = {dt} min.') for idx, row in df.iterrows(): df.loc[idx, 'alignment_output'] = str(output) df.loc[idx, 'alignment_parameters'] = str(parameters) ## modify all motion correction file to the aligned version data_dir = os.environ['DATA_DIR'] + 'data/interim/motion_correction/main/' for i in range(len(input_mmap_file_list)): row = df.iloc[i].copy() motion_correction_output_list.append(motion_correction_output) aligned_movie = movie[timepoints[i]:timepoints[i+1]] file_name = db.create_file_name(2, selected_rows.iloc[i].name) motion_correction_output_aligned = aligned_movie.save(data_dir + file_name + '_els' + '.mmap', order='C') new_output= {'main' : motion_correction_output_aligned } new_dict = eval(row['motion_correction_output']) new_dict.update(new_output) row['motion_correction_output'] = str(new_dict) df = db.append_to_or_merge_with_states_df(df, row) # # Delete the motion corrected movies # for fname in mc.fname_tot_rig: # os.remove(fname) return df
def main(): pass # For compatibility between running under Spyder and the CLI #%% Select file(s) to be processed (download if not present) root = '/Users/hheiser/Desktop/testing data/chronic_M2N3/0d_baseline/channel1' fnames = [r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M22\20191208\N1\1\file_00003.tif', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M22\20191208\N1\2\file_00004.tif', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M22\20191208\N1\3\file_00005.tif', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M22\20191208\N1\4\file_00006.tif', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M22\20191208\N1\5\file_00007.tif', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M22\20191208\N1\6\file_00008.tif'] fnames = ['Sue_2x_3000_40_-46.tif'] # filename to be processed if fnames[0] in ['Sue_2x_3000_40_-46.tif', 'demoMovie.tif']: fnames = [download_demo(fnames[0])] #%% First setup some parameters for data and motion correction # dataset dependent parameters fr = 30 # imaging rate in frames per second decay_time = 0.4 # length of a typical transient in seconds dxy = (2., 2.) # spatial resolution in x and y in (um per pixel) # note the lower than usual spatial resolution here max_shift_um = (12., 12.) # maximum shift in um patch_motion_um = (100., 100.) # patch size for non-rigid correction in um # motion correction parameters pw_rigid = True # flag to select rigid vs pw_rigid motion correction # maximum allowed rigid shift in pixels max_shifts = [int(a/b) for a, b in zip(max_shift_um, dxy)] # start a new patch for pw-rigid motion correction every x pixels strides = tuple([int(a/b) for a, b in zip(patch_motion_um, dxy)]) # overlap between pathes (size of patch in pixels: strides+overlaps) overlaps = (24, 24) # maximum deviation allowed for patch with respect to rigid shifts max_deviation_rigid = 3 mc_dict = { 'fnames': fnames, 'fr': fr, 'decay_time': decay_time, 'dxy': dxy, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': 'copy' } opts = params.CNMFParams(params_dict=mc_dict) #%% play the movie (optional) # playing the movie using opencv. It requires loading the movie in memory. # To close the video press q display_images = True if display_images: m_orig = cm.load_movie_chain(fnames) ds_ratio = 0.2 moviehandle = m_orig.resize(1, 1, ds_ratio) moviehandle.play(q_max=99.5, fr=30, magnification=1, do_loop=False) #%% start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) #%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # note that the file is not loaded in memory #%% Run (piecewise-rigid motion) correction using NoRMCorre mc.motion_correct(save_movie=True) #%% compare with original movie if display_images: m_orig = cm.load_movie_chain(fnames[:3]) m_els = cm.load(mmap_file[:3]) ds_ratio = 0.2 moviehandle = cm.concatenate([m_orig.resize(1, 1, ds_ratio) - mc.min_mov*mc.nonneg_movie, m_els.resize(1, 1, ds_ratio)], axis=2) moviehandle.play(fr=15, q_max=99.5, magnification=2) # press q to exit #%% MEMORY MAPPING border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries mmap_file = [r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M19\20191219\N2\1\file_00001_els__d1_512_d2_512_d3_1_order_F_frames_1147_.mmap', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M19\20191219\N2\2\file_00002_els__d1_512_d2_512_d3_1_order_F_frames_2520_.mmap', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M19\20191219\N2\3\file_00003_els__d1_512_d2_512_d3_1_order_F_frames_3814_.mmap', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M19\20191219\N2\4\file_00004_els__d1_512_d2_512_d3_1_order_F_frames_5154_.mmap', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M19\20191219\N2\5\file_00005_els__d1_512_d2_512_d3_1_order_F_frames_2677_.mmap', r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch2\M19\20191219\N2\6\file_00006_els__d1_512_d2_512_d3_1_order_F_frames_3685_.mmap'] fname_new = r'E:\PhD\Data\DG\M14_20191014\N1\memmap__d1_512_d2_512_d3_1_order_C_frames_34939_.mmap' # memory map the file in order 'C' fname_new = cm.save_memmap(mc.mmap_file, base_name='memmap_', order='C', border_to_0=0) # exclude borders # now load the file Yr, dims, T = cm.load_memmap(fname_new) images = np.reshape(Yr.T, [T] + list(dims), order='F') # load frames in python format (T x X x Y) #%% restart cluster to clean up memory cm.stop_server(dview=dview) c, dview, n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) #%% parameters for source extraction and deconvolution p = 1 # order of the autoregressive system gnb = 2 # number of global background components merge_thr = 0.85 # merging threshold, max correlation allowed rf = 15 # half-size of the patches in pixels. e.g., if rf=25, patches are 50x50 stride_cnmf = 6 # amount of overlap between the patches in pixels K = 4 # number of components per patch gSig = [4, 4] # expected half size of neurons in pixels # initialization method (if analyzing dendritic data using 'sparse_nmf') method_init = 'greedy_roi' ssub = 2 # spatial subsampling during initialization tsub = 2 # temporal subsampling during intialization # parameters for component evaluation opts_dict = {'fnames': fnames, 'fr': fr, 'nb': gnb, 'rf': rf, 'K': K, 'gSig': gSig, 'stride': stride_cnmf, 'method_init': method_init, 'rolling_sum': True, 'merge_thr': merge_thr, 'n_processes': n_processes, 'only_init': True, 'ssub': ssub, 'tsub': tsub} opts.change_params(params_dict=opts_dict) #%% RUN CNMF ON PATCHES # First extract spatial and temporal components on patches and combine them # for this step deconvolution is turned off (p=0) #opts.change_params({'p': 1,'rf':None, 'only_init':False}) opts.change_params({'p': 0}) cnm = cnmf.CNMF(n_processes, params=opts, dview=dview) cnm = cnm.fit(images) #%% RUN CNMF SEEDED WITH MANUAL MASK # load mask mask = np.asarray(imageio.imread('/Users/hheiser/Desktop/testing data/file_00020_no_motion/avg_mask_fixed.png'), dtype=bool) # get component ROIs from the mask and plot them Ain, labels, mR = cm.base.rois.extract_binary_masks(mask) # plot original mask and extracted labels to check mask fig, ax = plt.subplots(1,2) ax[0].imshow(-mR,cmap='binary') ax[0].set_title('Original mask') ax[1].imshow(labels) ax[1].set_title('Extracted labelled ROIs') """" plt.figure() crd = cm.utils.visualization.plot_contours( Ain.astype('float32'), mR, thr=0.99, display_numbers=True) # todo check if this is important for the pipeline plt.title('Contour plots of detected ROIs in the structural channel') """ opts.change_params({'rf': None, 'only_init': False}) # run CNMF seeded with this mask cnm_corr = cnmf.CNMF(n_processes, params=opts, dview=dview, Ain=Ain) cnm_corr_seed = cnm_corr_seed.fit(images) #cnm_seed = cnm_seed.fit_file(motion_correct=False) #%% ALTERNATE WAY TO RUN THE PIPELINE AT ONCE # you can also perform the motion correction plus cnmf fitting steps # simultaneously after defining your parameters object using # cnm1 = cnmf.CNMF(n_processes, params=opts, dview=dview) # cnm1.fit_file(motion_correct=True) #%% plot contours of found components Cn = cm.local_correlations(images, swap_dim=False) Cn[np.isnan(Cn)] = 0 cnm.estimates.plot_contours(img=Cn) plt.title('Contour plots of found components') #%% RE-RUN seeded CNMF on accepted patches to refine and perform deconvolution cnm.params.change_params({'p': p}) cnm2 = cnm.refit(images, dview=dview) #%% COMPONENT EVALUATION # the components are evaluated in three ways: # a) the shape of each component must be correlated with the data # b) a minimum peak SNR is required over the length of a transient # c) each shape passes a CNN based classifier min_SNR = 2 # signal to noise ratio for accepting a component rval_thr = 0.85 # space correlation threshold for accepting a component cnn_thr = 0.99 # threshold for CNN based classifier cnn_lowest = 0.1 # neurons with cnn probability lower than this value are rejected cnm2.params.set('quality', {'decay_time': decay_time, 'min_SNR': min_SNR, 'rval_thr': rval_thr, 'use_cnn': True, 'min_cnn_thr': cnn_thr, 'cnn_lowest': cnn_lowest}) cnm2.estimates.evaluate_components(images, params=cnm2.params, dview=dview) #%% PLOT COMPONENTS cnm2.estimates.plot_contours(img=Cn, idx=cnm2.estimates.idx_components) #%% VIEW TRACES (accepted and rejected) if display_images: cnm2.estimates.view_components(images, img=Cn, idx=cnm2.estimates.idx_components) cnm2.estimates.view_components(images, img=Cn, idx=cnm2.estimates.idx_components_bad) #%% update object with selected components #### -> will delete rejected components! cnm2.estimates.select_components(use_object=True) #%% Extract DF/F values cnm2.estimates.detrend_df_f(quantileMin=8, frames_window=250) #%% Show final traces cnm2.estimates.view_components(img=Cn) #%% reconstruct denoised movie (press q to exit) if display_images: cnm2.estimates.play_movie(images, q_max=99.9, gain_res=2, magnification=1, bpx=border_to_0, include_bck=True) # background not shown #%% STOP CLUSTER and clean up log files cm.stop_server(dview=dview) log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file) #%% save results dirname = fnames[0][:-4] + "_results.hdf5" cnm2.estimates.Cn = Cn cnm2.save(dirname) #load results cnm2 = cnmf.load_CNMF(dirname) mov_name = fnames[0][:-4] + "_movie_restored_2_gain.tif" helper.save_movie(cnm2.estimates,images,mov_name,frame_range=range(200),include_bck=True)
def test_computational_performance(fnames, path_ROIs, n_processes): import os import cv2 import glob import logging import matplotlib.pyplot as plt import numpy as np import tensorflow as tf import h5py from time import time try: cv2.setNumThreads(0) except: pass try: if __IPYTHON__: # this is used for debugging purposes only. allows to reload classes # when changed get_ipython().magic('load_ext autoreload') get_ipython().magic('autoreload 2') except NameError: pass import caiman as cm from caiman.motion_correction import MotionCorrect from caiman.utils.utils import download_demo, download_model from caiman.source_extraction.volpy.volparams import volparams from caiman.source_extraction.volpy.volpy import VOLPY from caiman.source_extraction.volpy.mrcnn import visualize, neurons import caiman.source_extraction.volpy.mrcnn.model as modellib from caiman.paths import caiman_datadir from caiman.summary_images import local_correlations_movie_offline from caiman.summary_images import mean_image from caiman.source_extraction.volpy.utils import quick_annotation from multiprocessing import Pool time_start = time() print('Start MOTION CORRECTION') # %% Load demo movie and ROIs fnames = fnames path_ROIs = path_ROIs #%% dataset dependent parameters # dataset dependent parameters fr = 400 # sample rate of the movie # motion correction parameters pw_rigid = False # flag for pw-rigid motion correction gSig_filt = (3, 3) # size of filter, in general gSig (see below), # change this one if algorithm does not work max_shifts = (5, 5) # maximum allowed rigid shift strides = ( 48, 48 ) # start a new patch for pw-rigid motion correction every x pixels overlaps = (24, 24 ) # overlap between pathes (size of patch strides+overlaps) max_deviation_rigid = 3 # maximum deviation allowed for patch with respect to rigid shifts border_nan = 'copy' opts_dict = { 'fnames': fnames, 'fr': fr, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = volparams(params_dict=opts_dict) # %% start a cluster for parallel processing dview = Pool(n_processes) #dview = None # %%% MOTION CORRECTION # first we create a motion correction object with the specified parameters mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) # Run correction mc.motion_correct(save_movie=True) time_mc = time() - time_start print(time_mc) print('START MEMORY MAPPING') # %% restart cluster to clean up memory dview.terminate() dview = Pool(n_processes) # %% MEMORY MAPPING border_to_0 = 0 if mc.border_nan == 'copy' else mc.border_to_0 # you can include the boundaries of the FOV if you used the 'copy' option # during motion correction, although be careful about the components near # the boundaries # memory map the file in order 'C' fname_new = cm.save_memmap_join(mc.mmap_file, base_name='memmap_', add_to_mov=border_to_0, dview=dview, n_chunks=1000) # exclude border time_mmap = time() - time_start - time_mc print('Start Segmentation') # %% SEGMENTATION # create summary images img = mean_image(mc.mmap_file[0], window=1000, dview=dview) img = (img - np.mean(img)) / np.std(img) Cn = local_correlations_movie_offline(mc.mmap_file[0], fr=fr, window=1500, stride=1500, winSize_baseline=400, remove_baseline=True, dview=dview).max(axis=0) img_corr = (Cn - np.mean(Cn)) / np.std(Cn) summary_image = np.stack([img, img, img_corr], axis=2).astype(np.float32) #%% three methods for segmentation methods_list = [ 'manual_annotation', # manual annotation needs user to prepare annotated datasets same format as demo ROIs 'quick_annotation', # quick annotation annotates data with simple interface in python 'maskrcnn' ] # maskrcnn is a convolutional network trained for finding neurons using summary images method = methods_list[0] if method == 'manual_annotation': with h5py.File(path_ROIs, 'r') as fl: ROIs = fl['mov'][()] # load ROIs elif method == 'quick_annotation': ROIs = quick_annotation(img_corr, min_radius=4, max_radius=10) elif method == 'maskrcnn': config = neurons.NeuronsConfig() class InferenceConfig(config.__class__): # Run detection on one image at a time GPU_COUNT = 1 IMAGES_PER_GPU = 1 DETECTION_MIN_CONFIDENCE = 0.7 IMAGE_RESIZE_MODE = "pad64" IMAGE_MAX_DIM = 512 RPN_NMS_THRESHOLD = 0.7 POST_NMS_ROIS_INFERENCE = 1000 config = InferenceConfig() config.display() model_dir = os.path.join(caiman_datadir(), 'model') DEVICE = "/cpu:0" # /cpu:0 or /gpu:0 with tf.device(DEVICE): model = modellib.MaskRCNN(mode="inference", model_dir=model_dir, config=config) weights_path = download_model('mask_rcnn') model.load_weights(weights_path, by_name=True) results = model.detect([summary_image], verbose=1) r = results[0] ROIs = r['masks'].transpose([2, 0, 1]) display_result = False if display_result: _, ax = plt.subplots(1, 1, figsize=(16, 16)) visualize.display_instances(summary_image, r['rois'], r['masks'], r['class_ids'], ['BG', 'neurons'], r['scores'], ax=ax, title="Predictions") time_seg = time() - time_mmap - time_mc - time_start print('Start SPIKE EXTRACTION') # %% restart cluster to clean up memory dview.terminate() dview = Pool(n_processes, maxtasksperchild=1) # %% parameters for trace denoising and spike extraction fnames = fname_new # change file ROIs = ROIs # region of interests index = list(range(len(ROIs))) # index of neurons weights = None # reuse spatial weights tau_lp = 5 # parameter for high-pass filter to remove photobleaching threshold = 4 # threshold for finding spikes, increase threshold to find less spikes contextSize = 35 # number of pixels surrounding the ROI to censor from the background PCA flip_signal = True # Important! Flip signal or not, True for Voltron indicator, False for others opts_dict = { 'fnames': fnames, 'ROIs': ROIs, 'index': index, 'weights': weights, 'tau_lp': tau_lp, 'threshold': threshold, 'contextSize': contextSize, 'flip_signal': flip_signal } opts.change_params(params_dict=opts_dict) #%% Trace Denoising and Spike Extraction vpy = VOLPY(n_processes=n_processes, dview=dview, params=opts) vpy.fit(n_processes=n_processes, dview=dview) # %% STOP CLUSTER and clean up log files #dview.terminate() log_files = glob.glob('*_LOG_*') for log_file in log_files: os.remove(log_file) time_ext = time() - time_mmap - time_mc - time_start - time_seg #%% print('file:' + fnames) print('number of processes' + str(n_processes)) print(time_mc) print(time_mmap) print(time_seg) print(time_ext) time_list = [time_mc, time_mmap, time_seg, time_ext] return time_list
def motion_correct( self, fname: str, co_fname: str) -> Tuple[np.ndarray, dict, Optional[np.ndarray]]: """ Uses caiman non-rigid motion correction to remove/reduce motion artefacts Note: ALways saves an intermediate mem-map representation in order C of the corrected 32-bit stack :param fname: The filename of the source file :param co_fname: Filename of a stack that should be co-aligned or None :return: [0]: Corrected stack as a memmap [1]: Wrapped CaImAn parameter dictionary [2]: Corrected co-stack as a memmap or None """ cont_folder = path.dirname(fname) # the containing folder stack_name = path.split(fname)[1] save_dir = cont_folder + f"/{self.ana_dir}" if not path.exists(save_dir): makedirs(save_dir) print("Created analysis directory", flush=True) out_name = save_dir + '/' + stack_name if co_fname is not None: co_stack_name = path.split(co_fname)[1] co_out_name = save_dir + '/' + co_stack_name else: co_out_name = None test_image = imread( fname, key=0) # load first frame of stack to compute resolution assert test_image.shape[0] == test_image.shape[1] resolution = self.fov_um / test_image.shape[0] fr = 1 / self.time_per_frame # frame-rate dxy = (resolution, resolution) # spatial resolution in um/pixel max_shift_um = (self.neuron_radius * 4, self.neuron_radius * 4 ) # maximally allow shift by ~2 cell diameters # maximum allowed rigid shift in pixels max_shifts = [int(a / b) for a, b in zip(max_shift_um, dxy)] # start a new patch for pw-rigid motion correction every x pixels strides = tuple( [int(a / b) for a, b in zip(self.patch_motion_um, dxy)]) # overlap between patches (size of patch in pixels: strides+overlaps) overlaps = (24, 24) # maximum deviation allowed for patch with respect to rigid shifts (unit unclear - likely pixels as it is int) max_deviation_rigid = 3 # create parameter dictionary mc_dict = { 'fnames': [fname], 'fr': fr, 'decay_time': self.decay_time, 'dxy': dxy, 'pw_rigid': self.pw_rigid, 'max_shifts': max_shifts, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': 'copy' } opts = params.CNMFParams(params_dict=mc_dict) # start a cluster for parallel processing c, dview, n_processes = cm.cluster.setup_cluster(backend='local', n_processes=None, single_thread=False) try: # motion correction mc = MotionCorrect(fname, dview=dview, **opts.get_group('motion')) # Run (piecewise-rigid motion) correction using NoRMCorre # if we don't save the movie into a memmap, there doesn't seem to be # any possibility to get at the corrected data later??? mc.motion_correct(save_movie=True) # memory mapping border_to_0 = 0 if mc.border_nan is 'copy' else mc.border_to_0 # memory map the file in order 'C' fname_new = cm.save_memmap(mc.mmap_file, base_name=out_name, order='C', border_to_0=border_to_0) # delete the original mem-map if mc.fname_tot_els is None: [remove(fn) for fn in mc.fname_tot_rig] else: [remove(fn) for fn in mc.fname_tot_els] # now load the new file and transform output into [z,y,x] stack yr, dims, n_t = cm.load_memmap(fname_new) images = np.reshape(yr.T, [n_t] + list(dims), order='F') if self.save_projection: # save anatomical projection as 16bit tif anat_projection = images.copy() anat_projection = np.sum(anat_projection, 0) anat_projection -= np.min(anat_projection) anat_projection /= np.max(anat_projection) anat_projection *= (2**16 - 1) anat_projection[anat_projection < 0] = 0 anat_projection[anat_projection > (2**16 - 1)] = (2**16 - 1) anat_projection = anat_projection.astype(np.uint16) imsave(out_name, anat_projection, imagej=True, resolution=(1 / dxy[0], 1 / dxy[1]), metadata={ 'axes': 'YX', 'unit': 'um' }) # Repeat for the co-stack if present if co_fname is not None: co_aligned_images = np.array(mc.apply_shifts_movie(co_fname)) if self.save_projection: # save anatomical projection as 16bit tif anat_projection = np.sum(co_aligned_images, 0) anat_projection -= np.min(anat_projection) anat_projection /= np.max(anat_projection) anat_projection *= (2**16 - 1) anat_projection[anat_projection < 0] = 0 anat_projection[anat_projection > (2**16 - 1)] = (2**16 - 1) anat_projection = anat_projection.astype(np.uint16) imsave(co_out_name, anat_projection, imagej=True, resolution=(1 / dxy[0], 1 / dxy[1]), metadata={ 'axes': 'YX', 'unit': 'um' }) else: co_aligned_images = None finally: cm.stop_server(dview=dview) return images, {"Motion Correction": mc_dict}, co_aligned_images
'decay_time': decay_time, 'pw_rigid': pw_rigid, 'max_shifts': max_shifts, 'gSig_filt': gSig_filt, 'strides': strides, 'overlaps': overlaps, 'max_deviation_rigid': max_deviation_rigid, 'border_nan': border_nan } opts = params.CNMFParams(params_dict=mc_dict) if motion_correct: # do motion correction rigid mc = MotionCorrect(fnames, dview=dview, **opts.get_group('motion')) mc.motion_correct(save_movie=True) fname_mc = mc.fname_tot_els if pw_rigid else mc.fname_tot_rig if pw_rigid: bord_px = np.ceil(np.maximum(np.max(np.abs(mc.x_shifts_els)), np.max(np.abs(mc.y_shifts_els)))).astype(np.int) else: bord_px = np.ceil(np.max(np.abs(mc.shifts_rig))).astype(np.int) plt.subplot(1, 2, 1); plt.imshow(mc.total_template_rig) # % plot template plt.subplot(1, 2, 2); plt.plot(mc.shifts_rig) # % plot rigid shifts plt.legend(['x shifts', 'y shifts']) plt.xlabel('frames') plt.ylabel('pixels');plt.savefig(newpath + r'/' + "shift.pdf",edgecolor='w',format='pdf',transparent=True) bord_px = 0 if border_nan is 'copy' else bord_px fname_new = cm.save_memmap(fname_mc, base_name='memmap_', order='C', border_to_0=bord_px)
class MakeMasks3D: def __init__(self, mc_opts, tiff, channels, planes, x_start, x_end): self.tiff = tiff self.channels = channels self.planes = planes self.x_start = x_start self.x_end = x_end self.xslice = slice(x_start, x_end) self.mc_opts = mc_opts self.opts = params.CNMFParams(params_dict=mc_opts) self.c, self.dview, self.n_processes = cm.cluster.setup_cluster( backend='local', n_processes=None, single_thread=False) self.file_list = [] self.images = [] self.motion_corrected_images = [] self.masks = [] def crop_tiffs(self): self.images = [] self.file_list = [] for plane in list(range(self.planes)): time_slice = slice(plane * self.channels + 1, -1, self.channels * self.planes) with ScanImageTiffReader(self.tiff) as reader: data = reader.data() data = data[time_slice, :, self.xslice] self.images.append(data) tif_name = self.tiff.split('.')[0] + '_template_plane' + str( plane) + '.tif' self.file_list.append(tif_name) tifffile.imsave(tif_name, data) def view_planes(self): fig, axes = plt.subplots(1, self.planes, constrained_layout=True) for i, ax in enumerate(axes): image = self.images[i].mean(axis=0) ax.imshow(image) ax.set_aspect('equal', 'box') ax.axis('off') ax.set_title(f'Plane {i}') fig.suptitle('Original') def view_corrected(self): fig, axes = plt.subplots(1, self.planes, constrained_layout=True) for i, ax in enumerate(axes): image = self.motion_corrected_images[i] ax.imshow(image) ax.set_aspect('equal', 'box') ax.axis('off') ax.set_title(f'Plane {i}') fig.suptitle('Corrected') # def view_sources(self): # if len(self.motion_corrected_images) > 0: # image_source = self.motion_corrected_images[0] # else: # image_source = self.images[0] # cm.utils.visualization.nb_plot_contour(image_source, self.masks[0].astype('float32'), # image_source.shape[0], image_source.shape[1]) def motion_correct_red(self): self.motion_corrected_images = [] for plane in list(range(self.planes)): print(f'Starting motion correction plane {plane}') self.mc = MotionCorrect(self.file_list[plane], dview=self.dview, **self.opts.get_group('motion')) self.mc.motion_correct() self.motion_corrected_images.append(self.mc.total_template_els) def extract_masks(self, radius=7): self.masks = [] if len(self.motion_corrected_images) > 0: image_source = self.motion_corrected_images else: image_source = self.images for plane in list(range(self.planes)): self.masks.append( cm.base.rois.extract_binary_masks_from_structural_channel( image_source[plane])[0]) def run(self): self.crop_tiffs() self.motion_correct_red()