├── .gitignore ├── 3D ├── buildcmap.m ├── demo_3D.m ├── gradientgen.m ├── plot4Dproj.m ├── plotCenteroverY.m └── plot_components_3D_GUI.m ├── @CNMF └── CNMF.m ├── CNMFSetParms.m ├── ISSUE_TEMPLATE.md ├── Initialization.fig ├── Initialization.m ├── README.md ├── Sources2D ├── Sources2D.m ├── displayNeurons.m ├── downSample.m ├── initComponents_endoscope.m ├── quickMerge.m ├── upSample.m ├── updateBG.m ├── updateSpatial_endoscope.m ├── updateTemporal_endoscope.m └── viewNeurons.m ├── TODO.txt ├── constrained_foopsi.m ├── deconvolution ├── MCMC │ ├── .gitignore │ ├── README.md │ ├── cont_ca_sampler.m │ ├── license.txt │ ├── plot_continuous_samples.m │ ├── sampling_demo_ar2.m │ ├── utilities │ │ ├── HMC_exact2.m │ │ ├── addSpike.m │ │ ├── get_initial_sample.m │ │ ├── get_next_spikes.m │ │ ├── lambda_rate.m │ │ ├── make_G_matrix.m │ │ ├── make_mean_sample.m │ │ ├── plot_marginals.m │ │ ├── removeSpike.m │ │ ├── replaceSpike.m │ │ ├── samples_cell2mat.m │ │ ├── tau_c2d.m │ │ └── tau_d2c.m │ └── wrapper.m ├── deconvolveCa.m ├── examples │ ├── ar1_constrained_foopsi.m │ ├── ar1_foopsi.m │ ├── ar1_mcmc.m │ ├── ar1_thresholded_foopsi.m │ ├── ar2_foopsi.m │ ├── ar2_mcmc.m │ ├── ar2_thresholded_foopsi.m │ ├── foopsi_kernel.m │ ├── foopsi_onnls.m │ ├── kernel_foopsi.m │ ├── kernel_thresholded_foopsi.m │ ├── show_results.m │ └── test_all.m ├── functions │ ├── GetSn.m │ ├── ar2exp.m │ ├── constrained_foopsi_cvx.m │ ├── estimate_parameters.m │ ├── estimate_time_constant.m │ ├── exp2ar.m │ ├── exp2kernel.m │ ├── foopsi.m │ ├── gen_data.m │ ├── gen_sinusoidal_data.m │ └── init_fig.m └── oasis │ ├── choose_lambda.m │ ├── constrained_oasisAR1.m │ ├── constrained_oasisAR2.m │ ├── create_kernel.m │ ├── deconvCa.m │ ├── dsKernel.m │ ├── foopsi_oasisAR1.m │ ├── foopsi_oasisAR2.m │ ├── oasisAR1.m │ ├── oasisAR2.m │ ├── onnls.m │ ├── test_oasis.m │ ├── thresholded_nnls.m │ ├── thresholded_oasisAR1.m │ ├── thresholded_oasisAR2.m │ ├── update_g.m │ ├── update_kernel_exp2.m │ └── update_lam.m ├── demoMovie.tif ├── demo_GUI.m ├── demo_patches.m ├── demo_patches_class.m ├── demo_script.m ├── demo_script_class.m ├── docs └── notes │ └── ROI_GUI_info.txt ├── documentation.pdf ├── endoscope ├── bsplineM.m ├── cnmfe_scripts │ ├── cnmfe_choose_data.m │ ├── cnmfe_demix_video.m │ ├── cnmfe_full.m │ ├── cnmfe_load_data.m │ ├── cnmfe_quick_merge.m │ ├── cnmfe_save_video.m │ ├── cnmfe_show_corr_pnr.m │ └── cnmfe_update_BG.m ├── correlation_image_endoscope.m ├── deconv_temporal.m ├── demos │ ├── data_endoscope.tif │ └── demo_endoscope.m ├── demosdata_endoscope_results.avi ├── detrend_data.m ├── dsData.m ├── extract_ac.m ├── greedyROI_endoscope.m ├── lle.m ├── local_background.m ├── nnls_spatial.m ├── nnls_spatial_thresh.m ├── remove_baseline.m ├── savegcf.m ├── struct2neuron.m ├── svdsecon.m ├── tif2mat.m ├── update_spatial_components_nb.m ├── update_temporal_components_nb.m └── writeTiff.m ├── estimate_percentile_level.m ├── initialize_components.m ├── license.txt ├── loadtiff.m ├── merge_components.m ├── postProcessCNMF.m ├── preprocess_data.m ├── read_file.m ├── register_ROIs.m ├── run_CNMF_patches.m ├── run_pipeline.m ├── tests └── TestRunCNMFPatches.m ├── update_spatial_components.m ├── update_temporal_components.m ├── update_temporal_components_fast.m ├── use_cases ├── 2016_CSHL_Imaging │ ├── demo_dendritic.m │ └── demo_somatic.m ├── 2017_CSHL_NeuralDataScience │ ├── demo_CSHL2017_SueAnn.m │ ├── demo_CSHL2017_neurofinder0200.m │ └── demo_SueAnn.mlx ├── 2017_CajalCourse │ └── demo_CajalCourse_2017.m └── outdated │ └── live scripts │ ├── demo_pipeline.mlx │ └── demo_script.mlx └── utilities ├── GUI ├── Initialization.fig ├── Initialization.m ├── untitled.fig └── untitled.m ├── GetSn.m ├── HALS.m ├── HALS_2d.m ├── HALS_initialization.m ├── HALS_spatial.m ├── HALS_temporal.m ├── Hungarian.m ├── MCEM_foopsi.m ├── ROI_GUI.fig ├── ROI_GUI.m ├── assign.m ├── bigread2.m ├── cell2str.m ├── classify_comp_corr.m ├── classify_components.m ├── classify_components_pixels.m ├── cnn_classifier.m ├── com.m ├── compute_event_exceptionality.m ├── compute_residuals.m ├── convert_file.m ├── correlation_image.m ├── correlation_image_3D.m ├── correlation_image_max.m ├── cvx_foopsi.m ├── determine_search_location.m ├── determine_search_location_old.m ├── detrend_df_f.m ├── detrend_df_f_auto.m ├── downsample_data.m ├── extract_DF_F.m ├── extract_DF_F_new.m ├── extract_DF_F_old.m ├── extract_DF_F_test.m ├── extract_max_activity.m ├── extract_patch.m ├── fast_nmf.m ├── find_unsaturatedPixels.m ├── get_noise_fft.m ├── graph_conn_comp_mex.cpp ├── graph_conn_comp_mex.mexa64 ├── graph_conn_comp_mex.mexmaci64 ├── graph_conn_comp_mex.mexw64 ├── graph_connected_comp.m ├── greedyROI.m ├── greedyROI_corr.m ├── gui_components.m ├── interp_missing_data.m ├── kde.m ├── kmeans_pp.m ├── lagrangian_foopsi_temporal.m ├── lars_regression_noise.m ├── make_G_matrix.m ├── make_dendritic_video.m ├── make_patch_video.m ├── manually_refine_components.m ├── memmap ├── construct_patches.m ├── memmap_file.m ├── memmap_file_sequence.m └── savefast.m ├── mm_fun.m ├── order_ROIs.m ├── order_components.m ├── patch_to_linear.m ├── plain_foopsi.m ├── play_movie.m ├── plotActivityTrace.m ├── plotROIContour.m ├── plot_components_GUI.m ├── plot_contours.m ├── plot_dend_components_GUI.m ├── prctfilt.m ├── read_file_old.m ├── read_neurofinder.m ├── register_multisession.m ├── run_movie.m ├── running_percentile.m ├── signalExtraction.m ├── sparse_NMF_initialization.m ├── structmerge.m ├── subdir.m ├── threshold_components.m ├── tiff_reader.m ├── trace_fit_extreme.m ├── trace_fit_extreme2.m ├── trace_fit_gaussian.m ├── update_order.m ├── update_order_greedy.m ├── update_spatial_components_old.m ├── update_spatial_lasso.m ├── view_components.m └── write_h5.m /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### specific files ### 4 | CSHL16/dendritic_demo.zip 5 | CSHL16/__MACOSX/._dendritic_demo.tif 6 | CSHL16/dendritic_demo.tif 7 | endoscope/demos/demos_labs/*.* 8 | use_cases/2017_CSHL_NeuralDataScience/demoSue2x.tif 9 | dendritic_demo.tif 10 | 11 | ### folders ### 12 | dev/* 13 | 14 | 15 | ### dev chosen ### 16 | *.gif 17 | *.mat 18 | *.zip 19 | 20 | ### Git ### 21 | *.orig 22 | 23 | ### Linux ### 24 | *~ 25 | 26 | # temporary files which can be created if a process still has a handle open of a deleted file 27 | .fuse_hidden* 28 | 29 | # KDE directory preferences 30 | .directory 31 | 32 | # Linux trash folder which might appear on any partition or disk 33 | .Trash-* 34 | 35 | # .nfs files are created when an open file is removed but is still being accessed 36 | .nfs* 37 | 38 | ### macOS ### 39 | *.DS_Store 40 | .AppleDouble 41 | .LSOverride 42 | 43 | # Icon must end with two \r 44 | Icon 45 | 46 | # Thumbnails 47 | ._* 48 | 49 | # Files that might appear in the root of a volume 50 | .DocumentRevisions-V100 51 | .fseventsd 52 | .Spotlight-V100 53 | .TemporaryItems 54 | .Trashes 55 | .VolumeIcon.icns 56 | .com.apple.timemachine.donotpresent 57 | 58 | # Directories potentially created on remote AFP share 59 | .AppleDB 60 | .AppleDesktop 61 | Network Trash Folder 62 | Temporary Items 63 | .apdisk 64 | 65 | ### Matlab ### 66 | ##--------------------------------------------------- 67 | ## Remove autosaves generated by the Matlab editor 68 | ## We have git for backups! 69 | ##--------------------------------------------------- 70 | 71 | # Windows default autosave extension 72 | *.asv 73 | 74 | # OSX / *nix default autosave extension 75 | *.m~ 76 | 77 | # Compiled MEX binaries (all platforms) 78 | *.mex* 79 | 80 | # Simulink Code Generation 81 | slprj/ 82 | 83 | # Session info 84 | octave-workspace 85 | 86 | # Simulink autosave extension 87 | *.autosave 88 | 89 | ### Windows ### 90 | # Windows thumbnail cache files 91 | Thumbs.db 92 | ehthumbs.db 93 | ehthumbs_vista.db 94 | 95 | # Folder config file 96 | Desktop.ini 97 | 98 | # Recycle Bin used on file shares 99 | $RECYCLE.BIN/ 100 | 101 | # Windows Installer files 102 | *.cab 103 | *.msi 104 | *.msm 105 | *.msp 106 | 107 | # Windows shortcuts 108 | *.lnk 109 | 110 | # End of https://www.gitignore.io/api/git,macos,linux,matlab,windows 111 | demo_script_old.m 112 | 113 | cnn_model.h5 114 | 115 | granule_love2.tif 116 | 117 | motion_corrected.tif 118 | -------------------------------------------------------------------------------- /3D/demo_3D.m: -------------------------------------------------------------------------------- 1 | clear; 2 | %% load file (courtesy of D. Pacheco and M. Murthy, Princeton University) 3 | 4 | addpath(genpath('../../ca_source_extraction')); 5 | nam = 'data3D.mat'; 6 | if ~exist(nam,'file') % download file if it doesn't exist in the directory 7 | url = 'https://www.dropbox.com/s/ii3aji4my1i81n2/data3D.mat?dl=1'; 8 | outfilename = websave(nam,url); 9 | end 10 | 11 | load(nam); 12 | 13 | if ndims(Y) == 4 14 | [d1,d2,d3,T] = size(Y); % dimensions of dataset 15 | else 16 | [d1,d2,T] = size(Y); 17 | d3 = 1; 18 | end 19 | d = d1*d2*d3; % total number of pixels 20 | 21 | %% Set parameters 22 | 23 | K = 200; % number of components to be found 24 | tau = [3,3,2]; % std of gaussian kernel (size of neuron) 25 | p = 0; % order of autoregressive system (p = 0 no dynamics for slow imaging rate) 26 | merge_thr = 0.95; % merging threshold 27 | 28 | options = CNMFSetParms(... 29 | 'd1',d1,'d2',d2,'d3',d3,... % dimensions of datasets 30 | 'search_method','dilate',... % search locations when updating spatial components 31 | 'maxIter',15,... % number of NMF iterations during initialization 32 | 'deconv_method','constrained_foopsi',... % activity deconvolution method 33 | 'temporal_iter',2,... % number of block-coordinate descent steps 34 | 'fudge_factor',0.98,... % bias correction for AR coefficients 35 | 'merge_thr',merge_thr,... % merging threshold 36 | 'gSig',tau,'nb',1 ... 37 | ); 38 | %% Data pre-processing 39 | 40 | [P,Y] = preprocess_data(Y,p); 41 | Cn = correlation_image_3D(Y); % for large datasets change with reshape(P.sn,d1,d2,d3), %max(Y,[],3); %std(Y,[],3); % image statistic (only for display purposes) 42 | 43 | %% show movie of projections 44 | % plot4Dproj(Y, Cn, [d1,d2,d3]); 45 | 46 | %% fast initialization of spatial components using greedyROI and HALS 47 | 48 | [Ain,Cin,bin,fin,center] = initialize_components(Y,K,tau,options,P); % initialize 49 | ff = find(sum(Ain)<1e-3*mean(sum(Ain))); % remove very small components 50 | Ain(:,ff) = []; 51 | Cin(ff,:) = []; 52 | center(ff,:) = []; 53 | 54 | %% display centers of found components 55 | plotCenteroverY(Cn, center, [d1,d2,d3]); % plot found centers against max-projections of background image 56 | 57 | %% update spatial components 58 | Yr = reshape(Y,d,T); 59 | %clear Y; 60 | [A,b,Cin] = update_spatial_components(Yr,Cin,fin,[Ain,bin],P,options); 61 | 62 | %% update temporal components 63 | P.p = 0; 64 | [C,f,P,S,YrA] = update_temporal_components(Yr,A,b,Cin,fin,P,options); 65 | 66 | %% 67 | %[ROIvars.rval_space,ROIvars.rval_time,ROIvars.max_pr,ROIvars.sizeA,keep] = classify_components(Yr,A,C,b,f,YrA,options); 68 | %% plot components 69 | %plot_components_3D_GUI(Y,A,C,b,f,Cn,options) 70 | %% merge found components and repeat (optional) 71 | %[Am,Cm,K_m,merged_ROIs,Pm,Sm] = merge_components(Yr,A,b,C,f,P,S,options); 72 | 73 | %% repeat (optional) 74 | %[A2,b2,Cm] = update_spatial_components(Yr,Cm,f,Am,Pm,options); 75 | %[C2,f2,P2,S2] = update_temporal_components(Yr,A2,b2,Cm,f,Pm,options); 76 | 77 | plot_components_3D_GUI(Y,A,C,b,f,Cn,options); -------------------------------------------------------------------------------- /3D/gradientgen.m: -------------------------------------------------------------------------------- 1 | function colormatrix = gradientgen(cmap2use, ncolors) 2 | if ~exist('cmap2use', 'var') || isempty(cmap2use); cmap2use = []; end 3 | if ~exist('ncolors', 'var') || isempty(ncolors); ncolors = []; end 4 | % uses buildcmap to generate a gradient between given colors 5 | % buildcmap input can be str or vector values 6 | cmaps = {'wr', 'wk', 'wb', 'wg', 'wm', 'wc', 'kr', 'mbg', 'gry'}; % but you can even mix 3 of them 7 | maxc = 180; 8 | if ~isempty(cmap2use) 9 | if isstr(cmap2use) 10 | cmap2use = cmap2use; 11 | else 12 | cmap2use = cmaps{cmap2use}; 13 | end 14 | cmap = buildcmap(cmap2use); 15 | cmap = cmap(round(76:255), :); 16 | if cmap2use == 1 17 | colormatrix = cmap(maxc,:); 18 | else % resampling 19 | colormatrix = interp1(1:maxc,cmap,1:maxc/(ncolors+1):maxc); 20 | colormatrix = colormatrix(1:ncolors,:); 21 | end 22 | else 23 | fprintf('Posible colormaps (') 24 | for i = 1:numel(cmaps); if i ~= numel(cmaps); fprintf([cmaps{i}, ' , ']); else fprintf([cmaps{i}]); end; end 25 | fprintf(') \n') 26 | colormatrix = []; 27 | end -------------------------------------------------------------------------------- /3D/plotCenteroverY.m: -------------------------------------------------------------------------------- 1 | function figH = plotCenteroverY(Y, icenter, sizY, params) 2 | % plotCenteroverY(Y, icenter, sizY, params) 3 | % Displays center or roi's over a XY, YZ and XZ projections of Y. 4 | % inputs: 5 | % Y : background image 2D or 3D matrix (spatial dimensions are 2D or 3D) 6 | % icenter: center or rois kxm (k == number of rois, m == spatial dimensions (2D or 3D)) 7 | % sizY: spatial dimensions of Y or icenter (2D or 3D); 8 | % params: extra parameters that edit the figure fitures 9 | 10 | global pi 11 | pi = []; 12 | pi.range = []; % fluorescence range (for caxis) 13 | pi.ititle = 'ROI centers'; % time lag 14 | pi.d2proj = [3 2 1]; % dimension to project 15 | pi.axesname = {'X', 'Y'; 'Z', 'Y'; 'Z', 'X'}; % axes name 16 | if length(sizY) == 3 17 | pi.rColor = gradientgen(9, sizY(3)); % color of rois: colorcode the depth 18 | else 19 | pi.rColor = gradientgen(9, size(icenter, 1)); % color of rois: colorcode the roi idx 20 | end 21 | pi.c2plot = [2, 1; 3, 1; 3, 2]; 22 | pi.figpos = [-1267 326 1156 510]; % figure position 23 | 24 | fop = fields(pi); 25 | if exist('params', 'var') && ~isempty(params) 26 | for ii = 1:length(fop) 27 | if isfield(params, fop{ii}) && ~isempty(params(1). (fop{ii})) 28 | pi.(fop{ii}) = params(1).(fop{ii}); 29 | end 30 | end 31 | end 32 | 33 | %% Plotting 34 | figH = figure('position', pi.figpos); 35 | colormap('gray') 36 | 37 | %% always reshape Y to target sizY 38 | Y = double(reshape(Y, sizY)); 39 | 40 | plotmuliproj(Y, icenter, sizY) 41 | end 42 | 43 | function plotmuliproj(Y, icenter, sizY) 44 | global pi 45 | %% figure features 46 | if numel(sizY) == 3 47 | hAxes(1) = subplot(1, 3, 1); 48 | hAxes(2) = subplot(1, 3, 2); 49 | hAxes(3) = subplot(1, 3, 3); 50 | else 51 | hAxes(1) = subplot(1, 2, 1); 52 | end 53 | 54 | if isempty(pi.range) 55 | pi.range = [min(Y(:)) max(Y(:))]; 56 | display(pi.range) 57 | end 58 | 59 | for a_idx = 1:length(hAxes) 60 | plotproj(hAxes, Y, a_idx) 61 | plotcenter(hAxes, icenter, a_idx) 62 | end 63 | end 64 | 65 | function plotproj(hAxes, Y, idx) 66 | global pi 67 | %% Plotting 68 | imagesc(squeeze(max(Y, [], pi.d2proj(idx))), 'Parent', hAxes(idx)) 69 | caxis(hAxes(idx), pi.range) 70 | %% Figure details 71 | if ~isempty(pi.range); caxis(hAxes(idx), pi.range); end 72 | xlabel(hAxes(idx), pi.axesname{idx, 1}); 73 | ylabel(hAxes(idx), pi.axesname{idx, 2}); 74 | title(hAxes(idx), pi.ititle); 75 | set(hAxes(idx), 'YTick', []); set(hAxes(idx), 'XTick', []) 76 | end 77 | 78 | function plotcenter(hAxes, icenter, idx) 79 | global pi 80 | hold(hAxes(idx), 'on') 81 | scatter(icenter(:, pi.c2plot(idx, 1)), icenter(:, pi.c2plot(idx, 2)), ... 82 | 50, pi.rColor(round(icenter(:, 3)), :), 'Parent', hAxes(idx)); 83 | end -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please note that the developer of this package is on leave until January 2019 and might not be able to support you. 2 | 3 | For better support, please use the template below to submit your issue. When your issue gets resolved please remember to close it. 4 | 5 | 6 | - **Describe the issue that you are experiencing** 7 | 8 | 9 | 10 | - **Copy error log below** 11 | 12 | 13 | 14 | - **If you're not reporting an error, type your message below** 15 | -------------------------------------------------------------------------------- /Initialization.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/Initialization.fig -------------------------------------------------------------------------------- /Sources2D/downSample.m: -------------------------------------------------------------------------------- 1 | function [obj_ds, Y_ds] = downSample(obj, Y) 2 | %% downsample data 3 | % input: 4 | % Y: d*T matrix or d1*d2*T matrix 5 | % output: 6 | % obj_ds: new object correspond to downsampled data 7 | % Y_ds: d1s*d2s*Ts, downsampled data 8 | 9 | %% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 10 | 11 | Y_ds = dsData(Y, obj.options); % call dsData to do downsampling 12 | [d1, d2, ~] = size(Y_ds); 13 | obj_ds = obj.copy(); 14 | obj_ds.Fs = obj.Fs/obj.options.tsub; 15 | ssub = obj.options.ssub; 16 | tsub = obj.options.tsub; 17 | % update parameters 18 | obj_ds.updateParams('d1', d1, 'd2',... 19 | d2, 'ssub', 1, 'tsub', 1, ... 20 | 'gSig', ceil(obj.options.gSig/ssub), ... 21 | 'gSiz', ceil(obj.options.gSiz/ssub), ... 22 | 'bSiz', ceil(obj.options.bSiz/ssub)); 23 | 24 | obj_ds.options.Fs = obj.Fs/tsub; 25 | if tsub~=1 26 | obj_ds.kernel = dsKernel(obj.kernel, tsub); 27 | end 28 | 29 | end -------------------------------------------------------------------------------- /Sources2D/upSample.m: -------------------------------------------------------------------------------- 1 | function upSample(obj, obj_ds, T) 2 | %% upsample the CNMF results 3 | % input: 4 | % obj_ds: class @Sources2D, results on downsampled data 5 | % T: original number of frames 6 | 7 | %% Author: Pengcheng Zhou, Carnegie Mellon University, 2015 8 | 9 | % dimension of raw data 10 | d1 = obj.options.d1; 11 | d2 = obj.options.d2; 12 | 13 | % dimension of downsampled data 14 | d1s = obj_ds.options.d1; 15 | d2s = obj_ds.options.d2; 16 | Ts = size(obj_ds.C, 2); 17 | 18 | % upsample spatial components 19 | As = reshape(full(obj_ds.A), d1s, d2s, []); 20 | obj.A = reshape(imresize(As, [d1, d2]), d1*d2, []); 21 | 22 | bs = reshape(obj_ds.b, d1s, d2s, []); 23 | obj.b = reshape(imresize(bs, [d1, d2]), d1*d2, []); 24 | 25 | % update temporal components 26 | if T~=Ts 27 | Cs = obj_ds.C; 28 | obj.C = imresize(Cs, [size(Cs, 1), T]); 29 | 30 | f = obj_ds.f; 31 | obj.f = imresize(f, [size(f, 1), T]); 32 | end 33 | % upsample contour coordinate 34 | 35 | % update Df 36 | 37 | % update C_df 38 | 39 | % update S_df 40 | 41 | % update options -------------------------------------------------------------------------------- /Sources2D/updateSpatial_endoscope.m: -------------------------------------------------------------------------------- 1 | function updateSpatial_endoscope(obj, Y, num, method, smin) 2 | %% udpate spatial components 3 | 4 | %% inputs: 5 | % Y: d X T matrix, data 6 | % num: scalar. If method=='hals', then num is the number of iterations to 7 | % update A; If method=='nnls', then num is the maximum number of neurons 8 | % overlapping at one pixel 9 | % method: method for updating the spatial components {'hals', 'nnls'}. 10 | % default: 'nnls' 11 | 12 | %% Author: Pengcheng Zhou, Carnegie Mellon University. 13 | 14 | %% input parameters number of iterations 15 | if ~exist('method', 'var')||isempty(method) 16 | method = 'nnls'; 17 | end 18 | if ~exist('num', 'var')||isempty(num) 19 | if strcmpi(method, 'nnls') 20 | num=5; 21 | else 22 | num = 10; 23 | end 24 | end 25 | if ~exist('IND_thresh', 'var')||isempty(IND_thresh) 26 | IND_thresh = []; 27 | end 28 | %% determine the search locations 29 | search_method = obj.options.search_method; 30 | params = obj.options; 31 | if strcmpi(search_method, 'dilate') 32 | obj.options.se = []; 33 | end 34 | IND = logical(determine_search_location(obj.A, search_method, params)); 35 | 36 | %% update spatial components 37 | if strcmpi(method, 'hals') 38 | obj.A = HALS_spatial(Y, obj.A, obj.C, IND, num); 39 | elseif strcmpi(method, 'nnls_thresh')&&(~isempty(IND_thresh)) 40 | try 41 | sn = obj.P.sn; 42 | catch 43 | sn = get_noise_fft(Y); 44 | obj.P.sn = sn; 45 | end 46 | 47 | obj.A = nnls_spatial_thresh(Y, obj.A, obj.C, IND, num, smin, sn); 48 | else 49 | obj.A = nnls_spatial(Y, obj.A, obj.C, IND, num); 50 | end 51 | 52 | %% thresholding the minimum number of neurons 53 | obj.delete(sum(obj.A, 1)<=obj.options.min_pixel); 54 | 55 | %% post-process 56 | % obj.post_process_spatial(); 57 | % if strcmpi(method, 'nnls') 58 | % IND = bsxfun(@gt, obj.A, max(obj.A, [], 1)/100); 59 | % obj.A = nnls_spatial(Y, obj.A, obj.C, IND, num); 60 | % end 61 | 62 | end 63 | -------------------------------------------------------------------------------- /Sources2D/updateTemporal_endoscope.m: -------------------------------------------------------------------------------- 1 | function [C_offset] = updateTemporal_endoscope(obj, Y, smin) 2 | %% run HALS by fixating all spatial components 3 | % input: 4 | % Y: d*T, fluorescence data 5 | % smin: scalar, threshold for detecting one spikes (>smin*sigma) 6 | % output: 7 | % C_raw: K*T, temporal components without being deconvolved 8 | 9 | % Author: Pengcheng Zhou, Carnegie Mellon University, adapted from Johannes 10 | 11 | % options 12 | maxIter = obj.options.maxIter; 13 | if ~exist('smin', 'var') || isempty(smin) 14 | smin = 3; 15 | end 16 | %% initialization 17 | A = obj.A; 18 | K = size(A, 2); % number of components 19 | C = obj.C; 20 | C_raw = zeros(size(C)); 21 | C_offset = zeros(K, 1); 22 | S = zeros(size(C)); 23 | A = full(A); 24 | U = A'*Y; 25 | V = A'*A; 26 | aa = diag(V); % squares of l2 norm all all components 27 | sn = zeros(1, K); 28 | kernel = obj.kernel; 29 | kernel_pars = zeros(K, 2); 30 | 31 | %% updating 32 | ind_del = false(K, 1); 33 | for miter=1:maxIter 34 | for k=1:K 35 | if ind_del 36 | continue; 37 | end 38 | temp = C(k, :) + (U(k, :)-V(k, :)*C)/aa(k); 39 | % estimate noise 40 | if miter==1 41 | sn(k) = get_noise_fft(temp); 42 | end 43 | 44 | % remove baseline 45 | [temp, C_offset(k)] = remove_baseline(temp, sn(k)); 46 | 47 | % deconvolution 48 | if obj.options.deconv_flag 49 | if miter==1 50 | [ck, sk, kernel] = deconvCa(temp, kernel, smin, true, false, sn(k)); 51 | kernel_pars(k, :) = kernel.pars; 52 | else 53 | kernel.pars = kernel_pars(k, :); 54 | [ck, sk, kernel] = deconvCa(temp, kernel, smin, false, false, sn(k)); 55 | end 56 | else 57 | ck = max(0, temp); 58 | end 59 | 60 | % save convolution kernels and deconvolution results 61 | C(k, :) = ck; 62 | 63 | if sum(ck(2:end))==0 64 | ind_del(k) = true; 65 | end 66 | % save the spike count in the last iteration 67 | if miter==maxIter 68 | if obj.options.deconv_flag 69 | S(k, :) = sk; 70 | end 71 | C_raw(k, :) = temp; 72 | end 73 | end 74 | end 75 | obj.A = bsxfun(@times, A, sn); 76 | obj.C = bsxfun(@times, C, 1./sn'); 77 | obj.C_raw = bsxfun(@times, C_raw, 1./sn'); 78 | obj.S = bsxfun(@times, S, 1./sn'); 79 | obj.P.kernel_pars = kernel_pars; 80 | obj.delete(ind_del); 81 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | ##TODO : 2 | 3 | 1) need to test the simple mode on bigger dataset and with the 4 | method available on matlab2017. 5 | 6 | 2) need to use the json matab package to see if the saving is working well 7 | 8 | 3) clicks are not performed well on some complex ROI shapes. 9 | 10 | 4) give more flexibility in the input and output parameters to allow the GUI 11 | to be called at different stages of the pipeline and to be close at different 12 | stages as well 13 | 14 | Thanks from JKOBJECT -------------------------------------------------------------------------------- /deconvolution/MCMC/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.m~ 3 | 4 | *.m~ 5 | -------------------------------------------------------------------------------- /deconvolution/MCMC/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/epnev/ca_source_extraction](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/epnev/ca_source_extraction?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | MCMC spike inference in continuous time 4 | ========================== 5 | 6 | The code takes as an input a time series vector of calcium observations 7 | and produces samples from the posterior distribution of the underlying 8 | spike in continuous time. The code also samples the model parameters 9 | (baseline, spike amplitude, initial calcium concentration, firing rate, 10 | noise variance) and also iteratively re-estimates the discrete time 11 | constant of the model. More info can be found at 12 | 13 | Pnevmatikakis, E., Merel, J., Pakman, A. & Paninski, L. (2014). 14 | Bayesian spike inference from calcium imaging data. Asilomar Conf. on 15 | Signals, Systems, and Computers. http://arxiv.org/abs/1311.6864 16 | 17 | For initializing the MCMC sampler, the algorithm uses the constrained deconvolution method maintained separately in https://github.com/epnev/constrained-foopsi 18 | 19 | ### Contributors 20 | 21 | Eftychios A. Pnevmatikakis, Simons Foundation 22 | 23 | John Merel, Columbia University 24 | 25 | ### Contact 26 | 27 | For questions join the chat room (see the button above) or open an issue (for bugs etc). 28 | 29 | ### Acknowledgements 30 | 31 | Special thanks to Tim Machado for providing the demo dataset. 32 | 33 | License 34 | ======= 35 | 36 | This program is free software; you can redistribute it and/or 37 | modify it under the terms of the GNU General Public License 38 | as published by the Free Software Foundation; either version 2 39 | of the License, or (at your option) any later version. 40 | 41 | This program is distributed in the hope that it will be useful, 42 | but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | GNU General Public License for more details. 45 | 46 | You should have received a copy of the GNU General Public License 47 | along with this program. If not, see . 48 | -------------------------------------------------------------------------------- /deconvolution/MCMC/sampling_demo_ar2.m: -------------------------------------------------------------------------------- 1 | % creating a demo for the MCMC sampler 2 | 3 | clearvars; 4 | addpath utilities 5 | dt = 1e-1; % Data is generated with provided dt but sampled with Dt = 1 6 | T = 7000; 7 | ld = 0.05; % rate spikes per second 8 | 9 | s = rand(1,round(T/dt)) < ld*dt; 10 | tau_rise = 2; 11 | tau_decay = 10; 12 | hmax = tau_decay/(tau_decay+tau_rise)*(tau_rise/(tau_decay+tau_rise))^(tau_rise/tau_decay); 13 | [g,h1] = tau_c2d(tau_rise,tau_decay,dt); 14 | 15 | b = hmax/4; % baseline value 16 | cin = [.2*b,.15*b]; % initial concentration 17 | c = [cin,filter(h1,[1,-g],s(3:end),filtic(h1,[1,-g],cin))] + b; % true calcium at original resolution 18 | c_true = c(round(1/dt):round(1/dt):round(T/dt)); % true calcium at sampled resolution 19 | sg = hmax/4; % noise level 20 | y = c_true + sg*randn(1,length(c_true)); % noisy observations 21 | 22 | figure;subplot(2,1,1); plot(dt:dt:T,c); hold all; scatter(1:T,y,'r*'); 23 | legend('True Calcium','Observed Values'); 24 | 25 | %% Run constrained deconvolution approach (constrained foopsi) 26 | 27 | [g2,h2] = tau_c2d(tau_rise,tau_decay,1); % generate discrete time constants 28 | 29 | [ca_foopsi,cb,c1,~,~,spikes_foopsi] = constrained_foopsi(y,[],[],g2); 30 | 31 | % do some plotting 32 | spiketimes{1} = find(s)*dt; 33 | spikeRaster = samples_cell2mat(spiketimes,T,1); 34 | f = find(spikeRaster); 35 | spikes = zeros(sum(spikeRaster),2); 36 | count = 0; 37 | for cnt = 1:length(f) 38 | spikes(count+(1:spikeRaster(f(cnt))),1) = f(cnt); 39 | spikes(count+(1:spikeRaster(f(cnt))),2) = 0.95 + 0.025*max(spikes_foopsi)*(1:spikeRaster(f(cnt))); 40 | count = count + spikeRaster(f(cnt)); 41 | end 42 | 43 | subplot(2,1,2); 44 | stem(spikes_foopsi); hold all; 45 | scatter(spikes(:,1),spikes(:,2)-0.95+max(spikes_foopsi),15,'magenta','filled'); 46 | axis([1,T,0,max(spikes(:,2))-0.95+max(spikes_foopsi)]); 47 | title('Foopsi Spikes','FontWeight','bold','Fontsize',14); xlabel('Timestep','FontWeight','bold','Fontsize',16); 48 | legend('Foopsi Spikes','Ground Truth'); 49 | drawnow; 50 | 51 | %% run continuous time MCMC sampler 52 | 53 | params.p = 2; 54 | params.g = g2; 55 | params.sp = spikes_foopsi; % pass results of foopsi for initialization (if not, they are computed) 56 | params.c = ca_foopsi; 57 | params.b = cb; 58 | params.c1 = c1; 59 | params.sn = sg; 60 | params.marg = 0; 61 | 62 | SAMPLES = cont_ca_sampler(y,params); %% MCMC 63 | plot_continuous_samples(SAMPLES,y(:)); 64 | M = plot_marginals(SAMPLES.ss,T,spikeRaster); -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/addSpike.m: -------------------------------------------------------------------------------- 1 | function [newSpikeTrain, newCalcium, newLL] = addSpike(oldSpikeTrain,oldCalcium,oldLL,filters,tau,obsCalcium,timeToAdd,indx,Dt,A) 2 | 3 | % Add a given spike to the existing spike train. 4 | 5 | % Inputs: 6 | % oldSpikeTrain: current spike train 7 | % oldCalcium: current noiseless calcium trace 8 | % oldLL: current value of the log-likelihood function 9 | % filters: exponential rise and decay kernels for calcium transient 10 | % tau: continuous time rise and decay time constants 11 | % obsCalcium: observed fluorescence trace 12 | % timetoAdd: time of the spike to be added 13 | % indx: place where the new spike is added in the existing spike train vector 14 | % Dt: time-bin width 15 | % A: spike amplitude 16 | 17 | % Outputs: 18 | % newSpikeTrain: new vector of spike times 19 | % newCalcium: new noiseless calcium trace 20 | % newLL: new value of the log-likelihood function 21 | 22 | % Author: Eftychios A. Pnevmatikakis and Josh Merel 23 | 24 | tau_h = tau(1); 25 | tau_d = tau(2); 26 | 27 | ef_h = filters{1,1}; 28 | ef_d = filters{1,2}; 29 | ef_nh = filters{2,1}; 30 | ef_nd = filters{2,2}; 31 | 32 | if isempty(oldSpikeTrain); indx = 1; end 33 | newSpikeTrain = [oldSpikeTrain(1:indx-1) timeToAdd oldSpikeTrain(indx:end)]; %possibly inefficient, change if problematic (only likely to be a problem for large numbers of spikes) 34 | 35 | %use infinite precision to scale the precomputed FIR approximation to the calcium transient 36 | wk_h = A*exp((timeToAdd - Dt*ceil(timeToAdd/Dt))/tau_h); 37 | wk_d = A*exp((timeToAdd - Dt*ceil(timeToAdd/Dt))/tau_d); 38 | 39 | %%%%%%%%%%%%%%%%% 40 | %handle ef_h first 41 | newCalcium = oldCalcium; 42 | tmp = 1 + (floor(timeToAdd):min((length(ef_h)+floor(timeToAdd)-1),length(newCalcium)-1)); 43 | wef_h = wk_h*ef_h(1:length(tmp)); 44 | newCalcium(tmp) = newCalcium(tmp) + wef_h; 45 | 46 | %if you really want to, ef*ef' could be precomputed and passed in 47 | relevantResidual = obsCalcium(tmp)-oldCalcium(tmp); 48 | relevantResidual(isnan(relevantResidual)) = 0; 49 | %newLL = oldLL - ( wk_h^2*norm(ef_h(1:length(tmp)))^2 - 2*relevantResidual*(wk_h*ef_h(1:length(tmp))')); 50 | newLL = oldLL - ( wk_h^2*ef_nh(length(tmp)) - 2*relevantResidual*wef_h(:)); 51 | oldCalcium = newCalcium; 52 | oldLL = newLL; 53 | %%%%%%%%%%%%%%%%% 54 | 55 | %%%%%%%%%%%%%%%%% 56 | %handle ef_d next 57 | tmp = 1 + (floor(timeToAdd):min((length(ef_d)+floor(timeToAdd)-1),length(newCalcium)-1)); 58 | wef_d = wk_d*ef_d(1:length(tmp)); 59 | newCalcium(tmp) = newCalcium(tmp) + wef_d; 60 | 61 | relevantResidual = obsCalcium(tmp)-oldCalcium(tmp); 62 | relevantResidual(isnan(relevantResidual)) = 0; 63 | %newLL = oldLL - ( wk_d^2*norm(ef_d(1:length(tmp)))^2 - 2*relevantResidual*(wk_d*ef_d(1:length(tmp))')); 64 | newLL = oldLL - ( wk_d^2*ef_nd(length(tmp)) - 2*relevantResidual*wef_d(:)); 65 | %%%%%%%%%%%%%%%%% -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/get_initial_sample.m: -------------------------------------------------------------------------------- 1 | function SAM = get_initial_sample(Y,params) 2 | 3 | % obtain initial sample by performing sparse noise-constrained deconvolution 4 | 5 | % Inputs: 6 | % Y: observed fluorescence trace 7 | % params: parameter struct (results of constrained foopsi can be passed here to avoid unnecessary computation) 8 | 9 | % Output: 10 | % SAM: sample structure with values for spikes in continuous time, 11 | % amplitude, baseline, noise, initial concentration and time constants 12 | 13 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation 14 | 15 | 16 | if isfield(params,'p'); options.p = params.p; else options.p = 1; end 17 | if isempty(params.c) || isempty(params.b) || isempty(params.c1) || isempty(params.g) || isempty(params.sn) || isempty(params.sp) 18 | fprintf('Initializing using noise constrained FOOPSI... '); 19 | options.bas_nonneg = params.bas_nonneg; 20 | [c,b,c1,g,sn,sp] = constrained_foopsi(Y,params.b,params.c1,params.g,params.sn,options); 21 | fprintf('done. \n'); 22 | else 23 | c = params.c; 24 | b = params.b; 25 | c1 = params.c1; 26 | g = params.g; 27 | sn = params.sn; 28 | sp = params.sp; 29 | end 30 | 31 | Dt = 1; 32 | T = length(Y); 33 | if ~exist('sp','var') 34 | G = make_G_matrix(T,params.g); 35 | sp = G*c; 36 | end 37 | s_in = sp>0.15*max(sp); 38 | spiketimes_ = Dt*(find(s_in) + rand(size(find(s_in))) - 0.5); 39 | spiketimes_(spiketimes_ >= T*Dt) = 2*T*Dt - spiketimes_(spiketimes_ >= T*Dt); 40 | SAM.lam_ = length(spiketimes_)/(T*Dt); 41 | SAM.spiketimes_ = spiketimes_; 42 | 43 | SAM.A_ = max(median(sp(s_in)),max(sp(s_in))/4); % initial amplitude value 44 | if length(g) == 2 45 | SAM.A_ = SAM.A_/sqrt(g(1)^2+4*g(2)); 46 | end 47 | 48 | SAM.b_ = max(b,min(Y)+range(Y)/25); % initial baseline value 49 | SAM.C_in = max(c1,(Y(1)-b)/10); % initial value sample 50 | SAM.sg = sn; % initial noise value 51 | SAM.g = g; % initial time constant value -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/lambda_rate.m: -------------------------------------------------------------------------------- 1 | function lam = lambda_rate(t,lambda) 2 | 3 | % function for calculating the spike rate at a given time. 4 | % Currently, only homogeneous Poisson prior rates are accepted. 5 | 6 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation. 7 | 8 | lam = lambda; -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/make_G_matrix.m: -------------------------------------------------------------------------------- 1 | function G = make_G_matrix(T,g,varargin) 2 | 3 | % creates the sparse Toeplitz matrix that models the AR dynamics 4 | 5 | % Inputs: 6 | % T: size of matrix (number of total timebins) 7 | % g: discrete time constants 8 | 9 | % Output: 10 | % G: matrix of AR dynamics 11 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation. 12 | 13 | if length(g) == 1 && g < 0 14 | g=0; 15 | end 16 | 17 | G = spdiags(ones(T,1)*[-flipud(g(:))',1],-length(g):0,T,T); 18 | if nargin == 3 19 | sl = [0;cumsum(varargin{1}(:))]; 20 | for i = 1:length(sl)-1 21 | G(sl(i)+1,sl(i+1))=0; 22 | end 23 | end -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/make_mean_sample.m: -------------------------------------------------------------------------------- 1 | function c_m = make_mean_sample(SAMPLES,Y) 2 | 3 | % construct mean calcium sample from samples structure SAMPLES 4 | 5 | % Inputs: 6 | % SAMPLES: samples struct output of cont_ca_sampler 7 | % Y: observed fluorescence trace 8 | 9 | % Output: 10 | % c_m: mean calcium sample 11 | 12 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation. 13 | 14 | T = length(Y); 15 | N = length(SAMPLES.ns); 16 | P = SAMPLES.params; 17 | P.f = 1; 18 | g = P.g(:); 19 | Dt = 1/P.f; % length of time bin 20 | if ~isfield(SAMPLES,'g'); 21 | SAMPLES.g = ones(N,1)*g'; 22 | end 23 | 24 | 25 | if length(SAMPLES.Cb) == 2 26 | marg = 1; % marginalized sampler 27 | else 28 | marg = 0; % full sampler 29 | end 30 | 31 | C_rec = zeros(N,T); 32 | for rep = 1:N 33 | %trunc_spikes = ceil(SAMPLES.ss{rep}/Dt); 34 | tau = SAMPLES.g(rep,:); 35 | gr = exp(-1./tau); 36 | 37 | ge = max(gr).^(0:T-1)'; 38 | s_1 = sparse(ceil(SAMPLES.ss{rep}/Dt),1,exp((SAMPLES.ss{rep} - Dt*ceil(SAMPLES.ss{rep}/Dt))/tau(1)),T,1); 39 | s_2 = sparse(ceil(SAMPLES.ss{rep}/Dt),1,exp((SAMPLES.ss{rep} - Dt*ceil(SAMPLES.ss{rep}/Dt))/tau(2)),T,1); 40 | if gr(1) == 0 41 | G1 = sparse(1:T,1:T,Inf*ones(T,1)); 42 | G1sp = zeros(T,1); 43 | else 44 | G1 = spdiags(ones(T,1)*[-min(gr),1],[-1:0],T,T); 45 | G1sp = G1\s_1(:); 46 | end 47 | G2 = spdiags(ones(T,1)*[-max(gr),1],[-1:0],T,T); 48 | Gs = (-G1sp+ G2\s_2(:))/diff(gr); 49 | if marg 50 | %C_rec(rep,:) = SAMPLES.Cb(1) + SAMPLES.Am(rep)*filter(1,[1,-SAMPLES.g(rep,:)],full(s_)+[SAMPLES.Cin(:,1)',zeros(1,T-p)]); 51 | C_rec(rep,:) = SAMPLES.Cb(1) + SAMPLES.Am(rep)*Gs + (ge*SAMPLES.Cin(:,1)); 52 | else 53 | %C_rec(rep,:) = SAMPLES.Cb(rep) + SAMPLES.Am(rep)*filter(1,[1,-SAMPLES.g(rep,:)],full(s_)+[SAMPLES.Cin(rep,:),zeros(1,T-p)]); 54 | C_rec(rep,:) = SAMPLES.Cb(rep) + SAMPLES.Am(rep)*Gs + (ge*SAMPLES.Cin(rep,:)'); 55 | end 56 | end 57 | 58 | c_m = mean(C_rec); -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/plot_marginals.m: -------------------------------------------------------------------------------- 1 | function [M,fig] = plot_marginals(sampleCell,T,truespikes,int_show) 2 | 3 | % Plots marginal posterior empirical pdfs for # of spikes for each timebin 4 | % similar to figure 1B in Pnevmatikakis et al., Neuron 2016 5 | 6 | % Inputs: 7 | % sampleCell: Cell array with spike times in continuous time (SAMPLES.ss) 8 | % T: Number of timebins 9 | % truespikes: Number of true spikes per timebin (vector of size T x 1) 10 | % int_show: Show only a specified interval (default: [1,T]) 11 | 12 | % Output: 13 | % M: matrix of empirical posterior pdfs for each timebin 14 | 15 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation 16 | 17 | if nargin < 4 18 | int_show = 1:T; 19 | end 20 | nT = length(int_show); 21 | 22 | if nargin == 2 23 | truespikes = -0.5*ones(1,nT); 24 | end 25 | 26 | if length(truespikes) == T 27 | truespikes = truespikes(int_show); 28 | end 29 | 30 | Mat = samples_cell2mat(sampleCell,T); 31 | Mat = Mat(:,int_show); 32 | 33 | mS = min(max([Mat(:);truespikes(:)])+1,6); 34 | M = zeros(mS,nT); 35 | for i = 1:nT 36 | M(:,i) = hist(Mat(:,i),0:mS-1)/size(Mat,1); 37 | end 38 | 39 | cmap = bone(100); 40 | cmap(2:26,:) = []; 41 | fig = figure; 42 | imagesc(M); axis xy; 43 | %set(gca,'Ytick',[0.5:(mS+.5)],'Yticklabel',[-1:(mS)]); %hold all; plot(traceData.spikeFrames+1); set(gca,'YLim',[1,5]) 44 | %set(gca,'YLim',[1.25,mS+.25]); 45 | hold all; scatter(1:nT,truespikes+1,[],'m'); 46 | set(gca,'YLim',[1.5,mS+.125]); 47 | pos = get(gca,'Position'); 48 | set(gca,'Ytick',0.5+[-0.5:mS-.5],'Yticklabel',[-1+(0:mS)]); 49 | colormap(cmap); 50 | ylabel('# of Spikes ','fontweight','bold','fontsize',14); 51 | xlabel('Timestep ','fontweight','bold','fontsize',14); 52 | title('Posterior Spike Histogram (MCMC) ','fontweight','bold','fontsize',14); 53 | cbar = colorbar('Location','East'); 54 | cpos = get(cbar,'Position'); 55 | set(cbar,'Position',[pos(1)+pos(4),cpos(2:4)]); 56 | %set(gca,'Xtick',[]) 57 | %set(cbar,'Color',[1,1,1]); 58 | set(cbar,'Fontsize',12); -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/removeSpike.m: -------------------------------------------------------------------------------- 1 | function [newSpikeTrain, newCalcium, newLL] = removeSpike(oldSpikeTrain,oldCalcium,oldLL,filters,tau,obsCalcium,timeToRemove,indx,Dt,A) 2 | 3 | % Remove a given spike from the existing spike train. 4 | 5 | % Inputs: 6 | % oldSpikeTrain: current spike train 7 | % oldCalcium: current noiseless calcium trace 8 | % oldLL: current value of the log-likelihood function 9 | % filters: exponential rise and decay kernels for calcium transient 10 | % tau: continuous time rise and decay time constants 11 | % obsCalcium: observed fluorescence trace 12 | % timetoRemove: time of the spike to be removed 13 | % indx: place where the spike to be removed is in the existing spike train vector 14 | % Dt: time-bin width 15 | % A: spike amplitude 16 | 17 | % Outputs: 18 | % newSpikeTrain: new vector of spike times 19 | % newCalcium: new noiseless calcium trace 20 | % newLL: new value of the log-likelihood function 21 | 22 | % Author: Eftychios A. Pnevmatikakis and Josh Merel 23 | 24 | tau_h = tau(1); 25 | tau_d = tau(2); 26 | 27 | ef_h = filters{1,1}; 28 | ef_d = filters{1,2}; 29 | ef_nh = filters{2,1}; 30 | ef_nd = filters{2,2}; 31 | 32 | newSpikeTrain = oldSpikeTrain; 33 | newSpikeTrain(indx) = []; 34 | 35 | %use infinite precision to scale the precomputed FIR approximation to the calcium transient 36 | wk_h = A*exp((timeToRemove - Dt*ceil(timeToRemove/Dt))/tau_h); 37 | wk_d = A*exp((timeToRemove - Dt*ceil(timeToRemove/Dt))/tau_d); 38 | 39 | %%%%%%%%%%%%%%%%% 40 | %handle ef_h first 41 | newCalcium = oldCalcium; 42 | tmp = 1+ (floor(timeToRemove):min((length(ef_h)+floor(timeToRemove)-1),length(newCalcium)-1)); 43 | wef_h = wk_h*ef_h(1:length(tmp)); 44 | newCalcium(tmp) = newCalcium(tmp) - wef_h; 45 | 46 | relevantResidual = obsCalcium(tmp)-oldCalcium(tmp); 47 | relevantResidual(isnan(relevantResidual)) = 0; 48 | newLL = oldLL - ( wk_h^2*ef_nh(length(tmp)) + 2*relevantResidual*wef_h(:)); 49 | oldCalcium = newCalcium; 50 | oldLL = newLL; 51 | %%%%%%%%%%%%%%%%% 52 | 53 | %%%%%%%%%%%%%%%%% 54 | %handle ef_d next 55 | newCalcium = oldCalcium; 56 | tmp = 1+ (floor(timeToRemove):min((length(ef_d)+floor(timeToRemove)-1),length(newCalcium)-1)); 57 | wef_d = wk_d*ef_d(1:length(tmp)); 58 | newCalcium(tmp) = newCalcium(tmp) - wef_d; 59 | 60 | relevantResidual = obsCalcium(tmp)-oldCalcium(tmp); 61 | relevantResidual(isnan(relevantResidual)) = 0; 62 | newLL = oldLL - ( wk_d^2*ef_nd(length(tmp)) + 2*relevantResidual*wef_d(:)); 63 | %%%%%%%%%%%%%%%% -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/samples_cell2mat.m: -------------------------------------------------------------------------------- 1 | function spikeRaster = samples_cell2mat(sampleCell,T,Dt) 2 | 3 | % Constructs matrix of spike raster plot from cell array of spike times 4 | 5 | % Inputs: 6 | % sampleCell: Cell array with spike times in continuous time (SAMPLES.ss) 7 | % T: End time of trace/experiment 8 | % Dt: Time-bin resolution (default: 1) 9 | 10 | % Output: 11 | % spikeRaster: Spike raster plot matrix 12 | 13 | % Author: Eftychios A. Pnevmatikakis and Josh Merel 14 | 15 | if nargin == 2 16 | Dt = 1; 17 | end 18 | bins = 0:Dt:(T-Dt); 19 | nsamples = length(sampleCell); 20 | spikeRaster = zeros(nsamples,length(bins)); 21 | for i = 1:nsamples 22 | tmp = histc([sampleCell{i}(:); inf],[bins, (T+1)]); 23 | spikeRaster(i,:) = tmp(1:(end-1))'; 24 | end -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/tau_c2d.m: -------------------------------------------------------------------------------- 1 | function [g,h1] = tau_c2d(tau_r,tau_d,dt) 2 | 3 | % convert continuous time constants to discrete with resolution dt 4 | % h(t) = (1-exp(-t/tau_r))*exp(-t/tau_d) 5 | % g: discrete time constants 6 | % h1: h(dt); 7 | % h*s can be written in discrete form as filter(h1,[1,-g],s) 8 | 9 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation 10 | 11 | A = [-(2/tau_d+1/tau_r), - (tau_r+tau_d)/(tau_r*tau_d^2); 1 0]; 12 | lc = eig(A*dt); 13 | ld = exp(lc); 14 | g = [sum(ld),-prod(ld)]; 15 | h1 = (1-exp(-dt/tau_r))*exp(-dt/tau_d); -------------------------------------------------------------------------------- /deconvolution/MCMC/utilities/tau_d2c.m: -------------------------------------------------------------------------------- 1 | function tau = tau_d2c(g,dt) 2 | 3 | % convert discrete time constantswith resolution dt to continuous 4 | % h(t) = (1-exp(-t/tau(1)))*exp(-t/tau(2)) 5 | 6 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation 7 | 8 | gr = max(roots([1,-g(:)']),0); 9 | p1_continuous = log(min(gr))/dt; 10 | p2_continuous = log(max(gr))/dt; 11 | tau_1 = -1/p1_continuous; %tau h - smaller (tau_d * tau_r)/(tau_d + tau_r) 12 | tau_2 = -1/p2_continuous; %tau decay - larger 13 | 14 | tau_rise = 1/(1/tau_1 - 1/tau_2); 15 | tau = [tau_rise,tau_2]; %tau_h , tau_d -------------------------------------------------------------------------------- /deconvolution/MCMC/wrapper.m: -------------------------------------------------------------------------------- 1 | clear; 2 | load traceData.mat; 3 | addpath utilities 4 | addpath(genpath('../constrained-foopsi')); 5 | %Y = squeeze(traceData.traces(129,7,:)); % pick a particular trace (low SNR) 6 | Y = mean(squeeze(traceData.traces(:,7,:))); % average over ROI (high SNR) 7 | 8 | %% run MCMC sampler and plot results 9 | params.p = 1; 10 | params.print_flag = 1; 11 | params.B = 300; 12 | SAMP = cont_ca_sampler(Y,params); 13 | plot_continuous_samples(SAMP,Y); -------------------------------------------------------------------------------- /deconvolution/examples/ar1_constrained_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 7: constrained-foopsi, AR1 7 | g = 0.95; % AR coefficient 8 | noise = .3; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 1; % number of trials 14 | seed = 13; % seed for genrating random variables 15 | [y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | 17 | % cvx solution 18 | [c_cvx, s_cvx] = constrained_foopsi(y, g, noise); 19 | % case 1: all parameters are known 20 | [c_oasis, s_oasis] = deconvolveCa(y, 'ar1', g, 'constrained', 'sn', noise); %#ok<*ASGLU> 21 | 22 | figure('name', 'constrained-FOOPSI, AR1, known: g, sn', 'papersize', [15, 4]); 23 | plot_cvx = true; 24 | show_results; 25 | plot_cvx = false; 26 | 27 | % case 2: nothing is known, estimate g with auto-correlation method 28 | [c_oasis, s_oasis,options] = deconvolveCa(y, 'ar1', 'constrained'); 29 | 30 | fprintf('true gamma: %.3f\n', g); 31 | fprintf('estimated gamma: %.3f\n', options.pars); 32 | 33 | figure('name', 'FOOPSI, AR1, estimated: g, sn', 'papersize', [15, 4]); 34 | show_results; 35 | 36 | % case 3: nothing is know, estimate g with auto-correlation method first 37 | % and then update it to minimize the RSS 38 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'constrained', ... 39 | 'optimize_pars'); 40 | 41 | fprintf('true gamma: %.3f\n', g); 42 | fprintf('estimated gamma: %.3f\n', options.pars); 43 | 44 | figure('name', 'FOOPSI, AR1, estimated: g, sn, update:g', 'papersize', [15, 4]); 45 | show_results; 46 | 47 | % case 4: nothing is know, estimate g with auto-correlation method first 48 | % and then update it to minimize the RSS, the baseline is also unknown 49 | true_b = 0.5; 50 | [c_oasis, s_oasis, options] = deconvolveCa(y+true_b, 'ar1', g,... 51 | 'constrained','optimize_b', 'sn', noise); 52 | fprintf('true gamma: %.3f\n', g); 53 | fprintf('estimated gamma: %.3f\n', options.pars); 54 | fprintf('true b: %.3f\n', true_b); 55 | fprintf('estimated b: %.3f\n', options.b); 56 | fprintf('tuning parameter: %.3f\n', options.lambda); 57 | 58 | figure('name', 'FOOPSI, AR1, estimated: g, sn, lambda', 'papersize', [15, 4]); 59 | show_results; 60 | 61 | % case 5: nothing is know, estimate g with auto-correlation method first 62 | % and then update it to minimize the RSS, the baseline is also unknown 63 | true_b = 0.5; 64 | [c_oasis, s_oasis, options] = deconvolveCa(y+true_b, 'ar1',... 65 | 'constrained','optimize_b', 'optimize_pars'); 66 | fprintf('true gamma: %.3f\n', g); 67 | fprintf('estimated gamma: %.3f\n', options.pars); 68 | fprintf('estimated b: %.3f\n', options.b); 69 | fprintf('tuning parameter: %.3f\n', options.lambda); 70 | 71 | figure('name', 'FOOPSI, AR1, estimated: g, sn, lambda, update:g', 'papersize', [15, 4]); 72 | show_results; 73 | 74 | %% -------------------------------------------------------------------------------- /deconvolution/examples/ar1_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 1: foopsi, AR1 model. This model is used when the sampling rate is low 7 | g = 0.95; % AR coefficient 8 | noise = .3; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 1; % number of trials 14 | seed = 13; % seed for genrating random variables 15 | [y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | 17 | % case 1: all parameters are known 18 | lambda = 2.4; 19 | [c_oasis, s_oasis] = deconvolveCa(y, 'ar1', g, 'foopsi', 'lambda', lambda); %#ok<*ASGLU> 20 | [c_cvx, s_cvx] = foopsi(y, g, lambda); 21 | 22 | figure('name', 'FOOPSI, AR1, known: g, lambda', 'papersize', [15, 4]); 23 | plot_cvx = true; 24 | show_results; 25 | plot_cvx = false; 26 | 27 | % case 2: know lambda 28 | lambda = 2.4; 29 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'foopsi', 'lambda', lambda); 30 | 31 | fprintf('true gamma: %.3f\n', g); 32 | fprintf('estimated gamma: %.3f\n', options.pars); 33 | 34 | figure('name', 'FOOPSI, AR1, known:lambda, estimated: g', 'papersize', [15, 4]); 35 | show_results; 36 | 37 | % case 3: know lambda, fit g 38 | lambda = 2.4; 39 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'foopsi', 'lambda', lambda, ... 40 | 'optimize_pars'); 41 | 42 | fprintf('true gamma: %.3f\n', g); 43 | fprintf('estimated gamma: %.3f\n', options.pars); 44 | 45 | figure('name', 'MCMC, AR1'); 46 | show_results; 47 | %%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% 48 | -------------------------------------------------------------------------------- /deconvolution/examples/ar1_mcmc.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 1: foopsi, AR1 model. This model is used when the sampling rate is low 7 | g = 0.95; % AR coefficient 8 | noise = .3; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 1; % number of trials 14 | seed = 13; % seed for genrating random variables 15 | [y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | 17 | % case 1: all parameters are known 18 | lambda = 2.4; 19 | params.p = 1; 20 | params.B = 1; 21 | [c_oasis, s_oasis] = deconvolveCa(y, 'mcmc', params); %#ok<*ASGLU> 22 | [c_cvx, s_cvx] = foopsi(y, g, lambda); 23 | 24 | figure('name', 'FOOPSI, AR1, known: g, lambda', 'papersize', [15, 4]); 25 | plot_cvx = true; 26 | show_results; 27 | plot_cvx = false; 28 | -------------------------------------------------------------------------------- /deconvolution/examples/ar1_thresholded_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 4: hard threshold, AR1 model 7 | g = 0.95; % AR coefficient 8 | noise = .3; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 1; % number of trials 14 | seed = 13; % seed for genrating random variables 15 | [y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | 17 | % case 1: all parameters are known 18 | smin = 0.5; 19 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', g, 'thresholded', 'smin', smin); %#ok<*ASGLU> 20 | 21 | figure('name', 'threshold, AR1, known: g, lambda, smin', 'papersize', [15, 4]); 22 | show_results; 23 | 24 | % case 2: know smin 25 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'thresholded', 'smin', smin); 26 | 27 | fprintf('true gamma: %.3f\n', g); 28 | fprintf('estimated gamma: %.3f\n', options.pars); 29 | 30 | figure('name', 'threshold, AR1, known:smin, estimated: g', 'papersize', [15, 4]); 31 | show_results; 32 | 33 | % case 3: optimize the thershold, g, and the baseline 34 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', g, ... 35 | 'thresholded', 'optimize_smin', 'optimize_pars', 'thresh_factor', 0.99); %#ok<*ASGLU> 36 | 37 | figure('name', 'threshold, AR1, known: g, sn, estimate: smin, g', 'papersize', [15, 4]); 38 | show_results; -------------------------------------------------------------------------------- /deconvolution/examples/ar2_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 2: foopsi, AR2 model 7 | g = [1.7, -0.712]; % AR coefficient 8 | noise = 1; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 20; % number of trials 14 | seed = 3; % seed for genrating random variables 15 | [Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | y = Y(1,:); 17 | true_c = trueC(1,:); %#ok<*NASGU> 18 | true_s = trueS(1,:); 19 | % case 1: all parameters are known 20 | lambda = 25; 21 | [c_oasis, s_oasis] = deconvolveCa(y, 'ar2', g, 'foopsi', 'lambda', lambda); %#ok<*ASGLU> 22 | 23 | figure('name', 'FOOPSI, AR2, known: g, lambda', 'papersize', [15, 4]); 24 | show_results; 25 | 26 | % case 2: know lambda 27 | lambda = 2.5; 28 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'foopsi', 'lambda',... 29 | lambda); 30 | fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); 31 | fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); 32 | 33 | figure('name', 'FOOPSI, AR2, known:lambda, estimated: g', 'papersize', [15, 4]); 34 | show_results; 35 | 36 | %%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% 37 | -------------------------------------------------------------------------------- /deconvolution/examples/ar2_mcmc.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 2: foopsi, AR2 model 7 | g = [1.7, -0.712]; % AR coefficient 8 | noise = 1; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 20; % number of trials 14 | seed = 3; % seed for genrating random variables 15 | [Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | y = Y(1,:); 17 | true_c = trueC(1,:); %#ok<*NASGU> 18 | true_s = trueS(1,:); 19 | % case 1: all parameters are known 20 | lambda = 25; 21 | params.p = 2; 22 | params.B = 300; 23 | [c_oasis, s_oasis] = deconvolveCa(y, 'mcmc', params); %#ok<*ASGLU> 24 | 25 | figure('name', 'FOOPSI, AR2, known: g, lambda', 'papersize', [15, 4]); 26 | show_results; 27 | -------------------------------------------------------------------------------- /deconvolution/examples/ar2_thresholded_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | 7 | %% threshold, AR2 model 8 | g = [1.7, -0.712]; % AR coefficient 9 | noise = 1; 10 | T = 3000; 11 | framerate = 30; 12 | firerate = 0.5; 13 | b = 0; % baseline 14 | N = 20; % number of trials 15 | seed = 3; % seed for genrating random variables 16 | [Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 17 | y = Y(1,:); 18 | true_c = trueC(1,:); %#ok<*NASGU> 19 | true_s = trueS(1,:); 20 | % case 1: all parameters are known 21 | smin = 0.5; 22 | [c_oasis, s_oasis] = deconvolveCa(y, 'ar2', g, 'thresholded', 'smin', smin); %#ok<*ASGLU> 23 | figure('name', 'threshold, AR2, known: g, smin', 'papersize', [15, 4]); 24 | show_results; 25 | 26 | % case 2: know smin 27 | smin = 0.5; 28 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'thresholded',... 29 | 'smin', smin); 30 | fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); 31 | fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); 32 | 33 | figure('name', 'threshold, AR2, known:smin, estimated: g', 'papersize', [15, 4]); 34 | show_results; 35 | 36 | %% case 3: know smin, update g 37 | smin = 0.5; 38 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'thresholded',... 39 | 'smin', smin, 'optimize_pars'); 40 | fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); 41 | fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); 42 | 43 | figure('name', 'threshold, AR2, known:smin, estimated: g', 'papersize', [15, 4]); 44 | show_results; 45 | 46 | %% case 3: estimate smin 47 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'thresholded',... 48 | 'optimize_smin','optimize_pars', 'thresh_factor', 1); 49 | % fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); 50 | % fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); 51 | fprintf('estimated smin: %.3f\n', options.smin); 52 | figure('name', 'threshold, AR2, known:smin, estimated: g', 'papersize', [15, 4]); 53 | show_results; 54 | %%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% 55 | -------------------------------------------------------------------------------- /deconvolution/examples/kernel_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | %% example 3: foopsi, convolution kernel 7 | g = [1.7, -0.712]; % AR coefficient 8 | noise = 1; 9 | T = 3000; 10 | framerate = 30; 11 | firerate = 0.5; 12 | b = 0; % baseline 13 | N = 20; % number of trials 14 | seed = 3; % seed for genrating random variables 15 | [Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 16 | y = Y(1,:); 17 | true_c = trueC(1,:); %#ok<*NASGU> 18 | true_s = trueS(1,:); 19 | taus = ar2exp(g); 20 | w = 200; 21 | taus = ar2exp(g); 22 | ht = exp2kernel(taus, w); 23 | % case 1: use the difference of two exponential functions to construct a 24 | % kernel 25 | lambda = 25; 26 | [c_oasis, s_oasis] = deconvolveCa(y, 'exp2', taus, 'foopsi', 'lambda', lambda, ... 27 | 'shift', 100, 'window', 200); %#ok<*ASGLU> 28 | 29 | figure('name', 'FOOPSI, exp2, known: g, lambda', 'papersize', [15, 4]); 30 | show_results; 31 | 32 | % case 2: use the kernel directly 33 | lambda = 25; 34 | [c_oasis, s_oasis] = deconvolveCa(y, 'kernel', ht, 'foopsi', 'lambda', ... 35 | lambda, 'shift', 100, 'window', 200); %#ok<*ASGLU> 36 | 37 | figure('name', 'FOOPSI, kernel, known: g, lambda', 'papersize', [15, 4]); 38 | show_results; 39 | 40 | 41 | %% case 3: estimate the time constants 42 | lambda = 0; 43 | taus = ar2exp(g); 44 | [c_oasis, s_oasis, options] = deconvolveCa(y, 'exp2', 'foopsi', 'lambda', lambda, ... 45 | 'shift', 100, 'window', 200, 'smin', 0.5); %#ok<*ASGLU> 46 | 47 | figure('name', 'FOOPSI, exp2, known: g, lambda', 'papersize', [15, 4]); 48 | show_results; 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /deconvolution/examples/kernel_thresholded_foopsi.m: -------------------------------------------------------------------------------- 1 | %% test modulate for all oasis functions. 2 | col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... 3 | [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors 4 | plot_cvx = false; 5 | 6 | 7 | %% threshold foopsi, convolution kernel 8 | g = [1.7, -0.712]; % AR coefficient 9 | noise = 1; 10 | T = 3000; 11 | framerate = 30; 12 | firerate = 0.5; 13 | b = 0; % baseline 14 | N = 20; % number of trials 15 | seed = 3; % seed for genrating random variables 16 | [Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); 17 | y = Y(1,:); 18 | true_c = trueC(1,:); %#ok<*NASGU> 19 | true_s = trueS(1,:); 20 | temp = roots([1, -g(1), -g(2)]); 21 | d = max(temp); 22 | r = min(temp); 23 | w = 200; 24 | ht = (exp(log(d)*(1:w)) - exp(log(r)*(1:w))) / (d-r); % convolution kernel 25 | 26 | % case 1: all parameters are known, the kernel is the sum of two 27 | % exponential functions 28 | smin = 0.5; 29 | pars = [d, r]; 30 | [c_oasis, s_oasis] = deconvolveCa(y, 'exp2', pars, 'thresholded', 'smin', smin); %#ok<*ASGLU> 31 | figure('name', 'threshold, exp2, known: taur, taud, smin', 'papersize', [15, 4]); 32 | show_results; 33 | 34 | % case 1: all parameters are known 35 | smin = 0.5; 36 | [c_oasis, s_oasis] = deconvolveCa(y, 'kernel', ht, 'thresholded', 'smin', smin); %#ok<*ASGLU> 37 | figure('name', 'threshold, kernel, known: kernel, smin', 'papersize', [15, 4]); 38 | show_results; 39 | %%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% 40 | -------------------------------------------------------------------------------- /deconvolution/examples/show_results.m: -------------------------------------------------------------------------------- 1 | init_fig; 2 | 3 | % c 4 | axes('position', [.05, .57, .95, .37]); 5 | hold on; 6 | plot(y, 'color', col{8}/255); 7 | alpha(.7); 8 | plot(true_c, 'color', col{3}/255, 'linewidth', 1.5); 9 | plot(c_oasis, '-.', 'color', col{5}/255); 10 | if plot_cvx && exist('c_cvx', 'var') 11 | plot(c_cvx, '-.', 'color', col{7}/255); 12 | end 13 | axis tight; 14 | xlim([0, 2000]); 15 | set(gca, 'xtick', [0, 25, 50, 75]*30); 16 | set(gca, 'xticklabel', []); 17 | set(gca, 'ytick', 0:2); 18 | ylabel('Fluor.'); 19 | box off; 20 | if plot_cvx 21 | legend('Data', 'Truth', 'OASIS', 'CVX', 'location', 'northeast', 'orientation', 'horizental'); 22 | else 23 | legend('Data', 'Truth', 'OASIS', 'location', 'northeast', 'orientation', 'horizental'); 24 | end 25 | % s 26 | axes('position', [.05, .18, .95, .37]); 27 | hold on; 28 | plot(true_s, 'color', col{3}/255, 'linewidth', 1.5); 29 | plot(s_oasis, '-.', 'color', col{5}/255); 30 | if plot_cvx && exist('s_cvx', 'var') 31 | plot(s_cvx, '-.', 'color', col{7}/255); 32 | end 33 | axis tight; 34 | xlim([0, 2000]); 35 | set(gca, 'xtick', [0, 25, 50, 75]*30); 36 | set(gca, 'xticklabel', get(gca, 'xtick')/30); 37 | set(gca, 'ytick', [0,1]); 38 | xlabel('Time [s]'); 39 | ylabel('Activity.'); -------------------------------------------------------------------------------- /deconvolution/examples/test_all.m: -------------------------------------------------------------------------------- 1 | %% FOOPSI (all done ) 2 | % AR1 3 | fprintf('AR1, FOOPSI...'); 4 | try 5 | ar1_foopsi; 6 | fprintf('success!\n\n'); 7 | drawnow; 8 | catch 9 | fprintf('fail!\n\n'); 10 | end 11 | 12 | % AR2 13 | fprintf('\nAR2, FOOPSI...'); 14 | try 15 | ar2_foopsi; 16 | fprintf('success!\n\n'); 17 | drawnow; 18 | catch 19 | fprintf('fail!\n\n'); 20 | end 21 | 22 | % kernel 23 | fprintf('\nkernel, FOOPSI...'); 24 | try 25 | kernel_foopsi; 26 | fprintf('success!\n\n'); 27 | drawnow; 28 | catch 29 | fprintf('fail!\n\n'); 30 | end 31 | 32 | 33 | %% Constrained FOOPSI (need AR2, kernel ) 34 | % AR1 35 | fprintf('\nAR1, constrained FOOPSI...'); 36 | try 37 | ar1_constrained_foopsi; 38 | fprintf('success!\n\n'); 39 | drawnow; 40 | catch 41 | fprintf('fail!\n\n'); 42 | end 43 | 44 | %% Thresholded FOOPSI (all done) 45 | % AR1 46 | fprintf('\nAR1, thresholded FOOPSI...'); 47 | try 48 | ar1_thresholded_foopsi; 49 | fprintf('success!\n\n'); 50 | drawnow; 51 | catch 52 | fprintf('fail!\n\n'); 53 | end 54 | 55 | % AR2 56 | fprintf('\nAR2, thresholded FOOPSI... '); 57 | try 58 | ar2_thresholded_foopsi; 59 | fprintf('success!\n\n'); 60 | drawnow; 61 | catch 62 | fprintf('fail!\n\n'); 63 | end 64 | 65 | 66 | % AR2 67 | fprintf('\nkernel, thresholded FOOPSI... '); 68 | try 69 | kernel_thresholded_foopsi; 70 | fprintf('success!\n\n'); 71 | drawnow; 72 | catch 73 | fprintf('fail!\n\n'); 74 | end 75 | 76 | %% MCMC 77 | % AR1 78 | fprintf('\nAR1, MCMC...'); 79 | try 80 | ar1_mcmc; 81 | fprintf('success!\n\n'); 82 | drawnow; 83 | catch 84 | fprintf('fail!\n\n'); 85 | end 86 | -------------------------------------------------------------------------------- /deconvolution/functions/GetSn.m: -------------------------------------------------------------------------------- 1 | function sn = GetSn(Y, range_ff, method) 2 | %% Estimate noise standard deviation 3 | 4 | %% inputs: 5 | % Y: N X T matrix, fluorescence trace 6 | % range_ff : 1 x 2 vector, nonnegative, max value <= 0.5, range of frequency (x Nyquist rate) over which the spectrum is averaged 7 | % method: string, method of averaging: Mean, median, exponentiated mean of logvalues (default) 8 | 9 | %% outputs: 10 | % sn: scalar, std of the noise 11 | 12 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 13 | % adapted from the MATLAB implemention by Eftychios Pnevmatikakis and the 14 | % Python implementation from Johannes Friedrich 15 | 16 | %% References 17 | % Pnevmatikakis E. et.al., Neuron 2016, Simultaneous Denoising, Deconvolution, and Demixing of Calcium Imaging Data 18 | 19 | %% input arguments 20 | if ~exist('range_ff', 'var') || isempty(range_ff) 21 | range_ff = [.25, .5]; 22 | end 23 | if ~exist('method', 'var') || isempty(method) 24 | method = 'logmexp'; 25 | end 26 | if any(size(Y)==1) 27 | Y = reshape(Y, [], 1); 28 | else 29 | Y = Y'; 30 | end 31 | 32 | %% estimate the noise 33 | [psdx, ff] = pwelch(Y, [],[],[], 1); 34 | indf = and(ff>=range_ff(1), ff<=range_ff(2)); 35 | switch method 36 | case 'mean' 37 | sn=sqrt(mean(psdx(indf, :)/2)); 38 | case 'median' 39 | sn=sqrt(median(psdx(indf,:)/2)); 40 | case 'logmexp' 41 | sn = sqrt(exp(mean(log(psdx(indf,:)/2)))); 42 | otherwise 43 | fprintf('wrong method! use logmexp instead.\n'); 44 | sn = sqrt(exp(mean(log(psdx(indf,:)/2)))); 45 | end 46 | sn = sn'; 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /deconvolution/functions/ar2exp.m: -------------------------------------------------------------------------------- 1 | function tau_dr = ar2exp(g) 2 | %% get parameters of the convolution kernel for AR2 process 3 | temp = roots([1, -g(1), -g(2)]); 4 | d = max(temp); 5 | r = min(temp); 6 | tau_d = -1/log(d); 7 | tau_r = -1/log(r); 8 | 9 | tau_dr = [tau_d, tau_r]; -------------------------------------------------------------------------------- /deconvolution/functions/constrained_foopsi_cvx.m: -------------------------------------------------------------------------------- 1 | function [c, s] = constrained_foopsi_cvx(y, g, sn, solver) 2 | %% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace 3 | % Solves the sparse non-negative deconvolution problem 4 | % min |s|_1 subject to s=G*c >=0 and |y-c|_2^2=\sigma*T^2 5 | 6 | %% inputs: 7 | % y: T*1 vector, One dimensional array containing the fluorescence intensities 8 | %withone entry per time-bin. 9 | % g: scalar, Parameter of the AR(1) process that models the fluorescence ... 10 | %impulse response. 11 | % sn: scalar, noise standard deviation 12 | % solver: string, optimization solver 13 | 14 | %% outputs 15 | % c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. 16 | % s: T*1 vector, discetized deconvolved neural activity (spikes) 17 | 18 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 19 | % ported from the Python implementation from Johannes Friedrich 20 | 21 | %% References 22 | % Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging 23 | % Pnevmatikakis E. et.al., Neuron 2016, Simultaneous Denoising, Deconvolution, and Demixing of Calcium Imaging Data 24 | 25 | %% initialization 26 | y = reshape(y, [], 1); 27 | T = length(y); 28 | if ~exist('g', 'var') || isempty(g); g = 0.95; end 29 | if ~exist('sn', 'var') || isempty(sn); sn = GetSn(y); end 30 | if ~exist('solver', 'var') || isempty(smin); solver = 'SDPT3'; end 31 | 32 | % construct the deconvolution matrix (s=G*c) 33 | len_g = length(g); 34 | g = reshape(g, 1, []); 35 | indc = bsxfun(@minus, (1:T)', 0:len_g); 36 | indr = repmat((1:T)', [1, len_g+1]); 37 | v = ones(T,1)*[1,-g]; 38 | ind = (indc>0); 39 | G = sparse(indr(ind), indc(ind), v(ind), T, T); 40 | 41 | %% run optimization 42 | cvx_solver(solver); 43 | cvx_begin quiet 44 | variable c(T) 45 | minimize(norm(c,1)) 46 | subject to 47 | G*c >=0; 48 | norm(y-c,2) <= sn*sqrt(T); 49 | cvx_end 50 | 51 | s = reshape(G*c, 1, []); 52 | s(1) = 0; 53 | c = reshape(c,1, []); 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /deconvolution/functions/estimate_parameters.m: -------------------------------------------------------------------------------- 1 | function [g, sn] = estimate_parameters(fluor, p, range_ff, method, lags, fudge_factor) 2 | %% Estimate noise standard deviation and AR coefficients if they are not present 3 | 4 | %% inputs: 5 | % fluor: N X T matrix, fluorescence trace 6 | % p: positive integer, order of AR system 7 | % lags: positive integer, number of additional lags where he autocovariance is computed 8 | % range_ff : 1 x 2 vector, nonnegative, max value <= 0.5, range of frequency (x Nyquist rate) over which the spectrum is averaged 9 | % method: string, method of averaging: Mean, median, exponentiated mean of logvalues (default) 10 | % fudge_factor: float (0< fudge_factor <= 1) shrinkage factor to reduce bias 11 | 12 | %% outputs 13 | % g: 1 x p vector, AR coefficient 14 | % sn: scalar, std of the noise 15 | 16 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 17 | % ported from the Python implementation from Johannes Friedrich 18 | 19 | %% References 20 | % Pnevmatikakis E. et.al., Neuron 2016, Simultaneous Denoising, Deconvolution, and Demixing of Calcium Imaging Data 21 | 22 | %% input arguments 23 | if ~exist('p', 'var') || isempty(p) 24 | p = 2; 25 | end 26 | if ~exist('range_ff', 'var') || isempty(range_ff) 27 | range_ff = [.25, .5]; 28 | end 29 | if ~exist('method', 'var') || isempty(method) 30 | method = 'logmexp'; 31 | end 32 | if ~exist('lags', 'var') || isempty(lags) 33 | lags = 5; 34 | end 35 | if ~exist('fudge_factor', 'var') || isempty(fudge_factor) 36 | fudge_factor = 1.0; 37 | end 38 | 39 | %% estimate noise level 40 | fluor = reshape(fluor, 1, []); 41 | sn = GetSn(fluor, range_ff, method); 42 | 43 | %% estmate AR coefficients 44 | g = estimate_time_constant(fluor, p, sn, lags, fudge_factor); -------------------------------------------------------------------------------- /deconvolution/functions/estimate_time_constant.m: -------------------------------------------------------------------------------- 1 | function g = estimate_time_constant(y, p, sn, lags, fudge_factor) 2 | %% Estimate noise standard deviation and AR coefficients if they are not present 3 | 4 | %% inputs: 5 | % y: N X T matrix, fluorescence trace 6 | % p: positive integer, order of AR system 7 | % sn: scalar, noise standard deviation, estimated if not provided 8 | % lags: positive integer, number of additional lags where he autocovariance is computed 9 | % fudge_factor: float (0< fudge_factor <= 1) shrinkage factor to reduce bias 10 | 11 | %% outputs 12 | % g: 1 x p vector, AR coefficient 13 | 14 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 15 | % adapted from the MATLAB implemention by Eftychios Pnevmatikakis and the 16 | % Python implementation from Johannes Friedrich 17 | 18 | %% References 19 | % Pnevmatikakis E. et.al., Neuron 2016, Simultaneous Denoising, Deconvolution, and Demixing of Calcium Imaging Data 20 | 21 | %% input arguments 22 | if ~exist('p', 'var') || isempty(p) 23 | p = 2; 24 | end 25 | if ~exist('sn', 'var') || isempty(sn) 26 | sn = GetSn(y); 27 | end 28 | if ~exist('lags', 'var') || isempty(lags) 29 | lags = 5; 30 | end 31 | if ~exist('fudge_factor', 'var') || isempty(fudge_factor) 32 | fudge_factor = 1; 33 | end 34 | 35 | %% estimate time constants 36 | lags = lags + p; 37 | if ~isempty(which('xcov')) %signal processing toolbox 38 | xc = xcov(y,lags,'biased'); 39 | else 40 | ynormed = (y - mean(y)); 41 | xc = nan(lags + 1, 1); 42 | for k = 0:lags 43 | xc(k + 1) = ynormed(1 + k:end)' * ynormed(1:end - k); 44 | end 45 | xc = [flipud(xc(2:end)); xc] / numel(y); 46 | end 47 | xc = xc(:); 48 | A = toeplitz(xc(lags+(1:lags)),xc(lags+(1:p))) - sn^2*eye(lags,p); 49 | g = pinv(A)*xc(lags+2:end); 50 | 51 | % while max(abs(roots([1,-g(:)']))>1) && p < 3 52 | % warning('No stable AR(%i) model found. Checking for AR(%i) model \n',p,p+1); 53 | % p = p + 1; 54 | % g = estimate_time_constants(y,p,sn,lags); 55 | % end 56 | % if p == 5 57 | % g = 0; 58 | % end 59 | 60 | % re-adjust time constant values 61 | rg = roots([1;-g(:)]); 62 | if ~isreal(rg); rg = real(rg) + .001*randn(size(rg)); end 63 | rg(rg>1) = 0.95 + 0.001*randn(size(rg(rg>1))); 64 | rg(rg<0) = 0.15 + 0.001*randn(size(rg(rg<0))); 65 | pg = poly(fudge_factor*rg); 66 | g = -pg(2:end); 67 | 68 | -------------------------------------------------------------------------------- /deconvolution/functions/exp2ar.m: -------------------------------------------------------------------------------- 1 | function g = exp2ar(tau_dr) 2 | %% convert a convolution function to an AR(2) model 3 | 4 | d = exp(-1/tau_dr(1)); 5 | r = exp(-1/tau_dr(2)); 6 | 7 | g(1) = d+r; 8 | g(2) = -d*r; -------------------------------------------------------------------------------- /deconvolution/functions/exp2kernel.m: -------------------------------------------------------------------------------- 1 | function ht = exp2kernel(taus, nmax) 2 | %% create the convolution kernel given tau_rise and tau_decay 3 | 4 | %% inputs: 5 | % taus: 1*2 vector, [tau_decay tau_rise] 6 | % nmax: scalar, length of the kernel 7 | 8 | %% outputs: 9 | % ht: nmax*1 kernel, convolution kernel 10 | 11 | %% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 12 | 13 | t = (1:nmax)'; 14 | d = exp(-1./taus(1)); 15 | r = exp(-1./taus(2)); 16 | ht = (exp(log(d)*t) - exp(log(r)*t) ) / (d - r); 17 | ht = ht/sum(ht); -------------------------------------------------------------------------------- /deconvolution/functions/foopsi.m: -------------------------------------------------------------------------------- 1 | function [c, s] = foopsi(y, g, lam, solver) 2 | %% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace 3 | % Solves the sparse non-negative deconvolution problem 4 | % min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g c_{t-1} >= 0 5 | 6 | %% inputs: 7 | % y: T*1 vector, One dimensional array containing the fluorescence intensities 8 | %withone entry per time-bin. 9 | % g: scalar, Parameter of the AR(1) process that models the fluorescence ... 10 | %impulse response. 11 | % lam: scalar, sparsity penalty parameter lambda. 12 | % solver: string, optimization solver 13 | 14 | %% outputs 15 | % c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. 16 | % s: T*1 vector, discetized deconvolved neural activity (spikes) 17 | 18 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 19 | % ported from the Python implementation from Johannes Friedrich 20 | 21 | %% References 22 | % Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging 23 | 24 | %% initialization 25 | y = reshape(y, [], 1); 26 | T = length(y); 27 | if ~exist('g', 'var') || isempty(g); g = estimate_time_constant(y, 2); end 28 | 29 | 30 | if ~exist('lam', 'var') || isempty(lam); lam = 0; end 31 | if ~exist('solver', 'var') || isempty(smin); solver = 'SDPT3'; end 32 | 33 | % construct the deconvolution matrix (s=G*c) 34 | len_g = length(g); 35 | g = reshape(g, 1, []); 36 | indc = bsxfun(@minus, (1:T)', 0:len_g); 37 | indr = repmat((1:T)', [1, len_g+1]); 38 | v = ones(T,1)*[1,-g]; 39 | ind = (indc>0); 40 | G = sparse(indr(ind), indc(ind), v(ind), T, T); 41 | 42 | %% run optimization 43 | % cvx_solver(solver); 44 | 45 | cvx_begin quiet 46 | variable c(T) 47 | minimize(0.5*(c-y)'*(c-y) + lam*(1-sum(g))*norm(c,1)) 48 | subject to 49 | G*c >=0; 50 | cvx_end 51 | 52 | s = reshape(G*c, 1, []); 53 | s(1) = 0; 54 | c = reshape(c,1, []); 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /deconvolution/functions/gen_data.m: -------------------------------------------------------------------------------- 1 | function [Y, truth, trueSpikes] = gen_data(gam, noise, T, framerate, ... 2 | firerate, b, N, seed) 3 | 4 | %% input arguments 5 | if ~exist('gam', 'var') || isempty(gam) 6 | gam = .95; 7 | end 8 | if ~exist('noise', 'var') || isempty(noise) 9 | noise = .3; 10 | end 11 | if ~exist('T', 'var') || isempty(T) 12 | T = 3000; 13 | end 14 | if ~exist('framerate', 'var') || isempty(framerate) 15 | framerate = 30; 16 | end 17 | if ~exist('firerate', 'var') || isempty(firerate) 18 | firerate = .5; 19 | end 20 | if ~exist('b', 'var') || isempty(b) 21 | b = 0; 22 | end 23 | if ~exist('N', 'var') || isempty(N) 24 | N = 20; 25 | end 26 | if ~exist('seed', 'var') || isempty(seed) 27 | seed = 13; 28 | end 29 | 30 | %% run simulation 31 | rng(seed); 32 | trueSpikes = (rand(N, T) < firerate/framerate); 33 | truth = double(trueSpikes); 34 | p = length(gam); 35 | gam = [flipud(reshape(gam, [], 1)); 1]; 36 | 37 | for t=(p+1):T 38 | truth(:, t) = truth(:, (t-p):t) * gam; 39 | end 40 | 41 | Y = b + truth + noise * randn(N, T); 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /deconvolution/functions/gen_sinusoidal_data.m: -------------------------------------------------------------------------------- 1 | function [Y, truth, trueSpikes] = gen_sinusoidal_data(gam, noise, T, framerate, ... 2 | firerate, b, N, seed) 3 | 4 | %% input arguments 5 | if ~exist('gam', 'var') || isempty(gam) 6 | gam = .95; 7 | end 8 | if ~exist('noise', 'var') || isempty(noise) 9 | noise = .3; 10 | end 11 | if ~exist('T', 'var') || isempty(T) 12 | T = 3000; 13 | end 14 | if ~exist('framerate', 'var') || isempty(framerate) 15 | framerate = 30; 16 | end 17 | if ~exist('firerate', 'var') || isempty(firerate) 18 | firerate = .5; 19 | end 20 | if ~exist('b', 'var') || isempty(b) 21 | b = 0; 22 | end 23 | if ~exist('N', 'var') || isempty(N) 24 | N = 20; 25 | end 26 | if ~exist('seed', 'var') || isempty(seed) 27 | seed = 13; 28 | end 29 | 30 | %% run simulation 31 | rng(seed); 32 | trueSpikes = bsxfun(@lt, rand(N, T),... 33 | 4 * firerate/framerate * sin((1:T)/50).^3); 34 | truth = double(trueSpikes); 35 | p = length(gam); 36 | gam = [flipud(reshape(gam, [], 1)); 1]; 37 | 38 | for t=(p+1):T 39 | truth(:, t) = truth(:, (t-p):t) * gam; 40 | end 41 | 42 | Y = b + truth + noise * randn(N, T); 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /deconvolution/functions/init_fig.m: -------------------------------------------------------------------------------- 1 | set(gcf, 'color', 'w', ... 2 | 'defaultAxesFontSize', 20, ...) 3 | 'defaultlinelinewidth',2, ... 4 | 'position', [0, 0, 100*get(gcf, 'papersize')], ... 5 | 'paperposition', [0, 0, get(gcf, 'papersize')]) 6 | -------------------------------------------------------------------------------- /deconvolution/oasis/choose_lambda.m: -------------------------------------------------------------------------------- 1 | function lam = choose_lambda(kernel,sn,prob) 2 | %% Choose regularizer weight for sparse deconvolution 3 | % The function chooses a regularization weight for sparse deconvolution 4 | % with a given kernel and noise level. The weight of the regularizer 5 | % is chosen such that noise alone cannot lead to a non-zero solution is 6 | % at least prob. 7 | 8 | % Inputs: 9 | % kernel: deconvolution kernel 10 | % if length(kernel) == 1 or length(kernel) == 2, then kernel 11 | % is treated as a set of discrete time constants g. Otherwise, 12 | % it is treated as the actual vector. 13 | % sn: noise level 14 | % prob: probability of zero solution (deafult: 0.99) 15 | 16 | % Output: 17 | % lam: regularization weight 18 | 19 | % Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation 20 | % based on ideas and discussions with J. Tubiana and G. Debregeas, 21 | % Laboratorie Jean Parrin, UPMC, France 22 | 23 | % Reference for this approach: 24 | % Selesnick, I. (2012). Sparse deconvolution (an MM algorithm) 25 | 26 | %% 27 | 28 | if nargin < 3 || isempty(prob) 29 | prob = 0.99; 30 | end 31 | 32 | if nargin < 2 || isempty(sn) 33 | sn = 1; 34 | warning('Noise value not provided. Using sn = 1...') 35 | end 36 | 37 | if length(kernel) <= 2 38 | kernel = filter(1,[1,-kernel(:)'],[1,zeros(1,999)]); 39 | end 40 | 41 | lam = sn*norm(kernel)*norminv(prob); -------------------------------------------------------------------------------- /deconvolution/oasis/create_kernel.m: -------------------------------------------------------------------------------- 1 | function kernel = create_kernel(kernel_type, pars, nMax, lb, ub, bound_pars) 2 | %% create convolution kernel 3 | %% inputs: 4 | % kernel_type: string, convolution kernel type. now support {'exp', 5 | % 'exp2', 'vector'} 6 | % pars: parameters for the selected kernel type 7 | % nMax: length of the kernel 8 | % lb: lower bound for each parameter 9 | % ub: upper bound for each parameter 10 | % bound_pars: logical variable, bound the parameters or not {1, 0} 11 | %% outputs 12 | % kernel: struct variable 13 | 14 | %% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 15 | 16 | %% kernel size 17 | if ~exist('nMax', 'var') || isempty(nMax) 18 | nMax = 100; 19 | end 20 | kernel.nMax = nMax; 21 | 22 | %% initialize kernel 23 | if ~exist('kernel_type', 'var') || isempty(kernel_type) 24 | kernel_type = 'exp2'; 25 | end 26 | if strcmpi(kernel_type, 'exp') 27 | % single exponential function: ~ exp(-t/tau) 28 | kernel.type = 'exp'; 29 | % parameter 30 | if ~exist('pars', 'var') || isempty(pars) 31 | kernel.pars = [5, .1]; 32 | else 33 | kernel = kernel.pars; 34 | end 35 | % function handle 36 | kernel.fhandle = @(pars, t) exp(-t/pars) * (1-exp(-1/pars)) ... 37 | / (1-exp(-nMax/pars)); 38 | elseif strcmpi(kernel_type, 'vector') 39 | % single vector 40 | kernel.type = 'vector'; 41 | % parameter 42 | if ~exist('pars', 'var') || isempty(pars) 43 | kernel.pars = exp(-(1:nMax)/10); 44 | else 45 | kernel.pars = pars; 46 | end 47 | % function handle 48 | kernel.fhandle = @(pars, t) pars/sum(pars); 49 | else 50 | % differencing of two exponential function: 51 | % ~ exp(-t/tau_d)-exp(-t/tau_r) 52 | kernel.type = 'exp2'; 53 | 54 | % parameters 55 | if ~exist('pars', 'var') || isempty(pars) 56 | kernel.pars = [10, 1]; 57 | else 58 | kernel.pars = pars; 59 | end 60 | % function handle 61 | kernel.fhandle = @(pars, t) (exp(-t/pars(1)) - exp(-t/pars(2))) ... 62 | /( (1-exp(-nMax/pars(1)))/(1-exp(-1/pars(1))) ... 63 | - (1-exp(-nMax/pars(2)))/(1-exp(-1/pars(2)))); 64 | end 65 | 66 | % lower and upper bounds for parameters 67 | if ~exist('lb', 'var') || isempty(lb) 68 | kernel.lb = 0.5*kernel.pars; 69 | else 70 | kernel.lb = lb; 71 | end 72 | if ~exist('ub', 'var') || isempty(ub) 73 | kernel.ub = 2*kernel.pars; 74 | else 75 | kernel.ub = ub; 76 | end 77 | 78 | % bound the parameters of not 79 | if ~exist('bound_pars', 'var')||isempty(bound_pars) 80 | kernel.bound_pars = true; 81 | else 82 | kernel.bound_pars = bound_pars; 83 | end -------------------------------------------------------------------------------- /deconvolution/oasis/dsKernel.m: -------------------------------------------------------------------------------- 1 | function kernel_new = dsKernel(kernel, tsub) 2 | %% downsample/upsample the convolution kernel 3 | %% inputs: 4 | % kernel: struct variable with fields {'kernel_type', 'pars', 'nMax', 'lb', 'ub', 'bound_pars'} 5 | % kernel_type: string, convolution kernel type. now support {'exp', 6 | % 'exp2', 'vector'} 7 | % pars: parameters for the selected kernel type 8 | % nMax: length of the kernel 9 | % lb: lower bound for each parameter 10 | % ub: upper bound for each parameter 11 | % bound_pars: logical variable, bound the parameters or not {1, 0} 12 | %% outputs 13 | % kernel: struct variable 14 | 15 | %% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 16 | 17 | kernel_new = kernel; 18 | if nargin<2 || isempty(tsub) 19 | return; 20 | end 21 | 22 | %% kernel size 23 | kernel_new.nMax = ceil(kernel.nMax/tsub); 24 | 25 | %% kernel type 26 | kernel_type = kernel.type; 27 | if strcmpi(kernel_type, 'exp') 28 | % single exponential function: ~ exp(-t/tau) 29 | kernel_new.pars = kernel.pars/tsub; 30 | elseif strcmpi(kernel_type, 'vector') 31 | % single vector 32 | len_kernel = length(kernel.pars); 33 | kernel_new.pars = resample(kernel.pars, ceil(len_kernel/tsub), len_kernel); 34 | else 35 | % differencing of two exponential function: 36 | % ~ exp(-t/tau_d)-exp(-t/tau_r) 37 | kernel_new.pars = kernel.pars/tsub; 38 | end 39 | 40 | %% lower and upper bounds for parameters 41 | kernel_new.lb = kernel.lb / tsub; 42 | kernel_new.ub = kernel.ub / tsub; -------------------------------------------------------------------------------- /deconvolution/oasis/test_oasis.m: -------------------------------------------------------------------------------- 1 | %% function 2 | clear; clc; close all; 3 | T = 1000; 4 | s = double(rand(1, T)>0.98); 5 | sig = 0.04; 6 | 7 | % example 8 | tau_d = 5; 9 | tau_r = 1; 10 | nMax = 100; 11 | pars = [tau_d, tau_r]; 12 | kernel = create_kernel('exp2', pars, nMax); 13 | 14 | t = 1:kernel.nMax; 15 | gt = kernel.fhandle(kernel.pars, t); 16 | c1 = conv(s, gt); 17 | c1 = c1(1:T); 18 | y1 = c1 + randn(1, T) * sig; 19 | 20 | %% use the true convolution kernel 21 | kernel0 = kernel; 22 | kernel0.pars = [10, 0.1]; 23 | kernel0.bound_pars = false; 24 | figure('position', [1,1,1500, 200]); 25 | plot(y1); 26 | hold on; 27 | plot(c1, 'r', 'linewidth', 2); 28 | plot(-s*0.1, 'r', 'linewidth', 2); 29 | tic; 30 | [chat, shat, kernel_fit, iters] = deconvCa(y1, kernel0, 2, true, false); 31 | toc; 32 | plot(chat,'-.g','linewidth', 2); 33 | plot(-shat*0.1, '-.g', 'linewidth', 2); %, '-.'); 34 | legend('data', 'ground truth: c','ground truth: s', 'OASIS:c', 'OASIS: s'); % 'gound truth: s', 'OASIS: c', 'OASIS: s'); -------------------------------------------------------------------------------- /deconvolution/oasis/update_g.m: -------------------------------------------------------------------------------- 1 | function [c, active_set, g, s] = update_g(y, active_set, g, lam) 2 | %% update the tuning parameter lambda to reduce |s|_1 while |y-c|_2^2 <= sn^2*T 3 | 4 | %% inputs: 5 | % y: T*1 vector, One dimensional array containing the fluorescence intensities 6 | %withone entry per time-bin. 7 | % active_set: npools*4 matrix, previous active sets 8 | % g: scalar, Parameter of the AR(1) process that models the fluorescence ... 9 | %impulse response. 10 | % lam: scalar, curret value of sparsity penalty parameter lambda. 11 | 12 | %% outputs 13 | % c: T*1 vector 14 | % s: T*1 vector, spike train 15 | % active_set: npool x 4 matrix, active sets 16 | % g: scalar 17 | 18 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 19 | % ported from the Python implementation from Johannes Friedrich 20 | 21 | %% References 22 | % Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging 23 | 24 | %% initialization 25 | len_active_set = size(active_set, 1); %number of active sets 26 | y = reshape(y,[],1); % fluorescence data 27 | maxl = max(active_set(:, 4)); % maximum ISI 28 | c = zeros(size(y)); % the optimal denoised trace 29 | 30 | %% find the optimal g and get the warm started active_set 31 | g = fminbnd(@rss_g, 0, 1); 32 | yp = y - lam*(1-g); 33 | for m=1:len_active_set 34 | tmp_h = exp(log(g)*(0:maxl)'); % response kernel 35 | tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) 36 | li = active_set(m, 4); 37 | ti = active_set(m, 3); 38 | idx = ti:(ti+li-1); 39 | active_set(m,1) = (yp(idx))'*tmp_h(1:li); 40 | active_set(m,2) = tmp_hh(li); 41 | end 42 | [c,s,active_set] = oasisAR1(y, g, lam, [], active_set); 43 | 44 | %% nested functions 45 | function rss = rss_g(g) 46 | h = exp(log(g)*(0:maxl)'); % response kernel 47 | hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) 48 | yp = y - lam*(1-g); % include the penalty term 49 | for ii=1:len_active_set 50 | li = active_set(ii, 4); 51 | ti = active_set(ii, 3); 52 | idx = ti:(ti+li-1); 53 | tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); 54 | c(idx) = tmp_v*h(1:li); 55 | end 56 | res = y-c; 57 | rss = res'*res; % residual sum of squares 58 | end 59 | end 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /deconvolution/oasis/update_lam.m: -------------------------------------------------------------------------------- 1 | function [c, active_set, lam, s, flag_lam] = update_lam(y, c, active_set, g, lam, thresh) 2 | %% update the tuning parameter lambda to reduce |s|_1 while |y-c|_2^2 <= sn^2*T 3 | 4 | %% inputs: 5 | % y: T*1 vector, One dimensional array containing the fluorescence intensities 6 | %withone entry per time-bin. 7 | % c: T*1 vector, previous c 8 | % active_set: npools*4 matrix, previous active sets 9 | % g: scalar, Parameter of the AR(1) process that models the fluorescence ... 10 | %impulse response. 11 | % lam: scalar, curret value of sparsity penalty parameter lambda. 12 | % thresh: maximum residual sn*T^2 13 | 14 | %% outputs 15 | % c: T*1 vector 16 | % s: T*1 vector, spike train 17 | % active_set: npool x 4 matrix, active sets 18 | % lam: scalar, new tuning parameter 19 | % flag_lam: bool, True if it update lam with success 20 | %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 21 | % ported from the Python implementation from Johannes Friedrich 22 | 23 | %% References 24 | % Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging 25 | 26 | c = reshape(c, [],1); 27 | y = reshape(y, [],1); 28 | len_active_set = size(active_set,1); 29 | 30 | res = y - c; 31 | RSS = res'*res; 32 | 33 | temp = zeros(size(c)); 34 | for ii=1:len_active_set 35 | ti = active_set(ii, 3); 36 | li = active_set(ii, 4); 37 | idx = 0:(li-1); 38 | temp(ti+idx) = (1-g^li)/ active_set(ii,2) * g.^(idx); 39 | end 40 | 41 | aa = temp'*temp; 42 | bb = res'*temp; 43 | cc = RSS-thresh; 44 | ll = (-bb + sqrt(bb^2-aa*cc)) / aa; 45 | if imag(ll)~=0 46 | flag_lam = false; 47 | s = [0; c(2:end)-c(1:(end-1))*g]; 48 | return; 49 | else 50 | flag_lam = true; 51 | end 52 | lam = lam + ll; 53 | 54 | active_set(:,1) = active_set(:,1) - ll*(1-g.^active_set(:,4)); 55 | [c, s, active_set] = oasisAR1(y, g, lam, 0, active_set); 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /demoMovie.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/demoMovie.tif -------------------------------------------------------------------------------- /demo_GUI.m: -------------------------------------------------------------------------------- 1 | clear; 2 | %% load file 3 | addpath(genpath('../ca_source_extraction')); 4 | 5 | clear; 6 | gcp; % start a local cluster 7 | 8 | filename = 'demoSue2x.tif'; 9 | if ~exist(filename,'file'); 10 | url = 'https://www.dropbox.com/s/36xdfd28eone0hj/demoSue2x.tif?dl=1'; 11 | fprintf('downloading the file...'); 12 | outfilename = websave(filename,url); 13 | fprintf('done. \n'); 14 | end 15 | 16 | 17 | Y = read_file(filename); 18 | Y = Y - min(Y(:)); 19 | if ~isa(Y,'single'); Y = single(Y); end % convert to single 20 | [d1,d2,T] = size(Y); % dimensions of dataset 21 | d = d1*d2; % total number of pixels 22 | 23 | %% Set parameters 24 | % All the parameters can be changed here look at the CNMFsetparams.m file 25 | % for more information about each parameters. 26 | K = 130; % number of components to be found 27 | tau = 4; % std of gaussian kernel (size of neuron) 28 | p = 2; % order of autoregressive system (p = 0 no dynamics, p=1 just decay, p = 2, both rise and decay) 29 | merge_thr = 0.8; % merging threshold 30 | options = CNMFSetParms(... 31 | 'd1',d1,'d2',d2,... % dimensions of datasets 32 | 'search_method','dilate','dist',3,... % search locations when updating spatial components 33 | 'deconv_method','constrained_foopsi',... % activity deconvolution method 34 | 'temporal_iter',2,... % number of block-coordinate descent steps 35 | 'fudge_factor',0.98,... % bias correction for AR coefficients 36 | 'merge_thr',merge_thr,... % merging threshold 37 | 'gSig',tau... 38 | ); 39 | %% Data pre-processing 40 | 41 | [P,Y] = preprocess_data(Y,p); 42 | [A,C,b,f,~] = initialize_components(Y,K,tau,options,P); % initialize 43 | Cn = correlation_image(Y); 44 | %% GUI ------ 45 | %this will create a User interface for the rest of the pipeline described in demoscript and 46 | %demo pipeline. LOOK at demo pipeline to understand how to use this GUI and what to pass it 47 | % 48 | %It is a mix of everyhting found in those pipelines. In the future it will be also called by 49 | %the initialization GUI 50 | % 51 | %run GUI will let you, refine the components manually, change the parameters and see the results, 52 | %analyse the trace of each components, use a classification algorithm to 53 | %find the components instead, add and remove components, save the ROIS 54 | %and finish the pipeline with button clicks. 55 | %It is still an optional method. 56 | 57 | % WARNING : do not use simplemode for now - minimum MATLAB VERSION 2014 58 | % save is only compatible with the JSON matlabpackage 59 | 60 | % here is what the GUI needs to receive in parameters 61 | GUIout = ROI_GUI(Y,A,P,options,Cn,C,b,f); 62 | pause; 63 | %% ----------- 64 | A =GUIout{1}; 65 | options = GUIout{2}; 66 | Cdec = GUIout{3}; 67 | ROIvars = GUIout{4}; 68 | YrA=GUIout{5}; 69 | Contours=GUIout{6}; 70 | b=GUIout{7}; 71 | f=GUIout{8}; 72 | Spikes=GUIout{9}; 73 | 74 | %% make movie 75 | 76 | make_patch_video(A,ROIvars.C,b,f,YrA,Contours,options) -------------------------------------------------------------------------------- /demo_patches_class.m: -------------------------------------------------------------------------------- 1 | % demo script for splitting the field of view in patches and processing in 2 | % parallel with or without memory mapping. The demo follows the file 3 | % demo_patches.m using the CNMF class object 4 | 5 | clear; 6 | %% setup path to file and package 7 | gcp; 8 | path_to_package = '../ca_source_extraction'; % path to the folder that contains the package 9 | addpath(genpath(path_to_package)); 10 | 11 | filename = '/Users/epnevmatikakis/Documents/Ca_datasets/Neurofinder/neurofinder.02.00/images/neurofinder0200_rig.tif'; 12 | % path to file (assumed motion corrected) 13 | 14 | is_memmaped = true; % choose whether you want to load the file in memory or not 15 | 16 | %% create object and load file 17 | 18 | CNM = CNMF(); 19 | if is_memmaped 20 | CNM.readFile(filename,is_memmaped); 21 | else 22 | CNM.readFile(filename,is_memmaped,1,2000); % load only a part of the file due to memory 23 | end 24 | 25 | %% set options and create patches 26 | 27 | patch_size = [32,32]; % size of each patch along each dimension (optional, default: [32,32]) 28 | overlap = [6,6]; % amount of overlap in each dimension (optional, default: [4,4]) 29 | K = 10; % number of components to be found 30 | gSig = 7; % std of gaussian kernel (size of neuron) 31 | p = 2; % order of autoregressive system (p = 0 no dynamics, p=1 just decay, p = 2, both rise and decay) 32 | gnb = 3; % order of background 33 | merge_thr = 0.8; % merging threshold 34 | 35 | options = CNMFSetParms(... 36 | 'd1',CNM.dims(1),'d2',CNM.dims(2),... 37 | 'search_method','dilate',... % search locations when updating spatial components 38 | 'deconv_method','constrained_foopsi',... % activity deconvolution method 39 | 'nb',1,... % number of background components per patch 40 | 'gnb',gnb,... % number of global background components 41 | 'ssub',2,... 42 | 'tsub',1,... 43 | 'p',p,... % order of AR dynamics 44 | 'merge_thr',merge_thr,... % merging threshold 45 | 'gSig',gSig,... 46 | 'spatial_method','regularized',... 47 | 'cnn_thr',0.2,... 48 | 'patch_space_thresh',0.25,... 49 | 'min_SNR',2); 50 | 51 | CNM.optionsSet(options); 52 | CNM.gnb = gnb; 53 | CNM.K = K; 54 | CNM.patch_size = patch_size; % size of each patch along each dimension (optional, default: [32,32]) 55 | CNM.overlap = overlap; % amount of overlap in each dimension (optional, default: [4,4]) 56 | CNM.createPatches(); % create patches 57 | 58 | 59 | %% fit all patches 60 | CNM.fitPatches(); 61 | 62 | %% component classification 63 | 64 | CNM.evaluateComponents(); % evaluate spatial components based on their correlation with the data 65 | CNM.CNNClassifier('') % evaluate spatial components with the CNN classifier 66 | CNM.eventExceptionality(); % evaluate traces 67 | CNM.keepComponents(); % keep the components that are above certain thresholds 68 | 69 | %% repeat processing 70 | 71 | CNM.updateSpatial(); 72 | CNM.updateTemporal(); 73 | CNM.extractDFF(); % extract DF/F values. 74 | 75 | %% do some plotting 76 | figure; 77 | CNM.correlationImage(); 78 | CNM.plotContours(); 79 | CNM.plotComponentsGUI(); % display all components -------------------------------------------------------------------------------- /demo_script_class.m: -------------------------------------------------------------------------------- 1 | clear; 2 | gcp; 3 | 4 | % same demo as demo_script.m but using the class @CNMF 5 | %% load file 6 | 7 | addpath(genpath('utilities')); 8 | addpath(genpath('deconvolution')); 9 | CNM = CNMF; % contruct CNMF object 10 | filename = 'demoMovie.tif'; % filename to be processed 11 | K = 40; % number of components to be found 12 | 13 | options = CNMFSetParms(... 14 | 'p',2,... % order of AR dynamics 15 | 'gSig',5,... % half size of neuron 16 | 'merge_thr',0.80,... % merging threshold 17 | 'nb',2,... % number of background components 18 | 'min_SNR',3,... % minimum SNR threshold 19 | 'space_thresh',0.5,... % space correlation threshold 20 | 'cnn_thr',0.2... % threshold for CNN classifier 21 | ); 22 | 23 | %% 24 | % Below is the standard processing pipeline. This processing can be 25 | % executed in one shot using the CNM.fit function: 26 | % CNM.fit(filename,options,K) 27 | 28 | 29 | %% load the dataset and create the object 30 | CNM.readFile(filename); % insert path to file here 31 | CNM.optionsSet(options); % setup the options structure 32 | 33 | %% Process the dataset 34 | 35 | CNM.preprocess; % preprocessing (compute some quantities) 36 | CNM.initComponents(K); % initialization 37 | CNM.plotCenters() % plot center of ROIs detected during initialization 38 | CNM.updateSpatial(); % update spatial components 39 | CNM.updateTemporal(0); % update temporal components (do not deconvolve at this point) 40 | 41 | %% component classification 42 | 43 | CNM.evaluateComponents(); % evaluate spatial components based on their correlation with the data 44 | CNM.CNNClassifier('') % evaluate spatial components with the CNN classifier 45 | CNM.eventExceptionality(); % evaluate traces 46 | CNM.keepComponents(); % keep the components that are above certain thresholds 47 | 48 | %% merge found components 49 | CNM.merge(); 50 | CNM.displayMerging(); 51 | 52 | %% repeat processing 53 | 54 | CNM.updateSpatial(); 55 | CNM.updateTemporal(); 56 | CNM.extractDFF(); % extract DF/F values. 57 | 58 | %% do some plotting 59 | figure; 60 | CNM.plotContours(); 61 | CNM.plotComponentsGUI(); % display all components -------------------------------------------------------------------------------- /docs/notes/ROI_GUI_info.txt: -------------------------------------------------------------------------------- 1 | ###################################### 2 | ########## DISCARDING INFO ########### 3 | 4 | In the GUI to refine the component, 5 | be carefull in using discarding 6 | 7 | 8 | Nonetheless, if you have used it by mistake: 9 | 10 | you can set a breakpoint somewhere in 11 | the replot function in the ROI GUI matlab file. 12 | once it is done, just change one variable. 13 | 14 | now go in the terminal of matlab 15 | and save your undiscarded idx that you can find in 16 | handles.keep as a list of bool 17 | and your discarded one un handles.disc 18 | as a list of bool with true meaning 19 | discarded. 20 | if you change the right index into false again, 21 | you will have directly un discarded this component. 22 | 23 | Jérémie KALFON 24 | -------------------------------------------------------------------------------- /documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/documentation.pdf -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_choose_data.m: -------------------------------------------------------------------------------- 1 | global data Ysiz d1 d2 numFrame; 2 | 3 | %% select file 4 | if ~exist('nam', 'var') || isempty(nam) 5 | % choose files manually 6 | try 7 | load .dir.mat; %load previous path 8 | catch 9 | dir_nm = [cd(), filesep]; %use the current path 10 | end 11 | [file_nm, dir_nm] = uigetfile(fullfile(dir_nm, '*.tif;*.mat')); 12 | nam = [dir_nm, file_nm]; % full name of the data file 13 | [dir_nm, file_nm, file_type] = fileparts(nam); 14 | else 15 | % use pre-specified file 16 | if exist(nam, 'file') 17 | [dir_nm, file_nm, file_type] = fileparts(nam); 18 | else 19 | dir_nm = 0; 20 | end 21 | end 22 | if dir_nm~=0 23 | save .dir.mat dir_nm; 24 | else 25 | fprintf('no file was selected. STOP!\n'); 26 | return; 27 | end 28 | 29 | %% convert the data to mat file 30 | nam_mat = [dir_nm, filesep, file_nm, '.mat']; 31 | if strcmpi(file_type, '.mat') 32 | fprintf('The selected file is *.mat file\n'); 33 | elseif exist(nam_mat, 'file') 34 | % the selected file has been converted to *.mat file already 35 | fprintf('The selected file has been replaced with its *.mat version.\n'); 36 | elseif or(strcmpi(file_type, '.tif'), strcmpi(file_type, '.tiff')) 37 | % convert 38 | tic; 39 | fprintf('converting the selected file to *.mat version...\n'); 40 | nam_mat = tif2mat(nam); 41 | fprintf('Time cost in converting data to *.mat file: %.2f seconds\n', toc); 42 | else 43 | fprintf('The selected file type was not supported yet! email me to get support (zhoupc1988@gmail.com)\n'); 44 | return; 45 | end 46 | 47 | %% information of the data 48 | data = matfile(nam_mat); 49 | Ysiz = data.Ysiz; 50 | d1 = Ysiz(1); %height 51 | d2 = Ysiz(2); %width 52 | numFrame = Ysiz(3); %total number of frames 53 | 54 | fprintf('\nThe data has been mapped to RAM. It has %d X %d pixels X %d frames. \nLoading all data requires %.2f GB RAM\n\n', d1, d2, numFrame, prod(Ysiz)*8/(2^30)); -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_demix_video.m: -------------------------------------------------------------------------------- 1 | %% play videos to verify the demixing results 2 | cell_id = []; 3 | while true 4 | temp = input('input cell ID (type 0 to end): '); 5 | temp = round(temp); 6 | if and(temp>=1, temp<=size(neuron.A, 2)) 7 | cell_id(end+1) = temp; %#ok 8 | else 9 | break; 10 | end 11 | end 12 | 13 | nc = ceil((length(cell_id)+1)/2); 14 | ctr = round( neuron.estCenter()); 15 | center = ctr(cell_id, :); 16 | bd = 10; 17 | r0 = max(1, min(center(:, 1))-bd); r1 = min(d1, max(center(:, 1))+bd); 18 | c0 = max(1, min(center(:, 2))-bd); c1 = min(d2, max(center(:, 2))+bd); 19 | indr = r0:r1; 20 | indc = c0:c1; 21 | center = bsxfun(@minus, center, [r0, c0]-1); 22 | Ysignal = neuron.reshape(Ysignal, 2); 23 | Ysignal_box = Ysignal(r0:r1, c0:c1, :); 24 | 25 | figure('position', [100, 500, 1400, 480]); 26 | avi_file = VideoWriter([dir_nm, file_nm, '_patch_neurons_2.avi']); 27 | avi_file.open(); 28 | ACmax = max(reshape(neuron.A(:, cell_id)*neuron.C(cell_id, :), 1, []))*0.5; 29 | ACmin = 100; 30 | subplot(2, round(nc/2)+1, 1); 31 | h_img = imagesc(Ysignal_box(:, :, 1), [ACmin, ACmax]); hold on; 32 | axis equal off tight; 33 | for m=1:length(cell_id) 34 | text(center(m,2), center(m, 1), num2str(m), 'color', 'g', 'fontsize', 12, 'fontweight', 'bold'); 35 | tmp_ctr = neuron.Coor{cell_id(m)}; 36 | xx = tmp_ctr(1, :); yy = tmp_ctr(2, :); 37 | ind = or(or(xxc1, yy>r1)); 38 | xx(ind) = []; 39 | yy(ind) = []; 40 | temp = plot(xx-c0, yy-r0, 'r'); 41 | end 42 | for t=1:2:T 43 | subplot(2, nc, 1); hold off; 44 | imagesc(Ysignal_box(:, :, t), [ACmin, ACmax]);hold on; 45 | axis equal off tight; 46 | for m=1:length(cell_id) 47 | text(center(m,2), center(m, 1), num2str(m), 'color', 'g', 'fontsize', 12, 'fontweight', 'bold'); 48 | tmp_ctr = neuron.Coor{cell_id(m)}; 49 | xx = tmp_ctr(1, :); yy = tmp_ctr(2, :); 50 | ind = or(or(xxc1, yy>r1)); 51 | xx(ind) = []; 52 | yy(ind) = []; 53 | temp = plot(xx-c0, yy-r0, 'r'); 54 | end 55 | title(sprintf('Time: %.2f Sec', t/neuron.Fs)); 56 | 57 | for m=1:length(cell_id) 58 | subplot(2, nc, m+1); 59 | img = neuron.reshape(neuron.A(:, cell_id(m))*neuron.C(cell_id(m), t), 2); 60 | img = img(indr, indc); 61 | imagesc(img, [ACmin, ACmax]); 62 | axis equal off tight; 63 | title(sprintf('neuron %d', m)); 64 | end 65 | drawnow(); 66 | frame = getframe(gcf); 67 | frame.cdata = imresize(frame.cdata, [480, 1400]); 68 | avi_file.writeVideo(frame); 69 | % disp(t); 70 | end 71 | avi_file.close(); 72 | -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_full.m: -------------------------------------------------------------------------------- 1 | %% upsample the CNMF results 2 | A0 = neuron_ds.reshape(neuron_ds.A, 2); 3 | C0 = neuron_ds.C; 4 | C0_raw = neuron_ds.C_raw; 5 | kernel_pars = neuron_ds.P.kernel_pars; 6 | K = size(C0, 1); % number of the neuron 7 | 8 | neuron.A = neuron.reshape(imresize(A0, [d1, d2]), 1); 9 | C = zeros(K, num2read); 10 | C(:, 1:T*tsub) = resample(C0', tsub, 1)'; 11 | temp = num2read - T*tsub; 12 | if temp>0 13 | C(:, (num2read-temp+1):end) = C(:, T*tsub) * ones(1, temp); 14 | end 15 | neuron.C = C; 16 | neuron.C_raw = zeros(K, num2read); 17 | neuron.S = zeros(K, num2read); 18 | neuron.P.kernel_pars = kernel_pars * tsub; 19 | 20 | %% load data 21 | Y = data.Y(:, :, sframe:(sframe+num2read-1)); 22 | Y = neuron.reshape(double(Y), 1); 23 | 24 | if ssub ==1 25 | neuron.P.sn = sn; 26 | elseif ~isfield(neuron.P, 'sn') || isempty(neuron.P.sn) 27 | sn = neuron.estNoise(Y); 28 | neuron.P.sn = sn; 29 | else 30 | sn = neuron.P.sn; 31 | end 32 | 33 | %% estimate the background 34 | rr = bg_neuron_ratio * neuron.options.gSiz; 35 | cnmfe_update_BG; 36 | 37 | %% update the spatial and components 38 | maxIter = 3; 39 | for miter=1:maxIter 40 | fprintf('Iteration %d/%d to update spatial and temporal components\n', miter, maxIter); 41 | tic; 42 | neuron.updateSpatial_endoscope(Ysignal, max_overlap); 43 | fprintf('Time cost in updating neuronal spatial components: %.2f seconds\n', toc); 44 | 45 | neuron.updateTemporal_endoscope(Ysignal, smin); 46 | fprintf('Time cost in updating neuronal temporal components: %.2f seconds\n', toc); 47 | end 48 | -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_load_data.m: -------------------------------------------------------------------------------- 1 | if and(ssub==1, tsub==1) 2 | neuron = neuron_full; 3 | Y = double(data.Y(:, :, sframe+(1:num2read)-1)); 4 | [d1s,d2s, T] = size(Y); 5 | fprintf('\nThe data has been loaded into RAM. It has %d X %d pixels X %d frames. \nLoading all data requires %.2f GB RAM\n\n', d1s, d2s, T, d1s*d2s*T*8/(2^30)); 6 | else 7 | [Y, neuron_ds] = neuron_full.load_data(nam_mat, sframe, num2read); 8 | [d1s,d2s, T] = size(Y); 9 | fprintf('\nThe data has been downsampled and loaded into RAM. It has %d X %d pixels X %d frames. \nLoading all data requires %.2f GB RAM\n\n', d1s, d2s, T, d1s*d2s*T*8/(2^30)); 10 | neuron = neuron_ds.copy(); 11 | end 12 | -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_quick_merge.m: -------------------------------------------------------------------------------- 1 | neuron_bk = neuron.copy(); 2 | [merged_ROI, newIDs] = neuron.quickMerge(merge_thr); % merge neurons based on the correlation computed with {'A', 'S', 'C'} 3 | % A: spatial shapes; S: spike counts; C: calcium traces 4 | if display_merge && ~isempty(merged_ROI) 5 | figure('position', [1,1, 1200, 600]); 6 | ind_before = false(size(neuron_bk.A, 2), 1); 7 | ind_after = false(size(neuron.A, 2), 1); 8 | m = 1; 9 | while m<=length(merged_ROI) 10 | subplot(221); 11 | tmp_img = neuron_bk.overlapA(merged_ROI{m}); 12 | imagesc(tmp_img); 13 | axis equal off tight; 14 | subplot(222); 15 | imagesc(tmp_img); 16 | axis equal off tight; 17 | [tmp_r, tmp_c, ~] = find(sum(tmp_img, 3)>0); 18 | xlim([min(tmp_c)-10, max(tmp_c)+10]); 19 | ylim([min(tmp_r)-10, max(tmp_r)+10]); 20 | % neuron.image(sum(Ain(:, merged_ROI{m}), 2)); 21 | axis off; 22 | subplot(2,2,3:4); 23 | tmp_C = neuron_bk.C_raw(merged_ROI{m}, :)'; 24 | tmp_C = bsxfun(@times, tmp_C, 1./max(tmp_C, [], 1)); 25 | plot(tmp_C, 'linewidth', 2); 26 | 27 | temp = input('keep this merge? (y(default)/n(cancel)/b(back))/e(end) ', 's'); 28 | if strcmpi(temp, 'n') 29 | ind_after(newIDs(m)) = true; 30 | ind_before(merged_ROI{m}) = true; 31 | m = m+1; 32 | elseif strcmpi(temp, 'b') 33 | m = m-1; 34 | elseif strcmpi(temp, 'e') 35 | break; 36 | else 37 | m = m+1; 38 | end 39 | end 40 | 41 | neuron.A = [neuron.A(:, ~ind_after), neuron_bk.A(:, ind_before)]; 42 | neuron.C = [neuron.C(~ind_after, :); neuron_bk.C(ind_before, :)]; 43 | neuron.C_raw = [neuron.C_raw(~ind_after, :); neuron_bk.C_raw(ind_before, :)]; 44 | neuron.S = [neuron.S(~ind_after, :); neuron_bk.S(ind_before, :)]; 45 | neuron.P.kernel_pars = [neuron.P.kernel_pars(~ind_after, :); neuron_bk.P.kernel_pars(ind_before, :)]; 46 | clear neuron_bk; 47 | end 48 | 49 | % sort neurons 50 | [Cpnr, srt] = sort(max(neuron.C, [], 2).*max(neuron.A, [], 1)', 'descend'); 51 | neuron.orderROIs(srt); 52 | [Ain, Cin] = neuron.snapshot(); % keep the initialization results 53 | 54 | %% view neurons 55 | if view_neurons 56 | neuron.viewNeurons([], neuron.C_raw); 57 | end -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_save_video.m: -------------------------------------------------------------------------------- 1 | %% 2 | Yac = neuron.reshape(neuron.A*neuron.C, 2); 3 | Ybg = neuron.reshape(Ybg, 2); 4 | % Y = neuron.reshape(Y, 2); 5 | Ysignal = neuron.reshape(Ysignal, 2); 6 | % ctr = round( neuron.estCenter()); 7 | % figure; 8 | % neuron.viewContours(Cn, .5, 0); 9 | % cell_IDs = []; 10 | 11 | figure('position', [0,0, 1248, 600]); 12 | % avi_file = VideoWriter('~/Dropbox/Public/Garret/day1/residual.avi'); 13 | if save_avi 14 | avi_file = VideoWriter([dir_nm, file_nm, '_results.avi']); 15 | avi_file.open(); 16 | end 17 | temp = quantile(Ybg(1:1000:numel(Ybg)), [0.0001, y_quantile]); 18 | Ymin = temp(1); 19 | Ymax = temp(2); 20 | ACmax = quantile(Yac(1:1000:numel(Yac)), ac_quantile); 21 | 22 | % subplot(4,6, [5,6,11,12]); 23 | for m=1:kt:T 24 | subplot(4,6, [1,2, 7, 8]); 25 | imagesc(Ybg(:, :,m)+Ysignal(:, :, m), [Ymin, Ymax]); 26 | set(gca, 'children', flipud(get(gca, 'children'))); 27 | axis equal; axis off tight; title('raw data'); hold on; colorbar; 28 | 29 | subplot(4, 6, [1,2, 7, 8]+12); 30 | imagesc(Ybg(:, :, m), [Ymin, Ymax]); 31 | set(gca, 'children', flipud(get(gca, 'children'))); 32 | axis equal; axis off tight; title('background'); 33 | colorbar; 34 | 35 | subplot(4,6, [3,4, 9,10]); 36 | imagesc(Ysignal(:, :, m), [0, ACmax]); hold on; 37 | set(gca, 'children', flipud(get(gca, 'children'))); 38 | axis equal; axis off tight; title('raw-background'); hold on; colorbar; 39 | 40 | 41 | subplot(4, 6, [3,4, 9,10]+12); 42 | imagesc(Ysignal(:, :, m)-Yac(:, :, m), [-ACmax, ACmax]/2); hold on; 43 | set(gca, 'children', flipud(get(gca, 'children'))); 44 | axis equal; axis off tight; title('residual'); hold on; colorbar; 45 | 46 | subplot(4,6, [5,6,11,12]); 47 | imagesc(Yac(:, :, m), [0, ACmax]); 48 | % imagesc(Ybg(:, :, m), [-50, 50]); 49 | text(d2/2-30, 10, sprintf('Time: %.2f Sec', m/neuron.Fs), 'color', 'w'); 50 | axis equal off tight; title('denoised'); colorbar; 51 | 52 | drawnow(); 53 | if save_avi 54 | temp = getframe(gcf); 55 | temp = imresize(temp.cdata, [600, 1248]); 56 | avi_file.writeVideo(temp); 57 | end 58 | end 59 | 60 | if save_avi 61 | avi_file.close(); 62 | end 63 | -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_show_corr_pnr.m: -------------------------------------------------------------------------------- 1 | [Cn, pnr] = neuron.correlation_pnr(Y(:, round(linspace(1, T, min(T, 1000))))); 2 | 3 | % show correlation image 4 | figure('position', [10, 500, 1776, 400]); 5 | subplot(131); 6 | imagesc(Cn, [0, 1]); colorbar; 7 | axis equal off tight; 8 | title('correlation image'); 9 | 10 | % show peak-to-noise ratio 11 | subplot(132); 12 | imagesc(pnr,[0,max(pnr(:))*0.98]); colorbar; 13 | axis equal off tight; 14 | title('peak-to-noise ratio'); 15 | 16 | % show pointwise product of correlation image and peak-to-noise ratio 17 | subplot(133); 18 | imagesc(Cn.*pnr, [0,max(pnr(:))*0.98]); colorbar; 19 | axis equal off tight; 20 | title('Cn*PNR'); -------------------------------------------------------------------------------- /endoscope/cnmfe_scripts/cnmfe_update_BG.m: -------------------------------------------------------------------------------- 1 | clear Ysignal; 2 | tic; 3 | Ybg = Y-neuron.A*neuron.C; 4 | rr = ceil(neuron.options.gSiz * bg_neuron_ratio); 5 | active_px = []; %(sum(IND, 2)>0); %If some missing neurons are not covered by active_px, use [] to replace IND 6 | [Ybg, Ybg_weights] = neuron.localBG(Ybg, spatial_ds_factor, rr, active_px, sn, 5); % estiamte local background. 7 | % subtract the background from the raw data. 8 | Ysignal = Y - Ybg; -------------------------------------------------------------------------------- /endoscope/correlation_image_endoscope.m: -------------------------------------------------------------------------------- 1 | function [Cn, PNR] = correlation_image_endoscope(Y, options) 2 | %% compute correlation image of endoscopic data. it has to spatially filter the data first 3 | %% Input: 4 | % Y: d X T matrx, imaging data 5 | % options: struct data of paramters/options 6 | % d1: number of rows 7 | % d2: number of columns 8 | % gSiz: maximum size of a neuron 9 | % nb: number of background 10 | % min_corr: minimum threshold of correlation for segementing neurons 11 | %% Output: 12 | % Cn: d1*d2, correlation image 13 | % PNR: d1*d2, peak to noise ratio 14 | %% Author: Pengcheng Zhou, Carnegie Mellon University. zhoupc1988@gmail.com 15 | 16 | %% use correlation to initialize NMF 17 | %% parameters 18 | d1 = options.d1; % image height 19 | d2 = options.d2; % image width 20 | gSig = options.gSig; % width of the gaussian kernel approximating one neuron 21 | gSiz = options.gSiz; % average size of neurons 22 | sig = 5; % thresholding noise by sig*std() 23 | 24 | if ismatrix(Y); Y = reshape(Y, d1, d2, []); end; % convert the 3D movie to a matrix 25 | Y(isnan(Y)) = 0; % remove nan values 26 | Y = double(Y); 27 | T = size(Y, 3); 28 | 29 | %% preprocessing data 30 | % create a spatial filter for removing background 31 | psf = fspecial('gaussian', round(gSiz), gSig); 32 | ind_nonzero = (psf(:)>=max(psf(:,1))); 33 | psf = psf-mean(psf(ind_nonzero)); 34 | psf(~ind_nonzero) = 0; 35 | 36 | % divide data into multiple patches 37 | patch_sz = [3, 3]; 38 | r0_patch = round(linspace(1, d1, 1+patch_sz(1))); 39 | c0_patch = round(linspace(1, d2, 1+patch_sz(2))); 40 | nr_patch = length(r0_patch)-1; 41 | nc_patch = length(c0_patch)-1; 42 | Cn = zeros(d1, d2); 43 | PNR = zeros(d1,d2); 44 | 45 | % compute correlation_image patch by patch 46 | bd = round(gSiz); 47 | for mr = 1:nr_patch 48 | r0 = max(1, r0_patch(mr)-bd); % minimum row index of the patch 49 | r1 = min(d1, r0_patch(mr+1)+bd-1); % maximum row index of the patch 50 | for mc = 1:nc_patch 51 | c0 = max(1, c0_patch(mc)-bd); % minimum column index of the patch 52 | c1 = min(d2, c0_patch(mc+1)+bd-1); % maximum column index of the patch 53 | 54 | % take the patch from the raw data 55 | nrows = (r1-r0+1); % number of rows in the patch 56 | ncols = (c1-c0+1); %number of columns in the patch 57 | Ypatch = double(Y(r0:r1, c0:c1, :)); 58 | 59 | % spatially filter the data 60 | HY = imfilter(Ypatch, psf, 'replicate'); 61 | 62 | % copute signal to noise ratio 63 | HY = reshape(HY, [], T); 64 | HY = bsxfun(@minus, HY, median(HY, 2)); 65 | HY_max = max(HY, [], 2); 66 | Ysig = get_noise_fft(HY, options); 67 | tmp_PNR = reshape(HY_max./Ysig, nrows, ncols); 68 | PNR(r0:r1, c0:c1) = max(PNR(r0:r1, c0:c1), tmp_PNR); 69 | 70 | 71 | % compute loal correlation 72 | HY(bsxfun(@lt, HY, Ysig*sig)) = 0; 73 | tmp_Cn = correlation_image(HY, [1,2], nrows, ncols); 74 | Cn(r0:r1, c0:c1) = max(Cn(r0:r1, c0:c1), tmp_Cn); 75 | 76 | end 77 | end -------------------------------------------------------------------------------- /endoscope/deconv_temporal.m: -------------------------------------------------------------------------------- 1 | function [C, P, S] = deconv_temporal(C,P,options) 2 | % deconvolve all temporal components independently using FOOPSI 3 | % The noise constrained deconvolution approach is used. Time constants can be re-estimated (default) 4 | 5 | % The update can happen either in parallel (default) or serial by tuning options.temporal_parallel. 6 | % In the case of parallel implementation the methods 'MCEM_foopsi' and 'noise_constrained' are not supported 7 | 8 | % INPUTS: 9 | % C: current estimate of temporal components (nr X T matrix) 10 | % P: struct for neuron parameters 11 | % options: struct for algorithm parameters 12 | 13 | % OUTPUTS: 14 | % C: temporal components (nr X T matrix) 15 | % P: struct for neuron parameters 16 | % S: deconvolved activity 17 | 18 | % Author: Pengcheng Zhou, Carnegie Mellon University, 2016 19 | % it's modified from udpate_temporal_components.m written by Eftychios 20 | 21 | defoptions = CNMFSetParms; 22 | if nargin<2; P.p = 2; end 23 | if P.p==0; return; end 24 | 25 | if ~isfield(options,'restimate_g') || isempty(options.restimate_g); restimate_g = defoptions.restimate_g; else restimate_g = options.restimate_g; end % re-estimate time constant (only with constrained foopsi) 26 | if ~isfield(options,'bas_nonneg'); options.bas_nonneg = defoptions.bas_nonneg; end 27 | if ~isfield(options,'fudge_factor'); options.fudge_factor = defoptions.fudge_factor; end 28 | if ~isfield(options,'temporal_parallel'); options.temporal_parallel = defoptions.temporal_parallel; end 29 | 30 | options.p = P.p; 31 | 32 | [K, T] = size(C); 33 | 34 | if ~isfield(P, 'gn'); options.restimate=false; end 35 | if options.restimate_g; P.gn = cell(K,1); end 36 | P.b = cell(K,1); 37 | P.c1 = cell(K,1); 38 | P.neuron_sn = cell(K,1); 39 | 40 | S = zeros(K, T); 41 | Cb = zeros(K,1); 42 | Sn = zeros(K,1); 43 | 44 | 45 | fprintf('Progress:\n'); 46 | fprintf(['\n' repmat('.',1,K) '\n\n']); 47 | if options.temporal_parallel 48 | tmp_gn = zeros(K, P.p); 49 | if ~restimate_g 50 | for jj=1:K 51 | tmp_gn(jj, :) = P.gn{jj}; 52 | end 53 | end 54 | parfor jj = 1:K 55 | if restimate_g 56 | [cc,cb,c1,gn,sn,spk] = constrained_foopsi(C(jj,:),[],[],[],[],options); 57 | else 58 | [cc,cb,c1,gn,sn,spk] = constrained_foopsi(C(jj,:),[],[],[],tmp_gn(jj,:),options); 59 | end 60 | tmp_gn(jj, :) = gn; 61 | gd = max(roots([1,-gn'])); % decay time constant for initial concentration 62 | gd_vec = gd.^((0:T-1)); 63 | C(jj,:) = full(cc(:)'+ c1*gd_vec)+cb; 64 | S(jj,:) = spk(:)'; 65 | Sn(jj) = sn; 66 | 67 | fprintf('\b|\n'); 68 | end 69 | for jj=1:K 70 | P.gn{jj} = tmp_gn(jj, :); 71 | end 72 | else 73 | for jj = 1:K 74 | if restimate_g 75 | [cc,cb,c1,gn,sn,spk] = constrained_foopsi(C(jj,:),[],[],[],[],options); 76 | else 77 | [cc,cb,c1,gn,sn,spk] = constrained_foopsi(C(jj,:),[],[],[],P.gn{jj},options); 78 | end 79 | P.gn{jj} = gn; 80 | gd = max(roots([1,-gn'])); % decay time constant for initial concentration 81 | gd_vec = gd.^((0:T-1)); 82 | C(jj,:) = full(cc(:)'+ c1*gd_vec)+cb; 83 | S(jj,:) = spk(:)'; 84 | Sn(jj) = sn; 85 | 86 | fprintf('\b|\n'); 87 | end 88 | end 89 | P.neuron_sn = Sn; -------------------------------------------------------------------------------- /endoscope/demos/data_endoscope.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/endoscope/demos/data_endoscope.tif -------------------------------------------------------------------------------- /endoscope/demosdata_endoscope_results.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/endoscope/demosdata_endoscope_results.avi -------------------------------------------------------------------------------- /endoscope/detrend_data.m: -------------------------------------------------------------------------------- 1 | function [Ydt, X, R] = detrend_data(Y,nk) 2 | %% detrend fluorescence signals with B-spline basis 3 | %% Inputs: 4 | % Y: d X T matrix, video data 5 | % nk: scalar, number of knots 6 | % Outputs: 7 | % Ydt: d X T matrix, detrended data 8 | % X: T*M matrix, each column is one basis 9 | % R: d*M matrix, coefficients of all basis for all pixels 10 | 11 | %% create basis 12 | [~, T] = size(Y); 13 | 14 | if ~exist('nk', 'var') 15 | nk = 5; 16 | end 17 | X = bsplineM((1:T)', linspace(1, T, nk), 4); 18 | 19 | %% compute coefficients of all spline basis 20 | R = (Y*X)/(X'*X); 21 | 22 | %% compute detrended data 23 | Ydt = Y-R*X'; -------------------------------------------------------------------------------- /endoscope/dsData.m: -------------------------------------------------------------------------------- 1 | function Y_ds = dsData(Y, options) 2 | %% downsampling data 3 | % input: 4 | % Y: d1*d2*T matrix. 5 | % time 6 | % options: struc data containing parameters 7 | % ssub: downsampling factor for spatial 8 | % tsub: downsampling factor for temporal 9 | % output: 10 | % Y_ds: downsampled data with (d1/ssub)*(d2/ssub)*(t/tsub) 11 | 12 | % Author: Pengcheng Zhou, Carnegie Mellon University, 2016 13 | 14 | % input arguments are not enough 15 | if nargin<2; Y_ds = Y; return; end 16 | 17 | % downsampling factors 18 | if (isfield(options, 'ssub')); ssub = options.ssub; else ssub = 1; end 19 | if (isfield(options, 'tsub')); tsub = options.tsub; else tsub = 1; end 20 | if or(isempty(ssub), ssub<1); ssub = 1; end 21 | if or(isempty(tsub), tsub<1); tsub = 1; end 22 | ssub = round(ssub); 23 | tsub = round(tsub); 24 | 25 | if and(ssub==1, tsub==1) 26 | fprintf('no downsampling required\n'); 27 | Y_ds = Y; 28 | return; 29 | end 30 | 31 | %% downsampe 32 | [d1, d2, T] = size(Y); 33 | 34 | % temporal downsampling 35 | Ts = floor(T/tsub); % remove few 36 | if tsub>1 37 | % temporal downsampling, take the mean of continuours tsub frames 38 | % if mod(T, tsub)~=0, discard the rest frames 39 | Y = squeeze(mean(reshape(Y(:, :, 1:(Ts*tsub)), d1, d2, tsub, Ts), 3)); 40 | end 41 | 42 | % spatial downsampling 43 | Y_ds = imresize(Y, 1/ssub); 44 | -------------------------------------------------------------------------------- /endoscope/extract_ac.m: -------------------------------------------------------------------------------- 1 | function [ai, ci, ind_success] = extract_ac(HY, Y, ind_ctr, sz) 2 | %% given a patch of raw & high-pass filtered calcium imaging data, extract 3 | % spatial and temporal component of one neuron (ai, ci). if succeed, then 4 | % return an indicator ind_succes with value 1; otherwise, 0. 5 | %% inputs: 6 | % HY: d X T matrix, filtered patch data 7 | % Y: d X T matrix, raw data 8 | % ind_ctr: scalar, location of the center 9 | % sz: 2 X 1 vector, size of the patch 10 | 11 | %% Author: Pengcheng Zhou, Carnegie Mellon University. 12 | 13 | %% parameters 14 | nr = sz(1); 15 | nc = sz(2); 16 | min_corr = 0.7; 17 | min_pixels = 5; 18 | 19 | %% find pixels highly correlated with the center 20 | HY(HY<0) = 0; % remove some negative signals from nearby neurons 21 | y0 = HY(ind_ctr, :); 22 | tmp_corr = reshape(corr(y0', HY'), nr, nc); 23 | data = HY(tmp_corr>min_corr, :); 24 | 25 | 26 | %% estimate ci with the mean or rank-1 NMF 27 | ci = mean(data, 1); 28 | % ci = ci - min(ci); % avoid nonnegative baseline 29 | % [~, ci] = nnmf(ci, 1); 30 | if norm(ci)==0 31 | ai=[]; 32 | ind_success=false; 33 | return; 34 | end 35 | 36 | %% extract spatial component 37 | % estiamte the background level using the boundary 38 | y_bg = median(Y(tmp_corr(:)- thr_noise * ci_noise) = 0; 48 | ai = max(0, dY*dci'/(dci*dci')); % use regression to estimate spatial component 49 | 50 | % post-process ai by bwlabel 51 | thr_ratio = 50; % thresholding nonzero pixels by its ratio with the maximum intensity 52 | temp = full(ai>max(ai)/thr_ratio); 53 | l = bwlabel(reshape(temp, nr, nc), 4); % remove disconnected components 54 | temp(l~=l(ind_ctr)) = false; 55 | ai(~temp(:)) = 0; 56 | if sum(ai(:)>0) < min_pixels %the ROI is too small 57 | ind_success=false; 58 | return; 59 | end 60 | 61 | % refine ci again 62 | ind_nonzero = (ai>0); 63 | % ci0 = ci; 64 | ai_mask = mean(ai(ind_nonzero))*ind_nonzero; 65 | ci = (ai-ai_mask)'*ai\((ai-ai_mask)'*Y); 66 | % if get_noise_fft(ci)>get_noise_fft(ci0) % refined ci should have smaller noise 67 | % ci = ci0; 68 | % end 69 | 70 | % set the baseline to be 0 71 | dci = [0, 0, ci(4:end)-ci(1:(end-3))]; 72 | ci = ci - median(ci(dci>0)); 73 | sn = get_noise_fft(ci); 74 | ci = ci / sn; 75 | ai = ai * sn; 76 | % ci(ci < -thr_noise) = 0; 77 | % return results 78 | if norm(ai)==0 79 | ind_success= false; 80 | else 81 | ind_success=true; 82 | end -------------------------------------------------------------------------------- /endoscope/remove_baseline.m: -------------------------------------------------------------------------------- 1 | function [y, b] = remove_baseline(y, sn) 2 | % estiamte baseline of the calcium traces and subtract it 3 | if ~exist('sn', 'var') || isempty(sn) 4 | sn = get_noise_fft(reshape(y, 1, [])); 5 | end 6 | sz = size(y); 7 | y = reshape(y, 1, []); 8 | y_diff = [-1, diff(y)]; 9 | b = median(y(and(y_diff>=0, y_diff 2 26 | V = X'*U; 27 | s = sqrt(abs(diag(D))); 28 | V = bsxfun(@(x,c)x./c, V, s'); 29 | S = diag(s); 30 | end 31 | else 32 | C = X'*X; 33 | [V,D] = eigs(C,k); 34 | clear C; 35 | U = X*V; % convert evecs from X'*X to X*X'. the evals are the same. 36 | %s = sqrt(sum(U.^2,1))'; 37 | s = sqrt(abs(diag(D))); 38 | U = bsxfun(@(x,c)x./c, U, s'); 39 | S = diag(s); 40 | end 41 | -------------------------------------------------------------------------------- /endoscope/tif2mat.m: -------------------------------------------------------------------------------- 1 | function nam_mat = tif2mat(nam) 2 | %% convert tiff files into mat files 3 | % inputs: 4 | % nam: file names 5 | % output: 6 | % nam_mat: name of the *.mat file 7 | % Author: Pengcheng Zhou, Carnegie Mellon University 8 | 9 | %% tiff file information 10 | if isempty(nam) 11 | nam_mat = []; 12 | fprintf('empty tiff file'); 13 | return; 14 | else 15 | [tmp_dir, tmp_file, ~] = fileparts(nam); 16 | nam_mat = sprintf('%s%s%s.mat', tmp_dir, filesep, tmp_file); 17 | end 18 | 19 | info = imfinfo(nam); 20 | T = length(info); % number of frames 21 | d1 = info.Height; % height of the image 22 | d2 = info.Width; % width of the image 23 | Ysiz = [d1, d2, T]'; 24 | 25 | fprintf('CNMF_E is converting TIFF file to *.mat file'); 26 | % create a mat file 27 | Tchunk = min(T, round(2^29/d1/d2)); %each chunk uses at most 4GB 28 | Y = bigread2(nam, 1, Tchunk); %#ok<*NASGU> 29 | save(nam_mat, 'Y', 'Ysiz', '-v7.3'); 30 | if Tchunk==T 31 | return; 32 | else 33 | data = matfile(nam_mat, 'Writable', true); 34 | t0 = Tchunk+1; 35 | while t0<=T 36 | num2read = min(t0+Tchunk-1, T) - t0 + 1; 37 | tmpY = bigread2(nam, t0, num2read); 38 | data.Y(:, :, (1:num2read)+t0-1) = tmpY; 39 | t0 = t0 + num2read; 40 | end 41 | end -------------------------------------------------------------------------------- /endoscope/writeTiff.m: -------------------------------------------------------------------------------- 1 | function writeTiff(I, filename) 2 | %% write tiff stack 3 | imwrite(I(:, :, 1), filename); 4 | for m=2:size(I, 3) 5 | imwrite(I(:, :, m), filename, 'writemode', 'append'); 6 | end -------------------------------------------------------------------------------- /estimate_percentile_level.m: -------------------------------------------------------------------------------- 1 | function [level,cdf_val] = estimate_percentile_level(data,window,shift) 2 | 3 | % Estimates the level of percentile filtering to be used in DF/F extraction 4 | % using a kernel density estimator. 5 | 6 | if ~exist('window','var'); window = 4000; end 7 | if ~exist('shift','var'); shift = 2000; end 8 | 9 | data = data(:); 10 | T = length(data); 11 | start_point = 1:shift:T; 12 | end_point = [window:shift:T,T]; 13 | 14 | min_ln = min(length(start_point),length(end_point)); 15 | start_point = start_point(1:min_ln); 16 | end_point = end_point(1:min_ln); 17 | ln_seg = end_point - start_point + 1; 18 | 19 | if ln_seg(end) < 2*window/3 20 | start_point(end) = []; 21 | end_point(end-1) = []; 22 | ln_seg = end_point - start_point + 1; 23 | end 24 | 25 | level = zeros(length(start_point),1); 26 | cdf_val = zeros(length(start_point),1); 27 | 28 | for i = 1:length(start_point) 29 | [~,density,xmesh,cdf] = kde(data(start_point(i):end_point(i))); 30 | [~,ind] = max(density); 31 | level(i) = xmesh(ind); 32 | cdf_val(i) = cdf(ind)*100; 33 | end 34 | 35 | % interp_points = start_point + round(ln_seg/2); 36 | % 37 | % if length(level) > 1 38 | % baseline = interp1(interp_points,level,1:T,'spline'); 39 | % else 40 | % baseline = level*ones(1,T); 41 | % end -------------------------------------------------------------------------------- /tests/TestRunCNMFPatches.m: -------------------------------------------------------------------------------- 1 | % Test suite for run_CNMF_patches 2 | % Use 'run(TestRunCNMFPatches)' to run the whole suite. 3 | classdef TestRunCNMFPatches < matlab.unittest.TestCase 4 | 5 | properties 6 | dataset % generate dataset to test with 7 | datasize % dataset size 8 | patches % patches coordinates 9 | end 10 | 11 | properties (ClassSetupParameter) 12 | sizY = struct('data2d', [128, 128, 500], ... 13 | 'data2d_small', [25, 25, 500], ... 14 | 'data3d', [128, 128, 7, 100]); 15 | memory_mapped = struct('memmapped', true, 'inRAM', false); 16 | end 17 | 18 | properties (MethodSetupParameter) 19 | patch_size = struct('default', {[]}, 'small', 25); 20 | end 21 | 22 | properties (TestParameter) 23 | cluster_pixels = struct('cluster_on', true, 'cluster_off', false); 24 | end 25 | 26 | methods (TestClassSetup) 27 | function createDataset(testCase, sizY, memory_mapped) 28 | rng(1) % fix random generator seed for reproducibility 29 | Y = randn(sizY); 30 | if memory_mapped 31 | Yr = reshape(Y, [], sizY(end)); 32 | F_dark = min(Yr(:)); 33 | filename = [tempname, '.mat']; 34 | save(filename, 'Yr', 'Y', 'F_dark', 'sizY', '-v7.3'); 35 | Y = matfile(filename, 'Writable', false); 36 | end 37 | testCase.datasize = sizY; 38 | testCase.dataset = Y; 39 | end 40 | end 41 | 42 | methods (TestClassTeardown) 43 | function cleanDataset(testCase) 44 | % clear create file, if any 45 | if isa(testCase.dataset, 'matlab.io.MatFile') 46 | delete(testCase.dataset.Properties.Source); 47 | end 48 | end 49 | end 50 | 51 | methods (TestMethodSetup) 52 | function createPatches(testCase, patch_size) 53 | if isempty(patch_size) 54 | testCase.patches = []; 55 | else 56 | data_ndims = length(testCase.datasize(1:end-1)); 57 | psize = [patch_size, patch_size, 5]; 58 | psize = psize(1:data_ndims); 59 | testCase.patches = construct_patches( ... 60 | testCase.datasize(1:end-1), psize); 61 | end 62 | end 63 | end 64 | 65 | methods (Test) 66 | function testRunning(testCase, cluster_pixels) 67 | % simply test that nothing crashes 68 | options = struct('cluster_pixels', cluster_pixels); 69 | run_CNMF_patches( ... 70 | testCase.dataset, 7, testCase.patches, [], [], options); 71 | end 72 | end 73 | end -------------------------------------------------------------------------------- /use_cases/2017_CSHL_NeuralDataScience/demo_SueAnn.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/use_cases/2017_CSHL_NeuralDataScience/demo_SueAnn.mlx -------------------------------------------------------------------------------- /use_cases/outdated/live scripts/demo_pipeline.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/use_cases/outdated/live scripts/demo_pipeline.mlx -------------------------------------------------------------------------------- /use_cases/outdated/live scripts/demo_script.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/use_cases/outdated/live scripts/demo_script.mlx -------------------------------------------------------------------------------- /utilities/GUI/Initialization.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/utilities/GUI/Initialization.fig -------------------------------------------------------------------------------- /utilities/GUI/untitled.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/utilities/GUI/untitled.fig -------------------------------------------------------------------------------- /utilities/GetSn.m: -------------------------------------------------------------------------------- 1 | function sn = GetSn(Y,range_ff,method) 2 | % estimate noise level with a power spectral density method 3 | L=length(Y); 4 | % if ~isempty(which('pmtm')) 5 | % [psd_Y,ff] = pmtm(Y,5/2,1000,1); 6 | % end 7 | if ~exist('range_ff','var'); range_ff = [0.25,0.5]; end 8 | if ~exist('method','var'); method = 'mean'; end 9 | if ~isempty(which('pwelch')); 10 | [psd_Y,ff]=pwelch(Y,round(L/8),[],1000,1); 11 | else 12 | xdft = fft(Y); 13 | xdft = xdft(1:round(L/2)+1); 14 | psd_Y = (1/L) * abs(xdft).^2; 15 | ff = 0:1/L:1/2; 16 | psd_Y(2:end-1) = 2*psd_Y(2:end-1); 17 | end 18 | ind=ff>range_ff(1); 19 | ind(ff>range_ff(2))=0; 20 | switch method 21 | case 'mean' 22 | sn=sqrt(mean(psd_Y(ind)/2)); 23 | case 'median' 24 | sn=sqrt(median(psd_Y(ind)/2)); 25 | case 'logmexp' 26 | sn = sqrt(exp(mean(log(psd_Y(ind)/2)))); 27 | end 28 | end -------------------------------------------------------------------------------- /utilities/HALS.m: -------------------------------------------------------------------------------- 1 | function [A, C, b, f] = HALS(Y, A, C, b, f, params) 2 | %% Hierarchical alternating least square method for solving NMF problem 3 | % Y = A*C + b*f 4 | 5 | %input: 6 | % Y: d1 X d2 X T, raw data. It will be reshaped to (d1*d2) X T in this 7 | % function 8 | % A: (d1*d2) X K, initial value of spatial components 9 | % C: K X T, initial value of temporal components 10 | % b: (d1*d2) X 1, initial value of background spatial component 11 | % f: 1 X T, initial value of background temporal component 12 | % params: parameters used in this function. 13 | % bSiz: blur size. A box kernel (bSiz X bSiz) will be convolved 14 | % with each neuron's initial spatial component, then all nonzero 15 | % pixels will be picked as pixels to be updated, and the rest will be 16 | % forced to be 0. 17 | % maxIter: maximum iteration of iterating HALS. 18 | 19 | % Author: Pengcheng Zhou, Carnegie Mellon University, based on a python 20 | % implementation from Johannes Friedrich, Columbia University, 2015. 21 | 22 | %% parameters 23 | if isfield(params, 'maxIter'), maxIter = params.maxIter; else maxIter=5; end 24 | if isfield(params, 'search_method'); method=params.search_method; else method='ellipse'; end 25 | if and(isfield(params, 'bSiz'), strcmpi(method, 'dilate')) 26 | params.se = strel('disk', params.bSiz); 27 | end 28 | if isfield(params,'init_method'); init_method = params.init_method; else init_method = 'greedy'; end 29 | 30 | Y = reshape(Y,size(A,1),[]); 31 | % search locations 32 | if strcmpi(init_method,'greedy') || strcmpi(init_method,'greedy_corr'); 33 | IND = determine_search_location(A,method,params); 34 | else 35 | IND = true(size(A)); 36 | end 37 | %% update spatial and temporal components neuron by neurons 38 | Yac = max(Y - b*f,0); 39 | for miter=1:maxIter 40 | % update neurons 41 | ind_del = find(std(A,0,1)==0); 42 | A(:, ind_del) = []; 43 | C(ind_del, :) = []; 44 | IND(:, ind_del) = []; 45 | % temporal 46 | C = HALS_temporal(Yac, A, C, 5); 47 | 48 | ind_del = find(std(C,0,2)==0); 49 | A(:, ind_del) = []; 50 | C(ind_del, :) = []; 51 | IND(:, ind_del) = []; 52 | % spatial 53 | A = HALS_spatial(Yac, A, C, IND, 5); 54 | end 55 | 56 | % update background 57 | Ybg = Y-A*C; 58 | for miter = 1:maxIter 59 | % temporal 60 | f = HALS_temporal(Ybg, b, f, 5); 61 | % spatial 62 | b = HALS_spatial(Ybg, b, f, [], 5); 63 | end -------------------------------------------------------------------------------- /utilities/HALS_2d.m: -------------------------------------------------------------------------------- 1 | function [A, C, b, f] = HALS_2d(Y, A, C, b, f, params) 2 | %% Hierarchical alternating least square method for solving NMF problem 3 | % Y = A*C + b*f 4 | 5 | %input: 6 | % Y: d1 X d2 X T, raw data. It will be reshaped to (d1*d2) X T in this 7 | % function 8 | % A: (d1*d2) X K, initial value of spatial components 9 | % C: K X T, initial value of temporal components 10 | % b: (d1*d2) X nb, initial value of background spatial component 11 | % f: nb X T, initial value of background temporal component 12 | % params: parameters used in this function. 13 | % bSiz: blur size. A box kernel (bSiz X bSiz) will be convolved 14 | % with each neuron's initial spatial component, then all nonzero 15 | % pixels will be picked as pixels to be updated, and the rest will be 16 | % forced to be 0. 17 | % maxIter: maximum iteration of iterating HALS. 18 | 19 | % Author: Pengcheng Zhou, Columbia University, based on a python 20 | % implementation from Johannes Friedrich, Columbia University, 2015. 21 | 22 | %% parameters 23 | if isfield(params, 'maxIter'), maxIter = params.maxIter; else maxIter=5; end 24 | if isfield(params, 'search_method'); method=params.search_method; else method='ellipse'; end 25 | if and(isfield(params, 'bSiz'), strcmpi(method, 'dilate')) 26 | params.se = strel('disk', params.bSiz); 27 | end 28 | % search locations 29 | IND = determine_search_location(A, method, params); 30 | 31 | %% update spatial and temporal components neuron by neurons 32 | 33 | for miter=1:maxIter 34 | %% update neurons 35 | Yac = Y - b*f; 36 | ind_del = find(std(A,0,1)==0); 37 | A(:, ind_del) = []; 38 | C(ind_del, :) = []; 39 | IND(:, ind_del) = []; 40 | % temporal 41 | C = HALS_temporal(Yac, A, C, 5); 42 | 43 | ind_del = find(std(C,0,2)==0); 44 | A(:, ind_del) = []; 45 | C(ind_del, :) = []; 46 | IND(:, ind_del) = []; 47 | % spatial 48 | A = HALS_spatial(Yac, A, C, IND, 5); 49 | 50 | %% update background 51 | Ybg = Y-A*C; 52 | % temporal 53 | f = HALS_temporal(Ybg, b, f, 5); 54 | % spatial 55 | b = HALS_spatial(Ybg, b, f, [], 5); 56 | end -------------------------------------------------------------------------------- /utilities/HALS_initialization.m: -------------------------------------------------------------------------------- 1 | function [A,C,b,f] = HALS_initialization(Y,K,options) 2 | 3 | defoptions = CNMFSetParms; 4 | if ~isfield(options,'max_iter_hals_in') || isempty(options.max_iter_hals_in); options.max_iter_hals_in = defoptions.max_iter_hals_in; end 5 | if ~isfield(options,'rem_prct') || isempty(options.rem_prct); options.rem_prct = defoptions.rem_prct; end 6 | if ~isfield(options,'nb') || isempty(options.nb); nb = defoptions.nb; else nb = options.nb; end 7 | 8 | init_hals_method = 'random'; 9 | 10 | if ~exist('K', 'var'), %find K neurons 11 | K = 30; 12 | warning(['number of neurons are not specified, set to be the default value', num2str(K)]); 13 | end 14 | 15 | dimY = ndims(Y) - 1; % dimensionality of imaged data (2d or 3d) 16 | sizY = size(Y); 17 | T = sizY(end); % # of timesteps 18 | dx = sizY(1:dimY); % # of voxels in each axis 19 | d = prod(dx); % total # of voxels 20 | 21 | med = prctile(Y,options.rem_prct,ndims(Y)); 22 | Y = bsxfun(@minus, Y, med); 23 | if strcmpi(init_hals_method,'random'); 24 | A = rand(d,K); 25 | Y = reshape(Y,d,T); 26 | C = HALS_temporal(Y,A,rand(K,T),10); 27 | elseif strcmpi(init_hals_method,'cor_im'); 28 | sk = max(round(T/1000),1); 29 | Cn = correlation_image(Y(:,:,1:sk:T)); 30 | Y = reshape(Y,d,T); 31 | Cnf = imgaussfilt(Cn,2.25); 32 | BW = imregionalmax(Cnf); 33 | C = Y(BW(:),:); 34 | A = max(Y*pinv(C),0); 35 | end 36 | 37 | for iter = 1:options.max_iter_hals_in 38 | A = HALS_spatial(Y, A, C); 39 | C = HALS_temporal(Y, A, C); 40 | end 41 | 42 | ind_del = find(std(C,0,2)==0); 43 | A(:, ind_del) = []; 44 | C(ind_del, :) = []; 45 | 46 | Y = bsxfun(@plus,Y-A*C,med(:)); 47 | 48 | b = [med(:),rand(d,nb-1)]; 49 | 50 | for nmfiter = 1:100 51 | f = max((b'*b)\(b'*Y),0); 52 | b = max((Y*f')/(f*f'),0); 53 | end -------------------------------------------------------------------------------- /utilities/HALS_spatial.m: -------------------------------------------------------------------------------- 1 | function A = HALS_spatial(Y, A, C, active_pixel, maxIter) 2 | %% run HALS by fixating all spatial components 3 | % input: 4 | % Y: d*T, fluorescence data 5 | % A: d*K, spatial components 6 | % C: K*T, temporal components 7 | % output: 8 | % A: d*K, updated spatial components 9 | 10 | % Author: Pengcheng Zhou, Carnegie Mellon University, adapted from Johannes 11 | % Friedrich's NIPS paper "Fast Constrained Non-negative Matrix 12 | % Factorization for Whole-Brain Calcium Imaging Data 13 | 14 | %% options for HALS 15 | if nargin<5; maxIter = 1; end; %maximum iteration number 16 | if nargin<4; active_pixel=true(size(A)); 17 | elseif isempty(active_pixel) 18 | active_pixel = true(size(A)); 19 | end; %determine nonzero pixels 20 | 21 | %% initialization 22 | A(~active_pixel) = 0; 23 | K = size(A, 2); % number of components 24 | U = mm_fun(C,Y); 25 | V = C*C'; 26 | cc = diag(V); % squares of l2 norm all all components 27 | 28 | %% updating 29 | for miter=1:maxIter 30 | for k=1:K 31 | tmp_ind = active_pixel(:, k); 32 | if any(tmp_ind) 33 | ak = max(0, A(tmp_ind, k)+(U(tmp_ind, k)-A(tmp_ind,:)*V(:, k))/cc(k)); 34 | A(tmp_ind, k) = ak; 35 | end 36 | end 37 | end -------------------------------------------------------------------------------- /utilities/HALS_temporal.m: -------------------------------------------------------------------------------- 1 | function [C,U] = HALS_temporal(Y, A, C, maxIter,tol,nonneg,flag_AY) 2 | %% run HALS by fixating all spatial components 3 | % input: 4 | % Y: d*T, fluorescence data or K*T, product A'*Y if flag_AY = true 5 | % A: d*K, spatial components 6 | % C: K*T, temporal components 7 | % maxIter: maximum number of iterations 8 | % tol: convergence threshold 9 | % noneg: restrict output to be non-negative 10 | % output: 11 | % C: K*T, updated temporal components 12 | % U: product A'*Y (for downstream use) 13 | 14 | % Author: Pengcheng Zhou, Carnegie Mellon University and Eftychios A. Pnevmatikakis, 15 | % adapted from Johannes Friedrich's NIPS paper "Fast Constrained Non-negative Matrix 16 | % Factorization for Whole-Brain Calcium Imaging Data 17 | 18 | %% options 19 | if nargin < 7 || isempty(flag_AY); flag_AY = false; end 20 | if nargin < 6 || isempty(nonneg); nonneg = true; end 21 | if nargin < 5 || isempty(tol); tol = 1e-4; end 22 | if nargin < 4 || isempty(maxIter); maxIter=1; end 23 | 24 | %% initialization 25 | K = size(A, 2); % number of components 26 | if flag_AY 27 | U = Y; 28 | else 29 | U = mm_fun(A,Y); 30 | end 31 | 32 | V = A'*A; 33 | aa = diag(V); % squares of l2 norm all all components 34 | %% updating 35 | 36 | repeat = 1; 37 | miter = 0; 38 | while repeat 39 | C_ = C; 40 | for k=1:K 41 | ck = C(k, :) + (U(k, :)-V(k, :)*C)/aa(k); 42 | if nonneg 43 | ck = max(0, ck); % update ck 44 | end 45 | C(k, :) = ck; 46 | end 47 | repeat = (miter < maxIter) && norm(C - C_,'fro')/norm(C_,'fro') > tol; 48 | miter = miter + 1; 49 | end -------------------------------------------------------------------------------- /utilities/ROI_GUI.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/CaImAn-MATLAB/25ec5f4566b89d6c7fb2aa5f36ad7c8ae19d95c3/utilities/ROI_GUI.fig -------------------------------------------------------------------------------- /utilities/assign.m: -------------------------------------------------------------------------------- 1 | function assign (varargin) 2 | % assign - make a list of assignments (matlab 5 or higher) 3 | % 4 | % ASSIGN('VAR1', VAL1, 'VAR2', VAL2, ...) makes the assignments 5 | % VAR1 = VAL1; VAR2 = VAL2; ... in the caller's workspace. 6 | % 7 | % This is most useful when passing in an option list to a 8 | % function. Thus in the function which starts: 9 | % function foo(x,y,varargin) 10 | % z = 0; 11 | % assign(varargin{:}); 12 | % the variable z can be given a non-default value by calling the 13 | % function like so: foo(x,y,'z',4); 14 | 15 | vars = {varargin{1:2:end}}; 16 | vals = {varargin{2:2:end}}; 17 | 18 | % use length(vals) not length(vars) in case of odd number of arguments 19 | for i = 1:length(vals), % changed 1 to a 2 20 | assignin('caller', vars{i}, vals{i}); 21 | end 22 | -------------------------------------------------------------------------------- /utilities/cell2str.m: -------------------------------------------------------------------------------- 1 | function str = cell2str(theCell) 2 | % CELL2STR - Convert 1-D cells to a string 3 | % 4 | % STR = CELL2STR(THECELL) 5 | % 6 | % Converts a 1-D cell to a string. 7 | % 8 | % Example: 9 | % A = {'test','test2','test3'}; 10 | % str = cell2str(A) 11 | % 12 | % produced str = 13 | % '{ 'test','test2','test3' }' 14 | % 15 | %1-dim cells only, only chars and matricies 16 | 17 | if isempty(theCell), str = '{}'; return; end; 18 | 19 | str = '{ '; 20 | for i=1:length(theCell), 21 | if ischar(theCell{i}) 22 | str = [str '''' theCell{i} ''', ']; 23 | elseif isnumeric(theCell{i}), 24 | str = [str mat2str(theCell{i}) ', ']; 25 | end; 26 | end; 27 | str = [str(1:end-2) ' }']; 28 | 29 | -------------------------------------------------------------------------------- /utilities/classify_components.m: -------------------------------------------------------------------------------- 1 | function [rval_space,rval_time,max_pr,sizeA,keep] = classify_components(Y,A,C,b,f,YrA,options) 2 | 3 | % perform several tests for component classification: 4 | % i) correlation test using the function classify_comp_corr 5 | % ii) calculate the probability that max of each temporal component is 6 | % due to noise through trace_fit_extreme.m 7 | % iii) filter component based on min/max size 8 | 9 | % OUTPUTS 10 | % rval_space: correlation in space 11 | % rval_time: correlation in time 12 | % max_pr: max probability 13 | % sizeA: size of each component 14 | % keep: binary flag vector on whether each component passes all tests. 15 | 16 | 17 | defoptions = CNMFSetParms; 18 | if nargin < 7 || isempty(options) 19 | options = defoptions; 20 | end 21 | 22 | if ~isfield(options,'max_pr_thr') || isempty(options.max_pr_thr); options.max_pr_thr = defoptions.max_pr_thr; end 23 | if ~isfield(options,'fr') || isempty(options.fr); fr = defoptions.fr; else; fr = options.fr; end 24 | if ~isfield(options,'t_int') || isempty(options.t_int); t_int = defoptions.t_int; else; t_int = options.t_int; end 25 | if ~isfield(options,'sn_fac') || isempty(options.t_int); sn_fac = defoptions.sn_fac; else; sn_fac = options.sn_fac; end 26 | if ~isfield(options,'max_size_thr') || isempty(options.max_size_thr); options.max_size_thr = defoptions.max_size_thr; end 27 | if ~isfield(options,'min_size_thr') || isempty(options.min_size_thr); options.min_size_thr = defoptions.min_size_thr; end 28 | if ~isfield(options,'size_thr') || isempty(options.size_thr); options.size_thr = defoptions.size_thr; end 29 | 30 | [rval_space,rval_time,ind_space,ind_time] = classify_comp_corr(Y,A,C,b,f,options); 31 | 32 | %AA = A'*A; 33 | %AY = mm_fun(A,Y); 34 | % if nargin < 6 || isempty(YrA) 35 | % YrA = bsxfun(@times, 1./sum(A.^2)',AY - AA*C); 36 | % end 37 | 38 | %traces = detrend_df_f(A,b,C,f,YrA,options); 39 | %max_pr = trace_fit_extreme(full(traces),fr,t_int,sn_fac); 40 | max_pr = ones(size(rval_space)); 41 | %fitness = compute_event_exceptionality(traces,0); 42 | %fitness_delta = compute_event_exceptionality(diff(traces,[],2),0); 43 | 44 | sizeA = zeros(size(A,2),1); 45 | for i = 1:length(sizeA) 46 | sizeA(i) = sum(A(:,i)>options.size_thr*max(A(:,i))); 47 | end 48 | 49 | keep = ind_space & ind_time & (max_pr > options.max_pr_thr) & (sizeA >= options.min_size_thr) & (sizeA <= options.max_size_thr); -------------------------------------------------------------------------------- /utilities/classify_components_pixels.m: -------------------------------------------------------------------------------- 1 | function ff = classify_components_pixels(A,P,options) 2 | 3 | % Classify components based on their spatial overlap with the active pixels 4 | % Each component is classified as true if when restricted to the active 5 | % pixels retains at least options.cl_thr of its l_2 norm 6 | 7 | % INPUTS 8 | % A : set of spatial components (d x K) 9 | % P : parameter structure (must include P.active_pixels) obtained from preprocess_data.m 10 | % options : options structure (optional) for reading the energy threshold 11 | 12 | % OUTPUT 13 | % ff : K x 1 binary vector classifying the components 14 | 15 | % Author: Eftychios A. Pnevmatikakis 16 | % Simons Foundation, 2016 17 | 18 | defoptions = CNMFSetParms; 19 | if nargin < 3 || isempty(options) 20 | options = defoptions; 21 | end 22 | 23 | if ~isfield(options,'cl_thr') || isempty(options.cl_thr) 24 | cl_thr = defoptions.cl_thr; 25 | else 26 | cl_thr = options.cl_thr; 27 | end 28 | 29 | ff = false(1,size(A,2)); 30 | for i = 1:size(A,2) 31 | a1 = A(:,i); 32 | a2 = A(:,i).*P.active_pixels(:); 33 | if sum(a2.^2) >= cl_thr^2*sum(a1.^2) 34 | ff(i) = true; 35 | end 36 | end -------------------------------------------------------------------------------- /utilities/cnn_classifier.m: -------------------------------------------------------------------------------- 1 | function [ind,value] = cnn_classifier(A,dims,classifier,thr) 2 | 3 | %cnn_classifer classify spatial components using a pretrained CNN 4 | %classifier using the keras importer add on. 5 | % IND = cnn_classifier(A,dims,classifier,thr) returns a binary vector indicating 6 | % whether the set of spatial components A, with dimensions of the field 7 | % of view DIMS, pass the threshold THR for the given CLASSIFIER 8 | % 9 | % [IND,VALUE] = cnn_classifier(A,dims,classifier,thr) also returns the 10 | % output value of the classifier 11 | % 12 | % INPUTS: 13 | % A: 2d matrix 14 | % dims: vector with dimensions of the FOV 15 | % classifier: path to pretrained classifier model (downloaded if it 16 | % doesn't exist) 17 | % thr: threshold for accepting component (default: 0.2) 18 | % 19 | % note: The function requires Matlab version 2017b (9.3) or later, Neural 20 | % Networks toolbox version 2017b (11.0) or later, the Neural Network 21 | % Toolbox(TM) Importer for TensorFlow-Keras Models. 22 | 23 | % Written by Eftychios A. Pnevmatikakis. Classifier trained by Andrea 24 | % Giovannucci, Flatiron Institute, 2017 25 | 26 | K = size(A,2); % number of components 27 | 28 | if verLessThan('matlab','9.3') || verLessThan('nnet','11.0') || isempty(which('importKerasNetwork')) 29 | warning(strcat('The function cnn_classifier requires Matlab version 2017b (9.3) or later, Neural\n', ... 30 | 'Networks toolbox version 2017b (11.0) or later, the Neural Networks ', ... 31 | 'Toolbox(TM) Importer for TensorFlow-Keras Models.')) 32 | ind = true(K,1); 33 | value = ones(K,1); 34 | else 35 | if ~exist('thr','var'); thr = 0.2; end 36 | 37 | A = A/spdiags(sqrt(sum(A.^2,1))'+eps,0,K,K); % normalize to sum 1 for each compoennt 38 | A_com = extract_patch(A,dims,[50,50]); % extract 50 x 50 patches 39 | 40 | if ~exist(classifier,'file') 41 | url = 'https://www.dropbox.com/s/1csymylbne7yyt0/cnn_model.h5?dl=1'; 42 | classifier = 'cnn_model.h5'; 43 | outfilename = websave(classifier,url); 44 | end 45 | 46 | net_classifier = importKerasNetwork(classifier,'ClassNames',["rejected","accepted"]); 47 | out = predict(net_classifier,double(A_com)); 48 | value = out(:,2); 49 | ind = (value >= thr); 50 | end -------------------------------------------------------------------------------- /utilities/com.m: -------------------------------------------------------------------------------- 1 | function cm = com(A,d1,d2,d3) 2 | 3 | % center of mass calculation 4 | % inputs: 5 | % A: d X nr matrix, each column in the spatial footprint of a neuron 6 | % d1, d2, d3: the dimensions of the 2-d (or 3-d) field of view 7 | 8 | % output: 9 | % cm: nr x 2 (or 3) matrix, with the center of mass coordinates 10 | 11 | if nargin < 4 12 | d3 = 1; 13 | end 14 | if d3 == 1 15 | ndim = 2; 16 | else 17 | ndim = 3; 18 | end 19 | 20 | nr = size(A,2); 21 | Coor.x = kron(ones(d2*d3,1),double(1:d1)'); 22 | Coor.y = kron(ones(d3,1),kron(double(1:d2)',ones(d1,1))); 23 | Coor.z = kron(double(1:d3)',ones(d2*d1,1)); 24 | cm = [Coor.x, Coor.y, Coor.z]'*A/spdiags(sum(A)',0,nr,nr); 25 | cm = cm(1:ndim,:)'; -------------------------------------------------------------------------------- /utilities/compute_residuals.m: -------------------------------------------------------------------------------- 1 | function R = compute_residuals(Y,A,b,C,f) 2 | 3 | % compute residual traces for each component 4 | 5 | % INPUTS 6 | % Y matrix of data in 2D format of pointer to file 7 | % A set of spatial components 8 | % b set of spatial background components 9 | % C set of temporal components 10 | % f set of temporal background component 11 | 12 | AA = A'*A; 13 | AY = mm_fun(A,Y); 14 | nA2 = sum(A.^2,1); 15 | R = bsxfun(@times, AY - AA*C - (A'*b)*f,1./nA2(:)); -------------------------------------------------------------------------------- /utilities/correlation_image.m: -------------------------------------------------------------------------------- 1 | function Cn = correlation_image(Y,sz,d1,d2,flag_norm) 2 | 3 | % construct correlation image based on neighboing pixels 4 | % Y: raw data 5 | % sz: define the relative location of neighbours. it can be scalar, 2 6 | % element vector or a binary matrix 7 | % scalar: number of nearest neighbours, either 4 or 8, default 4 8 | % 2 element vector: [rmin, rmax], the range of neighbours. the 9 | % distance between the neighbour and the pixel is d, dmin <= r < 10 | % dmax. 11 | % matrix: a squared matrix (2k+1)*(2k+1)indicating the location of neighbours 12 | % d1,d2: spatial dimensions 13 | % flag_norm: indicate whether Y has been normalized and centered ( 1 is 14 | % yes, 0 is no) 15 | 16 | % Author: Eftychios A. Pnevmatikakis, Simons Foundation, 2015 17 | % with modifications from Pengcheng Zhou, Carnegie Mellon University, 2015 18 | 19 | %% preprocess the raw data 20 | if nargin<5; flag_norm = false; end 21 | if ismatrix(Y) 22 | Y = reshape(Y,d1,d2,size(Y,2)); 23 | end 24 | if ~strcmpi(class(Y),'single'); Y = single(Y); end 25 | if (nargin<2); sz = [0,1,0; 1,0,1; 0,1,0]; end 26 | 27 | [d1,d2,~] = size(Y); % image dimension 28 | 29 | if (~flag_norm) 30 | % centering 31 | mY = mean(Y,3); 32 | Y = bsxfun(@minus, Y, mY); 33 | % normalizing 34 | sY = sqrt(mean(Y.*Y, 3)); 35 | Y = bsxfun(@times, Y, 1./sY); 36 | end 37 | 38 | %% construct a matrix indicating location of the matrix 39 | if isscalar(sz) 40 | if sz == 8 % 8 nearest neighbours 41 | sz = [1,1,1; 1,0,1; 1,1,1]; 42 | elseif sz==4 43 | sz = [0,1,0; 1,0,1; 0,1,0]; 44 | end 45 | elseif length(sz(:)) == 2 46 | % the specified neighbours has a distance within the domain [dmin, 47 | % dmax) 48 | sz = ceil(sz); 49 | dmin = min(sz); dmax = max(sz); 50 | rsub = (-dmax+1):(dmax-1); % row subscript 51 | csub = rsub; % column subscript 52 | [cind, rind] = meshgrid(csub, rsub); 53 | R = sqrt(cind.^2+rind.^2); 54 | sz = (R>=dmin) .* (R=dmin) .* (R=dmin) .* (Rmin_batch_size),1); 33 | 34 | Cn = cell(ln,1); 35 | 36 | for i = 1:ln-1 37 | if nd == 2 38 | if memmaped 39 | Cn{i} = correlation_image_3D(single(Y.Y(:,:,(i-1)*batch_size+1:i*batch_size)),sz,sizY); 40 | else 41 | Cn{i} = correlation_image_3D(single(Y(:,:,(i-1)*batch_size+1:i*batch_size)),sz,sizY); 42 | end 43 | elseif nd ==3 44 | if memmaped 45 | Cn{i} = correlation_image_3D(single(Y.Y(:,:,:,(i-1)*batch_size+1:i*batch_size)),sz,sizY); 46 | else 47 | Cn{i} = correlation_image_3D(single(Y(:,:,:,(i-1)*batch_size+1:i*batch_size)),sz,sizY); 48 | end 49 | end 50 | end 51 | 52 | if nd == 2 53 | if memmaped 54 | Cn{ln} = correlation_image_3D(single(Y.Y(:,:,(ln-1)*batch_size+1:T)),sz,sizY); 55 | else 56 | Cn{ln} = correlation_image_3D(single(Y(:,:,(ln-1)*batch_size+1:T)),sz,sizY); 57 | end 58 | elseif nd ==3 59 | if memmaped 60 | Cn{ln} = correlation_image_3D(single(Y.Y(:,:,:,(ln-1)*batch_size+1:T)),sz,sizY); 61 | else 62 | Cn{ln} = correlation_image_3D(single(Y(:,:,:,(ln-1)*batch_size+1:T)),sz,sizY); 63 | end 64 | end 65 | 66 | CI = max(cat(nd+1,Cn{:}),[],nd+1); -------------------------------------------------------------------------------- /utilities/cvx_foopsi.m: -------------------------------------------------------------------------------- 1 | function [c,b,c1] = cvx_foopsi(y,b,c1,sn,b_lb,g,w,keep) 2 | 3 | % implementation of constrained foopsi in CVX 4 | % Written by Eftychios Pnevmatikakis 5 | 6 | if isempty(b) 7 | bas_est = 1; 8 | else 9 | bas_est = 0; 10 | end 11 | if isempty(c1) 12 | c1_est = 1; 13 | else 14 | c1_est = 0; 15 | end 16 | gd = max(roots([1,-g(:)'])); 17 | T = length(y); 18 | G = spdiags(ones(T,1)*[-g(end:-1:1)',1],-length(g):0,T,T); 19 | gd_vec = gd.^((0:T-1)'); 20 | cvx_begin quiet 21 | variable c2(T) 22 | if bas_est; variable b; end 23 | if c1_est; variable c1; end 24 | minimize(w'*(G*c2)) 25 | subject to 26 | G*c2>=0; 27 | norm(y(keep)-c2(keep)-b-c1*gd_vec(keep))<=sqrt(sum(keep))*sn; 28 | if bas_est; b>=b_lb; end 29 | if c1_est; c1>=0; end 30 | cvx_end 31 | if strcmpi(cvx_status,'Infeasible'); 32 | %disp('Problem is infeasible, adjusting noise value.'); 33 | cvx_begin quiet 34 | variable c2(T) 35 | if bas_est; variable b; end 36 | if c1_est; variable c1; end 37 | minimize(norm(y(keep)-c2(keep)-b-c1*gd_vec(keep))) 38 | subject to 39 | G*c2>=0; 40 | if bas_est; b>=b_lb; end 41 | if c1_est; c1>=0; end 42 | cvx_end 43 | sn = cvx_optval/sqrt(sum(keep)); 44 | end 45 | c = c2; 46 | end -------------------------------------------------------------------------------- /utilities/detrend_df_f.m: -------------------------------------------------------------------------------- 1 | function [F_dff,F0] = detrend_df_f(A,b,C,f,YrA,options) 2 | 3 | % detrend and extract DF/F values from processed fluorescence traces 4 | % INPUTS 5 | % A: matrix of spatial components (2-d matrix, sparse) 6 | % b: matrix of spatial background (2-d matrix) 7 | % C: matrix of temporal components (2-d matrix) 8 | % f: matrix of temporal background (2-d matrix) 9 | % YrA: matrix of filtered residuals (2-d matrix, optional) 10 | % options: options structure used for specifying method for determining DF 11 | % default method is the median of the trace. By changing 12 | % options.df_prctile an arbitray percentile can be used (between 0 and 100). 13 | % a moving window can also be established by specifying options.df_window 14 | % 15 | % OUTPUTS 16 | % F_dff: detrended fluorescence in DF/F 17 | % F0: baseline fluorescence for each trace 18 | 19 | defoptions = CNMFSetParms; 20 | if nargin < 5 || isempty(options) 21 | options = defoptions; 22 | end 23 | if ~isfield(options,'df_prctile') || isempty(options.df_prctile) 24 | options.df_prctile = defoptions.df_prctile; 25 | end 26 | if ~isfield(options,'df_window') || isempty(options.df_window) 27 | options.df_window = defoptions.df_window; 28 | end 29 | 30 | F = diag(sum(A.^2))*(C + YrA); % fluorescence 31 | if isempty(options.df_window) || (options.df_window > size(C,2)) 32 | Fd = prctile(F,options.df_prctile,2); 33 | F0 = repmat(prctile((A'*b)*f,options.df_prctile,2) + Fd,1,size(C,2)); 34 | F_dff = (F - repmat(Fd,1,size(C,2)))./F0; 35 | else 36 | Fd = prctfilt(F,options.df_prctile,options.df_window); % detrended fluorescence 37 | F0 = prctfilt((A'*b)*f,options.df_prctile,options.df_window,[],0) + (F-Fd); % background + baseline for each component 38 | F_dff = Fd./F0; 39 | end -------------------------------------------------------------------------------- /utilities/detrend_df_f_auto.m: -------------------------------------------------------------------------------- 1 | function [F_dff,F0] = detrend_df_f_auto(A,b,C,f,YrA,options) 2 | 3 | % detrend and extract DF/F values from processed fluorescence traces 4 | % INPUTS 5 | % A: matrix of spatial components (2-d matrix, sparse) 6 | % b: matrix of spatial background (2-d matrix) 7 | % C: matrix of temporal components (2-d matrix) 8 | % f: matrix of temporal background (2-d matrix) 9 | % YrA: matrix of filtered residuals (2-d matrix, optional) 10 | % options: options structure used for specifying method for determining DF 11 | % default method is the median of the trace. By changing 12 | % options.df_prctile an arbitray percentile can be used (between 0 and 100). 13 | % a moving window can also be established by specifying options.df_window 14 | % 15 | % OUTPUTS 16 | % F_dff: detrended fluorescence in DF/F 17 | % F0: baseline fluorescence for each trace 18 | 19 | defoptions = CNMFSetParms; 20 | if nargin < 5 || isempty(options) 21 | options = defoptions; 22 | end 23 | if ~isfield(options,'df_prctile') || isempty(options.df_prctile) 24 | options.df_prctile = defoptions.df_prctile; 25 | end 26 | if ~isfield(options,'df_window') || isempty(options.df_window) 27 | options.df_window = defoptions.df_window; 28 | end 29 | 30 | F = diag(sum(A.^2))*(C + YrA); % fluorescence 31 | B = (A'*b)*f; 32 | 33 | [N,T] = size(F); 34 | 35 | F_dff = zeros(N,T); 36 | F0 = zeros(N,T); 37 | 38 | for i = 1:N 39 | if isempty(options.df_window) || (options.df_window > size(C,2)) 40 | [~,cdf] = estimate_percentile_level(F(i,:),T,T); 41 | cdf_level = median(cdf); 42 | Fd = prctile(F(i,:),cdf_level,2); 43 | F0(i,:) = repmat(prctile(B(i,:),cdf_level,2) + Fd,1,T); 44 | F_dff(i,:) = (F(i,:) - Fd)./F0(i,:); 45 | else 46 | [~,cdf] = estimate_percentile_level(F(i,:),options.df_window,round(options.df_window/2)); 47 | cdf_level = median(cdf); 48 | Fd = prctfilt(F(i,:),cdf_level,options.df_window); % detrended fluorescence 49 | F0(i,:) = prctfilt(B(i,:),cdf_level,options.df_window,[],0) + (F(i,:)-Fd); % background + baseline for each component 50 | F_dff(i,:) = Fd./F0(i,:); 51 | end 52 | end -------------------------------------------------------------------------------- /utilities/downsample_data.m: -------------------------------------------------------------------------------- 1 | function Y_ds = downsample_data(Y,direction,tsub,ssub,nrm) 2 | 3 | % downsampling for 2d or 3d imaging data (already loaded in memory) 4 | 5 | % INPUTS 6 | % Y: input dataset in 2D+T or 3D+T format 7 | % direction: direction of downsampling: 'space','time','spacetime' 8 | % tsub: degree of downsampling in time 9 | % ssub: degree of downsampling in space 10 | % nrm: norm to be used when averaging (default: 1, plain averaging) 11 | 12 | if nargin < 5 || isempty(nrm); nrm = 1; end 13 | if nargin < 4 || isempty(ssub); ssub = 1; end 14 | if nargin < 3 || isempty(tsub); tsub = 1; end 15 | if nargin < 2 || isempty(direction); direction = 'spacetime'; end 16 | 17 | ndimsY = ndims(Y) - 1; 18 | if ndimsY == 2 19 | [d1,d2,T] = size(Y); d3 = 1; 20 | elseif ndimsY == 3 21 | [d1,d2,d3,T] = size(Y); 22 | end 23 | 24 | d = [d1,d2,d3]; 25 | ds = d; 26 | 27 | Ts = floor(T/tsub); %reduced number of frames 28 | Y_ds = Y; 29 | if ~((ssub == 1) && (tsub == 1)) 30 | fprintf('starting resampling \n') 31 | if strcmpi(direction,'space') || strcmpi(direction,'spacetime'); 32 | if ssub~=1; 33 | ds(1:2) = ceil(d(1:2)/ssub); % do not subsample along z axis 34 | if ndimsY == 2; Y_ds = imresize(Y_ds, [ds(1), ds(2)], 'box'); end 35 | if ndimsY == 3; 36 | Y_ds = zeros([ds(1:2),T,ds(end)]); 37 | for z = 1:ds(3) 38 | Y_ds(:,:,:,z) = imresize(squeeze(Y_ds(:,:,z,:)), [ds(1), ds(2)], 'box'); 39 | end 40 | Y_ds = permute(Y_ds,[1,2,4,3]); 41 | end 42 | else 43 | Y_ds = Y; 44 | end 45 | end 46 | if strcmpi(direction,'time') || strcmpi(direction,'spacetime') 47 | if tsub~=1 48 | if nrm == 1 49 | if ndimsY == 2; Y_ds = squeeze(nanmean(reshape(Y_ds(:, :, 1:(Ts*tsub)),ds(1), ds(2), tsub, Ts), 3)); end 50 | if ndimsY == 3; Y_ds = squeeze(nanmean(reshape(Y_ds(:, :, :, 1:(Ts*tsub)),ds(1), ds(2), ds(3), tsub, Ts), 4)); end 51 | elseif nrm == Inf 52 | if ndimsY == 2; Y_ds = squeeze(max(reshape(Y_ds(:, :, 1:(Ts*tsub)),ds(1), ds(2), tsub, Ts),[], 3)); end 53 | if ndimsY == 3; Y_ds = squeeze(max(reshape(Y_ds(:, :, :, 1:(Ts*tsub)),ds(1), ds(2), ds(3), tsub, Ts),[], 4)); end 54 | else 55 | if ndimsY == 2; Y_ds = squeeze(nanmean(reshape(Y_ds(:, :, 1:(Ts*tsub)).^nrm,ds(1), ds(2), tsub, Ts), 3)).^(1/nrm); end 56 | if ndimsY == 3; Y_ds = squeeze(nanmean(reshape(Y_ds(:, :, :, 1:(Ts*tsub)).^nrm,ds(1), ds(2), ds(3), tsub, Ts), 4)).^(1/nrm); end 57 | end 58 | end 59 | end 60 | else 61 | fprintf('No downsampling is performed \n') 62 | end -------------------------------------------------------------------------------- /utilities/extract_DF_F.m: -------------------------------------------------------------------------------- 1 | function [C_df,Df] = extract_DF_F(Y,A,C,P,options,AY) 2 | 3 | % extract DF/F signals after performing NMF 4 | % inputs: Y raw data (d X T matrix, d # number of pixels, T # of timesteps) 5 | % A matrix of spatial components (d x K matrix, K # of components) 6 | % C matrix of temporal components (K x T matrix) 7 | % P neuron structure, used to read the baseline activity for each 8 | % component of C 9 | % options structure used for specifying method for determining DF 10 | % default method is the median of the trace. By changing 11 | % options.df_prctile an arbitray percentile can be used (between 0 and 100). 12 | % a moving window can also be established by specifying options.df_window 13 | % AY pass is the product A'*Y otherwise compute it 14 | 15 | % outputs: C_df temporal components in the DF/F domain 16 | % Df background for each component to normalize the filtered raw data 17 | 18 | % Written by: 19 | % Eftychios A. Pnevmatikakis, Simons Foundation, 2016 20 | 21 | %memmaped = isobject(Y); 22 | defoptions = CNMFSetParms; 23 | if nargin < 5 || isempty(options) 24 | options = defoptions; 25 | end 26 | if ~isfield(options,'df_prctile') || isempty(options.df_prctile) 27 | options.df_prctile = defoptions.df_prctile; 28 | end 29 | if ~isfield(options,'df_window') || isempty(options.df_window) 30 | options.df_window = defoptions.df_window; 31 | end 32 | if ~isfield(options,'full_A') || isempty(options.full_A); full_A = defoptions.full_A; else full_A = options.full_A; end 33 | 34 | [K,T] = size(C); 35 | 36 | if ~exist('AY','var') 37 | AY = mm_fun(A,Y); 38 | end 39 | 40 | Bas = zeros(K,T); 41 | 42 | if ~(nargin < 5 || isempty(P)) 43 | bas_val = cell2mat(P.b); 44 | Ntr = size(bas_val,2); 45 | if Ntr > 1 46 | ln = diff(P.cs_frtrs); 47 | for i = 1:Ntr 48 | Bas(:,:,P.cs_frtrs(i)+1:P.cs_frtrs(i+1)) = repmat(bas_val(:,i),1,ln(i)); 49 | end 50 | else 51 | Bas = repmat(bas_val,1,T); 52 | end 53 | end 54 | 55 | nA = sqrt(sum(A.^2))'; 56 | AA = A'*A; 57 | AA(1:K+1:end) = 0; 58 | 59 | Cf = bsxfun(@times,C - Bas,nA(:).^2); 60 | 61 | C2 = AY - AA*C; 62 | 63 | if isempty(options.df_window) || (options.df_window > size(C,2)) 64 | if options.df_prctile == 50 65 | Df = median(C2,2); 66 | else 67 | Df = prctile(C2,options.df_prctile,2); 68 | end 69 | C_df = bsxfun(@times,Cf,1./Df(:)); 70 | else 71 | if options.df_prctile == 50 72 | if verLessThan('matlab','2015b') 73 | warning('Median filtering at the boundaries might be inaccurate due to zero padding.') 74 | Df = medfilt1(C2,options.df_window,[],2); 75 | else 76 | Df = medfilt1(C2,options.df_window,[],2,'truncate'); 77 | end 78 | else 79 | Df = zeros(size(C2)); 80 | for i = 1:size(Df,1); 81 | df_temp = running_percentile(C2(i,:), options.df_window, options.df_prctile); 82 | Df(i,:) = df_temp(:)'; 83 | end 84 | end 85 | C_df = Cf./Df; 86 | end -------------------------------------------------------------------------------- /utilities/extract_DF_F_new.m: -------------------------------------------------------------------------------- 1 | function [C_df,Df] = extract_DF_F_new(A,C,b,f,P,options) 2 | 3 | % extract DF/F signals after performing NMF 4 | % inputs: Y raw data (d X T matrix, d # number of pixels, T # of timesteps) 5 | % A matrix of spatial components (d x K matrix, K # of components) 6 | % C matrix of temporal components (K x T matrix) 7 | % P neuron structure, used to read the baseline activity for each 8 | % component of C 9 | % options structure used for specifying method for determining DF 10 | % default method is the median of the trace. By changing 11 | % options.df_prctile an arbitray percentile can be used (between 0 and 100). 12 | % a moving window can also be established by specifying options.df_window 13 | 14 | % outputs: C_df temporal components in the DF/F domain 15 | % Df background for each component to normalize the filtered raw data 16 | 17 | % Written by: 18 | % Eftychios A. Pnevmatikakis, Simons Foundation, 2016 19 | 20 | %memmaped = isobject(Y); 21 | defoptions = CNMFSetParms; 22 | if nargin < 6 || isempty(options) 23 | options = defoptions; 24 | end 25 | if ~isfield(options,'df_prctile') || isempty(options.df_prctile) 26 | options.df_prctile = defoptions.df_prctile; 27 | end 28 | if ~isfield(options,'df_window') || isempty(options.df_window) 29 | options.df_window = defoptions.df_window; 30 | end 31 | if ~isfield(options,'full_A') || isempty(options.full_A); full_A = defoptions.full_A; else full_A = options.full_A; end 32 | 33 | [K,T] = size(C); 34 | 35 | Bas = zeros(K,T); 36 | 37 | if ~(nargin < 5 || isempty(P)) 38 | bas_val = cell2mat(P.b); 39 | Ntr = size(bas_val,2); 40 | if Ntr > 1 41 | ln = diff(P.cs_frtrs); 42 | for i = 1:Ntr 43 | Bas(:,:,P.cs_frtrs(i)+1:P.cs_frtrs(i+1)) = repmat(bas_val(:,i),1,ln(i)); 44 | end 45 | else 46 | Bas = repmat(bas_val,1,T); 47 | end 48 | end 49 | 50 | nA = sqrt(sum(A.^2)); 51 | 52 | AA = A'*A; 53 | AA(1:K+1:end) = 0; 54 | 55 | Cf = bsxfun(@times,C - Bas,nA(:).^2); 56 | C2 = repmat(AA*bas_val,1,T) + (A'*b)*f; 57 | 58 | if isempty(options.df_window) || (options.df_window > size(C,2)) 59 | if options.df_prctile == 50 60 | Df = median(C2,2); 61 | else 62 | Df = prctile(C2,options.df_prctile,2); 63 | end 64 | C_df = bsxfun(@times,Cf,1./Df(:)); 65 | else 66 | if options.df_prctile == 50 67 | if verLessThan('matlab','2015b') 68 | warning('Median filtering at the boundaries might be inaccurate due to zero padding.') 69 | Df = medfilt1(C2,options.df_window,[],2); 70 | else 71 | Df = medfilt1(C2,options.df_window,[],2,'truncate'); 72 | end 73 | else 74 | Df = zeros(size(C2)); 75 | for i = 1:size(Df,1); 76 | df_temp = running_percentile(C2(i,:), options.df_window, options.df_prctile); 77 | Df(i,:) = df_temp(:)'; 78 | end 79 | end 80 | C_df = Cf./Df; 81 | end -------------------------------------------------------------------------------- /utilities/extract_DF_F_old.m: -------------------------------------------------------------------------------- 1 | function [C_df,Df] = extract_DF_F_old(Y,A,C,ind,options) 2 | 3 | % extract DF/F signals after performing NMF 4 | % inputs: Y raw data (d X T matrix, d # number of pixels, T # of timesteps) 5 | % A matrix of spatial components (d x K matrix, K # of components) 6 | % C matrix of temporal components (K x T matrix) 7 | % ind index of component that represent the background (optional, if not 8 | % given it's estimated) 9 | % options structure used for specifying method for determining DF 10 | % default method is the median of the trace. By changing 11 | % options.df_prctile an arbitray percentile can be used (between 0 and 100). 12 | % a moving window can also be established by specifying options.df_window 13 | 14 | % outputs: C_df temporal components in the DF/F domain 15 | % Df background for each component to normalize the filtered raw data 16 | 17 | % Written by: 18 | % Eftychios A. Pnevmatikakis, Simons Foundation, 2015 19 | 20 | memmaped = isobject(Y); 21 | defoptions = CNMFSetParms; 22 | if nargin < 5 || isempty(options) 23 | options = defoptions; 24 | end 25 | if ~isfield(options,'df_prctile') || isempty(options.df_prctile) 26 | options.df_prctile = defoptions.df_prctile; 27 | end 28 | if ~isfield(options,'df_window') || isempty(options.df_window) 29 | options.df_window = defoptions.df_window; 30 | end 31 | if ~isfield(options,'full_A') || isempty(options.full_A); full_A = defoptions.full_A; else full_A = options.full_A; end 32 | 33 | nA = sqrt(sum(A.^2))'; 34 | [K,T] = size(C); 35 | d = size(A,1); 36 | A = A/spdiags(nA,0,K,K); % normalize spatial components to unit energy 37 | C = spdiags(nA,0,K,K)*C; 38 | 39 | if nargin < 4 || isempty(ind) 40 | [~,ind] = min(sum(A.^6)); % identify background component 41 | end 42 | 43 | non_bg = true(1,K); 44 | non_bg(ind) = false; % non-background components 45 | 46 | step = 5e3; 47 | if memmaped 48 | AY = zeros(K,T); 49 | for i = 1:step:d 50 | AY = AY + A(i:min(i+step-1,d),:)'*double(Y.Yr(i:min(i+step-1,d),:)); 51 | end 52 | else 53 | if issparse(A) && isa(Y,'single') 54 | if full_A 55 | AY = full(A)'*Y; 56 | else 57 | AY = A'*double(Y); 58 | end 59 | else 60 | AY = A'*Y; 61 | end 62 | end 63 | 64 | Yf = AY - (A'*A(:,non_bg))*C(non_bg,:); 65 | 66 | if isempty(options.df_window) || (options.df_window > size(C,2)) 67 | if options.df_prctile == 50 68 | Df = median(Yf,2); 69 | else 70 | Df = prctile(Yf,options.df_prctile,2); 71 | end 72 | C_df = spdiags(Df,0,K,K)\C; 73 | else 74 | if options.df_prctile == 50 75 | if verLessThan('matlab','2015b') 76 | warning('Median filtering at the boundaries might be inaccurate due to zero padding.') 77 | Df = medfilt1(Yf,options.df_window,[],2); 78 | else 79 | Df = medfilt1(Yf,options.df_window,[],2,'truncate'); 80 | end 81 | else 82 | Df = zeros(size(Yf)); 83 | for i = 1:size(Df,1); 84 | df_temp = running_percentile(Yf(i,:), options.df_window, options.df_prctile); 85 | Df(i,:) = df_temp(:)'; 86 | end 87 | end 88 | C_df = C./Df; 89 | end 90 | 91 | C_df(ind,:) = []; % 0; % FN modified so C_df does not include the background components and it has the same size as C. -------------------------------------------------------------------------------- /utilities/extract_max_activity.m: -------------------------------------------------------------------------------- 1 | function [LOCS,Ym] = extract_max_activity(Y,nlocs,width) 2 | 3 | % extract points of maximum activation for each pixel using the findpeaks 4 | % function. Requires the signal processing toolbox and uses the parallel 5 | % processing toolbox if present 6 | 7 | % INPUTS: 8 | % Y: input data 9 | % nlocs: number of local maxima for each location 10 | % width: length of each interval 11 | 12 | % OUTPUTS: 13 | % LOCS: max activation intervals 14 | % Ym: max activation values 15 | 16 | % Written by: 17 | % Eftychios A. Pnevmatikakis, Simons Foundation, 2016 18 | 19 | warning('off', 'MATLAB:maxNumCompThreads:Deprecated'); 20 | 21 | if nargin < 3 || isempty(width) 22 | width = 21; 23 | end 24 | 25 | if nargin < 2 || isempty(nlocs) 26 | nlocs = 30; 27 | end 28 | 29 | sizY = size(Y); 30 | T = sizY(end); 31 | d = prod(sizY(1:end-1)); 32 | if length(sizY) > 2 33 | Y = reshape(Y,d,T); 34 | end 35 | 36 | if ~mod(width,2); width = width + 1; end 37 | locs = zeros(d,nlocs); 38 | 39 | spatial_parallel = exist(which('parpool')); 40 | 41 | if spatial_parallel % solve BPDN problem for each pixel 42 | Nthr = max(20*maxNumCompThreads,round(d*T/2^24)); 43 | Nthr = min(Nthr,round(d/1e3)); 44 | siz_row = [floor(d/Nthr)*ones(Nthr-mod(d,Nthr),1);(floor(d/Nthr)+1)*ones(mod(d,Nthr),1)]; 45 | indeces = [0;cumsum(siz_row)]; 46 | loc_cell = cell(Nthr,1); 47 | for nthr = 1:Nthr 48 | lc_temp = zeros(siz_row(nthr),nlocs); 49 | Ytemp = double(Y(indeces(nthr)+1:indeces(nthr+1),:)); 50 | parfor px = 1:siz_row(nthr) 51 | [pks,lcs] = findpeaks(Ytemp(px,:),'MinPeakDistance',width); 52 | [~,srt] = sort(pks,'descend'); 53 | if length(srt) >= nlocs 54 | lc_temp(px,:) = lcs(srt(1:nlocs)); 55 | else 56 | rnd = randperm(floor(T/width)-1,nlocs-length(srt))*width; 57 | lc_temp(px,:) = [srt,rnd]; 58 | end 59 | end 60 | loc_cell{nthr} = lc_temp; 61 | if mod(nthr,50) == 0 62 | fprintf('%2.1f%% of pixels completed \n', indeces(nthr+1)*100/d); 63 | end 64 | end 65 | locs = cell2mat(loc_cell); 66 | else 67 | Y = double(Y); 68 | for i = 1:d 69 | [pks,lcs] = findpeaks(Y(i,:),'MinPeakDistance',width); 70 | [~,srt] = sort(pks,'descend'); 71 | if length(srt) >= nlocs 72 | locs(i,:) = lcs(srt(1:nlocs)); 73 | else 74 | rnd = randperm(floor(T/width)-1,nlocs-length(srt))*width; 75 | locs(i,:) = [srt,rnd]; 76 | end 77 | end 78 | end 79 | 80 | locs(locs<(width+1)/2) = (width+1)/2; 81 | locs(locs>T - (width+1)/2) = T - (width+1)/2; 82 | locs = sort(locs,2,'ascend'); 83 | LOCS = kron(locs,ones(1,width)) + repmat(kron(ones(1,nlocs),-(width-1)/2:(width-1)/2),d,1); 84 | if nargout == 2 85 | Ym = zeros(size(LOCS)); 86 | for i = 1:d 87 | Ym(i,:) = Y(i,LOCS(i,:)); 88 | end 89 | end -------------------------------------------------------------------------------- /utilities/extract_patch.m: -------------------------------------------------------------------------------- 1 | function A_com = extract_patch(A,dims,patch_size,padding) 2 | 3 | % Extractx a patch of size patch_size centered around the centroid of each 4 | % component. 5 | % INPUTS: 6 | % A: 2d matrix of spatial components 7 | % dims: dimensions of FOV 8 | % patch_size: dimensions of patch 9 | % padding: if true components remain centered and are zero padded, 10 | % otherwise they are shifted (default: true) 11 | 12 | % OUTPUT: 13 | % A_com: Nd matrix of patches 14 | 15 | if ~exist('padding','var'); padding = true; end 16 | 17 | nd = length(dims); 18 | if nd == 2; dims(3) = 1; patch_size(3) = 1; end 19 | K = size(A,2); 20 | A = A/spdiags(sqrt(sum(A.^2,1))'+eps,0,K,K); % normalize to sum 1 for each compoennt 21 | cm = com(A,dims(1),dims(2),dims(3)); 22 | xx = -ceil(patch_size(1)/2-1):floor(patch_size(1)/2); 23 | yy = -ceil(patch_size(2)/2-1):floor(patch_size(2)/2); 24 | zz = -ceil(patch_size(3)/2-1):floor(patch_size(3)/2); 25 | A_com = zeros([patch_size,K]); 26 | 27 | for i = 1:K 28 | int_x = round(cm(i,1)) + xx; 29 | pad_pre_x = 0; 30 | pad_pre_y = 0; 31 | pad_post_x = 0; 32 | pad_post_y = 0; 33 | if int_x(1)<1 34 | if padding 35 | pad_pre_x = 1 - int_x(1); 36 | int_x = 1:int_x(end); 37 | else 38 | int_x= int_x + 1 - int_x(1); 39 | end 40 | end 41 | if int_x(end)>dims(1) 42 | if padding 43 | pad_post_x = int_x(end) - dims(1); 44 | int_x = int_x(1):dims(1); 45 | else 46 | int_x = int_x - (int_x(end)-dims(1)); 47 | end 48 | end 49 | int_y = round(cm(i,2)) + yy; 50 | if int_y(1)<1 51 | if padding 52 | pad_pre_y = 1 - int_y(1); 53 | int_y = 1:int_y(end); 54 | else 55 | int_y = int_y + 1 - int_y(1); 56 | end 57 | end 58 | if int_y(end)>dims(2) 59 | if padding 60 | pad_post_y = int_y(end) - dims(2); 61 | int_y = int_y(1):dims(2); 62 | else 63 | int_y = int_y - (int_y(end)-dims(2)); 64 | end 65 | end 66 | if nd == 3 67 | int_z = round(cm(i,3)) + zz; 68 | if int_z(1)<1 69 | int_z = int_z + 1 - int_z(1); 70 | end 71 | if int_z(end)>dims(3) 72 | int_z = int_z - (int_z(end)-dims(3)); 73 | end 74 | else 75 | int_z = 1; 76 | end 77 | A_temp = reshape(full(A(:,i)),dims); 78 | A_temp = A_temp(int_x,int_y,int_z); 79 | if padding 80 | A_temp = padarray(A_temp,[pad_pre_x,pad_pre_y],0,'pre'); 81 | A_temp = padarray(A_temp,[pad_post_x,pad_post_y],0,'post'); 82 | end 83 | A_com(:,:,i) = A_temp; 84 | end -------------------------------------------------------------------------------- /utilities/fast_nmf.m: -------------------------------------------------------------------------------- 1 | function [W,H] = fast_nmf(A,B,k,max_iter) 2 | 3 | % fast NMF computation of a matrix decomponsed in A*B form 4 | 5 | if nargin < 4 || isempty(max_iter) 6 | max_iter = 20; 7 | end 8 | 9 | [W,H] = nnsvd(A,B,k); 10 | H = H'; 11 | 12 | for iter = 1:max_iter 13 | if isempty(B) 14 | B = 1; 15 | end 16 | W = max((A*(B*H'))/(H*H'),0); 17 | H = max((W'*W)\((W'*A)*B),0); 18 | %disp(iter) 19 | end 20 | 21 | function [W,H] = nnsvd(A,B,k) 22 | 23 | mf = @(x,y) mat_vec(A,B,x,y); 24 | sz = [size(A,1), size(B,2)]; 25 | if isempty(B) 26 | sz(2) = size(A,2); 27 | end 28 | [U,S,V] = svds(mf,sz,k); 29 | 30 | W = zeros(sz(1),k); 31 | H = zeros(sz(2),k); 32 | 33 | for j = 1:k 34 | x = U(:,j); 35 | y = V(:,j); 36 | xp = (x>0).*x; 37 | xn = xp - x; 38 | yp = (y>0).*y; 39 | yn = yp - y; 40 | nxp = norm(xp); 41 | nxn = norm(xn); 42 | nyp = norm(yp); 43 | nyn = norm(yn); 44 | if nxp*nyp > nxn*nyn 45 | u = xp/nxp; 46 | v = yp/nyp; 47 | sigma = nxp*nyp; 48 | else 49 | u = xn/nxn; 50 | v = yn/nyn; 51 | sigma = nxn*nyn; 52 | end 53 | W(:,j) = sqrt(S(j,j)*sigma)*u; 54 | H(:,j) = sqrt(S(j,j)*sigma)*v; 55 | end 56 | if isempty(B) 57 | avg = mean(A(:)); 58 | else 59 | avg = mean(A,1)*mean(B,2); 60 | end 61 | W(W==0) = avg; 62 | H(H==0) = avg; 63 | 64 | function y = mat_vec(A,B,x,method) 65 | 66 | if strcmp(method,'notransp') 67 | if isempty(B) 68 | y = A*x; 69 | else 70 | y = A*(B*x); 71 | end 72 | elseif strcmp(method,'transp') 73 | if isempty(B) 74 | y = A'*x; 75 | else 76 | y = B'*(A'*x); 77 | 78 | end 79 | end 80 | end 81 | end 82 | 83 | end -------------------------------------------------------------------------------- /utilities/find_unsaturatedPixels.m: -------------------------------------------------------------------------------- 1 | function normalPixels = find_unsaturatedPixels(Y, saturationValue, saturationThreshold, saturationTime) 2 | 3 | % finds the pixels/voxels that are saturated and returns the ones that are 4 | % not. A pixel is defined as saturated if its observed fluorescence is 5 | % above saturationThreshold*saturationValue at least saturationTime 6 | % fraction of the time. 7 | 8 | % Written by Weijian Yang and Eftychios A. Pnevmatikakis, based on an idea 9 | % from Weijian Yang and Darcy Peterka 10 | 11 | if nargin < 4 || isempty(saturationTime) 12 | saturationTime = 0.005; 13 | end 14 | 15 | if nargin < 3 || isempty(saturationThreshold) 16 | saturationThreshold = 0.9; 17 | end 18 | 19 | if nargin < 2 || isempty(saturationValue) 20 | saturationValue = 2^nextpow2(max(Y(:)))-1; 21 | end 22 | 23 | Ysat = (Y >= saturationThreshold*saturationValue); 24 | normalPixels = find(mean(Ysat,ndims(Y))> mex -O -largeArrayDims graph_conn_comp_mex.cpp 18 | % 19 | % 20 | 21 | sA = spfun(@(x) ones(size(x)),sA); 22 | if ~isequal(sA, sA') 23 | [ii jj] = find(sA); 24 | sA = sparse([ii jj],[jj ii], ones(1, 2*numel(ii)), size(sA,1), size(sA,2)); 25 | end 26 | [l c] = graph_conn_comp_mex(sA); 27 | l = double(l); % make it compatible of the rest of Matlab -------------------------------------------------------------------------------- /utilities/interp_missing_data.m: -------------------------------------------------------------------------------- 1 | function Y_interp = interp_missing_data(Y) 2 | % INTERP_MISSING_DATA - interpolate missing data using linear interpolation for each pixel 3 | % 4 | % [Y_INTERP] = INTERP_MISSING_DATA(Y) 5 | % 6 | % Given a matrix Y with possible NaN values, this function produces 7 | % a sparse matrix Y_INTERP that has the linearly interpolated values 8 | % of each pixel that exhibits a NaN value. The values are interpolated 9 | % over the last dimension of Y. 10 | % 11 | % Example: 12 | % yy = [0 0 ; 0 0]; 13 | % yy(:,:,2) = [0 NaN ; 0 2]; 14 | % yy(:,:,3) = [0.1 0.2 ; 0 2.3]; 15 | % Y_interp = interp_missing_data(yy); 16 | % % Y_interp is a sparse matrix : (3,2) 0.1000 17 | % 18 | % See also: INTERP1 19 | 20 | sizY = size(Y); 21 | dimY = length(sizY); 22 | d = prod(sizY(1:dimY-1)); 23 | T = sizY(end); 24 | mis_data = cell(d,1); 25 | 26 | for i = 1:d 27 | [ii,jj,kk] = ind2sub(sizY(1:dimY-1),i); 28 | if dimY == 2 29 | ytemp = Y(i,:); 30 | elseif dimY == 3 31 | ytemp = squeeze(Y(ii,jj,:)); 32 | elseif dimY == 4 33 | ytemp = squeeze(Y(ii,jj,kk,:)); 34 | end 35 | f = isnan(ytemp(:)); 36 | y_val = interp1(find(~f),ytemp(~f),find(f),'linear','extrap'); 37 | mis_data{i} = [i*ones(length(y_val),1),find(f(:)),y_val(:)]; 38 | end 39 | 40 | mis_data = cell2mat(mis_data); 41 | 42 | Y_interp = sparse(mis_data(:,1),mis_data(:,2),mis_data(:,3),d,T); 43 | -------------------------------------------------------------------------------- /utilities/kmeans_pp.m: -------------------------------------------------------------------------------- 1 | function [L,C] = kmeans_pp(X,k) 2 | %KMEANS_PP Cluster multivariate data using the k-means++ algorithm. 3 | % [L,C] = kmeans_pp(X,k) produces a 1-by-size(X,2) vector L with one class 4 | % label per column in X and a size(X,1)-by-k matrix C containing the 5 | % centers corresponding to each class. 6 | 7 | % Version: 2013-02-08 8 | % Authors: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be) 9 | % 10 | % References: 11 | % [1] J. B. MacQueen, "Some Methods for Classification and Analysis of 12 | % MultiVariate Observations", in Proc. of the fifth Berkeley 13 | % Symposium on Mathematical Statistics and Probability, L. M. L. Cam 14 | % and J. Neyman, eds., vol. 1, UC Press, 1967, pp. 281-297. 15 | % [2] D. Arthur and S. Vassilvitskii, "k-means++: The Advantages of 16 | % Careful Seeding", Technical Report 2006-13, Stanford InfoLab, 2006. 17 | 18 | 19 | % Copyright (c) 2013, Laurent Sorber 20 | % All rights reserved. 21 | % 22 | % Redistribution and use in source and binary forms, with or without 23 | % modification, are permitted provided that the following conditions are 24 | % met: 25 | % 26 | % * Redistributions of source code must retain the above copyright 27 | % notice, this list of conditions and the following disclaimer. 28 | % * Redistributions in binary form must reproduce the above copyright 29 | % notice, this list of conditions and the following disclaimer in 30 | % the documentation and/or other materials provided with the distribution 31 | % 32 | % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 33 | % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 | % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 | % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 36 | % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 37 | % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 | % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 | % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 40 | % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 41 | % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 | % POSSIBILITY OF SUCH DAMAGE. 43 | 44 | L = []; 45 | L1 = 0; 46 | 47 | while length(unique(L)) ~= k 48 | 49 | % The k-means++ initialization. 50 | C = X(:,1+round(rand*(size(X,2)-1))); 51 | L = ones(1,size(X,2)); 52 | for i = 2:k 53 | D = bsxfun(@minus, X, C); % D = X-C(:,L); 54 | D = cumsum(sqrt(dot(D, D, 1))); 55 | if D(end) == 0, C(:,i:k) = X(:,ones(1,k-i+1)); return; end 56 | C(:,i) = X(:,find(rand < D/D(end),1)); 57 | [~,L] = max(bsxfun(@minus,2*real(C'*X),dot(C,C,1).')); 58 | end 59 | 60 | % The k-means algorithm. 61 | while any(L ~= L1) 62 | L1 = L; 63 | for i = 1:k, l = L==i; C(:,i) = sum(X(:,l),2)/sum(l); end 64 | [~,L] = max(bsxfun(@minus,2*real(C'*X),dot(C,C,1).'),[],1); 65 | end 66 | 67 | end 68 | -------------------------------------------------------------------------------- /utilities/lagrangian_foopsi_temporal.m: -------------------------------------------------------------------------------- 1 | function [c,ld] = lagrangian_foopsi_temporal(y,a,thr,G,ld_in) 2 | 3 | % solves min sum(G*c) 4 | % s.t.: G*c >= 0, ||a(j)*c - y(j)|| <= thr(j) 5 | T = size(G,1); 6 | la = length(a); 7 | myfun = @(Ald) lagrangian_temporal_grad(Ald,y,thr); 8 | options = optimset('GradObj','On','Display','Off','Algorithm','interior-point','TolX',1e-6); 9 | if nargin < 5 10 | ld_in = 10*ones(length(a),1); 11 | end 12 | ld = fmincon(myfun,ld_in,[],[],[],[],zeros(length(a),1),[],[],options); 13 | 14 | function [f,grad] = lagrangian_temporal_grad(Al,y,thr) 15 | v = G'*ones(T,1); 16 | %options2 = optimset('Display','Off','Algorithm','interior-point-convex'); 17 | %c = quadprog(2*sum(Al.*(a.^2))*speye(T),v-2*((la>1)*sum(spdiags(Al.*a,0,la,la)*y,1)' + (la==1)*y'*(Al.*a)),-G,zeros(T,1),[],[],[],[],[],options2); 18 | c = plain_foopsi(((la>1)*sum(spdiags(Al.*a,0,la,la)*y,1)' + (la==1)*y'*(Al.*a)-v/2)/(sum(Al.*(a.^2))),G); 19 | f = v'*c; 20 | grad = (sum((a*c'-y).^2,2)-thr); 21 | f = f + Al(:)'*grad; 22 | f = -f; 23 | grad = -grad; 24 | end 25 | end -------------------------------------------------------------------------------- /utilities/make_G_matrix.m: -------------------------------------------------------------------------------- 1 | function G = make_G_matrix(T,g,varargin) 2 | 3 | if length(g) == 1 && g < 0 4 | g=0; 5 | end 6 | 7 | G = spdiags(ones(T,1)*[-flipud(g(:))',1],-length(g):0,T,T); 8 | if nargin == 3 9 | sl = [0;cumsum(varargin{1}(:))]; 10 | for i = 1:length(sl)-1 11 | G(sl(i)+1,sl(i+1))=0; 12 | end 13 | end -------------------------------------------------------------------------------- /utilities/memmap/construct_patches.m: -------------------------------------------------------------------------------- 1 | function patches = construct_patches(sizY,siz,overlap,min_size) 2 | 3 | % constructs the coordinates of the different patches for batch processing 4 | % INPUTS 5 | % sizY: size of input data (excluding time dimension) 6 | % siz: size of each patch (default: [32,32,4], if third spatial dimension is present) 7 | % overlap: amount of overlap in each direction (default: [4,4,2], if third spatial dimension is present) 8 | % min_size: minimum patch size is each direction, otherwise merge with previous patch (defalt: [4,4,2]) 9 | 10 | % OUTPUT 11 | % patches: cell structure with start/end points for each patch 12 | 13 | % Author: Eftychios A. Pnevmatikakis, Simons Foundation, 2016 14 | 15 | dimY = length(sizY); % dimension of dataset (2d or 3d) 16 | 17 | if nargin < 4 || isempty(min_size) 18 | min_size = [8,8,3*ones(1,dimY-2)]; 19 | end 20 | 21 | if nargin < 3 || isempty(overlap) 22 | overlap = [4,4,2*ones(1,dimY-2)]; 23 | end 24 | 25 | if nargin < 2 || isempty(siz) 26 | siz = [32,32,4*ones(1,dimY-2)]; 27 | end 28 | 29 | if any(siz<=overlap); error('Size of patch must be greater than the amount of overlap'); end 30 | 31 | x_start = 1:siz(1)-overlap(1):sizY(1)-overlap(1); 32 | x_end = min(x_start + siz(1) - 1,sizY(1)); 33 | if (x_end(end) - x_start(end) + 1 < min_size(1)) || (length(x_end) > 1 && (x_end(end) - x_end(end-1) < min_size(1))) 34 | x_start(end) = []; 35 | x_end(end-1) = []; 36 | end 37 | 38 | y_start = 1:siz(2)-overlap(2):sizY(2)-overlap(2); 39 | y_end = min(y_start + siz(2) - 1,sizY(2)); 40 | if (y_end(end) - y_start(end) + 1 < min_size(2)) || (length(y_end) > 1 && (y_end(end) - y_end(end-1) < min_size(2))) 41 | y_start(end) = []; 42 | y_end(end-1) = []; 43 | end 44 | 45 | if dimY == 3 46 | z_start = 1:siz(3)-overlap(3):sizY(3)-overlap(3); 47 | z_end = min(z_start + siz(3) - 1,sizY(3)); 48 | if z_end(end) - z_start(end) + 1 < min_size(3) 49 | z_start(end) = []; 50 | z_end(end-1) = []; 51 | end 52 | else 53 | z_start = 1; 54 | z_end = 1; 55 | end 56 | 57 | [X1,Y1,Z1] = meshgrid(x_start,y_start,z_start); 58 | [X2,Y2,Z2] = meshgrid(x_end,y_end,z_end); 59 | 60 | if dimY == 2 61 | Z1 = []; 62 | Z2 = []; 63 | end 64 | 65 | patches = mat2cell([X1(:),X2(:),Y1(:),Y2(:),Z1(:),Z2(:)],ones(numel(X1),1),2*dimY); -------------------------------------------------------------------------------- /utilities/memmap/memmap_file.m: -------------------------------------------------------------------------------- 1 | function data = memmap_file(filename,sframe,num2read,chunksize) 2 | 3 | % read a stacked tiff array, reshapes it to 2d array and saves it a mat file that can be memory mapped. 4 | % The file is saved both in its original format and as a reshaped 2d matrix 5 | 6 | % INPUTS 7 | % filename: path to tiff file 8 | % sframe: (optional) first frame to read (default: 1) 9 | % num2read: (optional) number of frames to read (default: until the end of file) 10 | % chunksize: (optional) read the file in chunks for big files (default: read all at once) 11 | 12 | % OUTPUT 13 | % data: object with the data containing: 14 | % Yr: reshaped data file 15 | % sizY: dimensions of original size 16 | % nY: minimum value of Y (not subtracted from the dataset) 17 | 18 | % Author: Eftychios A. Pnevmatikakis, Simons Foundation, 2016 19 | 20 | if nargin < 4 21 | chunksize = []; 22 | end 23 | 24 | if nargin < 3 25 | num2read = []; 26 | end 27 | 28 | if nargin < 2 || isempty(sframe) 29 | sframe = 1; 30 | end 31 | 32 | if isempty(chunksize) 33 | Y = read_file(filename,sframe,num2read); 34 | sizY = size(Y); 35 | Yr = reshape(Y,prod(sizY(1:end-1)),[]); 36 | nY = min(Yr(:)); 37 | %Yr = Yr - nY; 38 | %save([filename(1:end-3),'mat'],'Yr','Y','nY','sizY','-v7.3'); 39 | savefast([filename(1:end-3),'mat'],'Yr','Y','nY','sizY'); 40 | data = matfile([filename(1:end-3),'mat'],'Writable',true); 41 | else 42 | info = imfinfo(filename); 43 | blah=size(info); 44 | if isempty(num2read) 45 | numFrames = blah(1); 46 | else 47 | numFrames = min(blah(1),sframe+num2read-1); 48 | end 49 | nY = Inf; 50 | data = matfile([filename(1:end-3),'mat'],'Writable',true); 51 | Yt = imread(filename,'Index',1,'Info',info); 52 | sizY = [size(Yt),numFrames]; 53 | if length(sizY) == 3 54 | data.Y(sizY(1),sizY(2),sizY(3)) = Yt(1)*0; 55 | elseif length(sizY) == 4 56 | data.Y(sizY(1),sizY(2),sizY(3),sizY(4)) = Yt(1)*0; 57 | end 58 | data.Yr(numel(Yt),numFrames) = Yt(1)*0; 59 | for i = sframe:chunksize:numFrames 60 | Ytemp = read_file(filename,i,min(chunksize,numFrames-i+1)); 61 | Yr = reshape(Ytemp,prod(sizY(1:end-1)),[]); 62 | nY = min(nY,min(Yr(:))); 63 | data.Yr(:,i:i-1+size(Yr,2)) = Yr; 64 | if length(sizY) == 3 65 | data.Y(1:sizY(1),1:sizY(2),i-1+(1:size(Yr,2))) = Ytemp; 66 | elseif legnth(sizY) == 4 67 | data.Y(1:sizY(1),1:sizY(2),1:sizY(3),i-1+(1:size(Yr,2))) = Ytemp; 68 | end 69 | end 70 | data.nY = nY; 71 | data.sizY = [sizY(1:end-1),numFrames-sframe+1]; 72 | end -------------------------------------------------------------------------------- /utilities/memmap/memmap_file_sequence.m: -------------------------------------------------------------------------------- 1 | function data = memmap_file_sequence(foldername) 2 | 3 | % read a sequence of stacked tiff arrays, reshapes it to 2d array and saves it a mat file that can be memory mapped. 4 | % The file is saved both in its original format and as a reshaped 2d matrix 5 | 6 | % INPUTS 7 | % foldername: path to tiff folder containing a series of tiff files 8 | 9 | % OUTPUT 10 | % data: object with the data containing: 11 | % Yr: reshaped data file 12 | % sizY: dimensions of original size 13 | % nY: minimum value of Y (not subtracted from the dataset) 14 | 15 | % Author: Eftychios A. Pnevmatikakis, Simons Foundation, 2016 16 | 17 | nY = Inf; 18 | files = dir([foldername,'/*.tif']); 19 | T = 0; 20 | data = matfile([foldername,'/',files(1).name(1:end-8),'.mat'],'Writable',true); 21 | tt1 = tic; 22 | for i = 1:length(files) 23 | filename = [foldername,'/',files(i).name]; 24 | Y = tiff_reader(filename); 25 | sizY = size(Y); 26 | Yr = reshape(Y,prod(sizY(1:end-1)),[]); 27 | if i == 1; data.Yr(size(Yr,1),size(Yr,2)*length(files)) = single(0); end 28 | nY = min(min(Yr(:)),nY); 29 | if length(sizY) == 3 30 | if i == 1; data.Y(sizY(1),sizY(2),sizY(3)*length(files)) = single(0); end 31 | data.Y(1:sizY(1),1:sizY(2),T+(1:size(Yr,2))) = single(Y); 32 | elseif legnth(sizY) == 4 33 | if i == 1; data.Y(sizY(1),sizY(2),sizY(3),sizY(4)*length(files)) = single(0); end 34 | data.Y(1:sizY(1),1:sizY(2),1:sizY(3),T+(1:size(Yr,2))) = single(Y); 35 | end 36 | data.Yr(1:prod(sizY(1:end-1)),T+(1:size(Yr,2))) = single(Yr); 37 | T = sizY(end) + T; 38 | toc(tt1); 39 | end 40 | sizY(end) = T; 41 | data.sizY = sizY; 42 | data.nY = nY; -------------------------------------------------------------------------------- /utilities/order_ROIs.m: -------------------------------------------------------------------------------- 1 | function [A_or,C_or,S_or,P_or,srt,srt_val] = order_ROIs(A,C,S,P,srt) 2 | 3 | % ordering of the found components based on their maximum temporal 4 | % activation and their size (through their l_inf norm) 5 | % you can also pre-specify the ordering sequence 6 | 7 | nA = full(sqrt(sum(A.^2))); 8 | nr = length(nA); 9 | A = A/spdiags(nA(:),0,nr,nr); 10 | C = spdiags(nA(:),0,nr,nr)*C; 11 | mA = sum(A.^4).^(1/4); 12 | %sA = sum(A); 13 | mC = max(C,[],2); 14 | if ~exist('srt', 'var')||isempty(srt) 15 | [srt_val,srt] = sort(mC.*mA','descend'); 16 | end 17 | A_or = A(:,srt); 18 | C_or = C(srt,:); 19 | 20 | if nargin < 4 21 | P_or = []; 22 | else 23 | P_or = P; 24 | if isfield(P,'gn'); P_or.gn=P.gn(srt); end 25 | if isfield(P,'b'); P_or.b = cellfun(@times,P.b(srt),num2cell(nA(srt)'),'UniformOutput',false); end 26 | if isfield(P,'c1'); P_or.c1 = cellfun(@times,P.c1(srt),num2cell(nA(srt)'),'UniformOutput',false); end 27 | if isfield(P,'neuron_sn'); P_or.neuron_sn=num2cell(nA(srt)'.*cell2mat(P.neuron_sn(srt))); end 28 | end 29 | 30 | if nargin < 3 || isempty(S) 31 | S_or = []; 32 | else 33 | S = spdiags(nA(:),0,nr,nr)*S; 34 | S_or = S(srt,:); 35 | end -------------------------------------------------------------------------------- /utilities/order_components.m: -------------------------------------------------------------------------------- 1 | function [srt,n_events,n_act] = order_components(YrA,C,sn,options) 2 | 3 | % order components by how unlikely it is to produce the data under a no 4 | % spiking hypothesis. The function counts how many times the trace is above 5 | % the sum of the mode and a given number of standard deviations for a given 6 | % number of consecutive intervals. 7 | 8 | % INPUTS 9 | 10 | % YrA: Noise for each temporal component 11 | % C: Temporal components 12 | % sn: Standard deviation of each component (optional, estimated if not given) 13 | % options: Options structure 14 | % options.nsd: number of standard deviations to set threshold 15 | % options.nfr: number of consecutive frames for considering an event 16 | 17 | % OUPUTS 18 | 19 | % srt: Sorted components in decreasing order 20 | % n_event: Number of events for each components in decreasing order 21 | % n_act: Number of components with events (The srt(1:n_act) is the set of active components) 22 | 23 | % Written by: 24 | % Eftychios A. Pnevmatikakis, Simons Foundation, 2016 25 | 26 | if nargin < 3 || isempty(sn) 27 | sn = std(YrA,[],2); 28 | end 29 | 30 | defoptions = CNMFSetParms; 31 | if nargin < 4 || isempty(options) 32 | options = defoptions; 33 | end 34 | 35 | if ~isfield(options,'nsd') || isempty(options.nsd); options.nsd = defoptions.nsd; end % number of sd above the mode 36 | if ~isfield(options,'nfr') || isempty(options.nfr); options.nfr = defoptions.nfr; end % number of consecutive frames 37 | 38 | [K,T] = size(C); 39 | CY = C + YrA; 40 | md = zeros(K,1); 41 | %bd = zeros(K,1); 42 | 43 | for i = 1:K 44 | [bandwidth,density,xmesh]=kde(CY(i,:),2^floor(log2(T)-1)); 45 | [~,id] = max(density); 46 | md(i) = xmesh(id); 47 | %bd(i) = bandwidth; 48 | end 49 | 50 | FF = false(size(CY)); 51 | FF2 = false(size(CY)); 52 | for i = 1:K 53 | ff = (CY(i,:)>md(i)+options.nsd*sn(i)); 54 | FF(i,:) = ff; 55 | FF2(i,:) = bwareaopen(ff,options.nfr); 56 | end 57 | 58 | [n_events,srt] = sort(sum(FF2,2),'descend'); 59 | n_act = sum(n_events>0); 60 | -------------------------------------------------------------------------------- /utilities/patch_to_linear.m: -------------------------------------------------------------------------------- 1 | function idx = patch_to_linear(patch, sizY) 2 | % helper function to build linear indices from patch start/stop indices 3 | slice_idx = patch_to_indices(patch); 4 | subs_idx = cell(1, numel(slice_idx)); 5 | [subs_idx{:}] = ndgrid(slice_idx{:}); 6 | subs_idx = cellfun(@(x) x(:), subs_idx, 'un', false); 7 | idx = sub2ind(sizY(1:end-1), subs_idx{:}); 8 | 9 | function idx = patch_to_indices(patch) 10 | % helper function to build indices vector from patch start/stop indices 11 | idx = arrayfun(@(x,y) x:y, patch(1:2:end), patch(2:2:end), 'un', false); 12 | end 13 | end -------------------------------------------------------------------------------- /utilities/plain_foopsi.m: -------------------------------------------------------------------------------- 1 | function [Zin,ip_it] = plain_foopsi(H,D,I_est,eps) 2 | 3 | % solves argmin ||X-H||^2 subject to D*X>=0 with an interior point method 4 | % using I_est as the initial value and eps as the initial barrier weight 5 | 6 | 7 | ln = length(H); 8 | step_back_frac = 0.5; 9 | iter = 0; 10 | if nargin == 2 11 | I_est = 1e-3*ones(ln,1); 12 | eps = 1; 13 | end 14 | Zin = I_est(:); 15 | 16 | if nargin == 3 17 | eps = 1; 18 | end 19 | while eps>1e-5 20 | n = D*Zin; 21 | nnd = 10; 22 | E = norm(Zin-H)^2 - eps*sum(log(D*Zin)); 23 | grad = 2*(Zin-H) - eps*D'*(n.^(-1)); 24 | Hs = 2*speye(ln) + eps*D'*spdiags(n.^(-2),0,ln,ln)*D; 25 | while nnd/2>1 26 | iter = iter + 1; 27 | Z_dir = -Hs\grad; 28 | hit = -n./(D*Z_dir); 29 | if all(hit<0) 30 | s = 1; 31 | else 32 | s = min(1,.9*min(hit(hit>=0))); 33 | end 34 | E_new = E; s = s/step_back_frac; 35 | x_dg = grad'*Z_dir; 36 | while E_new > E + 0.25*s*x_dg 37 | s=s*step_back_frac; 38 | Z_new = Zin + s*Z_dir; 39 | n = D*Zin; 40 | E_new = norm(Z_new-H)^2 - eps*sum(log(D*Z_new)); 41 | end 42 | %E = E_new; 43 | Zin = Zin + s*Z_dir; 44 | nnd = -x_dg; 45 | E = norm(Zin-H)^2 - eps*sum(log(D*Zin)); 46 | n = D*Zin; 47 | grad = 2*(Zin-H) - eps*D'*(n.^(-1)); 48 | Hs = 2*speye(ln) + eps*D'*spdiags(n.^(-2),0,ln,ln)*D; 49 | %disp(nnd) 50 | end 51 | eps = eps/10; 52 | end 53 | %fprintf('Interior point method converged after %i iterations \n',iter); 54 | ip_it = iter; 55 | -------------------------------------------------------------------------------- /utilities/play_movie.m: -------------------------------------------------------------------------------- 1 | function play_movie(movs,labels,min_mov,max_mov) 2 | % play list (cell) of movies with labels, press key to stop playing 3 | % inputs: 4 | % movs: cell of movies 5 | % labels: cell of titles for movies 6 | % min_mov,max_mov: min and max of movie for setting clims on movies 7 | 8 | if ~iscell(movs) 9 | movs = {movs}; 10 | end 11 | if ~exist('labels','var') 12 | labels = cell(size(movs)); 13 | end 14 | if ~exist('min_mov','var') || ~exist('max_mov','var') 15 | nml = min(1e7,numel(movs{1})); 16 | min_mov = quantile(movs{1}(1:nml),0.001); 17 | max_mov = quantile(movs{1}(1:nml),1-0.001); 18 | end 19 | 20 | dialogBox = uicontrol('Style', 'PushButton', 'String', 'stop','Callback', 'delete(gcbf)'); 21 | 22 | num_movs = numel(movs); 23 | len_movs = size(movs{1},3); 24 | 25 | t = 0; 26 | while (ishandle(dialogBox)) && t= sframe 64 | imData(:,:,i-sframe+1) = video; 65 | end 66 | if i - sframe + 1 >= num2read 67 | break; 68 | end 69 | end 70 | else 71 | error('Unknown file extension. Only .tiff, .avi and .hdf5 files are currently supported'); 72 | end -------------------------------------------------------------------------------- /utilities/read_neurofinder.m: -------------------------------------------------------------------------------- 1 | function imgs = read_neurofinder(foldername,output_name) 2 | %% import neurofinder tiff multifile format 3 | 4 | format compact 5 | opts_tiff.append = false; 6 | opts_tiff.big = true; 7 | files = subdir(fullfile(foldername,'*.tif*')); 8 | numFiles = length(files) 9 | data_type = class(imread(files(1).name)); 10 | imgs = zeros([size(imread(files(1).name)),numFiles],data_type); 11 | for i = 1:length(files) 12 | fname = files(i).name; 13 | imgs(:,:,i) = imread(fname); 14 | if mod(i,100)==0 15 | disp(i) 16 | end 17 | end 18 | if ~isempty(output_name) 19 | disp('saving to tif') 20 | saveastiff(cast(imgs,data_type),output_name,opts_tiff); 21 | end 22 | -------------------------------------------------------------------------------- /utilities/structmerge.m: -------------------------------------------------------------------------------- 1 | function s_out = structmerge(s1, s2, varargin) 2 | % STRUCTMERGE - Merge struct variables into a common struct 3 | % 4 | % S_OUT = STRUCTMERGE(S1, S2, ...) 5 | % 6 | % Merges the structures S1 and S2 into a common structure S_OUT 7 | % such that S_OUT has all of the fields of S1 and S2. When 8 | % S1 and S2 share the same fieldname, the value of S2 is taken. 9 | % 10 | % The behavior of the function can be altered by passing additional 11 | % arguments as name/value pairs. 12 | % 13 | % Parameter (default) | Description 14 | % ------------------------------------------------------------ 15 | % ErrorIfNewField (0) | (0/1) Is it an error if S2 contains a 16 | % | field that is not present in S1? 17 | % 18 | % See also: STRUCT 19 | 20 | ErrorIfNewField = 0; 21 | 22 | assign(varargin{:}); 23 | 24 | f1 = fieldnames(s1); 25 | f2 = fieldnames(s2); 26 | 27 | if ErrorIfNewField, 28 | [c,f1i] = setdiff(f2,f1); 29 | if ~isempty(c), 30 | error(['Some fields of the second structure are not in the first: ' cell2str(c) '.']); 31 | end; 32 | end; 33 | 34 | s_out = s1; 35 | 36 | for i=1:length(f2), 37 | s_out = setfield(s_out,f2{i},getfield(s2,f2{i})); 38 | end; 39 | 40 | -------------------------------------------------------------------------------- /utilities/tiff_reader.m: -------------------------------------------------------------------------------- 1 | function Y = tiff_reader(name,T) 2 | 3 | % read tiff stack. Optional truncate to first T timesteps 4 | 5 | info = imfinfo(name); 6 | 7 | if nargin == 1 8 | T = numel(info); 9 | end 10 | 11 | d1 = info(1).Height; 12 | d2 = info(1).Width; 13 | 14 | Y = zeros(d1,d2,T); 15 | for t = 1:T 16 | Y(:,:,t) = imread(name, t, 'Info',info); 17 | end -------------------------------------------------------------------------------- /utilities/trace_fit_extreme.m: -------------------------------------------------------------------------------- 1 | function max_pr = trace_fit_extreme(C,fr,t_int,fac) 2 | 3 | if nargin < 4 || isempty(fac); fac = 1; end 4 | if nargin < 3 || isempty(t_int); t_int = 0.25; end 5 | if nargin < 2 || isempty(fr); fr = 30; end 6 | 7 | Np = round(t_int*fr); 8 | [K,T] = size(C); 9 | bas = zeros(K,1); 10 | sn = zeros(K,1); 11 | for i = 1:K 12 | [~,density,xmesh] = kde(C(i,:)); 13 | [~,ind] = max(density); 14 | bas(i) = xmesh(ind); 15 | sn(i) = std(C(i,C(i,:)0); % find overlapping components 5 | F(1:K+1:K^2) = 0; % remove diagonal elements 6 | rem_ind = 1:K; % remaining indeces 7 | 8 | dp = 0; 9 | while ~isempty(rem_ind); 10 | dp = dp+1; 11 | L = sort(app_vertex_cover(F(rem_ind,rem_ind)),'ascend'); 12 | ord_ind = setdiff(rem_ind,rem_ind(L)); 13 | O{dp} = ord_ind; 14 | lo(dp) = length(ord_ind); 15 | rem_ind = rem_ind(L); 16 | end 17 | O = fliplr(O); 18 | lo = fliplr(lo); 19 | 20 | function L = app_vertex_cover(A) 21 | L = []; 22 | while ~isempty(find(A, 1)) 23 | i = randsample(find(A),1); 24 | [u,~] = ind2sub(size(A),i); 25 | L = [L,u]; 26 | A(u,:) = 0; % edges from u 27 | A(:,u) = 0; % edges to u 28 | end 29 | end 30 | end -------------------------------------------------------------------------------- /utilities/update_order_greedy.m: -------------------------------------------------------------------------------- 1 | function [O,lo] = update_order_greedy(A) 2 | % greedy method for updating order 3 | K = size(A,2); 4 | if ~(size(A,1) == K) 5 | A = A'*A; 6 | end 7 | 8 | A = A>0; 9 | A(1:K+1:K^2) = 0; 10 | 11 | O{1} = 1; 12 | lo(1) = 1; 13 | for i = 2:K 14 | cont = true; 15 | for j = 1:length(O) 16 | if ~any(A(i,O{j})) 17 | O{j} = [O{j},i]; 18 | lo(j) = lo(j) + 1; 19 | cont = false; 20 | break; 21 | end 22 | end 23 | if cont 24 | O{length(O)+1} = j; 25 | lo = [lo,1]; 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /utilities/update_spatial_lasso.m: -------------------------------------------------------------------------------- 1 | function [A,C] = update_spatial_lasso(Y, A, C, IND, sn, q, maxIter, options) 2 | 3 | %% update spatial components using constrained non-negative lasso with warm started HALS 4 | 5 | % input: 6 | % Y: d x T, fluorescence data 7 | % A: d x K, spatial components + background 8 | % C: K x T, temporal components + background 9 | % IND: K x T, spatial extent for each component 10 | % sn: d x 1, noise std for each pixel 11 | % q: scalar, control probability for FDR (default: 0.75) 12 | % maxIter: maximum HALS iteration (default: 40) 13 | % options: options structure 14 | 15 | % output: 16 | % A: d*K, updated spatial components 17 | 18 | % Author: Eftychios A. Pnevmatikakis 19 | 20 | %% options for HALS 21 | 22 | memmaped = isobject(Y); 23 | 24 | %norm_C_flag = false; 25 | tol = 1e-3; 26 | repeat = 1; 27 | defoptions = CNMFSetParms; 28 | if nargin < 8; options = defoptions; end 29 | if nargin < 7 || isempty(maxIter); maxIter = 40; end 30 | if nargin < 6 || isempty(q); q = 0.75; end 31 | if nargin<5 || isempty(sn); sn = get_noise_fft(Y,options); end; 32 | if nargin<4 || isempty(IND); IND = determine_search_location(A,options.search_method,options); end 33 | if nargin < 2 || isempty(A); 34 | A = max(Y*C'/(C*C'),0); 35 | end 36 | 37 | % if norm_C_flag 38 | % nC = sqrt(sum(C.^2,2)); 39 | % A = bsxfun(@times,A,nC); 40 | % C = bsxfun(@times,C,1./nC(:)); 41 | % end 42 | 43 | [d,K] = size(A); 44 | 45 | nr = K - options.nb; 46 | IND(:,nr+1:K) = true; 47 | T = size(C,2); 48 | sn = double(sn); 49 | 50 | YC = spalloc(d,K,sum(IND(:))); 51 | if memmaped 52 | %d = size(A,1); 53 | step_size = 2e4; 54 | for t = 1:step_size:d 55 | YC(t:min(t+step_size-1,d),:) = (double(Y.Yr(t:min(t+step_size-1,d),:))*C').*IND(t:min(t+step_size-1,d),:); 56 | end 57 | else 58 | YC = double(mm_fun(C,Y)); 59 | % for k = 1:K 60 | % YC(IND(:, k),k) = double(Y(IND(:, k),:)*C(k,:)'); 61 | % end 62 | end 63 | 64 | %% initialization 65 | A = A.*IND; 66 | V = double(C*C'); 67 | cc = diag(V); % squares of l2 norm for all components 68 | 69 | %% updating (neuron by neuron) 70 | miter = 0; 71 | while repeat && miter < maxIter 72 | A_ = A; 73 | for k=1:K 74 | tmp_ind = IND(:, k); 75 | if k <= nr 76 | lam = sqrt(cc(k)); %max(sqrt(cc(tmp_ind))); 77 | else 78 | lam = 0; 79 | end 80 | LAM = norminv(q)*sn*lam; 81 | ak = max(0, A(tmp_ind, k)+(full(YC(tmp_ind, k)) - LAM(tmp_ind) - A(tmp_ind,:)*V(:, k))/cc(k)); 82 | A(tmp_ind, k) = ak; 83 | end 84 | miter = miter + 1; 85 | repeat = (sqrt(sum((A(:)-A_(:)).^2)/sum(A_(:).^2)) > tol); 86 | end 87 | 88 | f = C(nr+1:end,:); 89 | Yf = full(YC(:,nr+1:end)); %Y*f'; 90 | b = double(max((double(Yf) - A(:,1:nr)*double(C(1:nr,:)*f'))/(f*f'),0)); 91 | A(:,nr+1:end) = b; 92 | -------------------------------------------------------------------------------- /utilities/write_h5.m: -------------------------------------------------------------------------------- 1 | function write_h5(file,chunk) 2 | 3 | % rewrites a file into a hdf5 file 4 | 5 | if ~exist('chunk','var') || isempty(chunk); chunk = 2000; end 6 | keep_reading = true; 7 | Y_temp = read_file(file,1,chunk+1); 8 | cl = class(Y_temp); 9 | nd = ndims(Y_temp) - 1; 10 | sizY = size(Y_temp); 11 | d = prod(sizY(1:nd)); 12 | if sizY(end) < chunk+1 13 | keep_reading = false; 14 | else 15 | if nd == 2 16 | Y_temp(:,:,end) = []; 17 | elseif nd == 3 18 | Y_temp(:,:,:,end) = []; 19 | end 20 | sizY(end) = sizY(end)-1; 21 | end 22 | [pathstr, name, ext] = fileparts(file); 23 | h5_filename = [pathstr,'/',name,'.h5']; 24 | h5create(h5_filename,'/mov',[sizY(1:nd),Inf],'Chunksize',[sizY(1:nd),min(chunk,sizY(end))],'Datatype',cl); 25 | h5write(h5_filename,'/mov',Y_temp,[ones(1,nd),1],sizY); 26 | cnt = sizY(end); 27 | while keep_reading 28 | Y_temp = read_file(file,cnt+1,chunk+1); 29 | sizY = size(Y_temp); 30 | if sizY(end) < chunk+1 31 | keep_reading = false; 32 | else 33 | if nd == 2 34 | Y_temp(:,:,end) = []; 35 | elseif nd == 3 36 | Y_temp(:,:,:,end) = []; 37 | end 38 | sizY(end) = sizY(end)-1; 39 | end 40 | h5write(h5_filename,'/mov',Y_temp,[ones(1,nd),cnt+1],sizY); 41 | cnt = cnt + sizY(end); 42 | end --------------------------------------------------------------------------------