Skip to content

Commit

Permalink
Command-line processing, playMovie/signalSorter GUI, and new/updated …
Browse files Browse the repository at this point in the history
…functions

Changelog

This request has large usability updates to `signalSorter` and `playMovie` to make GUIs more responsive and user friendly. Also updated command-line examples and processing for users along with misc other function updates.

__New__
- `ciapkg.demo.runPreprocessing` - Addition to allow users to run pre-processing on a movie from a single function. To be expanded later.
- `ciapkg.io.getMovieInfo` - Wrapper to quickly get movie information. Options are the same as loadMovieList.
- `ciapkg.io.readFrame` - Fast reading of frame from files on disk. This is an alternative to loadMovieList that is much faster when only a single frame needs to be read.
- `ciapkg.signal_extraction.runPcaIca` - Wrapper to run PCA-ICA (Mukamel, 2009) cell extraction using two existing versions on CIAPKG.

__Upated__
- `playMovie` - major update to improve GUI. Updated slider and pause movie callbacks to reduce probability that slider starts to move erratically, move focus away from slider after use (so keyboard callbacks work), and improve pause handling. Made angle optional for options.primaryTrackingPoint. Refactored code to make easier to manage. Middle and right-click of mouse now lead to pausing. Check for NWB input file and change dataset name to accomodate. Create a shortcut menu for easier navigation. Add support for displaying in RGB when reading from AVI movies. Switch read from disk support to using ciapkg.io.readFrame so that playMovie uses the new standard interface for fast reading from disk.
- `signalSorter` - Display context menu for keyboard shortcuts, easier than separate figure. User can select with right-click or via a menu in the GUI. Users can now scroll through cells using mouse scroll wheel.
- `ciapkg.demo.cmdLinePipeline` - Updated to add support for cross-session analysis and use ciapkg.demo.runPreprocessing() to process the other imaging sessions. Update to use ciapkg.signal_extraction.runPcaIca for PCA-ICA to make easier for users to run in the future.
- `getOptions` - Added passArgs option, this mimics the ... construct in R, so users can pass along arguments without having to define them in the calling function (e.g. in the case of wrapper functions).
- `applyImagesToMovie` - Supports inputMovie as a character path to the movie.
- `loadMovieList` - Improved comments and options descriptions.
- `ciapkg.io.getMovieFileType` - addition of a second movie type, e.g. to differentiate NWB even though it is HDF5.
- `suptitle` - Added support for latex intepreter to allow more detailed information display.
- `computeSaleaeOutput` - Updated to make more easily usable with other miniscope sync signals. Remove eval call.
- `runICA` - added IcaOutputInfo output.
- `runPCA` - Compatibility fixes for matrix inputs.
- `changeFont` - Added support for changing font type.
  • Loading branch information
bahanonu committed Oct 19, 2020
1 parent 3d0e6bd commit 499ee32
Show file tree
Hide file tree
Showing 27 changed files with 1,895 additions and 751 deletions.
124 changes: 105 additions & 19 deletions +ciapkg/+demo/cmdLinePipeline.m
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
% Running calciumImagingAnalysis command line
% Below is an example `cacliumImagingAnalysis` pipeline using the command line for those that do not want to use the class or want to create their own custom batch analyses. It assumes you have already run `example_downloadTestData` to download the example test data.
% Running calciumImagingAnalysis (CIAPKG) imaging analysis via the command line
% Biafra Ahanonu
% Below is an example `cacliumImagingAnalysis` pipeline using the command line for users that do not want to use the calciumImagingAnalysis class or want to create their own custom batch analyses.
% It assumes you have already run `example_downloadTestData` to download the example test data.
% It will also run cross-day matching at the end.
% All sections marked "USER INTERFACE" indicate that a GUI will appear to view processed movie, conduct cell sorting, or other interface.
% Changelog
% 2020.09.15 [19:54:14] - Use ciapkg.getDir() to make sure demo always calls correct path regardless of where user is pointing. Also make playMovie calls have titles to make clearer to new users and allow a GUI-less option.
% 2020.09.23 [08:35:58] - Updated to add support for cross-session analysis and use ciapkg.demo.runPreprocessing() to process the other imaging sessions.
% 2020.10.17 [19:30:01] - Update to use ciapkg.signal_extraction.runPcaIca for PCA-ICA to make easier for users to run in the future.

guiEnabled = 0;
%% Initialize
guiEnabled = 1;
saveAnalysis = 1;
inputDatasetName = '/1';
rawFileRegexp = 'concat';

%% Download test data, only a single session
example_downloadTestData('downloadExtraFiles',0);

