├── .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 | [](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
--------------------------------------------------------------------------------