├── .gitignore ├── AttemptTransientMerges.m ├── BrowseOverlaps.m ├── CalcChunkSums.m ├── CalcPixelOverlaps.m ├── ChangeDirectory.m ├── ExtractBlobs.m ├── GetInitRegMaskInfo.m ├── GetSessNums.m ├── Get_T_Params.m ├── InterpretTraces.m ├── LinkBlobs.m ├── LoadFrames.m ├── MakeCircMask.m ├── MakeFakeMovie.m ├── MakeFilteredMovies.m ├── MakeInitialMask.m ├── MakeMaskSingleSession.m ├── MakeMouseSessionList.m ├── MakeTraceChunk.m ├── MakeTracesAndCorrs.m ├── MakeTransientROIs.m ├── Make_DFF.m ├── MergeTransientROIs.m ├── MidpointCircle.m ├── NP_FindSupraThresholdEpochs.m ├── OldMakeCircMask.m ├── ParseTenaspisInput.m ├── PercentileCutoff.m ├── PixelSetMovieAvg.m ├── PlotNeuronOutlines.m ├── PlotTransientMerge.m ├── README.md ├── RejectBadTransients.m ├── SegmentFrame.m ├── SegmentFrameChunk.m ├── Set_T_Params.m ├── Tenaspis3.m ├── Tenaspis4.m ├── Tenaspis4singlesession.m ├── Tenaspis4testing.m ├── TenaspisOutputSummary.m ├── TransientStats.m ├── UpdateCluDistances.m ├── UpdateClusterInfo.m ├── centerOfMass.m ├── get_closestCOM.m ├── get_name_date_session.m ├── gpl.txt ├── image_registerX.m ├── imagesc_gray.m ├── manual_reg.m ├── mask_multi_image_reg.m └── moviestats.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.jar 19 | *.rar 20 | *.tar 21 | *.zip 22 | 23 | *.asv 24 | 25 | # Logs and databases # 26 | ###################### 27 | *.log 28 | *.sql 29 | *.sqlite 30 | 31 | # OS generated files # 32 | ###################### 33 | .DS_Store 34 | .DS_Store? 35 | ._* 36 | .Spotlight-V100 37 | .Trashes 38 | ehthumbs.db 39 | Thumbs.db -------------------------------------------------------------------------------- /AttemptTransientMerges.m: -------------------------------------------------------------------------------- 1 | function [Trans2ROI,PixelList,Xcent,Ycent,FrameList,ObjList,PixelAvg,BigPixelAvg] = AttemptTransientMerges(DistThresh,Trans2ROI,PixelList,Xcent,Ycent,FrameList,ObjList,PixelAvg,BigPixelAvg,CircMask) 2 | % [Trans2ROI,PixelList,Xcent,Ycent,FrameList,ObjList,PixelAvg,BigPixelAvg] = AttemptTransientMerges(DistThresh,Trans2ROI,PixelList,Xcent,Ycent,FrameList,ObjList,PixelAvg,BigPixelAvg,CircMask) 3 | % Attempt to merge all cluster pairs where centroid distance is less than DistThresh 4 | % 5 | % 6 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | % This file is part of Tenaspis. 9 | % 10 | % Tenaspis is free software: you can redistribute it and/or modify 11 | % it under the terms of the GNU General Public License as published by 12 | % the Free Software Foundation, either version 3 of the License, or 13 | % (at your option) any later version. 14 | % 15 | % Tenaspis is distributed in the hope that it will be useful, 16 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | % GNU General Public License for more details. 19 | % 20 | % You should have received a copy of the GNU General Public License 21 | % along with Tenaspis. If not, see . 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | % 24 | %% Get parameters 25 | [MinTransientMergeCorrR,MaxTransientMergeCorrP] = Get_T_Params('MinTransientMergeCorrR','MaxTransientMergeCorrP'); 26 | 27 | %% setup some variables 28 | ClusterList = unique(Trans2ROI); % this ends up being the indices into the input data array elements that contain currently remaining clusters 29 | display([int2str(length(ClusterList)),' clusters left']); 30 | 31 | % Get distance from each cluster to all the others 32 | CluDist = pdist([Xcent',Ycent'],'euclidean'); 33 | CluDist = squareform(CluDist); 34 | 35 | %% Run actual merging functionality 36 | for i = 1:length(ClusterList) 37 | CurrClu = ClusterList(i); 38 | 39 | if (Trans2ROI(CurrClu) ~= CurrClu) 40 | % cluster already merged during this call, move to next iteration 41 | % of the for loop 42 | continue; 43 | end 44 | 45 | % Sort the Clusters from closest to farthest away from CurrClu 46 | [sortdist,sortidx] = sort(CluDist(CurrClu,:)); 47 | 48 | % keep clusters that are within the distance threshold that aren't CurrClu 49 | NearCluIdx = setdiff(intersect(ClusterList,sortidx(sortdist <= DistThresh)),CurrClu); 50 | 51 | % try merging each cluster in NearCluIdx into CurrClu 52 | MergeOK = []; 53 | for k = 1:length(NearCluIdx) 54 | CandIdx = NearCluIdx(k); % CandIdx is index of candidate cluster 55 | 56 | if (Trans2ROI(CandIdx) ~= CandIdx) 57 | % cluster already merged during this call, move to next iteration 58 | continue; 59 | end 60 | 61 | % determine correleation values for the union of CurrClu and 62 | % CandIdx 63 | 64 | u = union(PixelList{CurrClu},PixelList{CandIdx}); 65 | 66 | [~,idx1] = ismember(u,CircMask{CurrClu}); 67 | [~,idx2] = ismember(u,CircMask{CandIdx}); 68 | 69 | try 70 | [BigCorrVal,BigCorrP] = corr(BigPixelAvg{CurrClu}(idx1),BigPixelAvg{CandIdx}(idx2),'type','Spearman'); 71 | catch 72 | keyboard; 73 | end 74 | 75 | % if ((BigCorrVal >= 0.2) && (BigCorrVal < 0.3)) 76 | % PlotTransientMerge(BigPixelAvg{CurrClu},BigPixelAvg{CandIdx},idx1,idx2,CircMask{CurrClu},CircMask{CandIdx},PixelList{CurrClu},PixelList{CandIdx},Trans2ROI,CurrClu,CandIdx); 77 | % end 78 | 79 | 80 | if ((BigCorrP >= MaxTransientMergeCorrP) || (BigCorrVal < MinTransientMergeCorrR)) 81 | % reject the merge 82 | 83 | 84 | continue; 85 | end 86 | 87 | if (~isempty(intersect(FrameList{CandIdx},FrameList{CurrClu}))) 88 | % just in case by some messed up edge case it wants to merge 89 | % temporally overlapping clusters 90 | continue; 91 | end 92 | MergeOK = [MergeOK,CandIdx]; 93 | Trans2ROI(Trans2ROI == CandIdx) = CurrClu; % Update cluster number for all transients part of CandIdx to CurrClu 94 | end 95 | 96 | % If a merge happened, update all the cluster info for the next 97 | % iteration 98 | if ~isempty(MergeOK) 99 | [PixelList,PixelAvg,BigPixelAvg,Xcent,Ycent,FrameList,ObjList] = UpdateClusterInfo(... 100 | MergeOK,PixelList,PixelAvg,BigPixelAvg,CircMask,Xcent,Ycent,FrameList,ObjList,CurrClu); 101 | temp = UpdateCluDistances(Xcent,Ycent,CurrClu); % Update distances for newly merged clusters to all other clusters 102 | CluDist(CurrClu,:) = temp; 103 | CluDist(:,CurrClu) = temp; 104 | end 105 | 106 | end 107 | 108 | end 109 | -------------------------------------------------------------------------------- /BrowseOverlaps.m: -------------------------------------------------------------------------------- 1 | function [ output_args ] = BrowseOverlaps(moviefile,NeuronID,cx,PlaceMaps ) 2 | close all; 3 | 4 | % load basic shit 5 | load FinalOutput.mat; 6 | load BinSim.mat; 7 | load BigFinalPixelAvg.mat; 8 | 9 | [Xdim,Ydim,NumFrames] = Get_T_Params('Xdim','Ydim','NumFrames'); 10 | blankframe = zeros(Xdim,Ydim,'single'); 11 | t = (1:NumFrames)/20; 12 | 13 | display('checking buddies'); 14 | buddies = []; 15 | for i = 1:NumNeurons 16 | Overlap(i) = length(intersect(NeuronPixelIdxList{NeuronID},NeuronPixelIdxList{i}))./min(length(NeuronPixelIdxList{NeuronID}),length(NeuronPixelIdxList{i})); 17 | 18 | if ((i ~= NeuronID)&& (Overlap(i) > 0)) 19 | buddies = [buddies,i]; 20 | end 21 | end 22 | 23 | figure(5);histogram(BinSim(NeuronID,:),40); 24 | 25 | figure(1); 26 | a(1) = subplot(length(buddies)+1,1,1); 27 | plot(NeuronTraces.LPtrace(NeuronID,:));hold on; 28 | act = NP_FindSupraThresholdEpochs(PSAbool(NeuronID,:),eps); 29 | for j = 1:size(act,1) 30 | plot(act(j,1):act(j,2),NeuronTraces.LPtrace(NeuronID,act(j,1):act(j,2)),'-r','LineWidth',2); 31 | end 32 | axis tight 33 | for i = 1:length(buddies) 34 | a(i+1) = subplot(length(buddies)+1,1,i+1); 35 | plot(NeuronTraces.LPtrace(buddies(i),:));hold on; 36 | act = NP_FindSupraThresholdEpochs(PSAbool(buddies(i),:),eps); 37 | for j = 1:size(act,1) 38 | plot(act(j,1):act(j,2),NeuronTraces.LPtrace(buddies(i),act(j,1):act(j,2)),'-r','LineWidth',2); 39 | end 40 | farsims = sort(BinSim(NeuronID,Overlap == 0)); 41 | idx = findclosest(farsims,BinSim(NeuronID,buddies(i))); 42 | normrank = idx/length(find(Overlap == 0)); 43 | 44 | title([int2str(buddies(i)),' Overlap % ',num2str(Overlap(buddies(i))),' dws similarity: ',num2str(BinSim(NeuronID,buddies(i))),' pct ',num2str(normrank)]); 45 | axis tight; 46 | end 47 | linkaxes(a,'x'); 48 | set(gcf,'Position',[437 49 883 948]) 49 | 50 | figure(3); 51 | fb(1) = subplot(length(buddies)+1,2,1); 52 | temp = blankframe; 53 | temp(CircMask{NeuronID}) = BigFinalPixelAvg{NeuronID}; 54 | imagesc(temp);axis image;hold on;caxis([0 max(NeuronAvg{NeuronID})]);colorbar 55 | [b] = bwboundaries(NeuronImage{NeuronID}); 56 | b = b{1}; 57 | plot(b(:,2),b(:,1),'g'); 58 | 59 | 60 | 61 | for i = 1:length(buddies) 62 | [b] = bwboundaries(NeuronImage{buddies(i)}); 63 | b = b{1}; 64 | plot(b(:,2),b(:,1),'r'); 65 | end 66 | 67 | subplot(length(buddies)+1,2,2); 68 | imagesc(PlaceMaps{NeuronID});axis image;colorbar; 69 | 70 | for i = 1:length(buddies) 71 | fb(i+1) = subplot(length(buddies)+1,2,i*2+1); 72 | temp = blankframe; 73 | temp(CircMask{buddies(i)}) = BigFinalPixelAvg{buddies(i)}; 74 | imagesc(temp);colorbar; 75 | max(NeuronAvg{buddies(i)}), 76 | axis image;hold on; 77 | try caxis([0 max(NeuronAvg{buddies(i)})]);end 78 | [b] = bwboundaries(NeuronImage{buddies(i)}); 79 | b = b{1}; 80 | plot(b(:,2),b(:,1),'r'); 81 | [b] = bwboundaries(NeuronImage{NeuronID}); 82 | b = b{1}; 83 | plot(b(:,2),b(:,1),'g'); 84 | subplot(length(buddies)+1,2,i*2+2); 85 | imagesc(PlaceMaps{buddies(i)});axis image;colorbar; 86 | end 87 | 88 | linkaxes(fb,'xy'); 89 | set(gcf,'Position',[437 49 883 948]) 90 | 91 | while(1) 92 | pause; 93 | figure(1) 94 | display('pick a time to see the frame') 95 | [mx,my] = ginput(1); 96 | f = LoadFrames(moviefile,round(mx)); 97 | figure(2);set(gcf,'Position',[1130 337 773 600]); 98 | 99 | imagesc(f);caxis(cx);colorbar; 100 | hold on 101 | [b] = bwboundaries(NeuronImage{NeuronID}); 102 | b = b{1}; 103 | plot(b(:,2),b(:,1),'g'); 104 | for i = 1:length(buddies) 105 | [b] = bwboundaries(NeuronImage{buddies(i)}); 106 | b = b{1}; 107 | plot(b(:,2),b(:,1),'r'); 108 | end 109 | hold off; 110 | end 111 | 112 | -------------------------------------------------------------------------------- /CalcChunkSums.m: -------------------------------------------------------------------------------- 1 | function [PixelSum] = CalcChunkSums(FrameList,NumInputs,NumROIs,PixelIdx,ActBool) 2 | %UNTITLED5 Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | %% Load Chunk 6 | FrameChunk = LoadFrames('BPDFF.h5',FrameList); 7 | 8 | %% for each ROI, cut the FrameChunk according to active frames, sum it, and shove the sums into the output data structure 9 | PixelSum = cell(1,NumInputs); 10 | for i = 1:NumInputs % Number of ROI sets 11 | PixelSum{i} = cell(1,NumROIs(i)); 12 | for j = 1:NumROIs(i) 13 | % add frames where ROI was active 14 | ROIChunksum = sum(FrameChunk(:,:,ActBool{i}{j}(FrameList)),3); 15 | % shove ROIs pixels into PixelSum 16 | PixelSum{i}{j} = ROIChunksum(PixelIdx{i}{j}); 17 | end 18 | end 19 | 20 | end 21 | 22 | -------------------------------------------------------------------------------- /CalcPixelOverlaps.m: -------------------------------------------------------------------------------- 1 | function [ po] = CalcPixelOverlaps(idx,NeuronPixels) 2 | %[ po] = CalcPixelOverlaps(idx,MeanNeuron) 3 | % Detailed explanation goes here 4 | for j = 1:length(NeuronPixels) 5 | po(1,j) = length(intersect(NeuronPixels{idx},NeuronPixels{j}))/length(NeuronPixels{idx}); 6 | end 7 | 8 | end 9 | 10 | -------------------------------------------------------------------------------- /ChangeDirectory.m: -------------------------------------------------------------------------------- 1 | function [dirstr, MD_out] = ChangeDirectory(animal_id,sess_date,sess_num,change_dir_flag) 2 | % [dirstr, MD_out] = ChangeDirectory(animal_id,sess_date,sess_num,change_dir_flag) 3 | % 4 | % Changes to the appropriate working directory for the mouse in question, 5 | % and/or outputs that directory in dirstr. 6 | % 7 | % INPUTS 8 | % animal_id: String, ID of the animal. 9 | % 10 | % sess_date: String, date in the format MM_DD_YYYY. 11 | % 12 | % (optional) 13 | % sess_num: Scalar, session number. 14 | % 15 | % change_dir_flag: Logical, whether you want to move to that 16 | % directory. If change_dir_flag is not specified or is set to 1, this 17 | % will change to the working directory. If change_dir_flag is set to 18 | % 0, dirstr will still be output but you will remain in the original 19 | % directory. 20 | % 21 | % OUTPUT 22 | % dirstr: String, directory corresponding to inputs. 23 | % 24 | % MD_out: copy of mouse database structure matching the input 25 | % parameters. 26 | % 27 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 28 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 29 | % This file is part of Tenaspis. 30 | % 31 | % Tenaspis is free software: you can redistribute it and/or modify 32 | % it under the terms of the GNU General Public License as published by 33 | % the Free Software Foundation, either version 3 of the License, or 34 | % (at your option) any later version. 35 | % 36 | % Tenaspis is distributed in the hope that it will be useful, 37 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 38 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 39 | % GNU General Public License for more details. 40 | % 41 | % You should have received a copy of the GNU General Public License 42 | % along with Tenaspis. If not, see . 43 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 44 | 45 | %% 46 | %Default value of sess_num = 1. 47 | if ~exist('sess_num','var') 48 | sess_num = 1; 49 | end 50 | 51 | %Default value of change_dir_flag = 1. 52 | if ~exist('change_dir_flag','var') 53 | change_dir_flag = 1; 54 | end 55 | 56 | %Fetch Master Directory from upper level function(s). 57 | global MasterDirectory; 58 | if isempty(MasterDirectory) 59 | MasterDirectory = 'C:\MasterData'; 60 | disp('No ''MasterDirectory'' global variable detected. Using default of ''C:\MasterData'' ') 61 | end 62 | load(fullfile(MasterDirectory,'MasterDirectory.mat')); 63 | 64 | %Concatenate fields for searching. 65 | animals = {MD.Animal}; 66 | dates = {MD.Date}; 67 | sessions = [MD.Session]; 68 | 69 | %Find MD entry that matches the input animal, date, AND session. 70 | i = find(strcmp(animals,animal_id) & strcmp(dates,sess_date) & sessions == sess_num); 71 | 72 | if length(i) > 1 %If multiple entries match, throw an error. 73 | disp('Multiple directories found! Check MakeMouseSessionList.'); 74 | elseif isempty(i) %If no entries match, throw an error. 75 | disp('Directory not found! Check MakeMouseSessionList.'); 76 | else %If one entry matches, get directory name and... 77 | dirstr = MD(i).Location; 78 | MD_out = MD(i); 79 | 80 | if change_dir_flag %...if flagged, change directory. 81 | cd(dirstr); 82 | end 83 | end 84 | 85 | end 86 | -------------------------------------------------------------------------------- /ExtractBlobs.m: -------------------------------------------------------------------------------- 1 | function ExtractBlobs(PrepMask) 2 | % ExtractBlobs(PrepMask) 3 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | % This file is part of Tenaspis. 6 | % 7 | % Tenaspis is free software: you can redistribute it and/or modify 8 | % it under the terms of the GNU General Public License as published by 9 | % the Free Software Foundation, either version 3 of the License, or 10 | % (at your option) any later version. 11 | % 12 | % Tenaspis is distributed in the hope that it will be useful, 13 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | % GNU General Public License for more details. 16 | % 17 | % You should have received a copy of the GNU General Public License 18 | % along with Tenaspis. If not, see . 19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 | % 21 | disp('Extracting Blobs from movie'); 22 | 23 | %% Get parameters and set up Chunking variables 24 | [Xdim,Ydim,NumFrames,FrameChunkSize] = Get_T_Params('Xdim','Ydim','NumFrames','FrameChunkSize'); 25 | 26 | ChunkStarts = 1:FrameChunkSize:NumFrames; 27 | ChunkEnds = FrameChunkSize:FrameChunkSize:NumFrames; 28 | ChunkEnds(length(ChunkStarts)) = NumFrames; 29 | NumChunks = length(ChunkStarts); 30 | 31 | %% set up the PrepMask; i.e., which areas to exclude 32 | if ~exist('PrepMask','var') 33 | PrepMask = ones(Xdim,Ydim); 34 | end 35 | 36 | %% Find the blobs in each frame 37 | p = ProgressBar(NumChunks); % Initialize progress bar 38 | 39 | parfor i = 1:NumChunks 40 | Set_T_Params; % needed because SegFrame is called in a parfor and matlab doesn't distribute global variables to workers 41 | FrameList = ChunkStarts(i):ChunkEnds(i); 42 | 43 | BlobChunk(i) = SegmentFrameChunk(FrameList,PrepMask); 44 | p.progress; 45 | end 46 | p.stop; % Shut-down progress bar 47 | 48 | %% Distribute chunked outputs to cell arrays 49 | [BlobPixelIdxList,BlobWeightedCentroids,BlobMinorAxisLength] = deal(cell(1,NumFrames)); 50 | 51 | for i = 1:NumChunks 52 | FrameList = ChunkStarts(i):ChunkEnds(i); 53 | BlobPixelIdxList(FrameList) = BlobChunk(i).BlobPixelIdxList; 54 | BlobWeightedCentroids(FrameList) = BlobChunk(i).BlobWeightedCentroids; 55 | BlobMinorAxisLength(FrameList) = BlobChunk(i).BlobMinorAxisLength; 56 | end 57 | 58 | %% outputs get saved to disk 59 | disp('saving Blobs to disk'); 60 | save Blobs.mat BlobPixelIdxList BlobWeightedCentroids BlobMinorAxisLength; 61 | 62 | end -------------------------------------------------------------------------------- /GetInitRegMaskInfo.m: -------------------------------------------------------------------------------- 1 | function [init_date,init_sess] = GetInitRegMaskInfo(animal_id) 2 | % [init_date,init_sess] = GetInitRegMaskInfo(animal_id) 3 | % 4 | % Gets the date and session number of the initial session for the animal 5 | % specified as animal_id. This session will contain the minimum 6 | % projection of the initial recording to which future recording sessions 7 | % will be aligned. Animal entries and their respective initial dates and 8 | % session numbers must be manually edited in this function prior to 9 | % running it. 10 | % 11 | % INPUT 12 | % animal_id: String, ID of the animal. Must be unique and must match one 13 | % of the AI.animal fields below. 14 | % 15 | % OUTPUTS 16 | % init_date: String, date of the initial session in the format 17 | % MM_DD_YYYY. 18 | % 19 | % init_sess: Scalar, initial session number. 20 | % 21 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | % This file is part of Tenaspis. 24 | % 25 | % Tenaspis is free software: you can redistribute it and/or modify 26 | % it under the terms of the GNU General Public License as published by 27 | % the Free Software Foundation, either version 3 of the License, or 28 | % (at your option) any later version. 29 | % 30 | % Tenaspis is distributed in the hope that it will be useful, 31 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | % GNU General Public License for more details. 34 | % 35 | % You should have received a copy of the GNU General Public License 36 | % along with Tenaspis. If not, see . 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | 39 | 40 | %% Initial session data. 41 | i = 1; 42 | AI(i).animal = 'GCaMP6f_31'; %Manually specify animal ID here. 43 | AI(i).init_date = '09_29_2014'; %Manually specify initial date here. 44 | AI(i).init_sess = 1; %Manually specify initial session here. 45 | 46 | i = i+1; 47 | AI(i).animal = 'GCamp6f_30'; 48 | AI(i).init_date = '11_11_2014'; 49 | AI(i).init_sess = 1; 50 | 51 | i = i+1; 52 | AI(i).animal = 'GCamp6f_44'; 53 | AI(i).init_date = '07_10_2015'; 54 | AI(i).init_sess = 2; 55 | 56 | i = i+1; 57 | AI(i).animal = 'GCamp6f_45'; 58 | AI(i).init_date = '08_05_2015'; 59 | AI(i).init_sess = 1; 60 | 61 | i = i+1; 62 | AI(i).animal = 'GCamp6f_41'; 63 | AI(i).init_date = '08_05_2015'; 64 | AI(i).init_sess = 1; 65 | 66 | i = i+1; 67 | AI(i).animal = 'GCamp6f_46'; 68 | AI(i).init_date = '08_14_2015'; 69 | AI(i).init_sess = 1; 70 | 71 | i = i+1; 72 | AI(i).animal = 'GCamp6f_30_2'; 73 | AI(i).init_date = '06_10_2015'; 74 | AI(i).init_sess = 1; 75 | 76 | i = i+1; 77 | AI(i).animal = 'GCamp6f_45_treadmill'; 78 | AI(i).init_date = '11_30_2015'; 79 | AI(i).init_sess = 10; 80 | 81 | i = i+1; 82 | AI(i).animal = 'GCamp6f_48_treadmill'; 83 | AI(i).init_date = '04_18_2016'; 84 | AI(i).init_sess = 10; 85 | 86 | i = i+1; 87 | AI(i).animal = 'GCamp6f_45_altpilot'; 88 | AI(i).init_date = '01_13_2016'; 89 | AI(i).init_sess = 1; 90 | 91 | i = i+1; 92 | AI(i).animal = 'GCamp6f_48'; 93 | AI(i).init_date = '08_29_2015'; 94 | AI(i).init_sess = 1; 95 | 96 | i = i+1; 97 | AI(i).animal = 'GCamp6f_45_DNMP'; 98 | AI(i).init_date = '04_01_2016'; 99 | AI(i).init_sess = 1; 100 | 101 | i = i+1; 102 | AI(i).animal = 'Aquila'; 103 | AI(i).init_date = '04_28_2016'; 104 | AI(i).init_sess = 1; 105 | 106 | i = i+1; 107 | AI(i).animal = 'Libra'; 108 | AI(i).init_date = '05_13_2016'; 109 | AI(i).init_sess = 1; 110 | 111 | i = i+1; 112 | AI(i).animal = 'Bellatrix'; 113 | AI(i).init_date = '07_05_2016'; 114 | AI(i).init_sess = 10; 115 | 116 | i = i+1; 117 | AI(i).animal = 'Polaris'; 118 | AI(i).init_date = '07_05_2016'; 119 | AI(i).init_sess = 10; 120 | 121 | i = i+1; 122 | AI(i).animal = 'Bellatrix_AK'; 123 | AI(i).init_date = '11_07_2016'; 124 | AI(i).init_sess = 1; 125 | 126 | i = i+1; 127 | AI(i).animal = 'Polaris_AK'; 128 | AI(i).init_date = '11_09_2016'; 129 | AI(i).init_sess = 2; 130 | 131 | i = i+1; 132 | AI(i).animal = 'G50_AK'; 133 | AI(i).init_date = '03_13_2017'; 134 | AI(i).init_sess = 2; 135 | 136 | i = i+1 137 | AI(i).animal = 'Styx'; 138 | AI(i).init_date = '10_19_2017'; 139 | AI(i).init_sess = 1; 140 | 141 | % For each animal you have, add onto the structure array: 142 | % i = i+1; 143 | % AI(i).animal = _ANIMAL NAME HERE_ 144 | % AI(i).init_date = _INITIAL DATE HERE_ 145 | % AI(i).init_sess = _INITIAL SESSION NUMBER HERE_ 146 | 147 | %% Perform search. 148 | all_ids = {AI.animal}; %Cell array of all names. 149 | ind = find(strcmpi(animal_id,all_ids)); %Find name that matches input. 150 | 151 | %Set outputs. 152 | init_date = AI(ind).init_date; 153 | init_sess = AI(ind).init_sess; 154 | 155 | end -------------------------------------------------------------------------------- /GetSessNums.m: -------------------------------------------------------------------------------- 1 | function [SessNums] = GetSessNums(animalID) 2 | % [SessNums] = GetSessNums(animalID,userID) 3 | % Returns session index numbers for a particular animal for a particular 4 | % user 5 | % for use in multi-session data analysis 6 | close all; 7 | cd('C:\MasterData'); 8 | load MasterDirectory; 9 | SessNums = []; 10 | 11 | for i = 1:length(MD) 12 | if (strcmp(MD(i).Animal,animalID) & ~isempty(MD(i).Location)) 13 | SessNums = [SessNums,i]; 14 | end 15 | 16 | 17 | end 18 | 19 | -------------------------------------------------------------------------------- /Get_T_Params.m: -------------------------------------------------------------------------------- 1 | function [varargout] = Get_T_Params(varargin) 2 | % [varargout] = Get_T_Params(varargin) 3 | % 4 | % loads Tenaspis parameters from global variable. Set_T_Params must be 5 | % called before this in order to set this global variable 6 | % 7 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 8 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9 | % This file is part of Tenaspis. 10 | % 11 | % Tenaspis is free software: you can redistribute it and/or modify 12 | % it under the terms of the GNU General Public License as published by 13 | % the Free Software Foundation, either version 3 of the License, or 14 | % (at your option) any later version. 15 | % 16 | % Tenaspis is distributed in the hope that it will be useful, 17 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | % GNU General Public License for more details. 20 | % 21 | % You should have received a copy of the GNU General Public License 22 | % along with Tenaspis. If not, see . 23 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24 | 25 | global T_PARAMS; 26 | 27 | varargout = cell(1,length(varargin)); 28 | 29 | for i = 1:length(varargin) 30 | if (strcmp(varargin{i},'Xdim')) 31 | varargout(i) = {T_PARAMS.Xdim}; 32 | end 33 | 34 | if (strcmp(varargin{i},'Ydim')) 35 | varargout(i) = {T_PARAMS.Ydim}; 36 | end 37 | 38 | if (strcmp(varargin{i},'NumFrames')) 39 | varargout(i) = {T_PARAMS.NumFrames}; 40 | end 41 | 42 | if (strcmp(varargin{i},'FrameChunkSize')) 43 | varargout(i) = {T_PARAMS.FrameChunkSize}; 44 | end 45 | 46 | if (strcmp(varargin{i},'LowPassRadius')) 47 | varargout(i) = {T_PARAMS.LowPassRadius}; 48 | end 49 | 50 | if (strcmp(varargin{i},'HighPassRadius')) 51 | varargout(i) = {T_PARAMS.HighPassRadius}; 52 | end 53 | 54 | if (strcmp(varargin{i},'threshold')) 55 | varargout(i) = {T_PARAMS.threshold}; 56 | end 57 | 58 | if (strcmp(varargin{i},'threshsteps')) 59 | varargout(i) = {T_PARAMS.threshsteps}; 60 | end 61 | 62 | if (strcmp(varargin{i},'MaxBlobRadius')) 63 | varargout(i) = {T_PARAMS.MaxBlobRadius}; 64 | end 65 | 66 | if (strcmp(varargin{i},'MinBlobRadius')) 67 | varargout(i) = {T_PARAMS.MinBlobRadius}; 68 | end 69 | 70 | if (strcmp(varargin{i},'MaxAxisRatio')) 71 | varargout(i) = {T_PARAMS.MaxAxisRatio}; 72 | end 73 | 74 | if (strcmp(varargin{i},'MinSolidity')) 75 | varargout(i) = {T_PARAMS.MinSolidity}; 76 | end 77 | 78 | if (strcmp(varargin{i},'BlobLinkThresholdCoeff')) 79 | varargout(i) = {T_PARAMS.BlobLinkThresholdCoeff}; 80 | end 81 | 82 | if (strcmp(varargin{i},'MinNumFrames')) 83 | varargout(i) = {T_PARAMS.MinNumFrames}; 84 | end 85 | 86 | if (strcmp(varargin{i},'MaxCentroidTravelDistance')) 87 | varargout(i) = {T_PARAMS.MaxCentroidTravelDistance}; 88 | end 89 | 90 | if (strcmp(varargin{i},'MinPixelPresence')) 91 | varargout(i) = {T_PARAMS.MinPixelPresence}; 92 | end 93 | 94 | if (strcmp(varargin{i},'ROICircleWindowRadius')) 95 | varargout(i) = {T_PARAMS.ROICircleWindowRadius}; 96 | end 97 | 98 | if (strcmp(varargin{i},'DistanceThresholdList')) 99 | varargout(i) = {T_PARAMS.DistanceThresholdList}; 100 | end 101 | 102 | if (strcmp(varargin{i},'MaxTransientMergeCorrP')) 103 | varargout(i) = {T_PARAMS.MaxTransientMergeCorrP}; 104 | end 105 | 106 | if (strcmp(varargin{i},'MinTransientMergeCorrR')) 107 | varargout(i) = {T_PARAMS.MinTransientMergeCorrR}; 108 | end 109 | 110 | if (strcmp(varargin{i},'ROIBoundaryCoeff')) 111 | varargout(i) = {T_PARAMS.ROIBoundaryCoeff}; 112 | end 113 | 114 | if (strcmp(varargin{i},'AmplitudeThresholdCoeff')) 115 | varargout(i) = {T_PARAMS.AmplitudeThresholdCoeff}; 116 | end 117 | 118 | if (strcmp(varargin{i},'CorrPthresh')) 119 | varargout(i) = {T_PARAMS.CorrPthresh}; 120 | end 121 | 122 | if (strcmp(varargin{i},'MaxGapFillLen')) 123 | varargout(i) = {T_PARAMS.MaxGapFillLen}; 124 | end 125 | 126 | if (strcmp(varargin{i},'SlopeThresh')) 127 | varargout(i) = {T_PARAMS.SlopeThresh}; 128 | end 129 | 130 | if (strcmp(varargin{i},'MinBinSimRank')) 131 | varargout(i) = {T_PARAMS.MinBinSimRank}; 132 | end 133 | 134 | if (strcmp(varargin{i},'ROIoverlapthresh')) 135 | varargout(i) = {T_PARAMS.ROIoverlapthresh}; 136 | end 137 | 138 | if (strcmp(varargin{i},'MinPSALen')) 139 | varargout(i) = {T_PARAMS.MinPSALen}; 140 | end 141 | 142 | if (strcmp(varargin{i},'SampleRate')) 143 | varargout(i) = {T_PARAMS.SampleRate}; 144 | end 145 | 146 | if (strcmp(varargin{i},'SmoothSize')) 147 | varargout(i) = {T_PARAMS.SmoothSize}; 148 | end 149 | 150 | if (strcmp(varargin{i},'MinNumPSAepochs')) 151 | varargout(i) = {T_PARAMS.MinNumPSAepochs}; 152 | end 153 | 154 | if (strcmp(varargin{i},'MinNumTransients')) 155 | varargout(i) = {T_PARAMS.MinNumTransients}; 156 | end 157 | 158 | end 159 | 160 | -------------------------------------------------------------------------------- /InterpretTraces.m: -------------------------------------------------------------------------------- 1 | function InterpretTraces(Todebug) 2 | % function InterpretTraces(Todebug) 3 | % 4 | % This takes the output of MergeTransientROIs and creates a best-guess 5 | % estimate of when the neurons in the ROIs had calcium transients. An 6 | % outline of the procedure is below. 7 | % 8 | % A. Decide when calcium transients are present in each ROI, using: 9 | % 1) average value of pixels in each segmentation-identified ROI 10 | % 2) fluorescence traces: mean intensity in each ROI for each frame 11 | % - use amplitude to identify times when there may be a transient 12 | % 3) correlation r between those average pixel values and each frame of 13 | % the movie 14 | % - establishes a baseline correlation from segmentation transients, 15 | % and determines whether transients identified via amplitude are OK 16 | % or not based on whether the correlation is significant and 17 | % sufficiently high 18 | % 19 | % B. Determine the rising slope(s) of each transient identified in A 20 | % - putative spiking activity occurs during rising phase of calcium 21 | % transients 22 | % 23 | % C. Eliminate transients that overlap in space and time 24 | % - spatiotemporally overlapping transients suggest under-merged ROIs 25 | % - "wrong" ROI should have lower amplitude 26 | % - potentially eliminate under-merged ROIs 27 | % - only eliminates overlapping positive slopes; overlapping neurons can 28 | % be active in quick succession despite long decay of gCamp 29 | % 30 | % D. Remove ROIs with less than 2 transients from the data 31 | % 32 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 33 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 | % This file is part of Tenaspis. 35 | % 36 | % Tenaspis is free software: you can redistribute it and/or modify 37 | % it under the terms of the GNU General Public License as published by 38 | % the Free Software Foundation, either version 3 of the License, or 39 | % (at your option) any later version. 40 | % 41 | % Tenaspis 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 Tenaspis. If not, see . 48 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 49 | 50 | %% set up variables and load data 51 | if (~exist('Todebug','var')) 52 | Todebug = 0; 53 | end 54 | 55 | load('SegmentationROIs.mat','NeuronActivity','NumNeurons','NeuronTraces','NeuronPixelIdxList','NeuronAvg','NeuronFrameList','NeuronImage','NeuronObjList','NeuronROIidx','Trans2ROI'); 56 | [Xdim,Ydim,NumFrames,AmplitudeThresholdCoeff,CorrPthresh,MaxGapFillLen,SlopeThresh,MinBinSimRank,ROIoverlapthresh,MinPSALen,MinNumPSAepochs] = ... 57 | Get_T_Params('Xdim','Ydim','NumFrames','AmplitudeThresholdCoeff','CorrPthresh','MaxGapFillLen','SlopeThresh','MinBinSimRank','ROIoverlapthresh','MinPSALen','MinNumPSAepochs'); 58 | 59 | blankframe = zeros(Xdim,Ydim,'single'); 60 | PSAbool = false(NumNeurons,NumFrames); 61 | 62 | %% PART A %%%%%%%%%%%%%%%%%%% 63 | 64 | %% determine overlapping ROIs 65 | disp('calculating overlapping ROIs'); 66 | 67 | ROIoverlap = false(NumNeurons,NumNeurons); 68 | ROIpct = zeros(NumNeurons,NumNeurons,'single'); 69 | for i = 1:NumNeurons 70 | for j = i+1:NumNeurons 71 | if(~isempty(intersect(NeuronPixelIdxList{i},NeuronPixelIdxList{j}))) 72 | ROIoverlap(i,j) = true; 73 | ROIoverlap(j,i) = true; 74 | ROIpct(i,j) = length(intersect(NeuronPixelIdxList{i},NeuronPixelIdxList{j}))/min(length(NeuronPixelIdxList{i}),length(NeuronPixelIdxList{j})); 75 | ROIpct(j,i) = ROIpct(i,j); 76 | end 77 | end 78 | end 79 | 80 | %% For each neuron, find samples where there were either segmentation-identified transients or potential transients 81 | disp('analyzing traces for potential transients'); 82 | for i = 1:NumNeurons 83 | % calculate the amplitude threshold based on the 84 | % segmentation-identified frames 85 | %i = ceil(rand*NumNeurons); 86 | Threshold = min(NeuronTraces.LPtrace(i,NeuronActivity(i,:))); 87 | Threshold = Threshold - abs(Threshold)*AmplitudeThresholdCoeff; 88 | 89 | % find epochs where the trace was above amplitude threshold 90 | PosBool = logical(NeuronTraces.LPtrace(i,:) > Threshold); 91 | 92 | % find epochs where the correlation was significant 93 | CorrSig = NeuronTraces.CorrR(i,:).*(NeuronTraces.CorrP(i,:)< CorrPthresh); 94 | % find epochs where the significant correlation is nonzero and overlaps 95 | % with segmentation-identified activity 96 | GoodCS = logical(NeuronActivity(i,:).*(CorrSig > 0)); 97 | 98 | if (sum(GoodCS) == 0) 99 | continue; 100 | end 101 | 102 | % set the correlation threshold as the minimum r during these epochs 103 | CorrThresh = min(CorrSig(GoodCS)); 104 | 105 | % find epochs above the correlation threshold 106 | CorrEpochs = NP_FindSupraThresholdEpochs(CorrSig,CorrThresh); 107 | 108 | % identify good correlation epochs that are also above the amplitude 109 | % threshold for at least 1 frame 110 | GoodTrBool = false(1,NumFrames); 111 | for j = 1:size(CorrEpochs,1) 112 | % check and see if the amplitude threshold is breached during this 113 | % epochs, if so, keep it 114 | if(sum(PosBool(CorrEpochs(j,1):CorrEpochs(j,2))) > 0) 115 | GoodTrBool(CorrEpochs(j,1):CorrEpochs(j,2)) = true; 116 | end 117 | end 118 | 119 | % identify small gaps that we can fill in 120 | ZeroEpochs = NP_FindSupraThresholdEpochs(~GoodTrBool,eps); 121 | EpLen = ZeroEpochs(:,2)-ZeroEpochs(:,1)+1; 122 | GoodFill = EpLen <= MaxGapFillLen; 123 | ZeroEpochs = ZeroEpochs(GoodFill,:); 124 | 125 | % fill gaps 126 | for j = 1:size(ZeroEpochs,1) 127 | GoodTrBool(ZeroEpochs(j,1):ZeroEpochs(j,2)) = true; 128 | end 129 | 130 | % Part B: detect positive slopes 131 | InSlope = false; 132 | SlopeTr = NeuronTraces.DFDTtrace(i,:); 133 | for j = 1:NumFrames 134 | if (InSlope) 135 | % check if fluoresence slope is still postive 136 | if ((SlopeTr(j) > 0) && (GoodTrBool(j))) 137 | PSAbool(i,j) = true; 138 | else 139 | InSlope = false; 140 | end 141 | else 142 | % not currently in a slope 143 | if (GoodTrBool(j)) 144 | if (SlopeTr(j) >= SlopeThresh) 145 | % new slope 146 | InSlope = true; 147 | PSAbool(i,j) = true; 148 | % check if we can go backward to beginning of positive 149 | % slope (ok even if not ok correlation) 150 | BackCheck = j-1; 151 | while((SlopeTr(BackCheck) > SlopeThresh) && (BackCheck >= 2)) 152 | PSAbool(i,BackCheck) = true; 153 | BackCheck = BackCheck - 1; 154 | end 155 | end 156 | end 157 | end 158 | end 159 | 160 | %% plotting (optional) 161 | if (Todebug) 162 | a(1) = subplot(2,6,1:4); 163 | hold off; 164 | plot(NeuronTraces.LPtrace(i,:),'-b');hold on; 165 | plot(NeuronTraces.LPtrace(i,:).*NeuronActivity(i,:),'-k','LineWidth',2); 166 | plot(NeuronTraces.LPtrace(i,:).*GoodTrBool,'-r','LineWidth',1); 167 | plot(NeuronTraces.LPtrace(i,:).*PSAbool(i,:),'-g','LineWidth',1); 168 | axis tight; 169 | a(2) = subplot(2,6,7:10); 170 | hold off; 171 | plot(CorrSig,'-m'); 172 | hold on;plot(CorrSig.*(CorrSig > CorrThresh));axis tight;hold off; 173 | 174 | linkaxes(a,'x'); 175 | 176 | subplot(2,6,11);histogram(NeuronTraces.CorrR(i,NeuronActivity(i,:)),(-1:0.05:1));title(num2str(CorrThresh)); 177 | subplot(2,6,5);histogram(NeuronTraces.LPtrace(i,NeuronActivity(i,:)),(0:0.005:0.2)); 178 | pause; 179 | ToGo = 'y'; 180 | while(strcmpi(ToGo,'y')) 181 | disp('pick a time to see the frame') 182 | [mx,~] = ginput(1); 183 | f = LoadFrames('BPDFF.h5',ceil(mx)); 184 | b(1) = subplot(2,6,6);imagesc(f);axis image; 185 | caxis([0 max(f(NeuronPixelIdxList{i}))]); 186 | tempf = blankframe; 187 | tempf(NeuronPixelIdxList{i}) = NeuronAvg{i}; 188 | b(2) = subplot(2,6,12);imagesc(tempf);axis image; 189 | linkaxes(b); 190 | ToGo = input('do another frame? [y/n] -->','s'); 191 | end 192 | end 193 | end 194 | 195 | %% B2: Find ROIs that should have been merged but weren't 196 | % basic theory: if two ROIs created in segmentation are so close that they 197 | % yield outputs that are closer than statistically likely, they are 198 | % indistinguishable and should be merged 199 | 200 | % calculate binary similarity metric 201 | disp('calculating ROI activity similarity'); 202 | BinSim = zeros(NumNeurons,NumNeurons,'single'); 203 | p = ProgressBar(NumNeurons); 204 | for i = 1:NumNeurons 205 | for j = 1:NumNeurons 206 | exhits = round(sum(PSAbool(i,:))*sum(PSAbool(j,:))/NumFrames); 207 | if (sum(PSAbool(i,:) & PSAbool(j,:)) > exhits) 208 | BinSim(i,j) = (sum(PSAbool(i,:) & PSAbool(j,:))-exhits)/(min(sum(PSAbool(i,:)),sum(PSAbool(j,:)))-exhits); 209 | else 210 | if (exhits > 0) 211 | BinSim(i,j) = (sum(PSAbool(i,:) & PSAbool(j,:))-exhits)/(exhits); 212 | else 213 | BinSim(i,j) = 0; 214 | end 215 | end 216 | if (i == j) 217 | BinSim(i,j) = 0; 218 | end 219 | end 220 | p.progress; 221 | end 222 | p.stop; 223 | 224 | disp('calculating whether overlapping ROIs have more similar PSA than expected'); 225 | % determine how likely similarity metrics are compared to non-adjacent 226 | % population 227 | BadNeighbors = cell(1,NumNeurons); 228 | for i = 1:NumNeurons 229 | Neighbors = find(ROIpct(i,:) > ROIoverlapthresh); 230 | 231 | if (isempty(Neighbors)) 232 | continue; 233 | end 234 | 235 | NeighborSim = BinSim(i,Neighbors); 236 | 237 | FarSims = sort(BinSim(i,ROIoverlap(i,:) == 0)); 238 | BinSimRank = zeros(1,length(Neighbors)); 239 | 240 | for j = 1:length(NeighborSim) 241 | idx = findclosest(NeighborSim(j),FarSims); 242 | BinSimRank(j) = idx/length(FarSims); 243 | end 244 | 245 | BadNeighbors{i} = Neighbors(BinSimRank >= MinBinSimRank); 246 | 247 | end 248 | 249 | disp('merging ROIs that are practically indistinguishable') 250 | 251 | % make a list of where each row lives now (by default, its own index) 252 | ROIhome = 1:NumNeurons; 253 | NumMerges = 0; 254 | % for each neuron i 255 | for i = 1:NumNeurons 256 | % for each nasty neighbor j: Overlap over 50% and BinSim rank over 94 257 | for j = 1:length(BadNeighbors{i}) 258 | % find actual location of ROI 259 | idx1 = i; 260 | while(ROIhome(idx1) ~= idx1) 261 | idx1 = ROIhome(idx1); 262 | end 263 | 264 | idx2 = BadNeighbors{i}(j); 265 | while(ROIhome(idx2) ~= idx2) 266 | idx2 = ROIhome(idx2); 267 | end 268 | 269 | % determine who has more transients (counting ones added in clustering) 270 | Temp1 = NP_FindSupraThresholdEpochs(PSAbool(idx1,:),eps); 271 | Temp2 = NP_FindSupraThresholdEpochs(PSAbool(idx2,:),eps); 272 | if (size(Temp1,1) > size(Temp2,1)) 273 | target = idx1; 274 | ball = idx2; 275 | else 276 | target = idx2; 277 | ball = idx1; 278 | end 279 | 280 | PSAbool(target,:) = PSAbool(target,:) | PSAbool(ball,:); 281 | PSAbool(ball,:) = false; 282 | ROIhome(ball) = target; 283 | NumMerges = NumMerges+1; 284 | end 285 | end 286 | 287 | disp([int2str(NumMerges),' ROIs eliminated via merging']); 288 | 289 | %% B3: fill gaps again 290 | 291 | for i = 1:NumNeurons 292 | ZeroEpochs = NP_FindSupraThresholdEpochs(~PSAbool(i,:),eps); 293 | EpLen = ZeroEpochs(:,2)-ZeroEpochs(:,1)+1; 294 | GoodFill = EpLen <= MaxGapFillLen; 295 | ZeroEpochs = ZeroEpochs(GoodFill,:); 296 | 297 | % fill gaps 298 | for j = 1:size(ZeroEpochs,1) 299 | PSAbool(i,ZeroEpochs(j,1):ZeroEpochs(j,2)) = true; 300 | end 301 | end 302 | 303 | %% Part D: Kill the flimsy ROIs - remove PSA epochs shorter than MinPSALen 304 | NumActs = zeros(1,NumNeurons); 305 | AllPSALen = []; 306 | actlist = cell(1,NumNeurons); 307 | for i = 1:NumNeurons 308 | actlist{i} = NP_FindSupraThresholdEpochs(PSAbool(i,:),eps); 309 | if (~isempty(actlist{i})) 310 | 311 | PSALen = (actlist{i}(:,2)-actlist{i}(:,1))+1; 312 | AllPSALen = [AllPSALen;PSALen]; 313 | for j = 1:size(actlist{i},1) 314 | if (PSALen(j) < MinPSALen) 315 | PSAbool(i,actlist{i}(j,1):actlist{i}(j,2)) = false; 316 | end 317 | end 318 | end 319 | actlist{i} = NP_FindSupraThresholdEpochs(PSAbool(i,:),eps); 320 | NumActs(i) = size(actlist{i},1); 321 | end 322 | 323 | %% C. eliminate spatiotemporal overlaps 324 | disp('eliminating spatiotemporal overlaps'); 325 | 326 | p = ProgressBar(NumNeurons); 327 | 328 | for i = 1:NumNeurons 329 | Neighbors = find(ROIoverlap(i,:)); 330 | for j = 1:size(actlist{i},1) 331 | % do any neighbors have an epoch that starts or ends during this 332 | % one? 333 | actframes = (actlist{i}(j,1):actlist{i}(j,2)); 334 | nList = []; 335 | epList = []; 336 | meanDffList = []; 337 | for k = 1:length(Neighbors) 338 | nIdx = Neighbors(k); 339 | for m = 1:size(actlist{nIdx},1) 340 | if (ismember(actlist{nIdx}(m,1),actframes) || ismember(actlist{nIdx}(m,2),actframes)) 341 | % neuron nIdx epoch m overlaps with neuron i epoch j 342 | nList = [nList,nIdx]; 343 | epList = [epList,m]; 344 | meanDffList = [meanDffList,mean(NeuronTraces.LPtrace(nIdx,actlist{nIdx}(m,1):actlist{nIdx}(m,2)))]; 345 | end 346 | end 347 | end 348 | 349 | if (isempty(nList)) 350 | continue; 351 | end 352 | 353 | TijMeanDFF = mean(NeuronTraces.LPtrace(i,actlist{i}(j,1):actlist{i}(j,2))); 354 | 355 | nList = [i,nList]; 356 | epList = [j,epList]; 357 | meanDFFList = [TijMeanDFF,meanDffList]; 358 | [~,maxidx] = max(meanDFFList); 359 | 360 | for k = 1:length(nList) 361 | if ((k == maxidx) || (nList(k) == nList(maxidx))) 362 | continue; 363 | end 364 | 365 | % kill the epoch 366 | try 367 | PSAbool(nList(k),actlist{nList(k)}(epList(k),1):actlist{nList(k)}(epList(k),2)) = false; 368 | catch 369 | keyboard; 370 | end 371 | end 372 | for k = 1:length(nList) 373 | if (nList(k) ~= i) 374 | actlist{nList(k)} = NP_FindSupraThresholdEpochs(PSAbool(nList(k),:),eps); 375 | end 376 | end 377 | end 378 | actlist{i} = NP_FindSupraThresholdEpochs(PSAbool(i,:),eps); 379 | p.progress; 380 | end 381 | p.stop; 382 | 383 | for i = 1:NumNeurons 384 | NumActs(i) = size(actlist{i},1); 385 | end 386 | 387 | ActOK = NumActs >= MinNumPSAepochs; 388 | 389 | % 'NeuronActivity','NumNeurons','NeuronTraces','NeuronPixelIdxList','NeuronAvg','NeuronFrameList','NeuronImage','NeuronObjList','NeuronROIidx','Trans2ROI'); 390 | NeuronActivity = NeuronActivity(ActOK); 391 | NeuronPixelIdxList = NeuronPixelIdxList(ActOK); 392 | NeuronFrameList = NeuronFrameList(ActOK); 393 | NeuronImage = NeuronImage(ActOK); 394 | NeuronObjList = NeuronObjList(ActOK); 395 | NeuronROIidx = NeuronROIidx(ActOK); 396 | 397 | PSAbool = PSAbool(ActOK,:); 398 | disp('averaging ROIs over the movie'); 399 | NeuronAvg = PixelSetMovieAvg(PSAbool,NeuronPixelIdxList); 400 | 401 | NumNeurons = sum(ActOK); 402 | 403 | NeuronTraces.RawTrace = NeuronTraces.RawTrace(ActOK,:); 404 | NeuronTraces.LPtrace = NeuronTraces.LPtrace(ActOK,:); 405 | NeuronTraces.DFDTtrace = NeuronTraces.DFDTtrace(ActOK,:); 406 | NeuronTraces.CorrR = NeuronTraces.CorrR(ActOK,:); 407 | NeuronTraces.CorrP = NeuronTraces.CorrP(ActOK,:); 408 | 409 | save('FinalOutput.mat','NeuronActivity','NumNeurons','NeuronTraces','NeuronPixelIdxList',... 410 | 'NeuronAvg','NeuronFrameList','NeuronImage','NeuronObjList','NeuronROIidx','Trans2ROI','PSAbool','BinSim'); 411 | 412 | 413 | -------------------------------------------------------------------------------- /LinkBlobs.m: -------------------------------------------------------------------------------- 1 | function [] = LinkBlobs() 2 | %[] = LinkBlobs() 3 | % Load the output of ExtractBlobs.m and find sets of blobs that appear in 4 | % the same spot on consectuive frames - putative calcium transients 5 | % 6 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | % This file is part of Tenaspis. 9 | % 10 | % Tenaspis is free software: you can redistribute it and/or modify 11 | % it under the terms of the GNU General Public License as published by 12 | % the Free Software Foundation, either version 3 of the License, or 13 | % (at your option) any later version. 14 | % 15 | % Tenaspis is distributed in the hope that it will be useful, 16 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | % GNU General Public License for more details. 19 | % 20 | % You should have received a copy of the GNU General Public License 21 | % along with Tenaspis. If not, see . 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | % 24 | disp('Processing blobs into calcium transient ROIs: first step is to link blobs that appear in the same spot on consecutive frames'); 25 | 26 | %% load parameters 27 | [NumFrames,FrameChunkSize,BlobLinkThresholdCoeff] = Get_T_Params('NumFrames','FrameChunkSize','BlobLinkThresholdCoeff'); 28 | 29 | % Load Blob pixel lists and centroids 30 | disp('Loading blobs'); 31 | load('Blobs.mat','BlobPixelIdxList','BlobWeightedCentroids','BlobMinorAxisLength'); 32 | 33 | %% set up some variables 34 | TransientIdx = cell(1,NumFrames); 35 | InitNumBlobs = length(BlobPixelIdxList{1}); 36 | if (InitNumBlobs > 0) 37 | TransientIdx{1} = (1:InitNumBlobs); 38 | else 39 | TransientIdx{1} = []; 40 | end 41 | NextNewIdx = InitNumBlobs+1; 42 | 43 | FrameList = cell(1,InitNumBlobs); 44 | ObjList = cell(1,InitNumBlobs); 45 | for i = 1:InitNumBlobs 46 | FrameList{i} = 1; 47 | ObjList{i} = i; 48 | end 49 | 50 | %% Run through loop to connect blobs between successive frames 51 | p = ProgressBar(floor(NumFrames / FrameChunkSize)); 52 | disp('Linking Blobs'); 53 | 54 | for i = 2:NumFrames 55 | CurrNumBlobs = length(BlobPixelIdxList{i}); 56 | PrevNumBlobs = length(BlobPixelIdxList{i-1}); 57 | for j = 1:CurrNumBlobs 58 | CurrCent = BlobWeightedCentroids{i}{j}; 59 | FoundMatch = 0; 60 | for k = 1:PrevNumBlobs 61 | PrevCent = BlobWeightedCentroids{i-1}{k}; 62 | cdist = sqrt((PrevCent(1)-CurrCent(1))^2+(PrevCent(2)-CurrCent(2))^2); 63 | if (cdist < BlobMinorAxisLength{i-1}(k)*BlobLinkThresholdCoeff) 64 | FoundMatch = k; 65 | break; 66 | end 67 | end 68 | if (FoundMatch > 0) 69 | % get transient index of match 70 | PrevIdx = TransientIdx{i-1}(FoundMatch); 71 | % set this blob's transient index to match's 72 | TransientIdx{i}(j) = single(PrevIdx); 73 | % add this frame and object numbers to transient's bloblist 74 | FrameList{PrevIdx} = [FrameList{PrevIdx},single(i)]; 75 | ObjList{PrevIdx} = [ObjList{PrevIdx},single(j)]; 76 | else 77 | % Set up a new Transient 78 | TransientIdx{i}(j) = single(NextNewIdx); 79 | FrameList{NextNewIdx} = single(i); 80 | ObjList{NextNewIdx} = single(j); 81 | NextNewIdx = NextNewIdx + 1; 82 | end 83 | end 84 | if (mod(i,FrameChunkSize) == 0) 85 | p.progress; 86 | end 87 | end 88 | p.stop; 89 | 90 | %% save outputs 91 | disp('saving blob link information'); 92 | 93 | save BlobLinks.mat TransientIdx FrameList ObjList; 94 | 95 | -------------------------------------------------------------------------------- /LoadFrames.m: -------------------------------------------------------------------------------- 1 | function [frames] = LoadFrames(file,framenums) 2 | % [frames] = loadframe(file,framenums) 3 | % 4 | % Loads frames from an h5 file 5 | % 6 | % INPUTS: 7 | % file: fullpath to h5 file 8 | % 9 | % framenums: frame numbers of file to load 10 | % 11 | % OUTPUTS: 12 | % frames: an array of the frames you loaded 13 | % 14 | %% 15 | % Copyright 2015 by David Sullivan, Nathaniel Kinsky, and William Mau 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | % This file is part of Tenaspis. 18 | % 19 | % Tenaspis is free software: you can redistribute it and/or modify 20 | % it under the terms of the GNU General Public License as published by 21 | % the Free Software Foundation, either version 3 of the License, or 22 | % (at your option) any later version. 23 | % 24 | % Tenaspis is distributed in the hope that it will be useful, 25 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | % GNU General Public License for more details. 28 | % 29 | % You should have received a copy of the GNU General Public License 30 | % along with Tenaspis. If not, see . 31 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 32 | % 33 | %% Get parameters 34 | [Xdim,Ydim,NumFrames] = Get_T_Params('Xdim','Ydim','NumFrames'); 35 | 36 | %% find sets of consecutive frames in framenums and grab their indices 37 | fmap = zeros(1,max(framenums)); 38 | fmap(framenums) = 1; 39 | fep = NP_FindSupraThresholdEpochs(fmap,eps,0); 40 | loadchunks = []; 41 | 42 | for i = 1:size(fep,1) 43 | chunksize = fep(i,2)-fep(i,1)+1; 44 | loadchunks(i,1:2) = [fep(i,1),chunksize]; 45 | end 46 | 47 | %% load the frames 48 | curr = 1; 49 | 50 | frames = zeros(Xdim,Ydim,length(framenums),'single'); 51 | 52 | for i = 1:size(fep,1) 53 | frames(:,:,curr:(curr+loadchunks(i,2)-1)) = h5read(file,'/Object',[1 1 loadchunks(i,1) 1],[Xdim Ydim loadchunks(i,2) 1]); 54 | curr = curr+loadchunks(i,2); 55 | end 56 | 57 | end -------------------------------------------------------------------------------- /MakeCircMask.m: -------------------------------------------------------------------------------- 1 | % Draw a cInMatrcle InMatn a matrInMatx usInMatng the InMatnteger mInMatdpoInMatnt cInMatrcle algorInMatthm 2 | % Does not mInMatss or repeat pInMatxels 3 | % Created by : Peter Bone 4 | % Created : 19th March 2007 5 | function out = MidpointCircle(Xdim,Ydim, radius, yc, xc) 6 | 7 | InMat = zeros(Xdim,Ydim,'single'); 8 | 9 | value = 1; 10 | 11 | xc = int16(xc); 12 | yc = int16(yc); 13 | 14 | x = int16(0); 15 | y = int16(radius); 16 | d = int16(1 - radius); 17 | 18 | if 0 < (yc+y) & (yc+y) <= Ydim 19 | InMat(xc, yc+y) = value; 20 | end 21 | 22 | if 0 < (yc-y) & (yc-y) <= Ydim 23 | InMat(xc, yc-y) = value; 24 | end 25 | 26 | if 0 < (xc+y) & (xc+y) <= Xdim 27 | InMat(xc+y, yc) = value; 28 | end 29 | 30 | if 0 < (xc-y) & (xc-y) <= Xdim 31 | InMat(xc-y, yc) = value; 32 | end 33 | 34 | while ( x < y - 1 ) 35 | x = x + 1; 36 | if ( d < 0 ) 37 | d = d + x + x + 1; 38 | else 39 | y = y - 1; 40 | a = x - y + 1; 41 | d = d + a + a; 42 | end 43 | 44 | if 0 < (x+xc) & (x+xc) <= Xdim & 0 < (y+yc) & (y+yc) <= Ydim 45 | InMat( x+xc, y+yc) = value; 46 | end 47 | 48 | if 0 < (y+xc) & (y+xc) <= Xdim & 0 < (x+yc) & (x+yc) <= Ydim 49 | InMat( y+xc, x+yc) = value; 50 | end 51 | 52 | if 0 < (y+xc) & (y+xc) <= Xdim & 0 < (-x+yc) & (-x+yc) <= Ydim 53 | InMat( y+xc, -x+yc) = value; 54 | end 55 | 56 | if 0 < (x+xc) & (x+xc) <= Xdim & 0 < (-y+yc) & (-y+yc) <= Ydim 57 | InMat( x+xc, -y+yc) = value; 58 | end 59 | 60 | if 0 < (-x+xc) & (-x+xc) <= Xdim & 0 < (-y+yc) & (-y+yc) <= Ydim 61 | InMat(-x+xc, -y+yc) = value; 62 | end 63 | 64 | if 0 < (-y+xc) & (-y+xc) <= Xdim & 0 < (-x+yc) & (-x+yc) <= Ydim 65 | InMat(-y+xc, -x+yc) = value; 66 | end 67 | 68 | if 0 < (-y+xc) & (-y+xc) <= Xdim & 0 < (x+yc) & (x+yc) <= Ydim 69 | InMat(-y+xc, x+yc) = value; 70 | end 71 | 72 | if 0 < (-x+xc) & (-x+xc) <= Xdim & 0 < (y+yc) & (y+yc) <= Ydim 73 | InMat(-x+xc, y+yc) = value; 74 | end 75 | end 76 | 77 | for ii = xc-int16(radius):xc+(int16(radius)) 78 | for jj = yc-int16(radius):yc+(int16(radius)) 79 | tempR = sqrt((double(ii) - double(xc)).^2 + (double(jj) - double(yc)).^2); 80 | if(tempR <= double(int16(radius))) 81 | 82 | if 0 < ii & ii <= Xdim & 0 < jj & jj <= Ydim 83 | InMat(ii,jj)=value; 84 | end 85 | 86 | end 87 | end 88 | end 89 | 90 | out = single(find(InMat)); -------------------------------------------------------------------------------- /MakeFakeMovie.m: -------------------------------------------------------------------------------- 1 | function [ output_args ] = MakeFakeMovie(seed,bothdim,NeuronDensity,pAct,FilterDev) 2 | % Makes a fake dataset 3 | 4 | 5 | rng(seed); 6 | %% Set Parameters 7 | 8 | Xdim = bothdim; 9 | Ydim = bothdim; 10 | 11 | NeuronRad = 5; 12 | MaxDist = 6; 13 | BorderBuff = 40; 14 | 15 | %NeuronDensity = 0.01; 16 | NumNeurons = round(NeuronDensity*(Xdim-2*BorderBuff)*(Ydim-2*BorderBuff)); 17 | %NumNeurons = 150; 18 | NumFrames = 20000; 19 | RiseLen = 22; 20 | decrate = 0.982; 21 | %pAct = 0.001; 22 | %FilterDev = 7; % FilterDev default param is 7 23 | save FakeParams.mat Xdim Ydim NeuronRad NeuronDensity MaxDist BorderBuff NumNeurons NumFrames RiseLen decrate pAct FilterDev seed; 24 | 25 | %% Set up ROIs 26 | RiseInc = 1/RiseLen; 27 | 28 | RiseSweep = (1/RiseLen:1/RiseLen:1); 29 | 30 | BackgroundF = 1.5; 31 | 32 | 33 | 34 | TraceMat = zeros(NumNeurons,NumFrames); 35 | PSAbool = false(NumNeurons,NumFrames); 36 | 37 | LowPassFilter = fspecial('gaussian',[100 100],FilterDev); 38 | LowPassFilter = LowPassFilter; 39 | h5create('fake.h5','/Object',[Xdim Ydim NumFrames 1],'ChunkSize',... 40 | [Xdim Ydim 1 1],'Datatype','single'); 41 | 42 | 43 | 44 | % part 1: the neurons 45 | 46 | Cents = []; 47 | p = ProgressBar(NumNeurons); 48 | 49 | BigAvg = zeros(Xdim,Ydim); 50 | 51 | for i = 1:NumNeurons 52 | % 1. set x and y centroid randomly 53 | 54 | FoundGoodCent = false; 55 | 56 | while(~FoundGoodCent) 57 | % a. choose centroid randomly 58 | tempCent(1,1) = ceil(rand*Xdim); 59 | tempCent(1,2) = ceil(rand*Ydim); 60 | 61 | % b.0 check range 62 | if tempCent(1,1) <= BorderBuff | tempCent(1,1) > Xdim-BorderBuff | tempCent(1,2) <= BorderBuff | tempCent(1,2) > Ydim-BorderBuff 63 | continue; 64 | end 65 | 66 | % b. check whether too close 67 | tempdist = pdist([Cents;tempCent]); 68 | tempdist = squareform(tempdist); 69 | tempdist(i,i) = Inf; 70 | 71 | if (~any(tempdist(i,:) < MaxDist)) 72 | Cents(i,:) = tempCent; 73 | FoundGoodCent = true; 74 | end 75 | end 76 | 77 | % 2. set pixels based on centroid 78 | CircMask{i} = MakeCircMask(Xdim,Ydim,NeuronRad,tempCent(1,1),tempCent(1,2)); 79 | 80 | % 3. create spike trains 81 | CurrFrame = 2; 82 | InRise = false; 83 | RiseBank = 0; 84 | 85 | while (CurrFrame <= NumFrames) 86 | if (InRise) 87 | TraceMat(i,CurrFrame) = TraceMat(i,CurrFrame-1)+RiseInc; 88 | PSAbool(i,CurrFrame) = true; 89 | CurrFrame = CurrFrame + 1; 90 | 91 | RiseBank = RiseBank - RiseInc; 92 | if (RiseBank <= 0) 93 | InRise = false; 94 | end 95 | 96 | continue; 97 | end 98 | 99 | % not in a rise 100 | if (rand < pAct) 101 | % start a new rise 102 | InRise = true; 103 | RiseBank = 1; 104 | continue; 105 | else 106 | TraceMat(i,CurrFrame) = TraceMat(i,CurrFrame-1)*decrate; 107 | %PSAbool(i,CurrFrame) = true; 108 | CurrFrame = CurrFrame + 1; 109 | end 110 | end 111 | 112 | 113 | % b. model somatic GCaMP decays 114 | try 115 | BigAvg(CircMask{i}) = 1; 116 | catch 117 | keyboard; 118 | end 119 | imagesc(BigAvg); 120 | 121 | p.progress; 122 | end 123 | p.stop; 124 | 125 | 126 | % figure(1);imagesc(BigAvg); 127 | % 128 | blankframe = zeros(Xdim,Ydim,'single'); 129 | figure; 130 | % part 2: rendering 131 | p = ProgressBar(NumFrames) 132 | for i = 1:NumFrames 133 | 134 | % 1. start with blank frame 135 | temp = blankframe; 136 | % 2. add neurons 137 | for j = 1:NumNeurons 138 | temp(CircMask{j}) = temp(CircMask{j})+TraceMat(j,i); 139 | 140 | end 141 | 142 | 143 | 144 | % 3. add background 145 | temp = temp+0.2; 146 | 147 | %temp = temp+rand(Xdim,Ydim)*0.05; 148 | 149 | 150 | 151 | 152 | % 4. smear 153 | temp = imfilter(temp,LowPassFilter,'replicate')*1000; 154 | 155 | %imagesc(temp);axis image;colormap gray;colorbar;pause; 156 | % 5. save 157 | h5write('fake.h5','/Object',temp,[1 1 i 1],[Xdim Ydim 1 1]); 158 | p.progress; 159 | end 160 | p.stop; 161 | 162 | save FakeData.mat TraceMat CircMask PSAbool; 163 | end 164 | 165 | -------------------------------------------------------------------------------- /MakeFilteredMovies.m: -------------------------------------------------------------------------------- 1 | function MakeFilteredMovies(MotCorrh5,varargin) 2 | % MakeFilteredMovies(varargin) 3 | % 4 | % Tenaspis: Technique for Extracting Neuronal Activity from Single Photon Image Sequences 5 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % This file is part of Tenaspis. 8 | % 9 | % Tenaspis is free software: you can redistribute it and/or modify 10 | % it under the terms of the GNU General Public License as published by 11 | % the Free Software Foundation, either version 3 of the License, or 12 | % (at your option) any later version. 13 | % 14 | % Tenaspis is distributed in the hope that it will be useful, 15 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | % GNU General Public License for more details. 18 | % 19 | % You should have received a copy of the GNU General Public License 20 | % along with Tenaspis. If not, see . 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | % 23 | % Takes cropped, motion-corrected movie and makes two movies from it. 24 | % 25 | % INPUTS 26 | % NAME: 27 | % 'path' whose VALUE can be a string, the path containing the session 28 | % usually in the form X:\Animal\Date\Session. Default=runs uigetfile. 29 | % 30 | % 'd1' whose VALUE can be a logical, whether or not you want to also 31 | % make a first derivative movie from the 3-pixel smoothed movie. 32 | % Default=false. 33 | % 34 | % OUTPUTS - saved to directory above motion-corrected movie path. 35 | % 36 | % BPDFF.h5: SpatialBandPass DFF. Takes a 3-pixel smoothed version of the input movie and 37 | % divides it by the 20-pixel smoothed version of the same movie. Then, 38 | % take the DF/F of the quotient. 39 | % 40 | % LPDFF.h5: DF/F of the 3-pixel smoothed movie. 41 | 42 | %% Get Parameters and setup frame chunking 43 | Set_T_Params(MotCorrh5) 44 | [Xdim,Ydim,NumFrames,FrameChunkSize,HighPassRadius,LowPassRadius] = Get_T_Params('Xdim','Ydim','NumFrames','FrameChunkSize','HighPassRadius','LowPassRadius'); 45 | 46 | ChunkStarts = 1:FrameChunkSize:NumFrames; 47 | ChunkEnds = FrameChunkSize:FrameChunkSize:NumFrames; 48 | ChunkEnds(length(ChunkStarts)) = NumFrames; 49 | NumChunks = length(ChunkStarts); 50 | 51 | %% Parse inputs. 52 | p = inputParser; 53 | p.addParameter('d1',false,@(x) islogical(x)); 54 | p.parse(varargin{:}); 55 | 56 | d1 = p.Results.d1; 57 | 58 | %% more simple way to do this 59 | path = pwd; 60 | 61 | %% Output File names. 62 | BPDFF = fullfile(path,'BPDFF.h5'); % DF/F normalized spatial band pass filtered movie 63 | LPDFF = fullfile(path,'LPDFF.h5'); % DF/F normalized Low pass filtered movie 64 | LowPassName = fullfile(path,'LowPass.h5'); % Low pass filtered movie 65 | BandPassName = fullfile(path,'BandPass.h5'); % High pass filtered movie 66 | 67 | %% Set up. 68 | % create output files 69 | h5create(BandPassName,'/Object',[Xdim Ydim NumFrames 1],'ChunkSize',... 70 | [Xdim Ydim 1 1],'Datatype','single'); 71 | h5create(LowPassName,'/Object',[Xdim Ydim NumFrames 1],'ChunkSize',... 72 | [Xdim Ydim 1 1],'Datatype','single'); 73 | 74 | % create Spatial filters. 75 | HighPassFilter = fspecial('disk',HighPassRadius); 76 | LowPassFilter = fspecial('disk',LowPassRadius); 77 | 78 | %% Writing. 79 | disp('Filtering Movies') 80 | 81 | % Initialized ProgressBar 82 | p = ProgressBar(NumChunks); 83 | 84 | for i = 1:NumChunks 85 | FrameList = ChunkStarts(i):ChunkEnds(i); 86 | FrameChunk = LoadFrames(MotCorrh5,FrameList); 87 | 88 | HPChunk = imfilter(FrameChunk,HighPassFilter,'replicate'); 89 | LPChunk = imfilter(FrameChunk,LowPassFilter,'replicate'); 90 | 91 | if d1 92 | h5write(LowPassName,'/Object',LPChunk,[1 1 ChunkStarts(i) 1],... %Write Lowpass 93 | [Xdim Ydim length(FrameList) 1]); 94 | end 95 | 96 | h5write(BandPassName,'/Object',LPChunk./HPChunk,[1 1 ChunkStarts(i) 1],... %Write LP divide. 97 | [Xdim Ydim length(FrameList) 1]); 98 | p.progress; 99 | 100 | end 101 | p.stop; 102 | 103 | %% Calculate DF/F 104 | disp('Making BPDFF.h5...'); %DF/F of BP 105 | Make_DFF(BandPassName,BPDFF); 106 | 107 | % disp('Making LPDFF.h5...'); %DF/F of Low Pass 108 | % Make_DFF(LowPassName,LPDFF); 109 | 110 | %% Delete temporary files 111 | delete(BandPassName); 112 | 113 | end -------------------------------------------------------------------------------- /MakeInitialMask.m: -------------------------------------------------------------------------------- 1 | function [] = MakeInitialMask(infile) 2 | %[] = MakeBlobMask(file) 3 | 4 | temp = imread(infile); 5 | figure(901);imagesc(temp);axis equal; 6 | 7 | ToContinue = 'n'; 8 | display('draw a circle around the area with good cells'); 9 | while(strcmp(ToContinue,'y') ~= 1) 10 | mask = roipoly; 11 | figure;imagesc(mask); 12 | 13 | ToContinue = input('OK with the mask you just drew? [y/n] --->','s'); 14 | figure(901);imagesc(temp);axis equal; 15 | end 16 | save Initialmask.mat mask 17 | 18 | 19 | end 20 | 21 | -------------------------------------------------------------------------------- /MakeMaskSingleSession.m: -------------------------------------------------------------------------------- 1 | function MakeMaskSingleSession(movie) 2 | % MakeMaskSingleSession(movie) 3 | % 4 | % Makes a mask of the field of view after displaying a maximum 5 | % projection. Circle over a large area where you see cells. Saves as 6 | % singlesessionmask.mat with a logical matrix called neuronmask that is 7 | % true in the area over the mask. 8 | % 9 | % INPUT 10 | % movie: file name of movie you want to draw mask on. Must be same 11 | % dimensions as other movies in directory. 12 | % 13 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | % This file is part of Tenaspis. 16 | % 17 | % Tenaspis is free software: you can redistribute it and/or modify 18 | % it under the terms of the GNU General Public License as published by 19 | % the Free Software Foundation, either version 3 of the License, or 20 | % (at your option) any later version. 21 | % 22 | % Tenaspis is distributed in the hope that it will be useful, 23 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | % GNU General Public License for more details. 26 | % 27 | % You should have received a copy of the GNU General Public License 28 | % along with Tenaspis. If not, see . 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | 31 | close all; 32 | 33 | % Get movie information. 34 | [Xdim,Ydim,NumFrames] = Get_T_Params('Xdim','Ydim','NumFrames'); 35 | 36 | % step 1 build up a maximum projection, using every 5th frame 37 | newmax = zeros(Xdim,Ydim); 38 | for i = 1:5:NumFrames 39 | temp = LoadFrames(movie,i); 40 | newmax(temp > newmax) = temp(temp > newmax); 41 | end 42 | 43 | %% Draw mask. 44 | figure; 45 | ToContinue = 'n'; 46 | disp('draw a circle around the area with good cells'); 47 | while ~(strcmp(ToContinue,'y')) 48 | [neuronmask, xi, yi] = roipoly(imadjust(newmax)); 49 | figure;imagesc_gray(imadjust(newmax)); 50 | hold on 51 | plot(xi, yi,'r') 52 | 53 | ToContinue = input('OK with the mask you just drew? [y/n] --->','s'); 54 | end 55 | 56 | %% Save. 57 | save singlesessionmask.mat neuronmask; 58 | 59 | end 60 | 61 | -------------------------------------------------------------------------------- /MakeTraceChunk.m: -------------------------------------------------------------------------------- 1 | function [OutChunk] = MakeTraceChunk(FrameList,PixelIdxList,PixelAvg) 2 | %UNTITLED Summary of this function goes here 3 | % Detailed explanation goes here 4 | Set_T_Params('BPDFF.h5'); 5 | NumFrames = Get_T_Params('NumFrames'); 6 | NumNeurons = length(PixelIdxList); 7 | 8 | [CorrR,CorrP,RawTrace] = deal(zeros(NumNeurons,NumFrames,'single')); 9 | 10 | FrameChunk = LoadFrames('BPDFF.h5',FrameList); 11 | 12 | for j = 1:size(FrameChunk,3) 13 | frame = squeeze(FrameChunk(:,:,j)); 14 | for m = 1:NumNeurons 15 | RawTrace(m,FrameList(j)) = mean(frame(PixelIdxList{m})); 16 | [CorrR(m,FrameList(j)),CorrP(m,FrameList(j))] = corr(frame(PixelIdxList{m}),PixelAvg{m},'type','Spearman'); 17 | end 18 | end 19 | 20 | OutChunk.RawTrace = RawTrace; 21 | OutChunk.CorrR = CorrR; 22 | OutChunk.CorrP = CorrP; 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /MakeTracesAndCorrs.m: -------------------------------------------------------------------------------- 1 | function [DataOut] = MakeTracesAndCorrs(PixelIdxList,PixelAvg) 2 | % [varargout] = MakeTraces(varargin) 3 | % makes traces from pixel sets 4 | % inputs are length N cell arrays containing ROI pixel indices 5 | % vargout is a cell array of structs containing three elements, each a different NxT trace matrix 6 | % RawTrace: the unaltered mean of the pixels in the ROI 7 | % LPtrace: lowpass filter - RawTrace with a 3-pixel uniform window smoothing applied 8 | % DFDTtrace: LPtrace change per sample. 9 | 10 | %% get parameters 11 | [NumFrames,FrameChunkSize,SmoothSize] = Get_T_Params('NumFrames','FrameChunkSize','SmoothSize'); 12 | 13 | %% set up variables 14 | NumNeurons = length(PixelIdxList); 15 | disp(['making traces for ',int2str(NumNeurons),' ROIs']); 16 | 17 | [DataOut.RawTrace,DataOut.LPtrace,DataOut.DFDTtrace,DataOut.CorrR,DataOut.CorrP] = deal(zeros(NumNeurons,NumFrames,'single')); 18 | 19 | % Chunking variables 20 | ChunkStarts = 1:FrameChunkSize:NumFrames; 21 | ChunkEnds = FrameChunkSize:FrameChunkSize:NumFrames; 22 | ChunkEnds(length(ChunkStarts)) = NumFrames; 23 | NumChunks = length(ChunkStarts); 24 | 25 | %% process the chunks in parallel 26 | p = ProgressBar(NumChunks); 27 | parfor i = 1:NumChunks 28 | FrameList = ChunkStarts(i):ChunkEnds(i); 29 | TraceChunk{i} = MakeTraceChunk(FrameList,PixelIdxList,PixelAvg); 30 | p.progress; 31 | end 32 | p.stop; 33 | 34 | %% unpack the chunks 35 | disp('unpacking data chunks'); 36 | 37 | for i = 1:NumChunks 38 | DataOut.RawTrace = DataOut.RawTrace+TraceChunk{i}.RawTrace; 39 | DataOut.CorrR = DataOut.CorrR+TraceChunk{i}.CorrR; 40 | DataOut.CorrP = DataOut.CorrP+TraceChunk{i}.CorrP; 41 | end 42 | 43 | %% filter and take DFDT 44 | disp('filtering traces and calculating DF/DT'); 45 | 46 | for j = 1:NumNeurons 47 | DataOut.LPtrace(j,:) = convtrim(DataOut.RawTrace(j,:),ones(1,SmoothSize))./SmoothSize; 48 | DataOut.DFDTtrace(j,2:end) = zscore(diff(DataOut.LPtrace(j,:))); 49 | end 50 | 51 | 52 | end 53 | 54 | -------------------------------------------------------------------------------- /MakeTransientROIs.m: -------------------------------------------------------------------------------- 1 | function [] = MakeTransientROIs() 2 | %UNTITLED3 Summary of this function goes here 3 | % Detailed explanation goes here 4 | disp('Calculating ROIs for linked blobs (putative transients)'); 5 | 6 | %% Get parameters 7 | [Xdim,Ydim,NumFrames,MinPixelPresence,ROICircleWindowRadius,threshold,MinBlobRadius] = Get_T_Params('Xdim','Ydim','NumFrames','MinPixelPresence','ROICircleWindowRadius','threshold','MinBlobRadius'); 8 | 9 | threshold = threshold * 2; 10 | 11 | %% load data 12 | disp('loading data'); 13 | load('VettedTransients.mat','FrameList','ObjList'); 14 | load('Blobs.mat','BlobPixelIdxList'); 15 | 16 | %% setup some variables 17 | NumTransients = length(FrameList); 18 | [PixelIdxList,BinCent,BigAvg,CircMask,PixelAvg] = deal(cell(1,NumTransients)); 19 | TranBool = false(NumTransients,NumFrames); 20 | [Xcent,Ycent] = deal(zeros(1,NumTransients,'single')); 21 | MinBlobArea = ceil((MinBlobRadius^2)*pi); 22 | 23 | %% get pixel participation average and determine ROI 24 | disp('determining calcium transient ROIs'); 25 | blankframe = zeros(Xdim,Ydim,'single'); 26 | for i = 1:NumTransients 27 | PixFreq = blankframe; 28 | for j = 1:length(FrameList{i}) 29 | BlobPix = BlobPixelIdxList{FrameList{i}(j)}{ObjList{i}(j)}; 30 | PixFreq(BlobPix) = PixFreq(BlobPix)+1; 31 | end 32 | PixFreq = PixFreq./length(FrameList{i}); 33 | InROI = PixFreq > MinPixelPresence; 34 | PixelIdxList{i} = single(find(InROI)); 35 | props = regionprops(InROI,'Centroid'); 36 | BinCent{i} = props.Centroid; 37 | CircMask{i} = MakeCircMask(Xdim,Ydim,ROICircleWindowRadius,BinCent{i}(1),BinCent{i}(2)); 38 | BigAvg{i} = zeros(size(CircMask{i}),'single'); 39 | TranBool(i,FrameList{i}) = true; 40 | end 41 | 42 | %% go through the movie and get the average pixel values 43 | disp('averaging preliminary ROIs over the movie'); 44 | [BigPixelAvg] = PixelSetMovieAvg(TranBool,CircMask); 45 | 46 | %% Refine the ROIs 47 | GoodROI = false(1,NumTransients); 48 | 49 | for i = 1:NumTransients 50 | % threshold the averaged transient 51 | TempFrame = blankframe; 52 | TempFrame(CircMask{i}) = BigPixelAvg{i}; 53 | 54 | tryagain = true; 55 | tempthresh = threshold; 56 | while((tryagain) && (tempthresh <= max(TempFrame(:)))) 57 | tempthresh = tempthresh*1.1; 58 | pidxlist = SegmentFrame(TempFrame,[],false,tempthresh); 59 | 60 | % find the matching segment 61 | for j = 1:length(pidxlist) 62 | if (ismember(sub2ind([Xdim Ydim],round(BinCent{i}(2)),round(BinCent{i}(1))),pidxlist{j})) 63 | [~,idx] = max(TempFrame(pidxlist{j})); 64 | %keyboard; 65 | if(ismember(pidxlist{j}(idx),PixelIdxList{i})) 66 | % if new peak is in old ROI things are good 67 | tryagain = false; 68 | GoodROI(i) = true; 69 | PixelIdxList{i} = pidxlist{j}; 70 | PixelAvg{i} = TempFrame(PixelIdxList{i}); 71 | 72 | end 73 | break; 74 | end 75 | end 76 | 77 | end 78 | end 79 | 80 | %% Include only GoodROI (ROI that had some average pixels over threshold) 81 | FrameList = FrameList(GoodROI); 82 | ObjList = ObjList(GoodROI); 83 | PixelAvg = PixelAvg(GoodROI); 84 | PixelIdxList = PixelIdxList(GoodROI); 85 | BigPixelAvg = BigPixelAvg(GoodROI); 86 | CircMask = CircMask(GoodROI); 87 | 88 | NumTransients = sum(GoodROI); 89 | 90 | disp([int2str(sum(GoodROI)),' out of ',int2str(length(GoodROI)),' transients kept after thresholding the averages']); 91 | 92 | % % calculate centroids 93 | % disp('calculating weighted centroids'); 94 | % for i = 1:NumTransients 95 | % boolframe = blankframe; 96 | % boolframe(PixelIdxList{i}) = 1; 97 | % valframe = blankframe; 98 | % valframe(PixelIdxList{i}) = PixelAvg{i}; 99 | % props = regionprops(boolframe,valframe,'WeightedCentroid'); 100 | % oldXcent(i) = props.WeightedCentroid(1); 101 | % oldYcent(i) = props.WeightedCentroid(2); 102 | % end 103 | 104 | %% calculate peaks 105 | for i = 1:NumTransients 106 | [~,idx] = max(PixelAvg{i}); 107 | [Ycent(i),Xcent(i)] = ind2sub([Xdim Ydim],PixelIdxList{i}(idx)); 108 | end 109 | 110 | %% save outputs 111 | disp('saving data'); 112 | Trans2ROI = single(1:NumTransients); 113 | 114 | save TransientROIs.mat Trans2ROI Xcent Ycent FrameList ObjList PixelAvg PixelIdxList BigPixelAvg CircMask; 115 | 116 | 117 | 118 | end 119 | 120 | 121 | -------------------------------------------------------------------------------- /Make_DFF.m: -------------------------------------------------------------------------------- 1 | function [] = Make_DFF(moviefile,outfile) 2 | % [] = Make_DFF(moviefile,outfile) 3 | % 4 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | % This file is part of Tenaspis. 7 | % 8 | % Tenaspis is free software: you can redistribute it and/or modify 9 | % it under the terms of the GNU General Public License as published by 10 | % the Free Software Foundation, either version 3 of the License, or 11 | % (at your option) any later version. 12 | % 13 | % Tenaspis is distributed in the hope that it will be useful, 14 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | % GNU General Public License for more details. 17 | % 18 | % You should have received a copy of the GNU General Public License 19 | % along with Tenaspis. If not, see . 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % 22 | disp('applying the DF/F normalization to a movie'); 23 | 24 | %% Get Parameters and setup frame chunking 25 | [Xdim,Ydim,NumFrames,FrameChunkSize] = Get_T_Params('Xdim','Ydim','NumFrames','FrameChunkSize'); 26 | 27 | ChunkStarts = 1:FrameChunkSize:NumFrames; 28 | ChunkEnds = FrameChunkSize:FrameChunkSize:NumFrames; 29 | ChunkEnds(length(ChunkStarts)) = NumFrames; 30 | NumChunks = length(ChunkStarts); 31 | 32 | %% create output file ('ChunkSize' here not related to FrameChunkSize) 33 | h5create(outfile,'/Object',[Xdim Ydim NumFrames 1],'ChunkSize',[Xdim Ydim 1 1],'Datatype','single'); 34 | 35 | %% Get the average frame of the movie 36 | display('determining average frame'); 37 | avgframe = zeros(Xdim,Ydim); % Initialize variable 38 | 39 | p = ProgressBar(NumChunks); 40 | 41 | for i = 1:NumChunks 42 | FrameList = ChunkStarts(i):ChunkEnds(i); 43 | FrameChunk = LoadFrames(moviefile,FrameList); 44 | FrameChunk(isnan(FrameChunk)) = 0; 45 | avgframe = avgframe+sum(FrameChunk,3); 46 | p.progress; 47 | end 48 | p.stop; 49 | avgframe = avgframe./NumFrames; 50 | 51 | %% normalize frames and save 52 | display('normalizing frames and saving'); 53 | 54 | p = ProgressBar(NumChunks); 55 | 56 | for i = 1:NumChunks 57 | FrameList = ChunkStarts(i):ChunkEnds(i); 58 | FrameChunk = single(LoadFrames(moviefile,FrameList)); 59 | FrameChunk(isnan(FrameChunk)) = 0; 60 | NewChunk = (FrameChunk-avgframe)./avgframe; 61 | 62 | h5write(outfile,'/Object',NewChunk,[1 1 ChunkStarts(i) 1],[Xdim Ydim length(FrameList) 1]); 63 | p.progress; 64 | end 65 | p.stop; 66 | 67 | end 68 | -------------------------------------------------------------------------------- /MergeTransientROIs.m: -------------------------------------------------------------------------------- 1 | function [] = MergeTransientROIs() 2 | % [] = MergeTransientROIs() 3 | % Merges calcium transient ROIs into neuron ROIs 4 | 5 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % This file is part of Tenaspis. 8 | % 9 | % Tenaspis is free software: you can redistribute it and/or modify 10 | % it under the terms of the GNU General Public License as published by 11 | % the Free Software Foundation, either version 3 of the License, or 12 | % (at your option) any later version. 13 | % 14 | % Tenaspis is distributed in the hope that it will be useful, 15 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | % GNU General Public License for more details. 18 | % 19 | % You should have received a copy of the GNU General Public License 20 | % along with Tenaspis. If not, see . 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | % 23 | disp('merging transient ROIs into neuron ROIs'); 24 | 25 | %% load parameters 26 | [DistanceThresholdList,Xdim,Ydim,NumFrames,ROIBoundaryCoeff,MinNumTransients] = Get_T_Params('DistanceThresholdList','Xdim','Ydim','NumFrames','ROIBoundaryCoeff','MinNumTransients'); 27 | 28 | %% load data 29 | load('TransientROIs.mat','Trans2ROI','Xcent','Ycent','FrameList','ObjList','PixelAvg','PixelIdxList','BigPixelAvg','CircMask'); 30 | NumIterations = 0; 31 | NumCT = length(Trans2ROI); 32 | oldNumCT = NumCT; 33 | 34 | % run AutoMergeClu, each time incrementing the distance threshold 35 | % Since clusters start out temporally and spatially independent from one 36 | % another, this loop starts out by merging all the clusters that are very 37 | % close to one another into the same new cluster, then bumping up the 38 | % distance threshold incrementally until no new clusters are created or the 39 | % max distance threshold is reached. 40 | for i = 1:length(DistanceThresholdList) 41 | Cchanged = 1; 42 | oldNumCT = NumCT; % Update number 43 | while Cchanged == 1 44 | disp(['Merging neurons, iteration #',num2str(NumIterations+1),' distance ',num2str(DistanceThresholdList(i))]) 45 | 46 | % Iteratively merge spatially distant clusters together 47 | [Trans2ROI,PixelIdxList,Xcent,Ycent,FrameList,ObjList,PixelAvg,BigPixelAvg] = AttemptTransientMerges(DistanceThresholdList(i),Trans2ROI,PixelIdxList,Xcent,Ycent,FrameList,ObjList,PixelAvg,BigPixelAvg,CircMask); 48 | NumIterations = NumIterations+1; % Update number of iterations 49 | NumClu(NumIterations) = length(unique(Trans2ROI)); % Update number of clusters 50 | DistUsed(NumIterations) = DistanceThresholdList(i); % Updated distance threshold used 51 | 52 | if (NumClu(NumIterations) == oldNumCT) 53 | % If you end up with the same number of clusters as the previous iteration, exit 54 | break; 55 | else 56 | % Save number of clusters 57 | oldNumCT = NumClu(NumIterations); 58 | end 59 | end 60 | end 61 | 62 | %% Unpack the variables calculated above 63 | disp('Final ROI refinement'); 64 | NeuronROIidx = unique(Trans2ROI); % Get unique clusters and mappings between clusters and neurons 65 | NumNeurons = length(NeuronROIidx); % Final number of neurons 66 | blankframe = zeros(Xdim,Ydim,'single'); 67 | 68 | [NeuronPixelIdxList,NeuronImage,NeuronAvg,NeuronFrameList,NeuronObjList] = deal(cell(1,NumNeurons)); 69 | 70 | NeuronActivity = false(NumNeurons,NumFrames); 71 | 72 | for i = 1:NumNeurons 73 | currtran = NeuronROIidx(i); 74 | temp = blankframe; 75 | temp(PixelIdxList{currtran}) = PixelAvg{currtran}; 76 | temp = temp >= (max(PixelAvg{currtran})*ROIBoundaryCoeff); 77 | b = bwconncomp(temp,4); 78 | for j = 1:b.NumObjects 79 | if(~isempty(intersect(b.PixelIdxList{j},PixelIdxList{currtran}))) 80 | NeuronPixelIdxList{i} = b.PixelIdxList{j}; 81 | temp = blankframe; 82 | temp(NeuronPixelIdxList{i}) = 1; 83 | NeuronImage{i} = temp; 84 | [~,idx2] = ismember(NeuronPixelIdxList{i},CircMask{currtran}); 85 | NeuronAvg{i} = BigPixelAvg{currtran}(idx2); 86 | NeuronFrameList{i} = FrameList{currtran}; 87 | NeuronObjList{i} = ObjList{currtran}; 88 | NeuronActivity(i,NeuronFrameList{i}) = true; 89 | break; 90 | end 91 | end 92 | end 93 | 94 | %% Kill off the singletons! (presumed to be noise) 95 | for i = 1:NumNeurons 96 | temp = NP_FindSupraThresholdEpochs(NeuronActivity(i,:),eps); 97 | nTrans(i) = size(temp,1); 98 | end 99 | 100 | OKcount = nTrans >= MinNumTransients; 101 | NumNeurons = sum(OKcount); 102 | 103 | NeuronPixelIdxList = NeuronPixelIdxList(OKcount); 104 | NeuronImage = NeuronImage(OKcount); 105 | NeuronAvg = NeuronAvg(OKcount); 106 | NeuronFrameList = NeuronFrameList(OKcount); 107 | NeuronObjList = NeuronObjList(OKcount); 108 | NeuronROIidx = NeuronROIidx(OKcount); 109 | NeuronActivity = NeuronActivity((OKcount),:); 110 | nTrans = nTrans(OKcount); 111 | 112 | NeuronTraces = MakeTracesAndCorrs(NeuronPixelIdxList,NeuronAvg); 113 | 114 | disp('saving outputs'); 115 | save SegmentationROIs.mat NeuronPixelIdxList NeuronImage NeuronAvg NeuronFrameList ... 116 | NeuronObjList NeuronROIidx NumNeurons NeuronActivity NeuronTraces nTrans Trans2ROI 117 | 118 | end -------------------------------------------------------------------------------- /MidpointCircle.m: -------------------------------------------------------------------------------- 1 | % Draw a cInMatrcle InMatn a matrInMatx usInMatng the InMatnteger mInMatdpoInMatnt cInMatrcle algorInMatthm 2 | % Does not mInMatss or repeat pInMatxels 3 | % Created by : Peter Bone 4 | % Created : 19th March 2007 5 | function out = MidpointCircle(Xdim,Ydim, radius, xc, yc) 6 | 7 | InMat = zeros(Xdim,Ydim,'single'); 8 | 9 | value = 1; 10 | 11 | xc = int16(xc); 12 | yc = int16(yc); 13 | 14 | x = int16(0); 15 | y = int16(radius); 16 | d = int16(1 - radius); 17 | 18 | InMat(xc, yc+y) = value; 19 | InMat(xc, yc-y) = value; 20 | InMat(xc+y, yc) = value; 21 | InMat(xc-y, yc) = value; 22 | 23 | while ( x < y - 1 ) 24 | x = x + 1; 25 | if ( d < 0 ) 26 | d = d + x + x + 1; 27 | else 28 | y = y - 1; 29 | a = x - y + 1; 30 | d = d + a + a; 31 | end 32 | InMat( x+xc, y+yc) = value; 33 | InMat( y+xc, x+yc) = value; 34 | InMat( y+xc, -x+yc) = value; 35 | InMat( x+xc, -y+yc) = value; 36 | InMat(-x+xc, -y+yc) = value; 37 | InMat(-y+xc, -x+yc) = value; 38 | InMat(-y+xc, x+yc) = value; 39 | InMat(-x+xc, y+yc) = value; 40 | end 41 | 42 | for ii = xc-int16(radius):xc+(int16(radius)) 43 | for jj = yc-int16(radius):yc+(int16(radius)) 44 | tempR = sqrt((double(ii) - double(xc)).^2 + (double(jj) - double(yc)).^2); 45 | if(tempR <= double(int16(radius))) 46 | InMat(ii,jj)=value; 47 | end 48 | end 49 | end 50 | 51 | out = single(find(InMat)); -------------------------------------------------------------------------------- /NP_FindSupraThresholdEpochs.m: -------------------------------------------------------------------------------- 1 | function Epochs = NP_FindSupraThresholdEpochs(x,InThresh,omitends) 2 | % Epochs = NP_FindSupraThresholdEpochs(x,InThresh,omitends) 3 | % 4 | % Finds epochs where consecutive values of x are above InThresh. 5 | % 6 | % INPUTS: 7 | % x: one-dimensional array of values you wish to evaluate 8 | % 9 | % InThresh: threhold for x 10 | % 11 | % omitends: if x starts or ends in an epoch, omit these as valid 12 | % 13 | % 14 | % OUTPUTS: 15 | % 16 | % Epochs: a num_epochs x 2 array with the start and end indices for each 17 | % epoch. 18 | % 19 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % This file is part of Tenaspis. 22 | % 23 | % Tenaspis is free software: you can redistribute it and/or modify 24 | % it under the terms of the GNU General Public License as published by 25 | % the Free Software Foundation, either version 3 of the License, or 26 | % (at your option) any later version. 27 | % 28 | % Tenaspis is distributed in the hope that it will be useful, 29 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | % GNU General Public License for more details. 32 | % 33 | % You should have received a copy of the GNU General Public License 34 | % along with Tenaspis. If not, see . 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | if (nargin < 3) 37 | omitends = 1; 38 | end 39 | 40 | OverInThresh = (x > InThresh); 41 | % InEpoch = 0; 42 | % NumEpochs = 0; 43 | 44 | % ThreshEpochs= []; 45 | % 46 | % for i = 1:length(x) 47 | % if((OverInThresh(i) == 0) && (InEpoch == 1)) 48 | % ThreshEpochs(NumEpochs,2) = i-1; 49 | % InEpoch = 0; 50 | % continue; 51 | % end 52 | % 53 | % if((OverInThresh(i) == 1) && (InEpoch == 0)) 54 | % % New Epoch 55 | % NumEpochs = NumEpochs + 1; 56 | % ThreshEpochs(NumEpochs,1) = i; 57 | % InEpoch = 1; 58 | % continue; 59 | % end 60 | % end 61 | 62 | % Simplistic and faster way to do the above. 63 | deltaOverInThresh = diff([0 OverInThresh]); %Take the difference of the logical vector. 64 | onsets = find(deltaOverInThresh==1); %Find indices where OverInThresh went from 0 to 1. 65 | offsets = find(deltaOverInThresh==-1) - 1; %Find indices where OverInThresh went from 1 to 0. 66 | NumEpochs = size(onsets,2); %Number of epochs. 67 | if NumEpochs > 0 %If there is ever a suprathreshold event... 68 | ThreshEpochs(:,1) = onsets; 69 | 70 | if size(offsets,2) == NumEpochs 71 | ThreshEpochs(:,2) = offsets; 72 | else %Handles the case for when the trace is still active when the recording cuts off. 73 | ThreshEpochs(1:size(offsets,2),2) = offsets; 74 | ThreshEpochs(end,2) = length(x); 75 | end 76 | 77 | else %Otherwise, set empty. 78 | ThreshEpochs = []; 79 | end 80 | 81 | % if(OverInThresh(end) == 1) 82 | % ThreshEpochs(NumEpochs,2) = length(x); 83 | % end 84 | 85 | if (omitends == 1) 86 | if (OverInThresh(end)) 87 | %Still in an epoch at the end, omit it 88 | NumEpochs = NumEpochs - 1; 89 | ThreshEpochs = ThreshEpochs(1:NumEpochs,:); 90 | end 91 | 92 | if (OverInThresh(1)) 93 | NumEpochs = NumEpochs-1; 94 | ThreshEpochs = ThreshEpochs(2:NumEpochs+1,:); 95 | end 96 | end 97 | 98 | Epochs = ThreshEpochs; 99 | 100 | end -------------------------------------------------------------------------------- /OldMakeCircMask.m: -------------------------------------------------------------------------------- 1 | function [cmask] = OldMakeCircMask(Xdim,Ydim,radius,Xcent,Ycent) 2 | % Based on a stackoverflow response from user Amro 3 | 4 | t = linspace(0, 2*pi, 50); %# approximate circle with 50 points 5 | r = radius; %# radius 6 | c = [Xcent Ycent]; 7 | 8 | BW = poly2mask(r*cos(t)+c(1), r*sin(t)+c(2), Xdim, Ydim); 9 | cmask = single(find(BW)); 10 | end -------------------------------------------------------------------------------- /ParseTenaspisInput.m: -------------------------------------------------------------------------------- 1 | function [animal_id,sess_date,sess_num,no_movie_process,ManMask,no_blobs] = ParseTenaspisInput(args); 2 | % [animal_id,sess_date,sess_num,no_movie_process,ManMask,no_blobs] = ParseTenaspisInput(args); 3 | % 4 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | % This file is part of Tenaspis. 7 | % 8 | % Tenaspis is free software: you can redistribute it and/or modify 9 | % it under the terms of the GNU General Public License as published by 10 | % the Free Software Foundation, either version 3 of the License, or 11 | % (at your option) any later version. 12 | % 13 | % Tenaspis is distributed in the hope that it will be useful, 14 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | % GNU General Public License for more details. 17 | % 18 | % You should have received a copy of the GNU General Public License 19 | % along with Tenaspis. If not, see . 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | animal_id = []; 22 | sess_date = []; 23 | sess_num = []; 24 | no_movie_process = 0; 25 | ManMask = 0; 26 | no_blobs = 0; 27 | 28 | for i = 1:length(args) 29 | if (mod(i,2) == 0) 30 | continue; 31 | end 32 | if (strcmp(args{i},'animal_id')) 33 | animal_id = args{i+1}; 34 | end 35 | 36 | if (strcmp(args{i},'sess_date')) 37 | sess_date = args{i+1}; 38 | end 39 | 40 | if (strcmp(args{i},'sess_num')) 41 | sess_num = args{i+1}; 42 | end 43 | 44 | if (strcmp(args{i},'no_movie_process')) 45 | no_movie_process = args{i+1}; 46 | end 47 | 48 | if (strcmp(args{i},'manual_mask')) 49 | ManMask = args{i+1}; 50 | end 51 | 52 | if (strcmp(args{i},'no_blobs')) 53 | no_blobs = args{i+1}; 54 | end 55 | 56 | end 57 | 58 | end 59 | 60 | -------------------------------------------------------------------------------- /PercentileCutoff.m: -------------------------------------------------------------------------------- 1 | function [idx] = PercentileCutoff(InMat,val) 2 | 3 | InMatSorted = sort(InMat(:)); 4 | 5 | idx = ceil(val/100*length(InMatSorted)); 6 | idx = InMatSorted(idx); 7 | 8 | 9 | end 10 | 11 | -------------------------------------------------------------------------------- /PixelSetMovieAvg.m: -------------------------------------------------------------------------------- 1 | function [varargout] = PixelSetMovieAvg(varargin) 2 | % [varargout] = PixelSetMovieAvg(varargin) 3 | % calculates averages of pixel sets 4 | % inputs are NxT boolean activation matrices followed by length N cell 5 | % arrays containing pixel indices 6 | 7 | [Xdim,Ydim,NumFrames,FrameChunkSize] = Get_T_Params('Xdim','Ydim','NumFrames','FrameChunkSize'); 8 | 9 | % check that input is formatted right 10 | NumInputs = length(varargin)/2; 11 | if(mod(NumInputs,1) ~= 0) 12 | error('PixelSetMovieAvg requires an even number of inputs, see help'); 13 | end 14 | 15 | %% Chunking variables 16 | FrameChunkSize = FrameChunkSize; 17 | ChunkStarts = 1:FrameChunkSize:NumFrames; 18 | ChunkEnds = FrameChunkSize:FrameChunkSize:NumFrames; 19 | ChunkEnds(length(ChunkStarts)) = NumFrames; 20 | NumChunks = length(ChunkStarts); 21 | ChunkSums = cell(1,NumChunks); 22 | 23 | %% initialize outputs and unpack some variables from varargin for clarity 24 | for i = 1:NumInputs 25 | NumROIs(i) = length(varargin{i*2}); 26 | for j = 1:NumROIs(i) 27 | PixelAvg{i}{j} = single(zeros(size(varargin{i*2}{j}))); 28 | PixelIdx{i}{j} = varargin{i*2}{j}; 29 | ActBool{i}{j} = logical(varargin{(i-1)*2+1}(j,:)); 30 | end 31 | end 32 | 33 | %% average the chunks in parallel 34 | p = ProgressBar(NumChunks); 35 | parfor i = 1:NumChunks 36 | Set_T_Params; 37 | FrameList = ChunkStarts(i):ChunkEnds(i); 38 | ChunkSums{i} = CalcChunkSums(FrameList,NumInputs,NumROIs,PixelIdx,ActBool); 39 | p.progress; 40 | end 41 | p.stop; 42 | 43 | %% unpack the parallelized data, calculate the mean from the sum 44 | for j = 1:NumInputs 45 | for k = 1:NumROIs(j) 46 | for i = 1:NumChunks 47 | PixelAvg{j}{k} = PixelAvg{j}{k} + ChunkSums{i}{j}{k}; 48 | end 49 | PixelAvg{j}{k} = PixelAvg{j}{k}./sum(ActBool{j}{k}); 50 | end 51 | varargout(j) = PixelAvg(j); 52 | end 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | end 63 | 64 | -------------------------------------------------------------------------------- /PlotNeuronOutlines.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SharpWave/TENASPIS/cc33c25069af650149d2322af8f67ec57e199d3d/PlotNeuronOutlines.m -------------------------------------------------------------------------------- /PlotTransientMerge.m: -------------------------------------------------------------------------------- 1 | function [] = PlotTransientMerge(CurrBigPixelAvg,CandBigPixelAvg,idx1,idx2,CircMaskCurr,CircMaskCand,CurrPixelIdx,CandPixelIdx,Trans2ROI,CurrClu,CandIdx) 2 | 3 | % Plot the BigPixelAvg for both. with colorbar, # frames on top. Plot The ROI for both as a line. 4 | % Plot the points in the union as a scatter 5 | 6 | [Xdim,Ydim] = Get_T_Params('Xdim','Ydim'); 7 | 8 | blankframe = zeros(Xdim,Ydim,'single'); 9 | 10 | figure(1); 11 | 12 | s(1) = subplot(1,3,1); 13 | tempframeCurr = blankframe; 14 | tempframeCurr(CircMaskCurr) = CurrBigPixelAvg; 15 | MaxVal = max(tempframeCurr(CurrPixelIdx)); 16 | imagesc(tempframeCurr);axis image;caxis([0.01 MaxVal]);hold on;colorbar; 17 | title(['# transients',int2str(length(find(Trans2ROI == CurrClu)))]) 18 | tempframeOL = blankframe; 19 | tempframeOL(CurrPixelIdx) = 1; 20 | b1 = bwboundaries(tempframeOL); 21 | plot(b1{1}(:,2),b1{1}(:,1),'-r','LineWidth',1); 22 | 23 | s(2) = subplot(1,3,2); 24 | tempframeCand = blankframe; 25 | tempframeCand(CircMaskCand) = CandBigPixelAvg; 26 | MaxVal = max(tempframeCand(CandPixelIdx)); 27 | imagesc(tempframeCand);axis image;caxis([0.01 MaxVal]);hold on;colorbar; 28 | title(['# transients',int2str(length(find(Trans2ROI == CandIdx)))]) 29 | tempframeOL = blankframe; 30 | tempframeOL(CandPixelIdx) = 1; 31 | b2 = bwboundaries(tempframeOL); 32 | plot(b2{1}(:,2),b2{1}(:,1),'-r','LineWidth',1); 33 | plot(b1{1}(:,2),b1{1}(:,1),'-m','LineWidth',1);hold off; 34 | 35 | subplot(1,3,1); 36 | plot(b2{1}(:,2),b2{1}(:,1),'-m','LineWidth',1);hold off; 37 | 38 | subplot(1,3,3); 39 | plot(CurrBigPixelAvg(idx1),CandBigPixelAvg(idx2),'*');axis equal; 40 | [cr,cp] = corr(CurrBigPixelAvg(idx1),CandBigPixelAvg(idx2),'type','Spearman'); 41 | title(['Corr R: ',num2str(cr),' Corr P: ',num2str(cp)]); 42 | 43 | linkaxes(s); 44 | pause 45 | 46 | end 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TENASPIS 2 | (updated 5/15/2017) 3 | 4 | compatible with MATLAB 2016B (and later) only!!!! 5 | 6 | How to get started: 7 | 8 | 1. Your movie file needs to be motion-corrected, and currently, in the .h5 format used by Inscopix. Scripts for converting .mov and .avi files to .h5 are in the pipeline. 9 | 10 | 2. Examine the parameters in Set_T_Params.m and edit them if needed, then run Set_T_Params. 11 | 12 | 3. Run MakeFilteredMovies.m 13 | 14 | 4. Run Tenaspis4singlesession.m 15 | 16 | outputs are saved in FinalOutput.mat. Important outputs: 17 | 18 | PSAbool: Basically the rastergram for the recording session. N x T, where N is # of neurons and T is # of samples in the session 19 | 20 | NeuronTraces: a struct containing calcium traces for every neuron. Filtered, raw, and first derivative are available. 21 | 22 | NeuronImage: a binary matrix (same size as a movie frame) showing the ROI for each neuron 23 | 24 | NeuronPixelIdxList: same information as NeuronImage but just the list of pixels indices belonging to each ROI 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /RejectBadTransients.m: -------------------------------------------------------------------------------- 1 | function [] = RejectBadTransients() 2 | %UNTITLED2 Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | disp('Rejecting transients based on centroid travel distance and duration criteria'); 6 | 7 | %% load parameters 8 | [MinNumFrames,MaxCentroidTravelDistance] = Get_T_Params('MinNumFrames','MaxCentroidTravelDistance'); 9 | 10 | %% load data 11 | disp('Loading blob and link data'); 12 | load('BlobLinks.mat','FrameList','ObjList'); 13 | load('Blobs.mat','BlobWeightedCentroids'); 14 | 15 | %% setup vars 16 | NumTransients = length(FrameList); 17 | [GoodTransient,NotFirstFrame] = deal(true(1,NumTransients)); 18 | 19 | %% Analyze transient and apply criteria 20 | disp('analyzing transients for rejection'); 21 | for i = 1:NumTransients 22 | FirstFrame = FrameList{i}(1); 23 | LastFrame = FrameList{i}(end); 24 | TransientLength(i) = LastFrame-FirstFrame+1; 25 | 26 | FirstCent = BlobWeightedCentroids{FirstFrame}{ObjList{i}(1)}; 27 | LastCent = BlobWeightedCentroids{LastFrame}{ObjList{i}(end)}; 28 | TravelDist(i) = sqrt((FirstCent(1)-LastCent(1))^2+(FirstCent(2)-LastCent(2))^2); 29 | 30 | NotFirstFrame(i) = ~ismember(1,FrameList{i}); 31 | 32 | GoodTransient(i) = (TransientLength(i) >= MinNumFrames) && (TravelDist(i) < MaxCentroidTravelDistance) && NotFirstFrame(i); 33 | end 34 | 35 | %% optional plotting 36 | figure 37 | subplot(1,2,1); 38 | histogram(TransientLength,0:100);xlabel('transient length'); 39 | subplot(1,2,2); 40 | histogram(TravelDist,0:0.1:15);xlabel('travel distance'); 41 | 42 | %% save data for analysis purposes 43 | save TransientStats.mat TransientLength TravelDist; 44 | 45 | %% keep the good ones 46 | TravelDist = TravelDist(GoodTransient); 47 | TransientLength = TransientLength(GoodTransient); 48 | FrameList = FrameList(GoodTransient); 49 | ObjList = ObjList(GoodTransient); 50 | 51 | disp(['kept ',int2str(sum(GoodTransient)),' out of ',int2str(length(GoodTransient)),' transients']); 52 | 53 | %% save data 54 | disp('saving good transients'); 55 | save VettedTransients.mat TravelDist TransientLength FrameList ObjList; 56 | 57 | 58 | -------------------------------------------------------------------------------- /SegmentFrame.m: -------------------------------------------------------------------------------- 1 | function [BlobPixelIdxList,BlobWeightedCentroids,BlobMinorAxisLength] = SegmentFrame(frame,PrepMask,CheckPeaks,ThreshOverride) 2 | % [BlobPixelIdxList,BlobWeightedCentroids,BlobMinorAxisLength] = SegmentFrame(frame,PrepMask) 3 | % 4 | % Identifies local maxima and separates them out into neuron sized blobs. 5 | % Does so in an adaptive manner by iteratively bumping up the threshold 6 | % until no new blobs are identified. 7 | % 8 | % INPUTS: 9 | % 10 | % frame: a frame from an braing imaging movie 11 | % 12 | % PrepMask: a logical array the same size as frame indicating which areas 13 | % should be used for blob detection (ones) and which should be excluded 14 | % (zeros). 15 | % 16 | % OUTPUTS: 17 | % 18 | % BlobPixelIdxList: Cell array of lists of pixel indices belonging to 19 | % each blob 20 | % 21 | % BlobWeightedCentroids: Cell array of weighted centroid values for each 22 | % blob 23 | % 24 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 25 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 26 | % This file is part of Tenaspis. 27 | % 28 | % Tenaspis is free software: you can redistribute it and/or modify 29 | % it under the terms of the GNU General Public License as published by 30 | % the Free Software Foundation, either version 3 of the License, or 31 | % (at your option) any later version. 32 | % 33 | % Tenaspis is distributed in the hope that it will be useful, 34 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 | % GNU General Public License for more details. 37 | % 38 | % You should have received a copy of the GNU General Public License 39 | % along with Tenaspis. If not, see . 40 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41 | % 42 | %% Get Parameters 43 | 44 | [Xdim,Ydim,threshold,threshsteps,MaxBlobRadius,MinBlobRadius,MaxAxisRatio,MinSolidity] = ... 45 | Get_T_Params('Xdim','Ydim','threshold','threshsteps','MaxBlobRadius','MinBlobRadius','MaxAxisRatio','MinSolidity'); 46 | 47 | if(exist('ThreshOverride','var')) 48 | threshold = ThreshOverride; 49 | end 50 | 51 | if (~exist('PrepMask','var')) 52 | PrepMask = true(Xdim,Ydim); 53 | else 54 | if (isempty(PrepMask)) 55 | PrepMask = true(Xdim,Ydim); 56 | end 57 | end 58 | 59 | if (~exist('CheckPeaks','var')) 60 | CheckPeaks = true; 61 | end 62 | 63 | % Derived Parameters 64 | MaxBlobArea = ceil((MaxBlobRadius^2)*pi); 65 | MinBlobArea = ceil((MinBlobRadius^2)*pi); 66 | 67 | %% Setup variables for below 68 | badpix = find(PrepMask == 0); % Locations of pixels that are outside the mask and should be excluded 69 | blankframe = zeros(Xdim,Ydim,'single'); 70 | 71 | %% segment the frame at initial threshold 72 | threshframe = frame > threshold; % apply threshold, make it into a logical array 73 | threshframe = bwareaopen(threshframe,MinBlobArea,4); % remove blobs smaller than minpixels 74 | 75 | % Determine initial blobs and measurements 76 | rp = regionprops(bwconncomp(threshframe,4),'Area','Solidity','MajorAxisLength','MinorAxisLength','SubarrayIdx','Image','PixelIdxList'); 77 | GoodBlob = true(length(rp),1); 78 | 79 | % Determine whether any of the blobs go off of the mask and eliminate them 80 | for i = 1:length(rp) 81 | if (~isempty(intersect(rp(i).PixelIdxList,badpix))) 82 | GoodBlob(i) = false; 83 | end 84 | end 85 | rp = rp(GoodBlob); 86 | GoodBlob = true(length(rp),1); 87 | BlobPixelIdxList = cell(1,length(rp)); 88 | BlobWeightedCentroids = cell(1,length(rp)); 89 | BlobMinorAxisLength = zeros(1,length(rp),'single'); 90 | 91 | %% Test each blob for blob shape criteria; raise threshold and re-test if test fails 92 | for i = 1:length(rp) 93 | 94 | props = rp(i); 95 | currthresh = threshold; 96 | 97 | % Make a small matrix with actual and binarized pixel data for the blob 98 | SmallImage = frame(props.SubarrayIdx{1},props.SubarrayIdx{2}); 99 | SmallImage(props.Image == 0) = 0; 100 | BinImage = SmallImage > currthresh; 101 | 102 | % Sort the pixel matrix to determine the set of thresholds that will be used 103 | smsort = sort(SmallImage(:)); 104 | smsort = smsort(smsort > 0); 105 | PixPerThresh = ceil(length(smsort)./threshsteps); 106 | threshlist = smsort(PixPerThresh:PixPerThresh:length(smsort)); 107 | ThreshIdx = 1; 108 | 109 | % Determine whether initial blob passes size and shape criteria 110 | AxisRatio = props.MajorAxisLength/props.MinorAxisLength; 111 | CriteriaOK = (props.Solidity > MinSolidity) && (AxisRatio < MaxAxisRatio) && (props.Area < MaxBlobArea); 112 | 113 | while(~CriteriaOK && (ThreshIdx <= length(threshlist))) 114 | % Criteria not met on last check, but still thresholds to check 115 | 116 | % First increase threshold and take new binarized pixel data 117 | currthresh = threshlist(ThreshIdx); 118 | BinImage = SmallImage > currthresh; 119 | BinImage = bwareaopen(BinImage,MinBlobArea,4); 120 | 121 | % then check for the blob criteria again 122 | temp_props = regionprops(bwconncomp(BinImage,4),'Area','Solidity','MajorAxisLength','MinorAxisLength','SubarrayIdx','Image'); 123 | 124 | if (length(temp_props) ~= 1) 125 | % zero or multiple areas in the blob, abandon blob 126 | break; % CriteriaOK is still 0 127 | end 128 | 129 | AxisRatio = temp_props.MajorAxisLength/temp_props.MinorAxisLength; 130 | CriteriaOK = (temp_props.Solidity > MinSolidity) && (AxisRatio < MaxAxisRatio) && (temp_props.Area < MaxBlobArea); 131 | ThreshIdx = ThreshIdx + 1; 132 | end 133 | 134 | if (~CriteriaOK) 135 | % Couldn't find threshold that satisfied criteria 136 | GoodBlob(i) = 0; 137 | continue; 138 | end 139 | 140 | % Criteria satisfied, test for multiple peaks 141 | CritBinImage = BinImage; 142 | 143 | if (CheckPeaks) 144 | while (ThreshIdx <= length(threshlist)) 145 | % while more thresholds to check 146 | % take new binarized pixel data 147 | currthresh = threshlist(ThreshIdx); 148 | BinImage = SmallImage > currthresh; 149 | temp_conn = bwconncomp(BinImage,8); 150 | if (temp_conn.NumObjects > 1) 151 | % multiple peaks, abandon ship! 152 | GoodBlob(i) = 0; 153 | break; 154 | end 155 | if (temp_conn.NumObjects == 0) 156 | % this probably never happens 157 | break; 158 | end 159 | if (length(temp_conn.PixelIdxList{1}) < MinBlobArea) 160 | % Blob got small after raising threshold. At this point there 161 | % wouldn't be multiple peaks that we care about so the blob 162 | % will be included 163 | break; 164 | end 165 | ThreshIdx = ThreshIdx + 1; 166 | end 167 | end 168 | if (GoodBlob(i)) 169 | % Blob passed shape, size, and "multiple peak" criteria, so determine Pixel List and centroids in full frame coordinates 170 | tempbinframe = blankframe; 171 | tempbinframe(props.SubarrayIdx{1},props.SubarrayIdx{2}) = CritBinImage; 172 | temp_props = regionprops(bwconncomp(tempbinframe,4),frame,'PixelIdxList','WeightedCentroid','MinorAxisLength'); 173 | BlobPixelIdxList{i} = single(temp_props.PixelIdxList); 174 | BlobWeightedCentroids{i} = single(temp_props.WeightedCentroid); 175 | BlobMinorAxisLength(i) = single(temp_props.MinorAxisLength); 176 | end 177 | end 178 | 179 | %% Keep only blobs passing the shape, size, and peak criteria 180 | 181 | BlobPixelIdxList = BlobPixelIdxList(GoodBlob); 182 | BlobWeightedCentroids = BlobWeightedCentroids(GoodBlob); 183 | BlobMinorAxisLength = BlobMinorAxisLength(GoodBlob); 184 | 185 | end 186 | -------------------------------------------------------------------------------- /SegmentFrameChunk.m: -------------------------------------------------------------------------------- 1 | function BlobChunk = SegmentFrameChunk(FrameList,PrepMask) 2 | %BlobChunk = SegmentFrameChunk(FrameList,PrepMask) 3 | % Detailed explanation goes here 4 | 5 | FrameChunk = LoadFrames('BPDFF.h5',FrameList); 6 | 7 | NumFrames = size(FrameChunk,3); 8 | BlobChunk.BlobPixelIdxList = cell(1,NumFrames); 9 | BlobChunk.BlobWeightedCentroids = cell(1,NumFrames); 10 | BlobChunk.BlobMinorAxisLength = cell(1,NumFrames); 11 | 12 | for i = 1:NumFrames 13 | [BlobChunk.BlobPixelIdxList{i},... 14 | BlobChunk.BlobWeightedCentroids{i},... 15 | BlobChunk.BlobMinorAxisLength{i}] = ... 16 | SegmentFrame(squeeze(FrameChunk(:,:,i)),PrepMask); 17 | end 18 | 19 | end -------------------------------------------------------------------------------- /Set_T_Params.m: -------------------------------------------------------------------------------- 1 | function Set_T_Params(moviefile) 2 | % function Set_T_Params(moviefile) 3 | % 4 | % Sets Tenaspis parameters. Must be called at beginning of run 5 | % 6 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | % This file is part of Tenaspis. 9 | % 10 | % Tenaspis is free software: you can redistribute it and/or modify 11 | % it under the terms of the GNU General Public License as published by 12 | % the Free Software Foundation, either version 3 of the License, or 13 | % (at your option) any later version. 14 | % 15 | % Tenaspis is distributed in the hope that it will be useful, 16 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | % GNU General Public License for more details. 19 | % 20 | % You should have received a copy of the GNU General Public License 21 | % along with Tenaspis. If not, see . 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | 24 | clear T_PARAMS; 25 | global T_PARAMS; 26 | 27 | %% The dimensions of the movie - load from .mat file if possible, to save time when this function is called by parfor workers 28 | if (~exist('MovieDims.mat','file')) 29 | info = h5info(moviefile,'/Object'); 30 | [T_PARAMS.Xdim,Xdim] = deal(info.Dataspace.Size(1)); 31 | [T_PARAMS.Ydim,Ydim] = deal(info.Dataspace.Size(2)); 32 | [T_PARAMS.NumFrames,NumFrames] = deal(info.Dataspace.Size(3)); 33 | save MovieDims.mat Xdim Ydim NumFrames 34 | else 35 | load('MovieDims.mat','Xdim','Ydim','NumFrames'); 36 | T_PARAMS.Xdim = Xdim; 37 | T_PARAMS.Ydim = Ydim; 38 | T_PARAMS.NumFrames = NumFrames; 39 | end 40 | 41 | %% Implementation parameters (i.e. no effect on results) 42 | T_PARAMS.FrameChunkSize = 1250; % Number of frames to load at once for various functions. Setting this too high will crash due to RAM 43 | T_PARAMS.ROICircleWindowRadius = 35; % If this is too small the program crashes; higher values use more RAM and increase run time. Default is overkill 44 | 45 | %% General parameters used by multiple scripts 46 | T_PARAMS.SampleRate = 10; % Sample rate of the movie to be processed. 47 | 48 | %% MakeFilteredMovies 49 | T_PARAMS.HighPassRadius = 20; % Smoothing radius for high pass disk-kernel filtering. EDIT:SPACE 50 | T_PARAMS.LowPassRadius = 3; % Smoothing radius for low pass disk-kernel filtering. EDIT:SPACE 51 | 52 | %% ExtractBlobs / SegmentFrame params 53 | T_PARAMS.threshold = 0.01; % Pixel intensity baseline threshold for detecting blobs. Lower means more blobs but more noise and longer runs 54 | 55 | T_PARAMS.threshsteps = 10; % number of threshold increments to try in order to find criterion region within non-criterion blob and check for multiple peaks in criterion blobs 56 | % higher values mean slightly bigger ROIs at the cost of multiplying run time - edit this with care. 57 | 58 | T_PARAMS.MaxBlobRadius = 10; % Maximum radius for a circular shaped blob to be included. 59 | % trade off between not including multiple neurons and missing pixels that reliably 60 | % participate and can be used to differentiate ROIs in subsequent steps 61 | % EDIT:SPACE 62 | 63 | T_PARAMS.MinBlobRadius = 5; % Minimum radius for circular shaped blob to be included. 64 | % Increasing this eliminates noise at the cost 65 | % of losing low-intensity blobs. EDIT:SPACE 66 | 67 | T_PARAMS.MaxAxisRatio = 2; % Maximum ratio of major to minor axis length for blobs. Lower means more circular. 68 | % Keeps overly slivery blobs and some juxtaposition artifacts out of the data 69 | 70 | T_PARAMS.MinSolidity = 0.95; % Minimum blob 'solidity', which is the ratio of the perimeter of the convex hull to the actual perimeter. 71 | % Prevents jagged and strange shaped blobs; noise blobs picked up at low thresholds 72 | 73 | %% LinkBlobs params 74 | T_PARAMS.BlobLinkThresholdCoeff = 1; % multiplier for the blob minor axis length to determine whether to link blobs across frames 75 | % the higher this is, the more the blob is permitted to move on successive frames 76 | % The linkblobs procedure has almost no pitfalls; I wouldn't bother messing with this 77 | 78 | %% RejectBadTransients params 79 | T_PARAMS.MaxCentroidTravelDistance = 2; % maximum net distance that the centroid of a transient can travel. 80 | % Eliminates spurious blobs from overlapping transients. 81 | % EDIT:SPACE 82 | 83 | T_PARAMS.MinNumFrames = ceil(4/(20/T_PARAMS.SampleRate)); % minimum number of frames for transient to be included. EDIT:TIME 84 | 85 | %% MakeTransientROIs params 86 | T_PARAMS.MinPixelPresence = 0.5; %0.6321; % minimum fraction of frames in the transient for a pixel to be counted as part of an ROI. 87 | % Setting to 1 means the pixels in the smallest blob in the transient (often right before fadeout) will be chosen. 88 | % Setting to 0 means the maximum blob extent will be used. 89 | 90 | 91 | %% MergeTransientROIs paramsload 92 | T_PARAMS.DistanceThresholdList = [0,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,7,8,9,10]; % list of progressively increasing distance thresholds to try. EDIT:SPACE 93 | % With the correlation test being pretty robust I'm not sure that small increments are necessary 94 | T_PARAMS.MaxTransientMergeCorrP = 0.01; % maximum correlation p value for a transient merge 95 | T_PARAMS.MinTransientMergeCorrR = 0.2; % minimum correlation r value for a transient merge. 96 | % I played with higher values and they don't help us avoid bad merges, but cause some under-merging 97 | 98 | T_PARAMS.ROIBoundaryCoeff = 0.5; % ROI boundaries are determined by setting a threshold at some fraction of the peak mean intensity 99 | % lower values mean bigger ROIs 100 | 101 | T_PARAMS.SmoothSize = ceil(5/(20/T_PARAMS.SampleRate)); % length of window for temporal smoothing of traces. EDIT:SPACE 102 | T_PARAMS.MinNumTransients = 1; % ROIs with fewer transients than this are cut after segmentation. recommend setting to 1, meaning no cut 103 | 104 | %% DetectTracePSA 105 | T_PARAMS.AmplitudeThresholdCoeff = 2/3; % Determines amplitude threshold for finding new transients. 106 | % setting to 0 means new transient threshold is minimum intensity of segmentation-detected transients 107 | % setting to 1 means threshold is zero - Higher values mean lower threshold. 108 | 109 | T_PARAMS.CorrPthresh = 0.00001; % p value threshold for correlation between ROI average and ROI on a single frame 110 | 111 | T_PARAMS.SlopeThresh = 0.5; % minimum slope (z-score) for a new PSA epoch (i.e., positive slope) to begin 112 | % use a lower value if detected slopes aren't 113 | % starting early enough. Use a higher value if 114 | % 115 | 116 | T_PARAMS.MinPSALen = ceil(4/(20/T_PARAMS.SampleRate)); % minimum duration of PSA epochs, enforced right after detection. Helps to eliminate noise; 250ms is awfully short for a spiking epoch 117 | % EDIT:TIME 118 | 119 | %% MergeSuspiciousNeighors 120 | T_PARAMS.MinBinSimRank = 0.94; % minimum rank normalized Binary Similarity between two ROI actvity vectors for a merge (similarity must be this percentile of non-adjacent similarities) 121 | T_PARAMS.ROIoverlapthresh = 0.5; % minimum normalized overlap (% of area of smallest ROI) between ROIs for a merge 122 | 123 | T_PARAMS.MaxGapFillLen = ceil(4/(20/T_PARAMS.SampleRate)); % After detecting rising slopes, if the gaps between PSA epochs are this # of samples or smaller, fill them in. 124 | % smooths the skippyness in some borderline 125 | % cases. % EDIT:TIME 126 | 127 | %% FinalizeData 128 | T_PARAMS.MinNumPSAepochs = 4; % minimum number of PSA epochs for inclusion in final ROI set. i.e., we delete the ones with less than this 129 | % if there are some "straggler" under-merged ROIs this can help to remove them. 130 | % Higher values will yield a "cleaner" data set at the cost of omitting potentially valid but low firing neurons 131 | % EDIT:TIME? (questionable) 132 | end 133 | 134 | -------------------------------------------------------------------------------- /Tenaspis3.m: -------------------------------------------------------------------------------- 1 | function Tenaspis3(md,varargin) 2 | %Tenaspis3(md,varargin) 3 | % 4 | % Highest level function for extracting neurons from single-photon 5 | % imaging data. 6 | % 7 | % INPUTS 8 | % md: Master Directory entry. 9 | % 10 | % (optional) 11 | % preprocess: logical, whether you want to run MakeT2Movies. 12 | % Default=whether SLPDF exists in your directory. 13 | % 14 | % d1: logical, whether you want to make first derivative movie 15 | % during MakeT2Movies. Default=false. 16 | % 17 | % manualmask: logical, whether you want to draw mask manually. 18 | % Default=false. 19 | % 20 | % masterdirectory: string, path to master directory. 21 | % Default='C:/MasterData'. 22 | % 23 | % min_trans_length: scalar, minimum transient frame duration to be 24 | % included during MakeNeurons. Default=10. 25 | % 26 | % Tenaspis: Technique for Extracting Neuronal Activity from Single Photon 27 | % Image Sequences 28 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % This file is part of Tenaspis. 31 | % 32 | % Tenaspis is free software: you can redistribute it and/or modify 33 | % it under the terms of the GNU General Public License as published by 34 | % the Free Software Foundation, either version 3 of the License, or 35 | % (at your option) any later version. 36 | % 37 | % Tenaspis is distributed in the hope that it will be useful, 38 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 39 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 40 | % GNU General Public License for more details. 41 | % 42 | % You should have received a copy of the GNU General Public License 43 | % along with Tenaspis. If not, see . 44 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 45 | 46 | %% Parse inputs. 47 | cd(md.Location); 48 | 49 | p = inputParser; 50 | p.addRequired('md',@(x) isstruct(x)); 51 | p.addParameter('preprocess',... 52 | ~exist(fullfile(pwd,'SLPDF.h5'),'file')); %Make SLPDF and DFF movies. 53 | p.addParameter('d1',false); %Make first derivative movie. 54 | p.addParameter('manualmask',false); %Draw mask manually. 55 | p.addParameter('masterdirectory',... 56 | 'C:/MasterData',@(x) ischar(x)); %Master directory. 57 | p.addParameter('min_trans_length',... %Minimum transient length. 58 | 10,@(x) isnumeric(x) && isscalar(x)); 59 | p.parse(md,varargin{:}); 60 | 61 | %Compile. 62 | preprocess = p.Results.preprocess; 63 | d1 = p.Results.d1; 64 | manualmask = p.Results.manualmask; 65 | global MasterDirectory; %MasterDirectory is now a global variable. 66 | MasterDirectory = p.Results.masterdirectory; %Insert line 'global MasterDirectory' to fetch. 67 | min_trans_length = p.Results.min_trans_length; 68 | 69 | %Check whether initial mask exists. 70 | maskExist = exist(fullfile(MasterDirectory,[md.Animal,'_initialmask.mat']),'file'); 71 | 72 | %% Make SLPDF and DFF movies. 73 | if preprocess 74 | disp('No SLPDF or DFF detected. Making movies...'); 75 | MakeT2Movies('path',md.Location,'d1',d1); 76 | else 77 | disp('SLPDF and DFF movies found. Proceeding...'); 78 | end 79 | 80 | %% Register the masks. 81 | %Get directory for initial mask. 82 | [initDate,initSession] = GetInitRegMaskInfo(md.Animal); 83 | initDir = ChangeDirectory(md.Animal,initDate,initSession); 84 | 85 | %If initial mask doesn't exist or if manualmask is triggered... 86 | if maskExist==0 || manualmask 87 | disp('Mask does not exist or manual mask triggered. Draw mask now.'); 88 | cd(initDir); 89 | 90 | %Draw mask on the initial session's minimum projection. 91 | MakeMaskSingleSession('DFF.h5'); 92 | 93 | %Save to MasterDirectory. 94 | copyfile('singlesessionmask.mat',fullfile(MasterDirectory,[md.Animal,'_initialmask.mat'])); 95 | copyfile('ICmovie_min_proj.tif',fullfile(MasterDirectory,[md.Animal,'_init_min_proj.tif'])); 96 | end 97 | 98 | %Path for the initial mask. 99 | InitMaskPath = fullfile(MasterDirectory,[md.Animal,'_initialmask.mat']); 100 | 101 | %Image registration. 102 | mask_multi_image_reg(InitMaskPath,initDate,initSession,md); 103 | 104 | %% Extract blobs. 105 | %Load the mask. 106 | cd(md.Location); 107 | load(fullfile(pwd,'mask_reg.mat')); mask_reg = logical(mask_reg); 108 | 109 | disp('Extracting blobs...'); 110 | ExtractBlobs('SLPDF.h5',mask_reg); 111 | 112 | %% Connect blobs into transients. 113 | disp('Making transients...'); 114 | MakeTransients('DFF.h5'); 115 | !del InitClu.mat 116 | 117 | %% Group together individual transients under individual neurons. 118 | disp('Making neurons...'); 119 | MakeNeurons('min_trans_length',min_trans_length); 120 | 121 | %% Pull traces out of each neuron using the High-pass movie. 122 | disp('Normalizing traces...'); 123 | NormalTraces('SLPDF.h5'); 124 | MakeROIavg('SLPDF.h5'); 125 | load('ProcOut.mat','NeuronPixels'); 126 | load('ROIavg.mat'); 127 | MakeROIcorrtraces(NeuronPixels,ROIavg,'SLPDF.h5'); 128 | 129 | %% Expand transients. 130 | disp('Expanding transients...'); 131 | ExpandTransients(0); 132 | 133 | %% Calculate peak of all transients. 134 | AddPoTransients; 135 | 136 | %% Determine rising events/on-times for all transients. 137 | DetectGoodSlopes; 138 | 139 | %% Merge ambiguous neurons. 140 | load ('T2output.mat','FT','NeuronPixels'); 141 | for i = 1:2 142 | FTs{1} = FT; 143 | TrigAvgs = MakeTrigAvg(FTs); 144 | MergeROIs(FT,NeuronPixels,TrigAvgs{1}); 145 | load ('FinalOutput.mat','FT','NeuronPixels'); 146 | end 147 | FTs{1} = FT; 148 | TrigAvgs = MakeTrigAvg(FTs); 149 | MeanT = TrigAvgs{1}; 150 | save('MeanT.mat', 'MeanT', '-v7.3'); 151 | 152 | FinalTraces('SLPDF.h5'); 153 | 154 | end -------------------------------------------------------------------------------- /Tenaspis4.m: -------------------------------------------------------------------------------- 1 | function Tenaspis4(md,varargin) 2 | %Tenaspis4(md,varargin) 3 | % IMPORTANT NOTE: To automate Tenaspis you MUST do three things: 4 | % 1) Add the session(s) in question to your mouse directory (e.g. 5 | % MakeMouseSessionList), 6 | % 2) Designate an initial session you wish to use as a reference for all 7 | % subsequent sessions. 8 | % 3) Run Tenaspis4 with the 'manualmask' flag set to true for the initial 9 | % session you designated in step 2. You will be prompted early on to draw 10 | % a mask around all the good cells (i.e. excluding any dead space and/or 11 | % artifacts). You can then run all subsequent sessions without drawing a 12 | % mask, e.g. Tenaspis4(md) 13 | % 14 | % INPUTS 15 | % md: session entry. 16 | % 17 | % (optional, Name-Pair arguments) 18 | % preprocess: Logical, whether you want to run 19 | % MakeFilteredMovies. The h5 file you wish to run this on must 20 | % be located in the folder 'MotCorrMovie-Objects' in the MD 21 | % directory. Will automatically run if BPDFF.h5 is not 22 | % detected in the MD directory. 23 | % 24 | % d1: Logical, whether you want to make D1Movie. Default = false. 25 | % 26 | % manualmask: Logical, whether you want to manually draw the mask 27 | % for this session. If not, will automatically take mask from 28 | % initial session. Default = false. 29 | % 30 | % MasterDirectory: String, directory containing MD. 31 | % 32 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 33 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 | % This file is part of Tenaspis. 35 | % 36 | % Tenaspis is free software: you can redistribute it and/or modify 37 | % it under the terms of the GNU General Public License as published by 38 | % the Free Software Foundation, either version 3 of the License, or 39 | % (at your option) any later version. 40 | % 41 | % Tenaspis 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 Tenaspis. If not, see . 48 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 49 | 50 | %% Parse inputs. 51 | cd(md.Location); 52 | 53 | p = inputParser; 54 | p.addRequired('md',@(x) isstruct(x)); 55 | p.addParameter('preprocess',... 56 | ~exist(fullfile(pwd,'BPDFF.h5'),'file')); 57 | p.addParameter('d1',false); %Make first derivative movie. 58 | p.addParameter('manualmask',false); %Draw mask manually. 59 | p.addParameter('masterdirectory',... 60 | 'C:/MasterData',@(x) ischar(x)); %Master directory. 61 | p.parse(md,varargin{:}); 62 | 63 | %Compile. 64 | preprocess = p.Results.preprocess; 65 | d1 = p.Results.d1; 66 | manualmask = p.Results.manualmask; 67 | global MasterDirectory; %MasterDirectory is now a global variable. 68 | MasterDirectory = p.Results.masterdirectory; %Insert line 'global MasterDirectory' to fetch. 69 | 70 | %Check whether initial mask exists. 71 | maskExist = exist(fullfile(MasterDirectory,[md.Animal,'_initialmask.mat']),'file'); 72 | 73 | %% Make filtered movies. 74 | if preprocess 75 | disp('BPDFF.h5 and/or LPDFF.h5 not detected. Making movies...'); 76 | cd(fullfile(md.Location,'MotCorrMovie-Objects')); 77 | h5Movie = fullfile(pwd,ls('*.h5')); 78 | 79 | cd(md.Location); 80 | Set_T_Params(h5Movie); 81 | 82 | MakeFilteredMovies(h5Movie,'d1',d1); 83 | else 84 | disp('Appropriate movies detected. Proceeding...'); 85 | end 86 | 87 | %Make first derivative movie if specified. 88 | if d1 89 | disp('Making D1Movie.h5'); 90 | %Temporal smooth. 91 | TempSmoothMovie('LowPass.h5','SMovie.h5',20); 92 | 93 | %First derivative movie. 94 | multiplier_use = DFDT_Movie('SMovie.h5','D1Movie.h5'); 95 | if ~isempty(multiplier_use) 96 | delete D1Movie.h5 97 | multiplier_use = DFDT_Movie('SMovie.h5','D1Movie.h5',... 98 | multiplier_use); 99 | save multiplier.mat multiplier_use 100 | end 101 | delete SMovie.h5 102 | end 103 | 104 | %% Make mask and register it. 105 | %Get directory for initial mask. 106 | [initDate,initSession] = GetInitRegMaskInfo(md.Animal); 107 | initDir = ChangeDirectory(md.Animal,initDate,initSession); 108 | 109 | if maskExist==0 || manualmask 110 | disp('Mask does not exist or manual mask triggered. Draw mask now.'); 111 | cd(initDir); 112 | 113 | %Draw mask on the initial session's minimum projection. 114 | MakeMaskSingleSession('BPDFF.h5'); 115 | 116 | %Save to MasterDirectory. 117 | copyfile('singlesessionmask.mat',fullfile(MasterDirectory,[md.Animal,'_initialmask.mat'])); 118 | copyfile('ICmovie_min_proj.tif',fullfile(MasterDirectory,[md.Animal,'_init_min_proj.tif'])); 119 | end 120 | 121 | %Path for the initial mask. 122 | InitMaskPath = fullfile(MasterDirectory,[md.Animal,'_initialmask.mat']); 123 | 124 | %Image registration. 125 | mask_multi_image_reg(InitMaskPath,initDate,initSession,md); 126 | 127 | %% Extract blobs. 128 | %Load the mask. 129 | cd(md.Location); 130 | load(fullfile(pwd,'mask_reg.mat')); 131 | 132 | %Set new parameters based on BPDFF movie. 133 | Set_T_Params('BPDFF.h5'); 134 | 135 | %Check mask dimensions match movie dimensions. 136 | load('MovieDims.mat','Xdim','Ydim'); 137 | assert(size(mask_reg,1)==Xdim && size(mask_reg,2)==Ydim,['Warning!',... 138 | 'Dimensions of mask and MovieDims do not match.']); 139 | 140 | %Get blobs. 141 | disp('Extracting blobs...'); 142 | ExtractBlobs(mask_reg); 143 | 144 | %% Connect blobs into transients 145 | LinkBlobs(); 146 | RejectBadTransients(); 147 | MakeTransientROIs(); 148 | 149 | %% Group together individual transients under individual neurons and save data 150 | MergeTransientROIs; 151 | InterpretTraces(); 152 | 153 | end -------------------------------------------------------------------------------- /Tenaspis4singlesession.m: -------------------------------------------------------------------------------- 1 | function Tenaspis4singlesession() 2 | % Quick & dirty Tenaspis4 - must be in directory with imaging movie. 3 | % Requires singlesessionmask.mat be present for automated runs 4 | % use MakeMaskSingleSession if needed 5 | 6 | % REQUIREMENT: first call MakeFilteredMovies on your cropped motion-corrected 7 | % movie 8 | 9 | if ~exist('BPDFF.h5','file') 10 | [filename, pathname] = uigetfile({'*.h5;*.tif;*.tiff'}, ... 11 | 'Pick an imaging file:'); 12 | MakeFilteredMovies(fullfile(filename,pathname)); 13 | end 14 | 15 | % set global parameter variable 16 | Set_T_Params('BPDFF.h5'); 17 | 18 | %% Extract Blobs 19 | load singlesessionmask.mat; % if this isn't already present, make it 20 | ExtractBlobs(neuronmask); 21 | 22 | %% Connect blobs into transients 23 | LinkBlobs(); 24 | RejectBadTransients(); 25 | MakeTransientROIs(); 26 | 27 | %% Group together individual transients under individual neurons and save data 28 | MergeTransientROIs; 29 | InterpretTraces(); 30 | 31 | -------------------------------------------------------------------------------- /Tenaspis4testing.m: -------------------------------------------------------------------------------- 1 | function Tenaspis4testing() 2 | % Quick & dirty Tenaspis2 3 | % Requires singlesessionmask.mat be present for automated runs 4 | % use MakeMaskSingleSession if needed 5 | 6 | % REQUIREMENT: first call MakeFilteredMovies on your cropped motion-corrected 7 | % movie 8 | 9 | % set global parameter variable 10 | Set_T_Params('BPDFF.h5'); 11 | 12 | %% Extract Blobs 13 | %load singlesessionmask.mat; % if this isn't already present, make it 14 | 15 | [Xdim,Ydim] = Get_T_Params('Xdim','Ydim'); 16 | neuronmask = ones(Xdim,Ydim); 17 | ExtractBlobs(neuronmask); 18 | 19 | %% Connect blobs into transients 20 | LinkBlobs(); 21 | RejectBadTransients(); 22 | MakeTransientROIs(); 23 | 24 | %% Group together individual transients under individual neurons and save data 25 | MergeTransientROIs; 26 | InterpretTraces(); 27 | 28 | -------------------------------------------------------------------------------- /TenaspisOutputSummary.m: -------------------------------------------------------------------------------- 1 | function [] = TenaspisOutputSummary( input_args ) 2 | % this function calculates and plots all sorts of interesting stats about 3 | % Tenaspis output 4 | 5 | %% variables to consider in GLM: 6 | % ROI area 7 | % ROI Minor/Major axis ratio 8 | % ROI solidity 9 | % ROI distance from "center of prep" 10 | % ROI median transient amplitude 11 | % ROI correlation threshold 12 | % ROI amplitude threshold 13 | 14 | %% output variables to consider in GLM 15 | % ROI # of transients 16 | % some sort of ROI "sketchiness factor" - how much correlation w/ neighbors 17 | % in excess of expectations 18 | % -- expected correlation 19 | 20 | 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /TransientStats.m: -------------------------------------------------------------------------------- 1 | function [DistTrav,MeanThresh] = TransientStats(SegChain) 2 | % [DistTrav,MeanThresh] = TransientStats(SegChain) 3 | % 4 | % Gets statistics on each Transient identified in SegChain 5 | % 6 | % INPUTS: 7 | % 8 | % SegChain: see help for MakeTransients 9 | % 10 | % OUTPUTS: 11 | % 12 | % DistTrav: Absolute (not cumulative) distance traveled by the transient 13 | % from start to finish 14 | % 15 | % MeanThresh: mean threshold of the transient 16 | % 17 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | % This file is part of Tenaspis. 20 | % 21 | % Tenaspis is free software: you can redistribute it and/or modify 22 | % it under the terms of the GNU General Public License as published by 23 | % the Free Software Foundation, either version 3 of the License, or 24 | % (at your option) any later version. 25 | % 26 | % Tenaspis is distributed in the hope that it will be useful, 27 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | % GNU General Public License for more details. 30 | % 31 | % You should have received a copy of the GNU General Public License 32 | % along with Tenaspis. If not, see . 33 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 | 35 | % Load needed cc variable 36 | load('Blobs.mat','cc','PeakPix','ThreshList'); 37 | 38 | %% Calculate distance traveled for each transient 39 | DistTrav = nan(1,length(SegChain)); 40 | MeanThresh = nan(1,length(SegChain)); 41 | 42 | disp('Calculating statistics for all transients') 43 | 44 | % Initialize ProgressBar 45 | resol = 1; % Percent resolution for progress bar, in this case 10% 46 | p = ProgressBar(100/resol); 47 | update_inc = round(length(SegChain)/(100/resol)); % Get increments for updating ProgressBar 48 | 49 | for i = 1:length(SegChain) 50 | 51 | % Update progressbar 52 | if round(i/update_inc) == (i/update_inc) 53 | p.progress; % Also percent = p.progress; 54 | end 55 | 56 | if length(SegChain{i}) > 1 57 | Xc = []; Yc = []; thresh = []; 58 | for j = [1,length(SegChain{i})] 59 | % for each frame in the transient 60 | frame = SegChain{i}{j}(1); 61 | seg = SegChain{i}{j}(2); 62 | 63 | % Grab cc variable for appropriate frame and make it small. 64 | cc_use = cc{frame}; 65 | cc_use.PixelIdxList = cc{frame}.PixelIdxList(seg); 66 | cc_use.NumObjects = 1; 67 | 68 | % Get centroid location and parse out into x and y 69 | r = regionprops(cc_use,'Centroid'); 70 | Xc(j) = r.Centroid(1); 71 | Yc(j) = r.Centroid(2); 72 | 73 | % Get threshold 74 | end 75 | 76 | for j = 1:length(SegChain{i}) 77 | frame = SegChain{i}{j}(1); 78 | seg = SegChain{i}{j}(2); 79 | thresh(j) = ThreshList{frame}(seg); 80 | end 81 | 82 | DistTrav(i) = sqrt((Xc(end)-Xc(1))^2+(Yc(end)-Yc(1))^2); 83 | MeanThresh(i) = mean(thresh); 84 | 85 | elseif length(SegChain{i}) == 1 % Avoid doing any of the above if there is only one frame in the segment 86 | DistTrav(i) = 0; 87 | frame = SegChain{i}{1}(1); 88 | seg = SegChain{i}{1}(2); 89 | MeanThresh(i) = ThreshList{frame}(1); 90 | end 91 | 92 | end 93 | p.stop; 94 | 95 | %% Debugging code 96 | 97 | % keyboard; 98 | % % BrowseThrough 99 | % for i = 1:NumSegments 100 | % subplot(1,2,1);plot(Ac{i});xlabel('frame');ylabel('area of blob')' 101 | % subplot(1,2,2);plot(Xc{i},Yc{i});xlabel('x centroid');ylabel('y centroid'); 102 | % set(gca,'Xlim',[0 Xdim],'Ylim',[0 Ydim]) 103 | % pause; 104 | % end 105 | % keyboard; 106 | 107 | end 108 | 109 | -------------------------------------------------------------------------------- /UpdateCluDistances.m: -------------------------------------------------------------------------------- 1 | function temp = UpdateCluDistances(meanX,meanY,CluToUpdate) 2 | %temp = UpdateCluDistances(meanX,meanY,CluToUpdate) 3 | % 4 | % Gets the distance between the CluToUpdate and all other clusters. 5 | % 6 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | % This file is part of Tenaspis. 9 | % 10 | % Tenaspis is free software: you can redistribute it and/or modify 11 | % it under the terms of the GNU General Public License as published by 12 | % the Free Software Foundation, either version 3 of the License, or 13 | % (at your option) any later version. 14 | % 15 | % Tenaspis is distributed in the hope that it will be useful, 16 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | % GNU General Public License for more details. 19 | % 20 | % You should have received a copy of the GNU General Public License 21 | % along with Tenaspis. If not, see . 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | 24 | temp = sqrt((meanX-meanX(CluToUpdate)).^2+(meanY-meanY(CluToUpdate)).^2); 25 | % CluDist(CluToUpdate,:) = temp; 26 | % CluDist(:,CluToUpdate) = temp; 27 | 28 | 29 | end -------------------------------------------------------------------------------- /UpdateClusterInfo.m: -------------------------------------------------------------------------------- 1 | function [PixelList,PixelAvg,BigPixelAvg,Xcent,Ycent,FrameList,ObjList] = UpdateClusterInfo(FoodClu,PixelList,PixelAvg,BigPixelAvg,CircMask,... 2 | Xcent,Ycent,FrameList,ObjList,EaterClu) 3 | % [PixelList,PixelAvg,BigPixelAvg,Xcent,Ycent,FrameList,ObjList] = UpdateClusterInfo(FoodClus,PixelList,PixelAvg,BigPixelAvg,CircMask,... 4 | % Xcent,Ycent,FrameList,ObjList,EaterClu) 5 | % Copyright 2016 by David Sullivan, Nathaniel Kinsky, and William Mau 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % This file is part of Tenaspis. 8 | % 9 | % Tenaspis is free software: you can redistribute it and/or modify 10 | % it under the terms of the GNU General Public License as published by 11 | % the Free Software Foundation, either version 3 of the License, or 12 | % (at your option) any later version. 13 | % 14 | % Tenaspis is distributed in the hope that it will be useful, 15 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | % GNU General Public License for more details. 18 | % 19 | % You should have received a copy of the GNU General Public License 20 | % along with Tenaspis. If not, see . 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | % 23 | %% Get params 24 | [Xdim,Ydim,threshold] = Get_T_Params('Xdim','Ydim','threshold'); 25 | 26 | %% setup variables for averaging the pixels together 27 | tempFrameCount = zeros(size(CircMask{EaterClu}),'single'); 28 | tempAvg = zeros(size(CircMask{EaterClu}),'single'); 29 | blankframe = zeros(Xdim,Ydim,'single'); 30 | 31 | OrigEaterList = PixelList{EaterClu}; 32 | 33 | %% union the Food pixel lists into the eater pixel lists 34 | for j = 1:length(FoodClu) 35 | PixelList{EaterClu} = union(PixelList{EaterClu},PixelList{FoodClu(j)}); 36 | end 37 | 38 | %% for each cluster, add pixels that overlap with the currclu circmask 39 | AllClu = [EaterClu,FoodClu]; 40 | for j = 1:length(AllClu) 41 | [binans,firstidx] = ismember(CircMask{EaterClu},CircMask{AllClu(j)}); 42 | okpix = find(binans); 43 | tempFrameCount(okpix) = tempFrameCount(okpix)+length(FrameList{AllClu(j)}); 44 | tempAvg(okpix) = tempAvg(okpix)+BigPixelAvg{AllClu(j)}(firstidx(okpix))*length(FrameList{AllClu(j)}); 45 | end 46 | % take the mean 47 | tempAvg = tempAvg./tempFrameCount; 48 | BigPixelAvg{EaterClu} = tempAvg; 49 | 50 | %% concatenate the framelists and objlists 51 | for j = 1:length(FoodClu) 52 | FrameList{EaterClu} = [FrameList{EaterClu},FrameList{FoodClu(j)}]; 53 | ObjList{EaterClu} = [ObjList{EaterClu},ObjList{FoodClu(j)}]; 54 | end 55 | 56 | %% update ROI 57 | tempFrame = blankframe; 58 | tempFrame(CircMask{EaterClu}) = BigPixelAvg{EaterClu}; 59 | 60 | 61 | tempthresh = threshold; 62 | 63 | okmerge = false; 64 | while ((~okmerge) && (tempthresh < max(tempFrame(:)))) 65 | tempthresh = tempthresh+threshold/20; 66 | pidxlist = SegmentFrame(tempFrame,[],false,tempthresh); 67 | while (isempty(pidxlist)&& (tempthresh < max(tempFrame(:)))) 68 | tempthresh = tempthresh+threshold/20; 69 | pidxlist = SegmentFrame(tempFrame,[],false,tempthresh); 70 | end 71 | 72 | % find the matching segment 73 | for i = 1:length(pidxlist) 74 | if any(ismember(OrigEaterList,pidxlist{i})) 75 | [~,idx] = max(tempFrame(pidxlist{i})); 76 | if (ismember(pidxlist{i}(idx),OrigEaterList)) 77 | okmerge = true; 78 | break; 79 | end 80 | end 81 | 82 | end 83 | 84 | end 85 | 86 | if (tempthresh < max(tempFrame(:))) 87 | PixelList{EaterClu} = single(pidxlist{i}); 88 | end 89 | 90 | PixelAvg{EaterClu} = tempFrame(PixelList{EaterClu}); 91 | 92 | [~,idx] = max(PixelAvg{EaterClu}); 93 | [Ycent(EaterClu),Xcent(EaterClu)] = ind2sub([Xdim Ydim],PixelList{EaterClu}(idx)); 94 | 95 | %% update centroid 96 | % tempbin = blankframe; 97 | % tempbin(PixelList{EaterClu}) = 1; 98 | % tempval = blankframe; 99 | % tempval(PixelList{EaterClu}) = PixelAvg{EaterClu}; 100 | % props = regionprops(tempbin,tempval,'WeightedCentroid'); 101 | % Xcent(EaterClu) = single(props.WeightedCentroid(1)); 102 | % Ycent(EaterClu) = single(props.WeightedCentroid(2)); 103 | 104 | end -------------------------------------------------------------------------------- /centerOfMass.m: -------------------------------------------------------------------------------- 1 | function varargout = centerOfMass(A,varargin) 2 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % This file is part of Tenaspis. 5 | % 6 | % Tenaspis is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % Tenaspis is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with Tenaspis. If not, see . 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | % CENTEROFMASS finds the center of mass of the N-dimensional input array 20 | % 21 | % CENTEROFMASS(A) finds the gray-level-weighted center of mass of the 22 | % N-dimensional numerical array A. A must be real and finite. A warning 23 | % is issued if A contains any negative values. Any NaN elements of A will 24 | % automatically be ignored. CENTEROFMASS produces center of mass 25 | % coordinates in units of pixels. An empty array is returned if the 26 | % center of mass is undefined. 27 | % 28 | % The center of mass is reported under the assumption that the first 29 | % pixel in each array dimension is centered at 1. 30 | % 31 | % Also note that numerical arrays other than DOUBLE and SINGLE are 32 | % converted to SINGLE in order to prevent numerical roundoff error. 33 | % 34 | % Examples: 35 | % A = rgb2gray(imread('saturn.png')); 36 | % C = centerOfMass(A); 37 | % 38 | % figure; imagesc(A); colormap gray; axis image 39 | % hold on; plot(C(2),C(1),'rx') 40 | % 41 | % See also: 42 | % 43 | % 44 | 45 | % 46 | % Jered R Wells 47 | % 2013/05/07 48 | % jered [dot] wells [at] gmail [dot] com 49 | % 50 | % v1.0 51 | % 52 | % UPDATES 53 | % YYYY/MM/DD - jrw - v1.1 54 | % 55 | % 56 | 57 | %% INPUT CHECK 58 | narginchk(0,1); 59 | nargoutchk(0,1); 60 | fname = 'centerOfMass'; 61 | 62 | % Checked required inputs 63 | validateattributes(A,{'numeric'},{'real','finite'},fname,'A',1); 64 | 65 | %% INITIALIZE VARIABLES 66 | A(isnan(A)) = 0; 67 | if ~(strcmpi(class(A),'double') || strcmpi(class(A),'single')) 68 | A = single(A); 69 | end 70 | if any(A(:)<0) 71 | warning('MATLAB:centerOfMass:neg','Array A contains negative values.'); 72 | end 73 | 74 | %% PROCESS 75 | sz = size(A); 76 | nd = ndims(A); 77 | M = sum(A(:)); 78 | C = zeros(1,nd); 79 | if M==0 80 | C = []; 81 | else 82 | for ii = 1:nd 83 | shp = ones(1,nd); 84 | shp(ii) = sz(ii); 85 | rep = sz; 86 | rep(ii) = 1; 87 | ind = repmat(reshape(1:sz(ii),shp),rep); 88 | C(ii) = sum(ind(:).*A(:))./M; 89 | end 90 | end 91 | 92 | % Assemble the VARARGOUT cell array 93 | varargout = {C}; 94 | 95 | end % MAIN 96 | 97 | -------------------------------------------------------------------------------- /get_closestCOM.m: -------------------------------------------------------------------------------- 1 | function [ refpoints ] = get_closestCOM( xyvec,COM ) 2 | % [ refpoints ] = get_closestCOM( xyvec,COM ) 3 | %get_closestCOM Get closest COMs of cells to use 4 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | % This file is part of Tenaspis. 7 | % 8 | % Tenaspis is free software: you can redistribute it and/or modify 9 | % it under the terms of the GNU General Public License as published by 10 | % the Free Software Foundation, either version 3 of the License, or 11 | % (at your option) any later version. 12 | % 13 | % Tenaspis is distributed in the hope that it will be useful, 14 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | % GNU General Public License for more details. 17 | % 18 | % You should have received a copy of the GNU General Public License 19 | % along with Tenaspis. If not, see . 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % INPUTS 22 | % xyvec: n x 2 vector of points with xvalues in column 1 and y values in column 2 23 | % COM: 1 x k cell of 1 x 2 vectors , NOTE: [ yCOM xCOM] because MATLAB 24 | % is dumb like that 25 | % OUTPUTS 26 | % refpoints: centers of mass of selected cells, NOTE: [xCOM yCOM} 27 | 28 | xvec_use = [xyvec(:,2) xyvec(:,1)]; % Swap x and y input values to make up for MATLAB bug 29 | refpoints = zeros(size(xvec_use)); 30 | for j = 1: size(xvec_use,1) 31 | temp = cellfun(@(a) sqrt((xvec_use(j,:)-a)*(xvec_use(j,:)-a)'), COM); 32 | refpoints(j,1) = COM{find(min(temp) == temp)}(2); 33 | refpoints(j,2) = COM{find(min(temp) == temp)}(1); 34 | end 35 | 36 | end 37 | 38 | -------------------------------------------------------------------------------- /get_name_date_session.m: -------------------------------------------------------------------------------- 1 | function [ mouse_name, session_date, session_num ] = get_name_date_session( folder_path ) 2 | % [ mouse_name, session_data, session_num ] = get_name_date_session( folder_path ) 3 | % Gets mouse name, session date, and session number from folder path. 4 | % All values are strings 5 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % This file is part of Tenaspis. 8 | % 9 | % Tenaspis is free software: you can redistribute it and/or modify 10 | % it under the terms of the GNU General Public License as published by 11 | % the Free Software Foundation, either version 3 of the License, or 12 | % (at your option) any later version. 13 | % 14 | % Tenaspis is distributed in the hope that it will be useful, 15 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | % GNU General Public License for more details. 18 | % 19 | % You should have received a copy of the GNU General Public License 20 | % along with Tenaspis. If not, see . 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | 23 | % Formats for pulling files and sessions 24 | date_format = '(?\d+)_(?\d+)_(?\d+)'; 25 | session_format = '(?\d?) -'; 26 | mouse_format = '\\(?G\w+\d+)'; 27 | 28 | % Get date. 29 | temp = regexp(folder_path,date_format,'names'); 30 | temp_start = regexp(folder_path,date_format); % Get start index of date folder 31 | session_date = [temp.month '_' temp.day '_' temp.year]; 32 | 33 | % Get session number 34 | temp_folder =folder_path(temp_start + 9:end); % Grab everything after date 35 | temp2 = regexp(temp_folder,session_format,'names'); 36 | if isempty(temp2) 37 | % Assign session number as 1 if there are no subfolders within 38 | % the date folder 39 | session_num = num2str(1); 40 | else 41 | session_num = temp2.sesh_number; 42 | end 43 | %Get mouse name. 44 | temp3 = regexp(folder_path,mouse_format,'names'); 45 | 46 | mouse_name = temp3(1).name; 47 | 48 | end 49 | 50 | -------------------------------------------------------------------------------- /gpl.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /image_registerX.m: -------------------------------------------------------------------------------- 1 | function [RegistrationInfoX, unique_filename] = image_registerX(animal_name, ... 2 | base_date, base_session, reg_date, reg_session, varargin) 3 | % RegistrationInfoX = image_registerX(mouse_name, base_date, base_session, ... 4 | % reg_date, reg_session, ...) 5 | % 6 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | % This file is part of Tenaspis. 9 | % 10 | % Tenaspis is free software: you can redistribute it and/or modify 11 | % it under the terms of the GNU General Public License as published by 12 | % the Free Software Foundation, either version 3 of the License, or 13 | % (at your option) any later version. 14 | % 15 | % Tenaspis is distributed in the hope that it will be useful, 16 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | % GNU General Public License for more details. 19 | % 20 | % You should have received a copy of the GNU General Public License 21 | % along with Tenaspis. If not, see . 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | % 24 | % Image Registration Function - THIS FUNCTION ONLY REGISTERS ONE IMAGE TO ANOTHER 25 | % AND DOES NOT DEAL WITH ANY INDIVIDUAL CELLS. 26 | % this fuction allows you to register a given 27 | % recording session (the registered session) to a previous sesison ( the 28 | % base session) to track neuronal activity from session to session. It 29 | % also outputs a combined set of ROIs so that you can register a given 30 | % session to multiple subsequent sessions. 31 | % 32 | % INPUT VARIABLES (if none are entered, you will be prompted to enter in 33 | % the files to register manually) 34 | % mouse_name: string with mouse name 35 | % 36 | % base_date: date of base session 37 | % 38 | % base_session: session number for base session 39 | % 40 | % reg_date: date of session to register to base. List as 'mask' if you are 41 | % using in conjuction with mask_multi_image_reg. 42 | % 43 | % reg_session: session number for session to register to base. List as 'mask' if you are 44 | % using in conjuction with mask_multi_image_reg. 45 | % 46 | % manual_reg_enable: 0 if you want to disallow manually adjusting the 47 | % registration, 1 if you want to allow it (default) - Note 48 | % that this has not been extensively tested - use at your own 49 | % risk! 50 | % 51 | % varargins 52 | % 53 | % 'use_neuron_masks' (optional): 1 uses neuron masks to register sessions, not the 54 | % minimum projection. 0 = default 55 | % 56 | % OUTPUTS 57 | % 58 | % RegistrationInfoX: saves the location of the base file, the registered 59 | % file, the transform applied, and statistics about the 60 | % transform 61 | % 62 | % unique_filename: the filename under which RegistrationInfoX is saved 63 | 64 | %% User inputs - if set the same the function should run without any user input during the mapping portion 65 | 66 | 67 | %% MAGIC VARIABLES 68 | configname = 'multimodal'; % For images taken with similar contrasts, e.g. from the same device, same gain, etc. 69 | regtype = 'rigid'; % rigid = Translation, Rotation % Similarity = Translation, Rotation, Scale 70 | 71 | % Adjust registration algorithm values: 72 | % MONOMODAL 73 | mono_max_iterations = 1000; % optimizer.MaximumIterations = 100 default 74 | mono_max_step = 1e-3;% optimizer.MaximumStepLength = 0.0625 default 75 | mono_min_step = 1e-5; % optimizer.MinimumStepLength = 1e-5 default 76 | mono_relax = 0.5; %optimizer.RelaxationFactor = 0.5 default 77 | mono_gradient_tol = 1e-6; % optimizer.GradientMagnitudeTolerance = 1e-4 default 78 | % MULTIMODAL 79 | multi_max_iterations = 10000; % optimizer.MaximumIterations = 100 default 80 | multi_growth = 1.05; % optimizer.GrowthFactor = 1.05 default 81 | multi_epsilon = 1.05e-6; % optimizer.Epsilon = 1.05e-6 default 82 | multi_init_rad = 6.25e-4; % optimizer.InitialRadius = 6.25e-3 default 83 | 84 | % Minimum number of transients a neuron must have in order to be included 85 | % when using neuron masks to do registration 86 | min_trans_thresh = 3; 87 | %% Step 0: Get varargins 88 | 89 | % animal_name, base_date, base_session, reg_date, reg_session, manual_reg_enable, varargin) 90 | 91 | p = inputParser; 92 | p.addRequired('animal_name', @ischar); 93 | p.addRequired('base_date', @(a) ischar(a) && length(a) == 10); 94 | p.addRequired('base_session', @isnumeric); 95 | p.addRequired('reg_date', @(a) ischar(a) && length(a) == 10); 96 | p.addRequired('reg_session', @isnumeric); 97 | p.addOptional('manual_reg_enable', false, @(a) islogical(a) || (isnumeric(a) ... 98 | && a == 0 || a == 1)); 99 | p.addParameter('use_neuron_masks', false, @(a) islogical(a) || (isnumeric(a) ... 100 | && a == 0 || a == 1)); 101 | p.addParameter('name_append', '', @ischar); 102 | p.addParameter('suppress_output', false, @(a) islogical(a) || (isnumeric(a) ... 103 | && a == 0 || a == 1)); 104 | p.parse(animal_name, base_date, base_session, reg_date, reg_session,... 105 | varargin{:}); 106 | 107 | manual_reg_enable = p.Results.manual_reg_enable; 108 | use_neuron_masks = p.Results.use_neuron_masks; 109 | name_append = p.Results.name_append; 110 | suppress_output = p.Results.suppress_output; 111 | 112 | %% Step 1: Select images to compare and import the images 113 | 114 | if nargin == 0 % Prompt user to manually enter in files to register if no inputs are specified 115 | [base_filename, base_path, ~] = uigetfile('*.tif',... 116 | 'Pick the base image file: '); 117 | base_file = [base_path base_filename]; 118 | 119 | [reg_filename, reg_path, ~] = uigetfile('*.tif',... 120 | 'Pick the image file to register with the base file: ',[base_path base_filename]); 121 | register_file = [reg_path reg_filename]; 122 | [ animal_name, reg_date, reg_session ] = get_name_date_session(reg_path); 123 | else 124 | % Create strings to point to minimum projection files in each working 125 | % directory for registration 126 | base_path = ChangeDirectory(animal_name, base_date, base_session, 0); 127 | base_file = fullfile(base_path,'ICmovie_min_proj.tif'); 128 | reg_path = ChangeDirectory(animal_name, reg_date, reg_session, 0); 129 | register_file = fullfile(reg_path,'ICmovie_min_proj.tif'); 130 | 131 | end 132 | 133 | %% Step 1b: Define unique filename for file you are registering to that you will 134 | % eventually save in the base path 135 | unique_filename = fullfile(base_path,['RegistrationInfo-' animal_name '-' reg_date '-session' ... 136 | num2str(reg_session) name_append '.mat']); 137 | 138 | %% Step 2a: Skip out on everything if registration is already done! 139 | try 140 | load(unique_filename); 141 | if ~suppress_output % Don't spit out if flagged 142 | disp('IMAGE REGISTRATION ALREADY RAN!! Skipping this step'); 143 | end 144 | catch 145 | 146 | %% Step 2b: Get Images and pre-process - Note that this step is vital as it helps 147 | % correct for differences in overall illumination or contrast between 148 | % sessions. 149 | 150 | % Magic numbers 151 | disk_size = 15; 152 | pixel_thresh = 100; 153 | 154 | base_image_gray = uint16(imread(base_file)); 155 | base_image_untouch = base_image_gray; 156 | reg_image_gray = uint16(imread(register_file)); 157 | reg_image_untouch = reg_image_gray; 158 | 159 | if use_neuron_masks == 0 % Use minimum projection 160 | bg_base = imopen(base_image_gray,strel('disk',disk_size)); % remove noise/smooth via morphological opening 161 | base_image_gray = base_image_gray - bg_base; % create image emphasizing contrast between blood vessels and areas of high expression 162 | base_image_gray = imadjust(base_image_gray); % re-adjust pixel intensity values 163 | base_image_bw = imbinarize(base_image_gray); % threshold it 164 | base_image_bw = bwareaopen(base_image_bw,pixel_thresh,8); % eliminate noise / isolated pixels above threshold 165 | base_image = double(base_image_bw); 166 | 167 | bg_reg = imopen(reg_image_gray,strel('disk',disk_size)); 168 | reg_image_gray = reg_image_gray - bg_reg; 169 | reg_image_gray = imadjust(reg_image_gray); 170 | reg_image_bw = imbinarize(reg_image_gray); 171 | reg_image_bw = bwareaopen(reg_image_bw,pixel_thresh,8); 172 | reg_image = double(reg_image_bw); 173 | 174 | elseif use_neuron_masks == 1 % Create binary all neuron masks for registration 175 | ChangeDirectory(animal_name, base_date, base_session); 176 | load('FinalOutput.mat','PSAbool','NeuronImage') 177 | NumTransients = get_ntrans(PSAbool); 178 | base_image = create_AllICmask(NeuronImage(NumTransients > min_trans_thresh)) > 0; 179 | ChangeDirectory(animal_name, reg_date, reg_session); 180 | load('FinalOutput.mat','PSAbool','NeuronImage') 181 | NumTransients = get_ntrans(PSAbool); 182 | reg_image = create_AllICmask(NeuronImage(NumTransients > min_trans_thresh)) > 0; 183 | 184 | end 185 | 186 | 187 | 188 | %% Step 3: Run Registration Functions, get transform 189 | 190 | [optimizer, metric] = imregconfig(configname); 191 | if strcmp(configname,'monomodal') % Adjust defaults if desired. 192 | optimizer.MaximumIterations = mono_max_iterations; 193 | optimizer.MaximumStepLength = mono_max_step; 194 | optimizer.MinimumStepLength = mono_min_step; 195 | optimizer.RelaxationFactor = mono_relax; 196 | optimizer.GradientMagnitudeTolerance = mono_gradient_tol; 197 | 198 | elseif strcmp(configname,'multimodal') 199 | optimizer.MaximumIterations = multi_max_iterations; 200 | optimizer.GrowthFactor = multi_growth; 201 | optimizer.Epsilon = multi_epsilon; 202 | optimizer.InitialRadius = multi_init_rad; 203 | 204 | end 205 | 206 | % Run registration 207 | if ~manual_reg_enable 208 | disp('Running Registration...'); 209 | tform = imregtform(double(reg_image), double(base_image), regtype, optimizer, metric); 210 | elseif manual_reg_enable 211 | tform = affine2d(eye(3)); 212 | end 213 | 214 | %% Step 4: Apply registrations and plot out for qc purposes 215 | % Create no registration variable 216 | tform_noreg = tform; 217 | tform_noreg.T = eye(3); 218 | 219 | % Apply registration to 2nd session 220 | base_ref = imref2d(size(base_image_gray)); 221 | moving_reg = imwarp(reg_image,tform,'OutputView',imref2d(size(base_image)),... 222 | 'InterpolationMethod','nearest'); 223 | moving_reg_gray = imwarp(reg_image_gray,tform,'OutputView',... 224 | base_ref,'InterpolationMethod','nearest'); 225 | 226 | % Apply NO registration to 2nd session for comparison 227 | moving_noreg = imwarp(reg_image,tform_noreg,'OutputView',imref2d(size(base_image)),... 228 | 'InterpolationMethod','nearest'); 229 | moving_gray_noreg = imwarp(reg_image_gray,tform_noreg,'OutputView',... 230 | base_ref,'InterpolationMethod','nearest'); 231 | 232 | % Plot it out for comparison 233 | if ~suppress_output 234 | figure 235 | subplot(2,2,1); 236 | imagesc(base_image); colormap(gray); colorbar 237 | title('Base Image'); 238 | subplot(2,2,2); 239 | imagesc(reg_image); colormap(gray); colorbar 240 | title('Image to Register'); 241 | subplot(2,2,3) 242 | imagesc(moving_reg); colormap(gray); colorbar 243 | title('Registered Image') 244 | subplot(2,2,4) 245 | imagesc((moving_reg - base_image)); colormap(gray); colorbar 246 | title('Registered Image - Base Image') 247 | 248 | figure 249 | subplot(1,2,1) 250 | imagesc_gray(base_image_gray - moving_gray_noreg); 251 | title('Base Image - Unregistered 2nd image'); 252 | subplot(1,2,2) 253 | imagesc_gray(base_image_gray - moving_reg_gray); 254 | title('Base Image - Registered Image'); 255 | end 256 | 257 | %% Step 5: Give option to adjust manually if this doesn't work... NOTE that this is not very well supported... 258 | disp('Registration Stats:') 259 | disp(['X translation = ' num2str(tform.T(3,1)) ' pixels.']) 260 | disp(['Y translation = ' num2str(tform.T(3,2)) ' pixels.']) 261 | disp(['Rotation = ' num2str(mean([asind(tform.T(2,1)) acosd(tform.T(1,1))])) ' degrees.']) 262 | 263 | if ~exist('manual_reg_enable','var') || manual_reg_enable == 1 264 | manual_flag = input('Do you wish to manually adjust this registration? (y/n): ','s'); 265 | if strcmpi(manual_flag,'y') 266 | disp('Manual correction is not updated/debugged. Use at your own risk!') 267 | end 268 | elseif manual_reg_enable == 0 269 | manual_flag = 'n'; 270 | end 271 | % if strcmpi(manual_flag,'n') 272 | % use_manual_adjust = 0; 273 | % end 274 | while strcmpi(manual_flag,'y') 275 | manh = figure; 276 | manual_type = input('Do you wish to adjust by landmarks or none? (l/n): ','s'); 277 | while ~(strcmpi(manual_type,'l') || strcmpi(manual_type,'n')) 278 | manual_type = input('Do you wish to adjust by landmarks or my cell masks or none? (l/n): ','s'); 279 | end 280 | T_manual = []; 281 | while isempty(T_manual) 282 | if strcmpi(manual_type,'l') 283 | reg_type = 'landmark'; 284 | figure(1) 285 | h_base_landmark = subplot(1,2,1); 286 | load(fullfile(base_path,'FinalOutput.mat'),'NeuronImage') 287 | imagesc(create_AllICmask(NeuronImage)); title('Base Session neurons') 288 | h_reg_landmark = subplot(1,2,2); 289 | load(fullfile(reg_path,'FinalOutput.mat'),'NeuronImage') 290 | imagesc(create_AllICmask(NeuronImage)); title('Reg Session neurons') 291 | T_manual = manual_reg(h_base_landmark, h_reg_landmark, reg_type); 292 | elseif strcmpi(manual_type,'n') 293 | T_manual = eye(3); 294 | end 295 | end 296 | 297 | tform_manual = tform; 298 | tform_manual.T = T_manual; 299 | moving_reg_manual = imwarp(reg_image,tform_manual,'OutputView',imref2d(size(base_image)),'InterpolationMethod','nearest'); 300 | 301 | figure(manh) 302 | imagesc(abs(moving_reg_manual - base_image)); colormap(gray); colorbar 303 | title('Registered Image - Base Image after manual adjust') 304 | 305 | 306 | manual_flag = input('Do you wish to manually adjust again? (y/n)', 's'); 307 | % use_manual_adjust = 1; 308 | tform = tform_manual; 309 | end 310 | 311 | %% Step 6: Get index to pixels that are zeroed out as a result of registration 312 | moving_reg_untouch = imwarp(reg_image_untouch,tform,'OutputView',... 313 | imref2d(size(base_image_untouch)),'InterpolationMethod','nearest'); 314 | exclude_pixels = moving_reg_untouch(:) == 0; 315 | 316 | %% Step 7: Compile everything into a data-structure for saving. 317 | 318 | regstats.base_2nd_diff_noreg = sum(abs(base_image_gray(:) - moving_gray_noreg(:))); 319 | regstats.base_2nd_diff_reg = sum(abs(base_image_gray(:) - moving_reg_gray(:))); 320 | regstats.base_2nd_bw_diff_noreg = sum(abs(base_image(:) - moving_noreg(:))); 321 | regstats.base_2nd_bw_diff_reg = sum(abs(base_image(:) - moving_reg(:))); 322 | 323 | % Save info into RegistrationInfo data structure. 324 | RegistrationInfoX.mouse = animal_name; 325 | RegistrationInfoX.base_date = base_date; 326 | RegistrationInfoX.base_session = base_session; 327 | RegistrationInfoX.base_file = base_file; 328 | RegistrationInfoX.register_date = reg_date; 329 | RegistrationInfoX.register_session = reg_session; 330 | RegistrationInfoX.register_file = register_file; 331 | RegistrationInfoX.tform = tform; 332 | RegistrationInfoX.exclude_pixels = exclude_pixels; 333 | RegistrationInfoX.regstats = regstats; 334 | RegistrationInfoX.base_ref = base_ref; 335 | RegistrationInfoX.use_neuron_masks = use_neuron_masks; 336 | 337 | if exist('T_manual','var') 338 | RegistrationInfoX.tform_manual = tform_manual; 339 | regstats.base_2nd_bw_diff_reg_manual = sum(abs(base_image(:) - moving_reg_manual(:))); 340 | end 341 | 342 | save (unique_filename,'RegistrationInfoX'); 343 | 344 | end % End try/catch statement 345 | 346 | end 347 | 348 | %% Sub-function to get number of transients from PSAbool 349 | function [NumTransients] = get_ntrans(PSAmat) 350 | num_neurons = size(PSAmat,1); 351 | 352 | NumTransients = nan(num_neurons,1); 353 | for j = 1:num_neurons 354 | temp = NP_FindSupraThresholdEpochs(PSAmat(j,:),eps); 355 | NumTransients(j,1) = size(temp,1); 356 | end 357 | 358 | end -------------------------------------------------------------------------------- /imagesc_gray.m: -------------------------------------------------------------------------------- 1 | function [] = imagesc_gray(A) 2 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % This file is part of Tenaspis. 5 | % 6 | % Tenaspis is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % Tenaspis is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with Tenaspis. If not, see . 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | %imagesc_gray - simple function to run imagesc with colormap(gray) and 20 | %colorbar enabled 21 | 22 | imagesc(A); colormap(gca,gray); colorbar 23 | 24 | 25 | end 26 | 27 | -------------------------------------------------------------------------------- /manual_reg.m: -------------------------------------------------------------------------------- 1 | function [T_manual] = manual_reg(base_image_axes,reg_image_axes, reg_type, SigTrace_base,SigTrace_reg) 2 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % This file is part of Tenaspis. 5 | % 6 | % Tenaspis is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % Tenaspis is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with Tenaspis. If not, see . 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | % file2 = 'C:\Users\kinsky.AD\Documents\Lab\Imaging\GCamp Mice\GCamp6f_27\7_15_2014\rectangular plastic tub\ICmovie_min_proj.tif'; 20 | % file1 = 'C:\Users\kinsky.AD\Documents\Lab\Imaging\GCamp Mice\GCamp6f_27\7_15_2014\rectangle\ICmovie_min_proj.tif'; 21 | % file_combined = 'C:\Users\kinsky.AD\Documents\Lab\Imaging\GCamp Mice\GCamp6f_27\7_15_2014\combined\IC300-Objects\Obj_1\ICmovie_min_proj.tif'; 22 | 23 | % Save figures in case you need to re-write them... 24 | hgsave(base_image_axes,'base_mask_temp'); 25 | hgsave(reg_image_axes,'reg_mask_temp'); 26 | 27 | % figure(1); 28 | % base_image_axes = subplot(2,2,1); 29 | % reg_image_axes = subplot(2,2,2); 30 | 31 | if strcmpi(reg_type,'mask') && nargin ~= 5 32 | error('You did not enter enought input arguments. Please enter a SignalTrace.mat file for both the base and registered files') 33 | else 34 | end 35 | 36 | % Create COM variable 37 | for j = 1:size(SigTrace_base.GoodICf_comb,2) 38 | base_GoodCom{j} = centerOfMass(SigTrace_base.GoodICf_comb{j}*1); 39 | end 40 | SigTrace_base.GoodCom = base_GoodCom; 41 | for j = 1:size(SigTrace_reg.GoodICf,2) 42 | reg_GoodCom{j} = centerOfMass(SigTrace_reg.GoodICf{j}*1); 43 | end 44 | SigTrace_reg.GoodCom = reg_GoodCom; 45 | 46 | xbase = []; ybase = []; 47 | disp('Select Center of Base Image Cells to use as reference') 48 | [xbase, ybase] = getpts(base_image_axes); 49 | base_vec = [xbase ybase]; 50 | axes(base_image_axes); hold on; 51 | npoints_base = length(xbase); 52 | for j = 1:npoints_base 53 | % plot(xbase(j),ybase(j),'*') 54 | src_base = text(xbase(j)+10,ybase(j)-15,num2str(j)); 55 | set(src_base,'Color',[0 1 0]); 56 | 57 | end 58 | if strcmpi(reg_type,'mask') 59 | base_refpoints = get_closestCOM(base_vec,SigTrace_base.GoodCom); 60 | plot(base_refpoints(:,1), base_refpoints(:,2),'g*') 61 | else 62 | plot(xbase,ybase,'g*') 63 | end 64 | hold off 65 | 66 | xreg = []; yreg = []; 67 | disp('Select Center of Registered Image Cells to use as a reference') 68 | [xreg, yreg] = getpts(reg_image_axes); 69 | axes(reg_image_axes); hold on; 70 | reg_vec = [xreg yreg]; 71 | npoints_reg = length(xreg); 72 | for j = 1:npoints_reg 73 | % plot(xreg(j),yreg(j),'*') 74 | src_reg = text(xreg(j)+10,yreg(j)-15,num2str(j)); 75 | set(src_reg,'Color',[0 1 0]); 76 | 77 | end 78 | if strcmpi(reg_type,'mask') 79 | reg_refpoints = get_closestCOM(reg_vec, SigTrace_reg.GoodCom); 80 | plot(reg_refpoints(:,1), reg_refpoints(:,2),'g*') 81 | else 82 | plot(xreg,yreg,'g*') 83 | end 84 | 85 | hold off 86 | 87 | npoints_diff = npoints_base - npoints_reg; 88 | 89 | if npoints_diff ~=0 % Error control 90 | T_manual = []; 91 | disp('Error: you need to select the same number of points in both images!') 92 | else 93 | if strcmpi(reg_type,'landmark') 94 | u = [xbase ybase]; 95 | x = [xreg yreg]; 96 | elseif strcmpi(reg_type,'mask') 97 | u = base_refpoints; 98 | x = reg_refpoints; 99 | end 100 | 101 | dxu_mat = []; 102 | for j = 1:size(u,1)-1 103 | for k = j+1:size(u,1) 104 | du{j,k} = u(j,:) - u(k,:); 105 | alpha_var(j,k) = atan2d(du{j,k}(2),du{j,k}(1)); 106 | dx{j,k} = x(j,:) - x(k,:); 107 | beta_var(j,k) = atan2d(dx{j,k}(2),dx{j,k}(1)); 108 | 109 | end 110 | dxu_mat = [dxu_mat; u(j,:) - x(j,:)]; 111 | 112 | end 113 | 114 | dxu_use = mean(dxu_mat,1); 115 | phi = alpha_var - beta_var; 116 | for k = 1:length(phi(:)) 117 | if phi(k) > 180 118 | phi(k) = phi(k) - 360; 119 | end 120 | end 121 | 122 | phi_use = mean(mean(phi,1),2); 123 | 124 | % tform_manual = tform; 125 | T_manual = [cosd(phi_use) -sind(phi_use) 0 ; sind(phi_use) cosd(phi_use) 0 ; ... 126 | dxu_use(1) dxu_use(2) 1]; 127 | end 128 | 129 | 130 | 131 | 132 | % AllIC_reg_manual = imwarp(reg_data.AllIC,tform_manual,'OutputView',imref2d(size(base_image))); 133 | % moving_reg_manual = imwarp(reg_image,tform_manual,'OutputView',imref2d(size(base_image))); 134 | 135 | % figure(10) 136 | % imagesc(base_data.AllIC+ AllIC_reg_manual*2); colormap(jet) 137 | % title(['Combined Image Cells - Manual Adjust, rot = ' num2str(phi_use,'%1.2f') ' degrees']); 138 | 139 | 140 | % h = colorbar('YTick',[0 1 2 3],'YTickLabel', {'','Base Image Cells','Reg Image Cells','Overlapping Cells'}); 141 | % xlabel(['X shifted by ' num2str(dxu_use(1),'%1.1f') ' pixels']); 142 | % ylabel(['Y shifted by ' num2str(dxu_use(2),'%1.1f') ' pixels']); 143 | % 144 | % figure(11) 145 | % subplot(2,2,1) 146 | % imagesc(base_image); colormap(gray); colorbar 147 | % title('Base Image'); 148 | % subplot(2,2,2) 149 | % imagesc(reg_image); colormap(gray); colorbar 150 | % title('Image to Register'); 151 | % subplot(2,2,3) 152 | % imagesc(moving_reg_manual); colormap(gray); colorbar 153 | % title('Registered Image - Manual') 154 | % subplot(2,2,4) 155 | % imagesc(abs(moving_reg_manual - base_image)); colormap(gray); colorbar 156 | % title('Registered Image - Base Image') 157 | % 158 | % 159 | % tform3 = tform; 160 | % tform3.T = [1 0 0 ; 0 1 0; -11 21 1]; 161 | % 162 | % AllIC_reg_check = imwarp(reg_data.AllIC,tform3,'OutputView',imref2d(size(base_image))); 163 | % 164 | % figure(20) 165 | % imagesc(base_data.AllIC+ AllIC_reg_check*2); colormap(jet) 166 | % title(['Combined Image Cells - Check, rot = ' num2str(acosd(tform3.T(1,1)),'%1.2f') ' degrees']); 167 | % h = colorbar('YTick',[0 1 2 3],'YTickLabel', {'','Base Image Cells','Reg Image Cells','Overlapping Cells'}); 168 | % xlabel(['X shifted by ' num2str(tform3.T(3,1),'%1.1f') ' pixels']); 169 | % ylabel(['Y shifted by ' num2str(tform3.T(3,2),'%1.1f') ' pixels']); 170 | % 171 | % % Check image registration quality with histograms 172 | % edges = 0:10:1000; 173 | % 174 | % n_auto = histc(abs(moving_reg(:)-base_image(:)),edges); 175 | % n_manual = histc(abs(moving_reg_manual(:)-base_image(:)),edges); 176 | % 177 | % figure(22) 178 | % plot(edges,n_auto,'r-',edges,n_manual,'b-.'); 179 | % legend('Auto','Manual') 180 | % 181 | % % Overlay AllIC from separately registered sessions onto All_IC_combined 182 | % 183 | % base_image = im2double(imread(base_file)); 184 | % [moving_reg r_reg] = imregister(base_image, base_image, regtype, optimizer, metric); 185 | % 186 | % save ([ base_path 'RegistrationInfo.mat'], 'tform', 'tform_manual','AllIC',... 187 | % 'AllIC_reg','AllIC_reg_manual','base_file','register_file') 188 | 189 | end 190 | 191 | 192 | % u1 = [171 89]; % [0 0]; % 193 | % u2 = [143 377]; % [0.707 -.707]; % 194 | % u3 = [199 233]; % [-0.707 -.707]; % 195 | % 196 | % u12 = u2-u1; alpha1 = atan2d(u12(2),u12(1)); 197 | % u13 = u3-u1; alpha2 = atan2d(u13(2),u13(1)); 198 | % u23 = u3-u2; alpha3 = atan2d(u23(2),u23(1)); 199 | % 200 | % x1 = [164 110]; % [0 0]; % 201 | % x2 = [130 405]; % [0.707 .707]; % 202 | % x3 = [191 257]; % [0.707 -.707]; % 203 | % 204 | % x12 = x2-x1; beta1 = atan2d(x12(2),x12(1)); 205 | % x13 = x3-x1; beta2 = atan2d(x13(2),x13(1)); 206 | % x23 = x3-x2; beta3 = atan2d(x23(2),x23(1)); 207 | % 208 | % dx1 = x1 - u1; 209 | % dx2 = x2 - u2; 210 | % dx3 = x3 - u3; 211 | % dx_mat = [dx1 ; dx2 ; dx3 ]; 212 | % dx_use = mean(dx_mat,1); 213 | % 214 | % phi(1) = alpha1-beta1; 215 | % phi(2) = alpha2-beta2; 216 | % phi(3) = alpha3-beta3; 217 | % for j = 1:length(phi) 218 | % if abs(phi(j)) > 180 219 | % if phi(j) < 0 220 | % phi(j) = phi(j) + 360; 221 | % elseif phi(j) > 0 222 | % phi(j) = phi(j) - 360; 223 | % end 224 | % else 225 | % end 226 | % end 227 | % phi_use = mean(phi); 228 | % 229 | % 230 | % xtrans = -dx_use(1); -11; 231 | % ytrans = -dx_use(2); 21; 232 | % rot = phi_use; 233 | % 234 | % tform2 = tform; 235 | % tform2.T = [cosd(rot) -sind(rot) 0 ; sind(rot) cosd(rot) 0 ; xtrans ytrans 1]; 236 | % AllIC_reg = imwarp(reg_data.AllIC,tform2,'OutputView',imref2d(size(base_image))); 237 | % 238 | % tform3 = tform; 239 | % tform3.T = [1 0 0 ; 0 1 0; -11 21 1]; 240 | % figure(FigNum) 241 | % % subplot(3,1,1) 242 | % % imagesc(base_data.AllIC); title('Base Image Cells') 243 | % % subplot(3,1,2) 244 | % % imagesc(AllIC_reg*2); title('Registered Image Cells') 245 | % % subplot(3,1,3) 246 | % imagesc(base_data.AllIC+ AllIC_reg*2); title('Combined Image Cells'); colormap(jet) 247 | % h = colorbar('YTick',[0 1 2 3],'YTickLabel', {'','Base Image Cells','Reg Image Cells','Overlapping Cells'}); 248 | % 249 | % FigNum = FigNum + 1; 250 | % 251 | % x1 = [171 89] -------------------------------------------------------------------------------- /mask_multi_image_reg.m: -------------------------------------------------------------------------------- 1 | function [] = mask_multi_image_reg(base_mask_file, init_date, init_sess, reg_struct) 2 | % mask_multi_image_reg(base_mask_file, init_date, init_sess, reg_struct) 3 | % 4 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | % This file is part of Tenaspis. 7 | % 8 | % Tenaspis is free software: you can redistribute it and/or modify 9 | % it under the terms of the GNU General Public License as published by 10 | % the Free Software Foundation, either version 3 of the License, or 11 | % (at your option) any later version. 12 | % 13 | % Tenaspis is distributed in the hope that it will be useful, 14 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | % GNU General Public License for more details. 17 | % 18 | % You should have received a copy of the GNU General Public License 19 | % along with Tenaspis. If not, see . 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % 22 | % Registers a base file to multiple recording sessions and saves these 23 | % registrations in a .mat file claled Reg_NeuronIDs.mat in your base file 24 | % directory. 25 | % 26 | % INPUTS: 27 | % base_file: Full file path to the base session neuron mask you wish 28 | % to register to other sessions 29 | % 30 | % init_date, init_sess: date and session number for the base mask 31 | % file, should be located in GetInitRegMaskInfo 32 | % 33 | % num_session: Number of sessions you want to register base_file to. 34 | % You will be prompted via gui to select this number of files for 35 | % registration 36 | % 37 | % reg_struct: a structure with the fields .Animal (animal name), 38 | % .Date (date of the session you are registering), and .Session 39 | % (session number of the session you are registering) 40 | % 41 | % mask: the mask you wish to register to all the subsequent sessions 42 | % 43 | % OPTIONAL 44 | % OBSOLETE: 'reg_files': this string, followed by a 1xn cell array with the 45 | % full path to the filenames of the sessions you want to register the, 46 | % allows you to batch register the base mask to the sessions listed, 47 | % and will place mask.mat in the folder containing the file 48 | % specified. If not specified, you will be prompted to select each 49 | % of the files you want to register. 50 | % Example: mask_multi_image_reg(...,'reg_files',{'file1', 'file2',...}) 51 | % 52 | 53 | %% (OLD) Check for reg_file list 54 | % for j = 1:length(varargin) 55 | % if strcmpi(varargin{j},'reg_files') 56 | % reg_files = varargin{j+1}; 57 | % num_sessions = size(reg_files,2); 58 | % end 59 | % end 60 | 61 | %% Get number of sessions 62 | num_sessions = length(reg_struct); 63 | 64 | %% Get base path. 65 | % base_path = fileparts(base_file); 66 | 67 | %% Do the registrations. 68 | %Preallocate. 69 | % reg_filename = cell(1,num_sessions); 70 | % reg_path = cell(1,num_sessions); 71 | % reg_date = cell(1,num_sessions); 72 | 73 | %Select all the files first. 74 | % for this_session = 1:num_sessions 75 | % if ~exist('reg_struct','var') 76 | % [reg_filename{this_session}, reg_path{this_session}] = uigetfile('*.tif', ['Pick file to register #', num2str(this_session), ': ']); 77 | % else 78 | % [reg_path{this_session}, name, ext] = fileparts(reg_files{this_session}); 79 | % reg_filename{this_session} = [name ext]; 80 | % end 81 | % %Get date. 82 | % date_format = ['(?\d+)_(?\d+)_(?\d+)']; 83 | % temp = regexp(reg_path{this_session},date_format,'names'); 84 | % reg_date{this_session} = [temp.month '_' temp.day '_' temp.year]; 85 | % end 86 | % 87 | % %Get base date. 88 | % temp = regexp(base_file,date_format,'names'); 89 | % base_date = [temp.month '_' temp.day '_' temp.year]; 90 | % 91 | % %Get mouse name. 92 | % mouse_format = '(?G\d+)'; 93 | % mouse = regexp(base_file,mouse_format,'names'); 94 | % 95 | % %Get full file path. 96 | % reg_file = fullfile(reg_path, reg_filename); 97 | 98 | %% Do the registrations. 99 | for this_session = 1:num_sessions 100 | %Display. 101 | disp(['Registering base neuron mask to ', reg_struct(this_session).Date, '...']); 102 | 103 | %Perform image registration. Note that this is backward from what 104 | %we usually do, as we are now taking the base file and registering 105 | %it to all the files in reg_file, not vice versa... 106 | reginfo_temp = image_registerX(reg_struct(this_session).Animal, reg_struct(this_session).Date, ... 107 | reg_struct(this_session).Session, init_date, init_sess, 0); 108 | 109 | % Create a registered mask from the bask mask 110 | mask = importdata(base_mask_file); 111 | mask_reg = imwarp(mask,reginfo_temp.tform,'OutputView',... 112 | reginfo_temp.base_ref,'InterpolationMethod','nearest'); 113 | 114 | %Save the registered mask in the registered session file 115 | save_path = ChangeDirectory(reg_struct(this_session).Animal, ... 116 | reg_struct(this_session).Date, reg_struct(this_session).Session); 117 | save (fullfile(save_path,'mask_reg.mat'), 'mask_reg'); 118 | end 119 | 120 | end 121 | -------------------------------------------------------------------------------- /moviestats.m: -------------------------------------------------------------------------------- 1 | function [meanframe,stdframe,meanframepos,stdframepos] = moviestats(file) 2 | %[meanframe,stdframe,meanframepos,stdframepos] = moviestats(file) 3 | % 4 | % Copyright 2015 by David Sullivan and Nathaniel Kinsky 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | % This file is part of Tenaspis. 7 | % 8 | % Tenaspis is free software: you can redistribute it and/or modify 9 | % it under the terms of the GNU General Public License as published by 10 | % the Free Software Foundation, either version 3 of the License, or 11 | % (at your option) any later version. 12 | % 13 | % Tenaspis is distributed in the hope that it will be useful, 14 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | % GNU General Public License for more details. 17 | % 18 | % You should have received a copy of the GNU General Public License 19 | % along with Tenaspis. If not, see . 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % 22 | % Gets basic statistics about movie frames. 23 | % 24 | % INPUT 25 | % file: Movie file. 26 | % 27 | % OUTPUTS 28 | % meanframe: 1xF vector (F = number of frames), mean value of pixels 29 | % per frame. 30 | % 31 | % stdframe: 1xF vector, standard deviation of pixel intensity per 32 | % frame. 33 | % 34 | % meanframepos: 1xF vector, mean value of positive pixels per frame. 35 | % 36 | % stdframepos: 1xF vector, SD of positive pixel intensity per frame. 37 | % 38 | 39 | %% Set up. 40 | %Get movie info. 41 | info = h5info(file,'/Object'); 42 | NumFrames = info.Dataspace.Size(3); 43 | 44 | % Pre-allocate 45 | meanframe = zeros(1,NumFrames); 46 | stdframe = zeros(1,NumFrames); 47 | 48 | %If demanded, also provide the mean values and standard deviations of 49 | %positive pixels. 50 | if nargout > 2 51 | meanframepos = zeros(1,NumFrames); 52 | stdframepos = zeros(1,NumFrames); 53 | end 54 | 55 | % Initialize Progress Bar 56 | resol = 1; % Percent resolution for progress bar, in this case 10% 57 | update_inc = round(NumFrames/(100/resol)); % Get increments for updating ProgressBar 58 | p = ProgressBar(100/resol); 59 | 60 | %% Calculate stats. 61 | for i = 1:NumFrames 62 | frame = double(loadframe(file,i,info)); 63 | meanframe(i) = mean(frame(:)); %Take the mean of the pixels. 64 | stdframe(i) = std(frame(:)); %Take the standard deviation of the pixels. 65 | 66 | if (nargout > 2) 67 | pos = find(frame(:) > 0); %Get positive pixels. 68 | meanframepos(i) = mean(frame(pos)); %Mean of positive pixels. 69 | stdframepos(i) = std(frame(pos)); %SD of positive pixels. 70 | end 71 | 72 | % Update progress bar 73 | if round(i/update_inc) == (i/update_inc) 74 | p.progress; % Also percent = p.progress; 75 | end 76 | 77 | end 78 | 79 | p.stop; % Terminate progress bar 80 | 81 | end 82 | 83 | --------------------------------------------------------------------------------