%% Load movie to analyze
analysisFolderPath = [ciapkg.getDir() filesep 'data' filesep '2014_04_01_p203_m19_check01'];
inputMoviePath = [analysisFolderPath filesep 'concat_recording_20140401_180333.h5'];
inputMovie = loadMovieList(inputMoviePath);
inputMoviePath = getFileList(analysisFolderPath,rawFileRegexp,'sortMethod','natural');
% inputMoviePath = [analysisFolderPath filesep 'concat_recording_20140401_180333.h5'];
inputMovie = loadMovieList(inputMoviePath,'inputDatasetName',inputDatasetName);

%% Visualize slice of the movie
%% USER INTERFACE Visualize slice of the movie
if guiEnabled==1
playMovie(inputMovie(:,:,1:500),'extraTitleText','Raw movie');
% Alternatively, visualize by entering the file path
playMovie(inputMoviePath,'extraTitleText','Raw movie directly from file');
end

%% Downsample input movie if need to
%% USER INTERFACE Downsample input movie if need to
if guiEnabled==1
inputMovieD = downsampleMovie(inputMovie,'downsampleDimension','space','downsampleFactor',4);
playMovie(inputMovie,'extraMovie',inputMovieD,'extraTitleText','Raw movie vs. down-sampled movie');
Expand All @@ -40,7 +50,7 @@
inputMovie = removeStripsFromMovie(inputMovie,'options',sopts);
end

%% Get coordinates to crop from the user separately
%% USER INTERFACE Get coordinates to crop from the user separately
if guiEnabled==1
[cropCoords] = getCropCoords(squeeze(inputMovie(:,:,1)));
toptions.cropCoords = cropCoords;
Expand Down Expand Up @@ -76,31 +86,30 @@
%% Run temporal downsampling
inputMovie3 = downsampleMovie(inputMovie3,'downsampleDimension','time','downsampleFactor',4);

%% Final check of movie before cell extraction
%% USER INTERFACE Final check of movie before cell extraction
if guiEnabled==1
playMovie(inputMovie3,'extraTitleText','Processed movie for cell extraction');
end

%% Run PCA-ICA cell extraction
nPCs = 300; nICs = 225;
[PcaOutputSpatial, PcaOutputTemporal, PcaOutputSingularValues, PcaInfo] = run_pca(inputMovie3, nPCs, 'movie_dataset_name','/1');
[IcaFilters, IcaTraces, IcaInfo] = run_ica(PcaOutputSpatial, PcaOutputTemporal, PcaOutputSingularValues, size(inputMovie3,1), size(inputMovie3,2), nICs, 'output_units','fl','mu',0.1,'term_tol',5e-6,'max_iter',1e3);
IcaTraces = permute(IcaTraces,[2 1]);
nPCs = 300;
nICs = 225;
pcaicaStruct = ciapkg.signal_extraction.runPcaIca(inputMovie3,nPCs,nICs,'version',2,'output_units','fl','mu',0.1,'term_tol',5e-6,'max_iter',1e3);

%% Save outputs to NWB format
[~,folderName,~] = fileparts(analysisFolderPath);
% mkdir([analysisFolderPath filesep 'nwbFiles']);
nwbFilePath = [analysisFolderPath filesep 'nwbFiles' filesep folderName '_pcaicaAnalysis.nwb'];
if saveAnalysis==1
saveNeurodataWithoutBorders(IcaFilters,{IcaTraces},'pcaica',nwbFilePath);
saveNeurodataWithoutBorders(pcaicaStruct.IcaFilters,{pcaicaStruct.IcaTraces},'pcaica',nwbFilePath);
end

%% Run cell extraction using matrix
%% USER INTERFACE Run cell sorting using matrix outputs from cell extraction.
if guiEnabled==1
[outImages, outSignals, choices] = signalSorter(IcaFilters,IcaTraces,'inputMovie',inputMovie3);
[outImages, outSignals, choices] = signalSorter(pcaicaStruct.IcaFilters,pcaicaStruct.IcaTraces,'inputMovie',inputMovie3);
end

%% Run signal sorting using NWB
%% USER INTERFACE Run signal sorting using NWB files from cell extraction.
if saveAnalysis==1&guiEnabled==1
disp(repmat('=',1,21));disp('Running signalSorter using NWB file input.')
[outImages, outSignals, choices] = signalSorter(nwbFilePath,[],'inputMovie',inputMovie3);
Expand All @@ -111,7 +120,7 @@
subplot(1,2,1);imagesc(max(IcaFilters,[],3));axis equal tight; title('Raw filters')
subplot(1,2,2);imagesc(max(outImages,[],3));axis equal tight; title('Sorted filters')

%% Create an overlay of extraction outputs on the movie and signal-based movie
%% USER INTERFACE Create an overlay of extraction outputs on the movie and signal-based movie
[inputMovieO] = createImageOutlineOnMovie(inputMovie3,IcaFilters,'dilateOutlinesFactor',0);
if guiEnabled==1
playMovie(inputMovieO,'extraMovie',inputMovie3,'extraTitleText','Overlay of cell outlines on processed movie');
Expand All @@ -120,4 +129,81 @@
[signalMovie] = createSignalBasedMovie(IcaTraces,IcaFilters,'signalType','peak');
if guiEnabled==1
playMovie(signalMovie,'extraMovie',inputMovie3,'extraTitleText','Cell activity-based movie');
end
end

movieM = cellfun(@(x) normalizeVector(x,'normRange','zeroToOne'),{inputMovie3,inputMovieO,signalMovie},'UniformOutput',false);
playMovie(cat(2,movieM{:}));

%% Run pre-processing on 3 batch movies then do cross-session alignment
batchMovieList = {...
[ciapkg.getDir() filesep 'data' filesep 'batch' filesep '2014_08_05_p104_m19_PAV08'],...
[ciapkg.getDir() filesep 'data' filesep 'batch' filesep '2014_08_06_p104_m19_PAV09'],...
[ciapkg.getDir() filesep 'data' filesep 'batch' filesep '2014_08_07_p104_m19_PAV10']...
};

% USER INTERFACE Get the motion correction crop coordinates
cropCoordsCell = {};
nFolders = length(batchMovieList);
for folderNo = 1:nFolders
analysisFolderPath = batchMovieList{folderNo};
inputMoviePath = getFileList(analysisFolderPath,rawFileRegexp,'sortMethod','natural');
% inputMoviePath = [analysisFolderPath filesep 'concat_recording_20140401_180333.h5'];
inputMovie = loadMovieList(inputMoviePath,'inputDatasetName',inputDatasetName,'frameList',1:2);

[cropCoords] = getCropCoords(squeeze(inputMovie(:,:,1)));
% toptions.cropCoords = cropCoords;
cropCoordsCell{folderNo} = cropCoords;
end

%% Run pre-processing on each of the movies.
procMovieCell = cell([1 nFolders]);
for folderNo = 1:nFolders
inputMoviePath = getFileList(analysisFolderPath,rawFileRegexp,'sortMethod','natural');
inputMovie = loadMovieList(inputMoviePath,'inputDatasetName',inputDatasetName,'frameList',[]);
procOpts.motionCorrectionCropCoords = cropCoordsCell{folderNo};
procOpts.dfofMovie = 1;
procOpts.motionCorrectionFlag = 1;
procOpts.normalizeMovieFlag = 1;
procOpts.normalizeType = 'divideByLowpass';
procOpts.freqLow = 0;
procOpts.freqHigh = 7;
procOpts.downsampleTimeFactor = 4;
procMovieCell{folderNo} = ciapkg.demo.runPreprocessing(inputMovie,'options',procOpts);
end
disp('Done with pre-processing!')

%% Run cell-extraction on the movies
pcaicaStructCell = cell([1 nFolders]);
nPCs = 300;
nICs = 225;
for folderNo = 1:nFolders
inputMoviePath = getFileList(analysisFolderPath,rawFileRegexp,'sortMethod','natural');
pcaicaStruct{folderNo} = ciapkg.signal_extraction.runPcaIca(procMovieCell{folderNo},nPCs,nICs,'version',2,'outputUnits','fl','mu',0.1,'term_tol',5e-6,'max_iter',1e3);
end
disp('Done with PCA-ICA analysis pre-processing!')

%% Run cross-session alignment of cells
% Create input images, cell array of [x y nCells] matrices
inputImages = cellfun(@(x) x.IcaFilters,pcaicaStruct,'UniformOutput',false);

% options to change
opts.maxDistance = 5; % distance in pixels between centroids for them to be grouped
opts.trialToAlign = 1; % which session to start alignment on
opts.nCorrections = 1; %number of rounds to register session cell maps.
opts.RegisTypeFinal = 2; % 3 = rotation/translation and iso scaling; 2 = rotation/translation, no iso scaling

% Run alignment code
[alignmentStruct] = matchObjBtwnTrials(inputImages,'options',opts);

% Global IDs is a matrix of [globalID sessionID]
% Each (globalID, sessionID) pair gives the within session ID for that particular global ID
globalIDs = alignmentStruct.globalIDs;

% View the cross-session matched cells, saved to `private\_tmpFiles` sub-folder.
[success] = createMatchObjBtwnTrialsMaps(inputImages,alignmentStruct);

% Display cross-session matching movies
disp('Playing movie frames')
crossSessionMovie1 = 'private\_tmpFiles\matchObjColorMap50percentMatchedSession_matchedCells.avi';
crossSessionMovie2 = 'private\_tmpFiles\matchObjColorMapAllMatchedSession_matchedCells.avi';
playMovie(crossSessionMovie1,'extraMovie',crossSessionMovie2,'rgbDisplay',1);
Loading

0 comments on commit 499ee32

Please sign in to comment.