├── .DS_Store ├── .gitignore ├── PCA ├── findImageSubsetStatistics.m ├── find_PCA_projections.m ├── makeMultiComponentPlot_radon_fromVecs.m └── onlineImagePCA_radon.m ├── README.md ├── README.txt ├── findEmbeddings.m ├── findPosturalEigenmodes.m ├── findProjections.m ├── findRadonPixels.m ├── findWavelets.m ├── parameters.txt ├── runAlignment.m ├── runEmbeddingSubSampling.m ├── runExample.m ├── runExample_noSubsampling.m ├── run_tSne.m ├── segmentation_alignment ├── alignImages_Radon_parallel_avi.m ├── alignTwoImages.m ├── align_subroutine_parallel_avi.m ├── basisImage.tiff ├── dftregistration.m └── segmentImage_combo.m ├── setRunParameters.m ├── t_sne ├── calculateKLCost.m ├── d2p_sparse.m ├── file_embeddingSubSampling.m ├── findPointDensity.m ├── findTDistributedProjections_fmin.m ├── findTemplatesFromData.m ├── returnCorrectSigma_sparse.m ├── returnTemplates.m ├── tsne_d.m └── tsne_p_sparse.m ├── utilities ├── argmax.m ├── argmin.m ├── autoFindThreshold_gmm.m ├── close_parpool.m ├── combineCells.m ├── derivative7.m ├── findAllImagesInFolders.m ├── findKLDivergences.m ├── findListKLDivergences.m ├── findWatershedRegions.m ├── gaussianfilterdata.m ├── gmixPlot.m ├── largeBWConnComp.m ├── rescaleImage.m ├── returnCellLengths.m ├── sampleFromMatrix.m ├── setup_parpool.m └── shuffledMatrix.m └── wavelet ├── fastWavelet_morlet_convolution_parallel.m └── morletConjFT.m /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonberman/MotionMapper/1b7e84931beae780ffd765b850a4a7f7378acace/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | runExample_smallData.m 2 | *.m~ 3 | -------------------------------------------------------------------------------- /PCA/findImageSubsetStatistics.m: -------------------------------------------------------------------------------- 1 | function [meanRadon,stdRadon,vidObjs] = findImageSubsetStatistics(alignedImageDirectory,numToTest,thetas,scale) 2 | %findImageSubsetStatistics finds the Radon-transform space mean and 3 | %standard deviations for all of the files in a directory 4 | % 5 | % Input variables: 6 | % 7 | % alignedImageDirectory -> directory containing aligned .avi files 8 | % numToTest -> number of images from which to calculate values 9 | % thetas -> angles used in Radon transform 10 | % scale -> image scaling factor% 11 | % 12 | % Output variable2: 13 | % 14 | % meanRadon -> mean values of pixels in Radon-transform space 15 | % stdRadon -> standard deviations of pixels in Radon-transform space 16 | % vidObjs -> VideoReader objects for each of the aligned avi files 17 | % 18 | % (C) Gordon J. Berman, 2014 19 | % Princeton University 20 | 21 | 22 | files = findAllImagesInFolders(alignedImageDirectory,'avi'); 23 | L = length(files); 24 | 25 | lengths = zeros(L,1); 26 | vidObjs = cell(L,1); 27 | parfor i=1:L 28 | vidObjs{i} = VideoReader(files{i}); 29 | lengths(i) = vidObjs{i}.NumberOfFrames; 30 | end 31 | 32 | N = sum(lengths); 33 | cumsumLengths = [0;cumsum(lengths)]; 34 | 35 | 36 | if nargin < 2 || isempty(numToTest) 37 | numToTest = N; 38 | end 39 | 40 | if numToTest > N 41 | idx = 1:N; 42 | numToTest = N; 43 | else 44 | idx = sort(randperm(N,numToTest)); 45 | end 46 | 47 | 48 | groupings = cell(L,1); 49 | for i=1:L 50 | groupings{i} = idx(idx > cumsumLengths(i) & idx <= cumsumLengths(i+1)); 51 | end 52 | 53 | testImage = read(vidObjs{1},1); 54 | testImage = testImage(:,:,1); 55 | 56 | s = size(testImage); 57 | nX = round(s(1)/scale); 58 | nY = round(s(2)/scale); 59 | s = [nX nY]; 60 | testImage = radon(imresize(testImage,s),thetas); 61 | sR = size(testImage); 62 | 63 | 64 | radonImages = zeros(sR(1),sR(2),numToTest); 65 | fprintf(1,'Calculating Image Radon Transforms\n'); 66 | count = 0; 67 | for i=1:L 68 | 69 | fprintf(1,'\t Computing Transforms for File #%7i out of %7i\n',i,L); 70 | 71 | M = length(groupings{i}); 72 | currentImages = zeros(sR(1),sR(2),M); 73 | currentIdx = groupings{i} - cumsumLengths(i); 74 | q = vidObjs{i}; 75 | 76 | parfor j=1:M 77 | 78 | image = read(q,currentIdx(j)); 79 | image = image(:,:,1); 80 | a = double(imresize(image,s)); 81 | lowVal = min(a(a>0)); 82 | highVal = max(a(a>0)); 83 | a = (a - lowVal) / (highVal - lowVal); 84 | 85 | currentImages(:,:,j) = radon(a,thetas); 86 | 87 | end 88 | 89 | radonImages(:,:,count + (1:M)) = currentImages; 90 | count = count + M; 91 | 92 | clear currentImages currentIdx M 93 | 94 | end 95 | 96 | 97 | 98 | fprintf(1,'Calculating Mean and Standard Deviation\n'); 99 | meanRadon = zeros(sR); 100 | stdRadon = zeros(sR); 101 | for i=1:sR(1) 102 | for j=1:sR(2) 103 | meanRadon(i,j) = mean(squeeze(radonImages(i,j,:))); 104 | stdRadon(i,j) = std(squeeze(radonImages(i,j,:))); 105 | end 106 | end 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /PCA/find_PCA_projections.m: -------------------------------------------------------------------------------- 1 | function projections = find_PCA_projections(files,coeffs,meanValues,... 2 | pixels,thetas,numProjections,scale,batchSize) 3 | %find_PCA_projections finds the projection of a set of images onto 4 | %postural eigenmodes (called by findProjections.m) 5 | % 6 | % Input variables: 7 | % 8 | % filePath -> cell array of VideoReader objects 9 | % coeffs -> postural eignmodes (L x (M mean value for each of the pixels 11 | % pixels -> radon-transform space pixels to use (Lx1 or 1xL array) 12 | % thetas -> angles used in Radon transform 13 | % numProjections -> # of projections to find 14 | % scale -> image scaling factor 15 | % batchSize -> # of files to process at once 16 | % 17 | % 18 | % Output variables: 19 | % 20 | % projections -> N x d array of projection values 21 | % 22 | % 23 | % (C) Gordon J. Berman, 2014 24 | % Princeton University 25 | 26 | 27 | 28 | Nf = length(files); 29 | lengths = zeros(Nf,1); 30 | for i=1:Nf 31 | lengths(i) = files{i}.NumberOfFrames; 32 | end 33 | N = sum(lengths); 34 | 35 | L = length(pixels); 36 | 37 | if nargin < 6 || isempty(numProjections) 38 | numProjections = length(coeffs(1,:)); 39 | end 40 | coeffs = coeffs(:,1:numProjections); 41 | 42 | 43 | testImage = read(files{1},1); 44 | testImage = testImage(:,:,1); 45 | s = size(testImage); 46 | nX = round(s(1)/scale); 47 | nY = round(s(2)/scale); 48 | s = [nX nY]; 49 | 50 | sM = size(meanValues); 51 | if sM(1) == 1 52 | meanValues = meanValues'; 53 | end 54 | 55 | 56 | projections = zeros(N,numProjections); 57 | totalImages = 0; 58 | for t=1:Nf 59 | 60 | fprintf(1,'Processing File #%5i out of %5i\n',t,Nf); 61 | 62 | M = lengths(t); 63 | 64 | if batchSize > M 65 | currentBatchSize = M; 66 | else 67 | currentBatchSize = batchSize; 68 | end 69 | 70 | num = ceil(M/currentBatchSize); 71 | currentImage = 0; 72 | 73 | currentVideoReader = files{t}; 74 | 75 | tempData = zeros(currentBatchSize,L); 76 | for i=1:num 77 | 78 | fprintf(1,'\t Batch #%5i of %5i\n',i,num); 79 | 80 | tempData(:) = 0; 81 | if i == num 82 | maxJ = M - currentImage; 83 | tempData = tempData(1:maxJ,:); 84 | else 85 | maxJ = currentBatchSize; 86 | end 87 | 88 | iterationIdx = currentImage + (1:maxJ); 89 | 90 | 91 | parfor j=1:maxJ 92 | 93 | a = read(currentVideoReader,iterationIdx(j)); 94 | a = double(imresize(a(:,:,1),s)); 95 | lowVal = min(a(a>0)); 96 | highVal = max(a(a>0)); 97 | a = (a - lowVal) / (highVal - lowVal); 98 | 99 | R = radon(a,thetas); 100 | tempData(j,:) = R(pixels) - meanValues; 101 | 102 | end 103 | 104 | projections(totalImages + (1:maxJ),:) = tempData*coeffs; 105 | totalImages = totalImages + maxJ; 106 | currentImage = currentImage + maxJ; 107 | 108 | end 109 | 110 | 111 | end 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /PCA/makeMultiComponentPlot_radon_fromVecs.m: -------------------------------------------------------------------------------- 1 | function image = makeMultiComponentPlot_radon_fromVecs(C,N,thetas,pixels,imageSize) 2 | %makes an pictoral representation of a set of postural eigenmodes 3 | % 4 | % Inputs: 5 | % C -> Lxd matrix of eigenvectors (each along a column) to be plotted 6 | % N -> number of eigenvectors to be chosen (first N will be used) 7 | % thetas -> angles in radon transform 8 | % pixels -> Radon-transformed space pixels that are used 9 | % imageSize -> size of Radon-transformed image 10 | 11 | if nargin < 2 || isempty(N) 12 | N = length(C(1,:)); 13 | end 14 | 15 | if nargin < 5 || isempty(imageSize) 16 | imageSize = [201 90]; 17 | end 18 | 19 | L = ceil(sqrt(N)); 20 | M = ceil(N/L); 21 | 22 | r1 = imageSize(1); 23 | r2 = imageSize(2); 24 | 25 | test = iradon(zeros(r1,r2),thetas); 26 | s = size(test); 27 | P = s(1); 28 | Q = s(2); 29 | 30 | currentImage = zeros(r1,r2); 31 | for i=1:N 32 | currentImage(pixels) = C(:,i); 33 | X1 = mod(i-1,M)+1; 34 | Y1 = ceil(i/M); 35 | image(((Y1-1)*P+1):(Y1*P),((X1-1)*Q+1):(X1*Q)) = iradon(currentImage,thetas); 36 | end 37 | 38 | imagesc(image); 39 | axis equal 40 | axis off 41 | caxis([-3e-3 3e-3]) -------------------------------------------------------------------------------- /PCA/onlineImagePCA_radon.m: -------------------------------------------------------------------------------- 1 | function [mu,vecs,vals] = onlineImagePCA_radon(files,batchSize,scale,pixels,thetas,numPerFile) 2 | %onlineImagePCA_radon finds postural eigenmodes based upon a set of 3 | %aligned images (called by findPosturalEigenmodes.m). 4 | % 5 | % Input variables: 6 | % 7 | % files -> cell array of VideoReader objects 8 | % batchSize -> # of images to process at once 9 | % scale -> image scaling factor 10 | % pixels -> radon-transform space pixels to use (Lx1 or 1xL array) 11 | % thetas -> angles used in Radon transform 12 | % numPerFile -> # of images to use per file 13 | % 14 | % 15 | % Output variables: 16 | % 17 | % mu -> mean value for each of the pixels 18 | % vecs -> postural eignmodes (LxL array). Each column (vecs(:,i)) is 19 | % an eigenmode corresponding to the eigenvalue vals(i) 20 | % vals -> eigenvalues of the covariance matrix 21 | % 22 | % 23 | % (C) Gordon J. Berman, 2014 24 | % Princeton University 25 | 26 | 27 | if nargin < 3 || isempty(scale); 28 | scale = 10/7; 29 | end 30 | 31 | if nargin < 6 || isempty(numPerFile) 32 | numPerFile = -1; 33 | end 34 | 35 | 36 | Nf = length(files); 37 | lengths = zeros(Nf,1); 38 | for i=1:Nf 39 | lengths(i) = files{i}.NumberOfFrames; 40 | end 41 | 42 | 43 | L = length(pixels); 44 | 45 | 46 | testImage = read(files{1},1); 47 | testImage = testImage(:,:,1); 48 | s = size(testImage); 49 | nX = round(s(1)/scale); 50 | nY = round(s(2)/scale); 51 | s = [nX nY]; 52 | 53 | firstBatch = true; 54 | tempMu = zeros(1,L); 55 | totalImages = 0; 56 | for t=1:Nf 57 | 58 | fprintf(1,'Processing File #%5i out of %5i\n',t,Nf); 59 | 60 | M = lengths(t); 61 | if numPerFile == -1 62 | currentNumPerFile = M; 63 | else 64 | currentNumPerFile = numPerFile; 65 | end 66 | 67 | 68 | if M < currentNumPerFile 69 | currentIdx = 1:M; 70 | else 71 | currentIdx = randperm(M,currentNumPerFile); 72 | end 73 | M = min([lengths(t) currentNumPerFile]); 74 | 75 | 76 | if M < batchSize 77 | currentBatchSize = M; 78 | else 79 | currentBatchSize = batchSize; 80 | end 81 | num = ceil(M/currentBatchSize); 82 | 83 | currentVideoReader = files{t}; 84 | 85 | currentImage = 0; 86 | X = zeros(currentBatchSize,L); 87 | for j=1:num 88 | 89 | fprintf(1,'\t Batch #%5i out of %5i\n',j,num); 90 | 91 | if firstBatch 92 | 93 | firstBatch = false; 94 | 95 | parfor i=1:currentBatchSize 96 | 97 | a = read(currentVideoReader,currentIdx(i)); 98 | a = double(imresize(a(:,:,1),s)); 99 | lowVal = min(a(a>0)); 100 | highVal = max(a(a>0)); 101 | a = (a - lowVal) / (highVal - lowVal); 102 | 103 | R = radon(a,thetas); 104 | X(i,:) = R(pixels); 105 | 106 | end 107 | currentImage = currentBatchSize; 108 | 109 | mu = sum(X); 110 | C = cov(X).*currentBatchSize + (mu'*mu)./ currentBatchSize; 111 | 112 | else 113 | 114 | if j == num 115 | maxJ = M - currentImage; 116 | else 117 | maxJ = currentBatchSize; 118 | end 119 | 120 | tempMu(:) = 0; 121 | iterationIdx = currentIdx((1:maxJ) + currentImage); 122 | parfor i=1:maxJ 123 | 124 | a = read(currentVideoReader,iterationIdx(i)); 125 | a = double(imresize(a(:,:,1),s)); 126 | 127 | lowVal = min(a(a>0)); 128 | highVal = max(a(a>0)); 129 | a = (a - lowVal) / (highVal - lowVal); 130 | 131 | R = radon(a,thetas); 132 | y = R(pixels); 133 | X(i,:) = y'; 134 | tempMu = tempMu + y'; 135 | 136 | end 137 | 138 | mu = mu + tempMu; 139 | C = C + cov(X(1:maxJ,:)).*maxJ + (tempMu'*tempMu)./maxJ; 140 | currentImage = currentImage + maxJ; 141 | 142 | end 143 | 144 | end 145 | 146 | totalImages = totalImages + currentImage; 147 | 148 | 149 | end 150 | 151 | 152 | 153 | mu = mu ./ totalImages; 154 | C = C ./ totalImages - mu'*mu; 155 | 156 | fprintf(1,'Finding Principal Components\n'); 157 | [vecs,vals] = eig(C); 158 | 159 | vals = flipud(diag(vals)); 160 | vecs = fliplr(vecs); 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MotionMapper 2 | ============ 3 | 4 | Sample implementation of the MotionMapper behavioral analysis methods initially described in the paper “Mapping the stereotyped behaviour of freely-moving fruit flies” by Berman, GJ, Choi, DM, Bialek, W, and Shaevitz, JW, J. Royal Society Interface, 99, 20140672 (2014). 5 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This code represents a sample implementation of the MotionMapper behavioral analysis methods initially described in the paper “Mapping the stereotyped behaviour of freely-moving fruit flies” by Berman, GJ, Choi, DM, Bialek, W, and Shaevitz, JW (Journal of the Royal Society, Interface, 11, 20140672). 2 | 3 | 4 | This MATLAB code is presented in order to provide a more explicit representation of the algorithms described in the article text. 5 | 6 | ********* THIS IS !!!!NOT!!!! INTENDED TO BE STAND-ALONE SOFTWARE ********* 7 | 8 | As this code is presented for the sake of methodological repeatability (and not as “Black Box” software), the use of this software is at your own risk. The authors are not responsible for any damage that may result from errors in the software. 9 | 10 | Downloaders of this software are free to use, modify, or redistribute this software how they see fit, but only for non-commercial purposes and all modified versions may only be shared under the same conditions as this (see license below). For any further questions about this code, please email Gordon Berman at gberman(a t )princeton[dot)edu. 11 | 12 | This code was tested to perform properly using .avi movies of behaving flies, as described in the above paper. If desired, these (very large) movies can be obtained through emailing Joshua Shaevitz ( shaevitz[ @t]princeton(d ot)edu ). All tests were performed on a 12-core, 2.93 GHz Mac Pro with 64 GB of RAM installed. 13 | 14 | Many aspects of the code are memory-limited, so adjusting run parameters in order to fit the specifics of your hardware will likely be necessary. A listing of all parameters, their descriptions, and default values can be found in parameters.txt (Note: this is just a listing. Altering parameter values within this file will NOT affect the algorithms). 15 | 16 | All that being said, if any questions/concerns/bugs arise, please feel free to email me (Gordon), and I will do my absolute best to answer/resolve them. 17 | 18 | ******* 19 | 20 | 21 | 1) Add all directories to your path. 22 | 23 | 2) An example run-through of all the portions of the algorithm can be found in runExample.m. Given a folder of .avi movies (specified as ‘filePath’ at the top of the aforementioned file), this will run through each of the steps in the algorithm. It should be noted again that this code is not currently tested to work cross-platform or for any movies other than the ones presented in the original paper. 24 | 25 | 26 | 3) All default parameters can be adjusted within setRunParameters.m. Additionally, parameters can be set by inputting a struct containing the desired parameter name and value into the function (see code for details). 27 | 28 | 29 | 4) The major sub-routines for the method all can be run from individual files in the main directory, each named as coherently as possible: 30 | 31 | runAlignment.m -> Image segmentation and alignment. 32 | 33 | findRadonPixels.m -> Find image pixels with highest variance 34 | 35 | findPosturalEigenmodes.m -> Calculates a set of postural eigenmodes 36 | 37 | findProjections.m -> Finds time series of images projected onto eigenmodes 38 | 39 | findWavelets.m -> Computes the Morlet wavelet transform for a set of projections 40 | 41 | runEmbeddingSubSampling.m -> Finds a training set for t-SNE given a folder of projection files 42 | 43 | run_tSne.m -> Runs the t-SNE algorithm 44 | 45 | findEmbeddings.m -> Embeds a set of projections into a previously found embedding 46 | 47 | Details about this inputs and outputs to each of these functions can be found in within the file comments. 48 | 49 | 50 | 51 | ******* 52 | 53 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. 54 | -------------------------------------------------------------------------------- /findEmbeddings.m: -------------------------------------------------------------------------------- 1 | function [zValues,outputStatistics] = ... 2 | findEmbeddings(projections,trainingData,trainingEmbedding,parameters) 3 | %findEmbeddings finds the optimal embedding of a data set into a previously 4 | %found t-SNE embedding 5 | % 6 | % Input variables: 7 | % 8 | % projections -> N x (pcaModes x numPeriods) array of projection values 9 | % trainingData -> Nt x (pcaModes x numPeriods) array of wavelet 10 | % amplitudes containing Nt data points 11 | % trainingEmbedding -> Nt x 2 array of embeddings 12 | % parameters -> struct containing non-default choices for parameters 13 | % 14 | % 15 | % Output variables: 16 | % 17 | % zValues -> N x 2 array of embedding results 18 | % outputStatistics -> struct containing embedding outputs 19 | % 20 | % 21 | % (C) Gordon J. Berman, 2014 22 | % Princeton University 23 | 24 | if nargin < 4 25 | parameters = []; 26 | end 27 | parameters = setRunParameters(parameters); 28 | 29 | 30 | setup_parpool(parameters.numProcessors) 31 | 32 | 33 | d = length(projections(1,:)); 34 | numModes = parameters.pcaModes; 35 | numPeriods = parameters.numPeriods; 36 | 37 | if d == numModes*numPeriods 38 | 39 | data = projections; 40 | data(:) = bsxfun(@rdivide,data,sum(data,2)); 41 | 42 | minT = 1 ./ parameters.maxF; 43 | maxT = 1 ./ parameters.minF; 44 | Ts = minT.*2.^((0:numPeriods-1).*log(maxT/minT)/(log(2)*(numPeriods-1))); 45 | f = fliplr(1./Ts); 46 | 47 | else 48 | 49 | fprintf(1,'Finding Wavelets\n'); 50 | [data,f] = findWavelets(projections,numModes,parameters); 51 | data(:) = bsxfun(@rdivide,data,sum(data,2)); 52 | 53 | end 54 | 55 | fprintf(1,'Finding Embeddings\n'); 56 | [zValues,zCosts,zGuesses,inConvHull,meanMax,exitFlags] = ... 57 | findTDistributedProjections_fmin(data,trainingData,... 58 | trainingEmbedding,parameters); 59 | 60 | 61 | 62 | outputStatistics.zCosts = zCosts; 63 | outputStatistics.f = f; 64 | outputStatistics.numModes = numModes; 65 | outputStatistics.zGuesses = zGuesses; 66 | outputStatistics.inConvHull = inConvHull; 67 | outputStatistics.meanMax = meanMax; 68 | outputStatistics.exitFlags = exitFlags; 69 | 70 | 71 | 72 | 73 | 74 | if parameters.numProcessors > 1 && parameters.closeMatPool 75 | close_parpool 76 | end -------------------------------------------------------------------------------- /findPosturalEigenmodes.m: -------------------------------------------------------------------------------- 1 | function [vecs,vals,meanValue] = findPosturalEigenmodes(filePath,pixels,parameters) 2 | %findPosturalEigenmodes finds postural eigenmodes based upon a set of 3 | %aligned images within a directory. 4 | % 5 | % Input variables: 6 | % 7 | % filePath -> cell array of VideoReader objects or a directory 8 | % containing aligned .avi files 9 | % pixels -> radon-transform space pixels to use (Lx1 or 1xL array) 10 | % parameters -> struct containing non-default choices for parameters 11 | % 12 | % 13 | % Output variables: 14 | % 15 | % vecs -> postural eignmodes (LxL array). Each column (vecs(:,i)) is 16 | % an eigenmode corresponding to the eigenvalue vals(i) 17 | % vals -> eigenvalues of the covariance matrix 18 | % meanValue -> mean value for each of the pixels 19 | % 20 | % (C) Gordon J. Berman, 2014 21 | % Princeton University 22 | 23 | 24 | if nargin < 3 25 | parameters = []; 26 | end 27 | parameters = setRunParameters(parameters); 28 | 29 | 30 | setup_parpool(parameters.numProcessors) 31 | 32 | 33 | if iscell(filePath) 34 | 35 | vidObjs = filePath; 36 | 37 | else 38 | 39 | files = findAllImagesInFolders(filePath,'avi'); 40 | N = length(files); 41 | vidObjs = cell(N,1); 42 | parfor i=1:N 43 | vidObjs{i} = VideoReader(files{i}); 44 | end 45 | 46 | end 47 | 48 | 49 | numThetas = parameters.num_Radon_Thetas; 50 | spacing = 180/numThetas; 51 | thetas = linspace(0,180-spacing,numThetas); 52 | scale = parameters.rescaleSize; 53 | batchSize = parameters.pca_batchSize; 54 | numPerFile = parameters.pcaNumPerFile; 55 | 56 | [meanValue,vecs,vals] = ... 57 | onlineImagePCA_radon(vidObjs,batchSize,scale,pixels,thetas,numPerFile); 58 | 59 | 60 | 61 | if parameters.numProcessors > 1 && parameters.closeMatPool 62 | close_parpool 63 | end -------------------------------------------------------------------------------- /findProjections.m: -------------------------------------------------------------------------------- 1 | function projections = findProjections(filePath,vecs,meanValues,pixels,parameters) 2 | %findPosturalEigenmodes finds the projection of a set of images onto 3 | %postural eigenmodes. 4 | % 5 | % Input variables: 6 | % 7 | % filePath -> cell array of VideoReader objects or a directory 8 | % containing aligned .avi files 9 | % vecs -> postural eignmodes (L x (M mean value for each of the pixels 11 | % pixels -> radon-transform space pixels to use (Lx1 or 1xL array) 12 | % parameters -> struct containing non-default choices for parameters 13 | % 14 | % 15 | % Output variables: 16 | % 17 | % projections -> N x d array of projection values 18 | % 19 | % 20 | % (C) Gordon J. Berman, 2014 21 | % Princeton University 22 | 23 | 24 | if nargin < 5 25 | parameters = []; 26 | end 27 | parameters = setRunParameters(parameters); 28 | 29 | 30 | setup_parpool(parameters.numProcessors) 31 | 32 | %files = findAllImagesInFolders(filePath,'tiff'); 33 | %N = length(files); 34 | 35 | if iscell(filePath) 36 | 37 | vidObjs = filePath; 38 | 39 | else 40 | 41 | files = findAllImagesInFolders(filePath,'avi'); 42 | N = length(files); 43 | vidObjs = cell(N,1); 44 | parfor i=1:N 45 | vidObjs{i} = VideoReader(files{i}); 46 | end 47 | 48 | end 49 | 50 | 51 | 52 | numThetas = parameters.num_Radon_Thetas; 53 | spacing = 180/numThetas; 54 | thetas = linspace(0,180-spacing,numThetas); 55 | scale = parameters.rescaleSize; 56 | numProjections = parameters.numProjections; 57 | batchSize = parameters.pca_batchSize; 58 | 59 | projections = find_PCA_projections(vidObjs,vecs(:,1:numProjections),... 60 | meanValues,pixels,thetas,numProjections,scale,batchSize); 61 | 62 | 63 | if parameters.numProcessors > 1 && parameters.closeMatPool 64 | close_parpool 65 | end 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /findRadonPixels.m: -------------------------------------------------------------------------------- 1 | function [pixels,thetas,means,stDevs,vidObjs] = findRadonPixels(filePath,numToTest,parameters) 2 | %findRadonPixels finds a set of pixels that contain much of the observed 3 | %variance in the images given a set of aligned .tiff files. A gui will 4 | %pop-up asking the user to select a cut-off point. The left-most minimum 5 | %of the distribution is usually optimal for this 6 | % 7 | % Input variables: 8 | % 9 | % filePath -> directory containing aligned .tiff files 10 | % numToTest -> number of images from which to calculate values 11 | % parameters -> struct containing non-default choices for parameters 12 | % 13 | % 14 | % Output variables: 15 | % 16 | % pixels -> list of the chosen high-variance pixels 17 | % thetas -> list of the thetas used in the Radon transform 18 | % means -> double array containing the mean radon-transform values 19 | % stDevs -> double array containing the standard deviation of the 20 | % radon-transform values 21 | % vidObjs -> VideoReader objects for each of the aligned avi files 22 | % 23 | % (C) Gordon J. Berman, 2014 24 | % Princeton University 25 | 26 | if nargin < 3 27 | parameters = []; 28 | end 29 | parameters = setRunParameters(parameters); 30 | 31 | 32 | setup_parpool(parameters.numProcessors) 33 | 34 | 35 | numThetas = parameters.num_Radon_Thetas; 36 | spacing = 180/numThetas; 37 | thetas = linspace(0,180-spacing,numThetas); 38 | scale = parameters.rescaleSize; 39 | 40 | 41 | 42 | [means,stDevs,vidObjs] = findImageSubsetStatistics(filePath,numToTest,thetas,scale); 43 | 44 | 45 | [Y,X] = hist(stDevs(:),100); 46 | figure 47 | test = true; 48 | 49 | semilogy(X,Y,'o-') 50 | title('Select Truncation Point (Best if at Local Minimum)','fontsize',16,'fontweight','bold'); 51 | xlabel('Standard Deviation','fontsize',14,'fontweight','bold') 52 | ylabel('Number of Counts','fontsize',14,'fontweight','bold') 53 | while test 54 | 55 | [x,~] = ginput(1); 56 | pixels = find(stDevs(:) > x); 57 | title(['# of Pixels = ' num2str(length(pixels)) '. Is this OK? [y/n]'],'fontsize',16,'fontweight','bold'); 58 | 59 | [~,~,button] = ginput(1); 60 | while isempty(button) 61 | [~,~,button] = ginput(1); 62 | end 63 | 64 | while button ~= 121 && button ~= 110 && button ~= 89 && button ~= 78 65 | [~,~,button] = ginput(1); 66 | end 67 | 68 | if button == 121 || button == 89 69 | test = false; 70 | end 71 | 72 | end 73 | 74 | 75 | if parameters.numProcessors > 1 && parameters.closeMatPool 76 | close_parpool 77 | end 78 | -------------------------------------------------------------------------------- /findWavelets.m: -------------------------------------------------------------------------------- 1 | function [amplitudes,f] = findWavelets(projections,numModes,parameters) 2 | %findWavelets finds the wavelet transforms resulting from a time series 3 | % 4 | % Input variables: 5 | % 6 | % projections -> N x d array of projection values 7 | % numModes -> # of transforms to find 8 | % parameters -> struct containing non-default choices for parameters 9 | % 10 | % 11 | % Output variables: 12 | % 13 | % amplitudes -> wavelet amplitudes (N x (pcaModes*numPeriods) ) 14 | % f -> frequencies used in wavelet transforms (Hz) 15 | % 16 | % 17 | % (C) Gordon J. Berman, 2014 18 | % Princeton University 19 | 20 | 21 | if nargin < 3 22 | parameters = []; 23 | end 24 | parameters = setRunParameters(parameters); 25 | 26 | 27 | L = length(projections(1,:)); 28 | if nargin < 2 || isempty(numModes) 29 | numModes = L; 30 | else 31 | if numModes > L 32 | numModes = L; 33 | end 34 | end 35 | 36 | 37 | setup_parpool(parameters.numProcessors) 38 | 39 | 40 | 41 | omega0 = parameters.omega0; 42 | numPeriods = parameters.numPeriods; 43 | dt = 1 ./ parameters.samplingFreq; 44 | minT = 1 ./ parameters.maxF; 45 | maxT = 1 ./ parameters.minF; 46 | Ts = minT.*2.^((0:numPeriods-1).*log(maxT/minT)/(log(2)*(numPeriods-1))); 47 | f = fliplr(1./Ts); 48 | 49 | 50 | N = length(projections(:,1)); 51 | amplitudes = zeros(N,numModes*numPeriods); 52 | for i=1:numModes 53 | amplitudes(:,(1:numPeriods)+(i-1)*numPeriods) = ... 54 | fastWavelet_morlet_convolution_parallel(... 55 | projections(:,i),f,omega0,dt)'; 56 | end 57 | 58 | 59 | if parameters.numProcessors > 1 && parameters.closeMatPool 60 | close_parpool 61 | end 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /parameters.txt: -------------------------------------------------------------------------------- 1 | 2 | A listing of all parameters and their default values. Default values can be altered within setRunParameters.m. How to change parameters on a run-by-run basis is shown in runExample.m. 3 | 4 | 5 | 6 | 7 | %%%%%%%% General Parameters %%%%%%%% 8 | 9 | 10 | %number of processors to use in parallel code 11 | numProcessors = 12; 12 | 13 | %whether or not to close the matlabpool after running a routine 14 | closeMatPool = false; 15 | 16 | 17 | 18 | 19 | 20 | %%%%%%%% Segmentation and Alignment Parameters %%%%%%%% 21 | 22 | %angle spacing for alignement Radon transform 23 | alignment_angle_spacing = 1; 24 | 25 | %tolerance for translational alignment 26 | pixelTol = .1; 27 | 28 | %minimum area for use in image dilation/erosion 29 | minArea = 3500; 30 | 31 | %asymmetry threshold used in eliminating rotational degeneracy 32 | asymThreshold = 150; 33 | 34 | %line about which directional symmetry is 35 | %determined for eliminating rotational degeneracy 36 | symLine = 110; 37 | 38 | %initial guess for rotation angle 39 | initialPhi = 0; 40 | 41 | %initial dilation size for image segmentation 42 | dilateSize = 5; 43 | 44 | %parameter for Canny edge detection 45 | cannyParameter = .1; 46 | 47 | %threshold for image segmentation 48 | imageThreshold = 40; 49 | 50 | %largest allowed percentage reduction in area from frame to frame 51 | maxAreaDifference = .15; 52 | 53 | %toggle switch for image segmentation (alignment still performed) 54 | segmentationOff = false; 55 | 56 | %threshold for seperating body from background 57 | bodyThreshold = 150; 58 | 59 | 60 | 61 | 62 | %%%%%%%% PCA Parameters %%%%%%%% 63 | 64 | %number of angles in radon transform 65 | num_Radon_Thetas = 90; 66 | 67 | %image scaling factor 68 | rescaleSize = 10/7; 69 | 70 | %batch size for running online PCA 71 | pca_batchSize = 20000; 72 | 73 | %number of projections to find in PCA 74 | numProjections = 100; 75 | 76 | %number of PCA modes to use in later analyses 77 | pcaModes = 50; 78 | 79 | 80 | 81 | %%%%%%%% Wavelet Parameters %%%%%%%% 82 | 83 | %number of wavelet frequencies to use 84 | numPeriods = 25; 85 | 86 | %dimensionless Morlet wavelet parameter 87 | omega0 = 5; 88 | 89 | %sampling frequency (Hz) 90 | samplingFreq = 100; 91 | 92 | %minimum frequency for wavelet transform (Hz) 93 | minF = 1; 94 | 95 | %maximum frequency for wavelet transform (Hz) 96 | maxF = 50; 97 | 98 | 99 | 100 | 101 | 102 | 103 | %%%%%%%% t-SNE Parameters %%%%%%%% 104 | 105 | 106 | %2^H (H is the transition entropy) 107 | perplexity = 32; 108 | 109 | %relative convergence criterium for t-SNE 110 | relTol = 1e-4; 111 | 112 | %number of dimensions for use in t-SNE 113 | num_tsne_dim = 2; 114 | 115 | %binary search tolerance for finding pointwise transition region 116 | sigmaTolerance = 1e-5; 117 | 118 | %maximum number of non-zero neighbors in P 119 | maxNeighbors = 200; 120 | 121 | %initial momentum 122 | momentum = .5; 123 | 124 | %value to which momentum is changed 125 | final_momentum = 0.8; 126 | 127 | %iteration at which momentum is changed 128 | mom_switch_iter = 250; 129 | 130 | %iteration at which lying about P-values is stopped 131 | stop_lying_iter = 125; 132 | 133 | %degree of P-value expansion at early iterations 134 | lie_multiplier = 4; 135 | 136 | %maximum number of iterations 137 | max_iter = 1000; 138 | 139 | %initial learning rate 140 | epsilon = 500; 141 | 142 | %minimum gain for delta-bar-delta 143 | min_gain = .01; 144 | 145 | %readout variable for t-SNE 146 | tsne_readout = 1; 147 | 148 | %embedding batchsize 149 | embedding_batchSize = 20000; 150 | 151 | %maximum number of iterations for the Nelder-Mead algorithm 152 | maxOptimIter = 100; 153 | 154 | %number of points in the training set 155 | trainingSetSize = 35000; 156 | 157 | %local neighborhood definition in training set creation 158 | kdNeighbors = 5; 159 | 160 | %t-SNE training set stopping critereon 161 | training_relTol = 2e-3; 162 | 163 | %t-SNE training set perplexity 164 | training_perplexity = 20; 165 | 166 | %number of points to evaluate in each training set file 167 | training_numPoints = 10000; 168 | 169 | %minimum training set template length 170 | minTemplateLength = 1; 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /runAlignment.m: -------------------------------------------------------------------------------- 1 | function outputStruct = runAlignment(fileName,outputPath,startImage,finalImage,parameters) 2 | %runAlignment runs the alignment and segmentation routines on a .avi file 3 | % and saves the output files to a directorty 4 | % 5 | % Input variables: 6 | % 7 | % fileName -> avi file to be analyzed 8 | % outputPath -> path to which files are saved 9 | % startImage -> first image in path to be analyzed 10 | % finalImage -> last image in path to be analyzed 11 | % parameters -> struct containing non-default choices for parameters 12 | % 13 | % 14 | % Output variable: 15 | % 16 | % outputStruct -> struct containing found alignment variables 17 | % 18 | % (C) Gordon J. Berman, 2014 19 | % Princeton University 20 | 21 | 22 | if ~exist(outputPath,'dir') 23 | mkdir(outputPath); 24 | end 25 | 26 | 27 | if nargin < 3 || isempty(startImage) 28 | startImage = 1; 29 | end 30 | 31 | 32 | if nargin < 4 || isempty(finalImage) 33 | finalImage = []; 34 | end 35 | 36 | 37 | if nargin < 5 || isempty(parameters) 38 | parameters = []; 39 | end 40 | 41 | parameters = setRunParameters(parameters); 42 | 43 | 44 | setup_parpool(parameters.numProcessors) 45 | 46 | 47 | [Xs,Ys,angles,areas,~,framesToCheck,svdskipped,areanorm] = ... 48 | alignImages_Radon_parallel_avi(fileName,startImage,finalImage,... 49 | outputPath,parameters); 50 | 51 | 52 | %See alignImages_Radon_parallel_avi for definitions of these variables 53 | outputStruct.Xs = Xs; 54 | outputStruct.Ys = Ys; 55 | outputStruct.angles = angles; 56 | outputStruct.areas = areas; 57 | outputStruct.parameters = parameters; 58 | outputStruct.framesToCheck = framesToCheck; 59 | outputStruct.svdskipped = svdskipped; 60 | outputStruct.areanorm = areanorm; 61 | 62 | 63 | if parameters.numProcessors > 1 && parameters.closeMatPool 64 | close_parpool 65 | end 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /runEmbeddingSubSampling.m: -------------------------------------------------------------------------------- 1 | function [trainingSetData,trainingSetAmps,projectionFiles] = runEmbeddingSubSampling(projectionDirectory,parameters) 2 | %runEmbeddingSubSampling generates a training set given a set of .mat files 3 | % 4 | % Input variables: 5 | % 6 | % projectionDirectory -> directory path containing .mat projection 7 | % files. Each of these files should contain 8 | % an N x pcaModes variable, 'projections' 9 | % parameters -> struct containing non-default choices for parameters 10 | % 11 | % 12 | % Output variables: 13 | % 14 | % trainingSetData -> normalized wavelet training set 15 | % (N x (pcaModes*numPeriods) ) 16 | % trainingSetAmps -> Nx1 array of training set wavelet amplitudes 17 | % projectionFiles -> cell array of files in 'projectionDirectory' 18 | % 19 | % 20 | % (C) Gordon J. Berman, 2014 21 | % Princeton University 22 | 23 | 24 | if nargin < 2 25 | parameters = []; 26 | end 27 | parameters = setRunParameters(parameters); 28 | 29 | setup_parpool(parameters.numProcessors) 30 | 31 | 32 | projectionFiles = findAllImagesInFolders(projectionDirectory,'.mat'); 33 | 34 | N = parameters.trainingSetSize; 35 | L = length(projectionFiles); 36 | numPerDataSet = round(N/L); 37 | numModes = parameters.pcaModes; 38 | numPeriods = parameters.numPeriods; 39 | 40 | trainingSetData = zeros(numPerDataSet*L,numModes*numPeriods); 41 | trainingSetAmps = zeros(numPerDataSet*L,1); 42 | useIdx = true(numPerDataSet*L,1); 43 | 44 | for i=1:L 45 | 46 | fprintf(1,['Finding training set contributions from data set #' ... 47 | num2str(i) '\n']); 48 | 49 | currentIdx = (1:numPerDataSet) + (i-1)*numPerDataSet; 50 | 51 | [yData,signalData,~,signalAmps] = ... 52 | file_embeddingSubSampling(projectionFiles{i},parameters); 53 | 54 | [trainingSetData(currentIdx,:),trainingSetAmps(currentIdx)] = ... 55 | findTemplatesFromData(signalData,yData,signalAmps,... 56 | numPerDataSet,parameters); 57 | 58 | a = sum(trainingSetData(currentIdx,:),2) == 0; 59 | useIdx(currentIdx(a)) = false; 60 | 61 | end 62 | 63 | trainingSetData = trainingSetData(useIdx,:); 64 | trainingSetAmps = trainingSetAmps(useIdx); 65 | 66 | 67 | if parameters.numProcessors > 1 && parameters.closeMatPool 68 | close_parpool 69 | end 70 | -------------------------------------------------------------------------------- /runExample.m: -------------------------------------------------------------------------------- 1 | %%example script that will run the code for a set of .avi files that are 2 | %%found in filePath 3 | 4 | %Place path to folder containing example .avi files here 5 | filePath = ''; 6 | 7 | %add utilities folder to path 8 | addpath(genpath('./utilities/')); 9 | addpath(genpath('./PCA/')); 10 | addpath(genpath('./segmentation_alignment/')); 11 | addpath(genpath('./t_sne/')); 12 | addpath(genpath('./wavelet/')); 13 | 14 | %find all avi files in 'filePath' 15 | imageFiles = findAllImagesInFolders(filePath,'.avi'); 16 | L = length(imageFiles); 17 | numZeros = ceil(log10(L+1e-10)); 18 | 19 | %define any desired parameter changes here 20 | parameters.samplingFreq = 100; 21 | parameters.trainingSetSize = 5000; 22 | 23 | %initialize parameters 24 | parameters = setRunParameters(parameters); 25 | 26 | firstFrame = 1; 27 | lastFrame = []; 28 | 29 | %% Run Alignment 30 | 31 | %creating alignment directory 32 | alignmentDirectory = [filePath '/alignment_files/']; 33 | if ~exist(alignmentDirectory,'dir') 34 | mkdir(alignmentDirectory); 35 | end 36 | 37 | 38 | %run alignment for all files in the directory 39 | fprintf(1,'Aligning Files\n'); 40 | alignmentFolders = cell(L,1); 41 | for ii=1:L 42 | 43 | fprintf(1,'\t Aligning File #%4i out of %4i\n',ii,L); 44 | 45 | fileNum = [repmat('0',1,numZeros-length(num2str(ii))) num2str(ii)]; 46 | tempDirectory = [alignmentDirectory 'alignment_' fileNum '/']; 47 | alignmentFolders{ii} = tempDirectory; 48 | 49 | outputStruct = runAlignment(imageFiles{ii},tempDirectory,firstFrame,lastFrame,parameters); 50 | 51 | save([tempDirectory 'outputStruct.mat'],'outputStruct'); 52 | 53 | clear outputStruct 54 | clear fileNum 55 | clear tempDirectory 56 | 57 | end 58 | 59 | 60 | %% Find image subset statistics (a gui will pop-up here) 61 | 62 | fprintf(1,'Finding Subset Statistics\n'); 63 | numToTest = parameters.pca_batchSize; 64 | [pixels,thetas,means,stDevs,vidObjs] = findRadonPixels(alignmentDirectory,numToTest,parameters); 65 | 66 | 67 | %% Find postural eigenmodes 68 | 69 | fprintf(1,'Finding Postural Eigenmodes\n'); 70 | [vecs,vals,meanValues] = findPosturalEigenmodes(vidObjs,pixels,parameters); 71 | 72 | vecs = vecs(:,1:parameters.numProjections); 73 | 74 | figure 75 | makeMultiComponentPlot_radon_fromVecs(vecs(:,1:25),25,thetas,pixels,[201 90]); 76 | caxis([-3e-3 3e-3]) 77 | colorbar 78 | title('First 25 Postural Eigenmodes','fontsize',14,'fontweight','bold'); 79 | drawnow; 80 | 81 | 82 | %% Find projections for each data set 83 | 84 | projectionsDirectory = [filePath './projections/']; 85 | if ~exist(projectionsDirectory,'dir') 86 | mkdir(projectionsDirectory); 87 | end 88 | 89 | fprintf(1,'Finding Projections\n'); 90 | for i=1:L 91 | 92 | fprintf(1,'\t Finding Projections for File #%4i out of %4i\n',i,L); 93 | projections = findProjections(alignmentFolders{i},vecs,meanValues,pixels,parameters); 94 | 95 | fileNum = [repmat('0',1,numZeros-length(num2str(i))) num2str(i)]; 96 | fileName = imageFiles{i}; 97 | 98 | save([projectionsDirectory 'projections_' fileNum '.mat'],'projections','fileName'); 99 | 100 | clear projections 101 | clear fileNum 102 | clear fileName 103 | 104 | end 105 | 106 | 107 | %% Use subsampled t-SNE to find training set 108 | 109 | fprintf(1,'Finding Training Set\n'); 110 | [trainingSetData,trainingSetAmps,projectionFiles] = ... 111 | runEmbeddingSubSampling(projectionsDirectory,parameters); 112 | 113 | %% Run t-SNE on training set 114 | 115 | 116 | fprintf(1,'Finding t-SNE Embedding for the Training Set\n'); 117 | [trainingEmbedding,betas,P,errors] = run_tSne(trainingSetData,parameters); 118 | 119 | 120 | %% Find Embeddings for each file 121 | 122 | fprintf(1,'Finding t-SNE Embedding for each file\n'); 123 | embeddingValues = cell(L,1); 124 | for i=1:L 125 | 126 | fprintf(1,'\t Finding Embbeddings for File #%4i out of %4i\n',i,L); 127 | 128 | load(projectionFiles{i},'projections'); 129 | projections = projections(:,1:parameters.pcaModes); 130 | 131 | [embeddingValues{i},~] = ... 132 | findEmbeddings(projections,trainingSetData,trainingEmbedding,parameters); 133 | 134 | clear projections 135 | 136 | end 137 | 138 | %% Make density plots 139 | 140 | 141 | 142 | maxVal = max(max(abs(combineCells(embeddingValues)))); 143 | maxVal = round(maxVal * 1.1); 144 | 145 | sigma = maxVal / 40; 146 | numPoints = 501; 147 | rangeVals = [-maxVal maxVal]; 148 | 149 | [xx,density] = findPointDensity(combineCells(embeddingValues),sigma,numPoints,rangeVals); 150 | 151 | densities = zeros(numPoints,numPoints,L); 152 | for i=1:L 153 | [~,densities(:,:,i)] = findPointDensity(embeddingValues{i},sigma,numPoints,rangeVals); 154 | end 155 | 156 | 157 | figure 158 | maxDensity = max(density(:)); 159 | imagesc(xx,xx,density) 160 | axis equal tight off xy 161 | caxis([0 maxDensity * .8]) 162 | colormap(jet) 163 | colorbar 164 | 165 | 166 | 167 | figure 168 | 169 | N = ceil(sqrt(L)); 170 | M = ceil(L/N); 171 | maxDensity = max(densities(:)); 172 | for i=1:L 173 | subplot(M,N,i) 174 | imagesc(xx,xx,densities(:,:,i)) 175 | axis equal tight off xy 176 | caxis([0 maxDensity * .8]) 177 | colormap(jet) 178 | title(['Data Set #' num2str(i)],'fontsize',12,'fontweight','bold'); 179 | end 180 | 181 | 182 | 183 | close_parpool 184 | 185 | -------------------------------------------------------------------------------- /runExample_noSubsampling.m: -------------------------------------------------------------------------------- 1 | %%example script that will run the code for a single .avi file (moviePath) 2 | %%This version does not perform subsampling to find a training set 3 | 4 | %Place path to folder containing example .avi files here 5 | moviePath = ''; 6 | 7 | %add utilities folder to path 8 | addpath(genpath('./utilities/')); 9 | addpath(genpath('./PCA/')); 10 | addpath(genpath('./segmentation_alignment/')); 11 | addpath(genpath('./t_sne/')); 12 | addpath(genpath('./wavelet/')); 13 | 14 | %set file path 15 | [filePath,fileName,~] = fileparts(moviePath); 16 | filePath = [filePath '/' fileName '/']; 17 | imageFiles = {moviePath}; 18 | L = length(imageFiles); 19 | numZeros = ceil(log10(L+1e-10)); 20 | 21 | [status,~]=unix(['ls ' filePath]); 22 | if status ~= 0 23 | unix(['mkdir ' filePath]); 24 | end 25 | 26 | %define any desired parameter changes here 27 | parameters.samplingFreq = 100; 28 | parameters.trainingSetSize = 5000; 29 | 30 | %initialize parameters 31 | parameters = setRunParameters(parameters); 32 | 33 | firstFrame = 1; 34 | lastFrame = []; 35 | 36 | %% Run Alignment 37 | 38 | %creating alignment directory 39 | alignmentDirectory = [filePath '/alignment_files/']; 40 | if ~exist(alignmentDirectory,'dir') 41 | mkdir(alignmentDirectory); 42 | end 43 | 44 | 45 | %run alignment for all files in the directory 46 | fprintf(1,'Aligning Files\n'); 47 | alignmentFolders = cell(L,1); 48 | ii=1; 49 | 50 | fileNum = [repmat('0',1,numZeros-length(num2str(ii))) num2str(ii)]; 51 | tempDirectory = [alignmentDirectory 'alignment_' fileNum '/']; 52 | alignmentFolders{ii} = tempDirectory; 53 | outputStruct = runAlignment(imageFiles{ii},tempDirectory,firstFrame,lastFrame,parameters); 54 | 55 | save([tempDirectory 'outputStruct.mat'],'outputStruct'); 56 | 57 | 58 | 59 | 60 | 61 | %% Find image subset statistics (a gui will pop-up here) 62 | 63 | fprintf(1,'Finding Subset Statistics\n'); 64 | numToTest = parameters.pca_batchSize; 65 | [pixels,thetas,means,stDevs,vidObjs] = findRadonPixels(alignmentDirectory,numToTest,parameters); 66 | 67 | 68 | %% Find postural eigenmodes 69 | 70 | fprintf(1,'Finding Postural Eigenmodes\n'); 71 | [vecs,vals,meanValues] = findPosturalEigenmodes(vidObjs,pixels,parameters); 72 | 73 | vecs = vecs(:,1:parameters.numProjections); 74 | 75 | figure 76 | makeMultiComponentPlot_radon_fromVecs(vecs(:,1:25),25,thetas,pixels,[201 90]); 77 | caxis([-3e-3 3e-3]) 78 | colorbar 79 | title('First 25 Postural Eigenmodes','fontsize',14,'fontweight','bold'); 80 | drawnow; 81 | 82 | 83 | %% Find projections 84 | 85 | projectionsDirectory = [filePath './projections/']; 86 | if ~exist(projectionsDirectory,'dir') 87 | mkdir(projectionsDirectory); 88 | end 89 | 90 | fprintf(1,'Finding Projections\n'); 91 | ii=1; 92 | projections = findProjections(alignmentFolders{ii},vecs,meanValues,pixels,parameters); 93 | 94 | fileNum = [repmat('0',1,numZeros-length(num2str(ii))) num2str(ii)]; 95 | fileName = imageFiles{ii}; 96 | 97 | save([projectionsDirectory 'projections_' fileNum '.mat'],'projections','fileName'); 98 | 99 | 100 | %% Embed training set 101 | 102 | fprintf(1,'Calculating Wavelet Transform\n'); 103 | [data,f] = findWavelets(projections,parameters.pcaModes,parameters); 104 | 105 | amps = sum(data,2); 106 | data(:) = bsxfun(@rdivide,data,amps); 107 | 108 | skipLength = round(length(data(:,1))/parameters.trainingSetSize); 109 | 110 | trainingSetData = data(skipLength:skipLength:end,:); 111 | trainingAmps = amps(skipLength:skipLength:end); 112 | parameters.signalLabels = log10(trainingAmps); 113 | 114 | 115 | fprintf(1,'Finding t-SNE Embedding for Training Set\n'); 116 | [trainingEmbedding,betas,P,errors] = run_tSne(trainingSetData,parameters); 117 | 118 | 119 | %% Find All Embeddings 120 | 121 | fprintf(1,'Finding t-SNE Embedding for all Data\n'); 122 | embeddingValues = cell(L,1); 123 | i=1; 124 | 125 | [embeddingValues{ii},~] = findEmbeddings(data,trainingSetData,trainingEmbedding,parameters); 126 | 127 | 128 | 129 | %% Make density plots 130 | 131 | 132 | maxVal = max(max(abs(combineCells(embeddingValues)))); 133 | maxVal = round(maxVal * 1.1); 134 | 135 | sigma = maxVal / 40; 136 | numPoints = 501; 137 | rangeVals = [-maxVal maxVal]; 138 | 139 | [xx,density] = findPointDensity(combineCells(embeddingValues),sigma,numPoints,rangeVals); 140 | 141 | densities = zeros(numPoints,numPoints,L); 142 | for i=1:L 143 | [~,densities(:,:,ii)] = findPointDensity(embeddingValues{ii},sigma,numPoints,rangeVals); 144 | end 145 | 146 | 147 | figure 148 | maxDensity = max(density(:)); 149 | imagesc(xx,xx,density) 150 | axis equal tight off xy 151 | caxis([0 maxDensity * .8]) 152 | colormap(jet) 153 | colorbar 154 | 155 | 156 | 157 | figure 158 | 159 | N = ceil(sqrt(L)); 160 | M = ceil(L/N); 161 | maxDensity = max(densities(:)); 162 | for i=1:L 163 | subplot(M,N,ii) 164 | imagesc(xx,xx,densities(:,:,ii)) 165 | axis equal tight off xy 166 | caxis([0 maxDensity * .8]) 167 | colormap(jet) 168 | title(['Data Set #' num2str(ii)],'fontsize',12,'fontweight','bold'); 169 | end 170 | 171 | 172 | 173 | close_parpool 174 | 175 | -------------------------------------------------------------------------------- /run_tSne.m: -------------------------------------------------------------------------------- 1 | function [yData,betas,P,errors] = run_tSne(data,parameters) 2 | %run_tSne runs the t-SNE algorithm on an array of normalized wavelet amplitudes 3 | % 4 | % Input variables: 5 | % 6 | % data -> Nxd array of wavelet amplitudes (will normalize if 7 | % unnormalized) containing N data points 8 | % parameters -> struct containing non-default choices for parameters 9 | % 10 | % 11 | % Output variables: 12 | % 13 | % yData -> N x parameters.num_tsne_dim array of embedding results 14 | % betas -> Nx1 array of local region size parameters 15 | % P -> full space transition matrix 16 | % errors -> P.*log2(P./Q) as a function of t-SNE iteration 17 | % 18 | % 19 | % (C) Gordon J. Berman, 2014 20 | % Princeton University 21 | 22 | if nargin < 2 23 | parameters = []; 24 | end 25 | 26 | parameters = setRunParameters(parameters); 27 | 28 | 29 | vals = sum(data,2); 30 | if max(vals) > 1 || min(vals) < 1 31 | data = bsxfun(@rdivide,data,vals); 32 | end 33 | 34 | fprintf(1,'Finding Distances\n'); 35 | D = findKLDivergences(data); 36 | 37 | 38 | fprintf(1,'Computing t-SNE\n'); 39 | [yData,betas,P,errors] = tsne_d(D,parameters); -------------------------------------------------------------------------------- /segmentation_alignment/alignImages_Radon_parallel_avi.m: -------------------------------------------------------------------------------- 1 | function [Xs,Ys,angles,areas,parameters,framesToCheck,svdskipped,areanorm] = ... 2 | alignImages_Radon_parallel_avi(file_path,startImage,finalImage,image_path,parameters) 3 | %alignImages_Radon_parallel_avi runs the alignment and segmentation routines on a .avi file 4 | % and saves the output files to a directorty (called by ../runAlignment.m) 5 | % 6 | % Input variables: 7 | % 8 | % file_path -> avi file to be analyzed 9 | % startImage -> first frame of the avi file to be analyzed 10 | % finalImage -> last frame of the avi file to be analyzed 11 | % image_path -> path to which files are saved 12 | % parameters -> struct containing parameters 13 | % 14 | % 15 | % Output variables: 16 | % 17 | % Xs -> alignment x translations 18 | % Ys -> alignment y translations 19 | % angles -> alignment rotations 20 | % areas -> segmented areas after segmentation 21 | % framesToCheck -> frames where a large rotation occurs in a single 22 | % frame. This might signal a 180 degree rotation 23 | % error 24 | % svdskipped -> blank frames where alignment is skipped 25 | % areanorm -> normalizing factor for fly size 26 | % 27 | % (C) Gordon J. Berman, 2014 28 | % Princeton University 29 | 30 | warning off MATLAB:polyfit:RepeatedPointsOrRescale; 31 | warning off MATLAB:audiovideo:aviinfo:FunctionToBeRemoved; 32 | 33 | readout = 100; 34 | nDigits = 8; 35 | 36 | spacing = parameters.alignment_angle_spacing; 37 | pixelTol = parameters.pixelTol; 38 | minArea = parameters.minArea; 39 | asymThreshold = parameters.asymThreshold; 40 | symLine = parameters.symLine; 41 | initialPhi = parameters.initialPhi; 42 | dilateSize = parameters.dilateSize; 43 | cannyParameter = parameters.cannyParameter; 44 | imageThreshold = parameters.imageThreshold; 45 | maxAreaDifference = parameters.maxAreaDifference; 46 | segmentationOff = parameters.segmentationOff; 47 | basisImage = parameters.basisImage; 48 | bodyThreshold = parameters.bodyThreshold; 49 | numProcessors = parameters.numProcessors; 50 | rangeExtension = parameters.rangeExtension; 51 | 52 | %Choose starting and finishing images 53 | 54 | vidObj = VideoReader(file_path); 55 | nFrames = vidObj.NumberOfFrames; 56 | 57 | if isempty(startImage) 58 | startImage = 1000; 59 | end 60 | 61 | if isempty(finalImage) 62 | if nFrames < 361000 63 | finalImage = nFrames; 64 | else 65 | finalImage = 361000; 66 | end 67 | end 68 | 69 | 70 | segmentationOptions.imageThreshold = imageThreshold; 71 | segmentationOptions.cannyParameter = cannyParameter; 72 | segmentationOptions.dilateSize = dilateSize; 73 | segmentationOptions.minArea = minArea; 74 | segmentationOptions.spacing = spacing; 75 | segmentationOptions.pixelTol = pixelTol; 76 | segmentationOptions.maxAreaDifference = maxAreaDifference; 77 | segmentationOptions.segmentationOff = segmentationOff; 78 | segmentationOptions.asymThreshold = asymThreshold; 79 | segmentationOptions.symLine = symLine; 80 | 81 | 82 | %Area normalization and (possibly) bodyThreshold finding 83 | 84 | idx = randi([startImage,nFrames],[parameters.areaNormalizationNumber,1]); 85 | basisSize = sum(basisImage(:)>0); 86 | s = size(basisImage); 87 | 88 | temp=vidObj.read(idx(1)); 89 | if size(temp,3)>1 90 | IS_RGB = true; 91 | fprintf('WARNING: your movie is RGB. Using only R channel for processing.\n') 92 | else 93 | IS_RGB = false; 94 | end 95 | currentImageSet = uint8(zeros(s(1),s(2),parameters.areaNormalizationNumber)); 96 | 97 | parfor ii=1:length(idx) 98 | temp = vidObj.read(idx(ii)); 99 | if IS_RGB 100 | currentImageSet(:,:,ii) = temp(:,:,1); 101 | else 102 | currentImageSet(:,:,ii) = temp; 103 | end 104 | end 105 | 106 | if bodyThreshold < 0 107 | T = zeros(length(idx),parameters.areaNormalizationNumber); 108 | parfor i=1:length(idx) 109 | [testImage,mask] = segmentImage_combo(currentImageSet(:,:,i),5,.05,[],[],[],1000,true); 110 | if sum(mask(:)) > 1000 111 | II = testImage(testImage>0); 112 | T(i) = autoFindThreshold_gmm(II,3); 113 | end 114 | end 115 | 116 | T = T(T>0); 117 | bodyThreshold = quantile(T,.25); 118 | parameters.bodyThreshold = bodyThreshold; 119 | 120 | end 121 | 122 | 123 | if parameters.asymThreshold < 0 124 | parameters.asymThreshold = parameters.bodyThreshold; 125 | asymThreshold = parameters.asymThreshold; 126 | end 127 | 128 | 129 | imageSizes = zeros(size(idx)); 130 | for j = 1:parameters.areaNormalizationNumber 131 | a = currentImageSet(:,:,j); 132 | imageSizes(j) = sum(imcomplement(a(:))>bodyThreshold); 133 | end 134 | imageSize = median(imageSizes); 135 | areanorm = sqrt(basisSize/imageSize); 136 | 137 | 138 | if isempty(image_path) 139 | image_path = input('Image Path = ?: ', 's'); 140 | end 141 | 142 | [status,~]=unix(['ls ' image_path]); 143 | if status == 1 144 | unix(['mkdir ' image_path]); 145 | end 146 | 147 | if ~segmentationOff 148 | referenceImage = segmentImage_combo(basisImage,dilateSize,... 149 | cannyParameter,imageThreshold,[],[],minArea,true); 150 | else 151 | referenceImage = basisImage; 152 | end 153 | 154 | [ii,~] = find(referenceImage > 0); 155 | minRangeValue = min(ii) - rangeExtension; 156 | maxRangeValue = max(ii) + rangeExtension; 157 | 158 | segmentationOptions.referenceImage = referenceImage; 159 | segmentationOptions.minRangeValue = minRangeValue; 160 | segmentationOptions.maxRangeValue = maxRangeValue; 161 | 162 | %define groupings 163 | imageVals = startImage:finalImage; 164 | numImages = length(imageVals); 165 | minNumPer = floor(numImages / numProcessors+1e-20); 166 | remainder = mod(numImages,numProcessors); 167 | count = 1; 168 | groupings = cell(numProcessors,1); 169 | for i=1:numProcessors 170 | if i <= remainder 171 | groupings{i} = imageVals(count:(count+minNumPer)); 172 | count = count + minNumPer + 1; 173 | else 174 | groupings{i} = imageVals(count:(count+minNumPer-1)); 175 | count = count + minNumPer; 176 | end 177 | end 178 | 179 | 180 | 181 | % Write Out Grouping Start and Finish indices 182 | groupidx = zeros(length(groupings),2); 183 | for i = 1:length(groupings) 184 | groupidx(i,1) = groupings{i}(1); 185 | groupidx(i,2) = groupings{i}(end); 186 | end 187 | 188 | 189 | %initialize new avi files 190 | alignmentFiles = cell(numProcessors,1); 191 | fDigits = ceil(log10(numProcessors+1e-10)); 192 | for i=1:numProcessors 193 | qq = num2str(i); 194 | qq = [repmat('0',1,fDigits - length(qq)) qq]; 195 | alignmentFiles{i} = VideoWriter([image_path '/' qq '.avi']); 196 | end 197 | 198 | x1s = zeros(numProcessors,1); 199 | y1s = zeros(numProcessors,1); 200 | angle1s = zeros(numProcessors,1); 201 | area1s = zeros(numProcessors,1); 202 | svdskip1s = zeros(numProcessors,1); 203 | 204 | currentPhis = zeros(numProcessors,1); 205 | 206 | 207 | %initialize First Images 208 | 209 | images = cell(numProcessors,1); 210 | for j=1:numProcessors 211 | 212 | fprintf(1,'Finding initial orientation for processor #%2i\n',j); 213 | 214 | i = groupings{j}(1); 215 | 216 | originalImage = read(vidObj,i); 217 | if length(size(originalImage)) == 3 218 | originalImage = originalImage(:,:,1); 219 | end 220 | 221 | if ~segmentationOff 222 | imageOut = segmentImage_combo(originalImage,dilateSize,cannyParameter,... 223 | imageThreshold,[],[],minArea,true); 224 | imageOut = rescaleImage(imageOut,areanorm); 225 | else 226 | imageOut = originalImage; 227 | imageOut = rescaleImage(imageOut,areanorm); 228 | end 229 | 230 | imageOut2 = imageOut; 231 | imageOut2(imageOut2 < asymThreshold) = 0; 232 | 233 | if max(imageOut2(:)) ~= 0 234 | 235 | [angle1s(j),x1s(j),y1s(j),~,~,image] = ... 236 | alignTwoImages(referenceImage,imageOut2,initialPhi,spacing,pixelTol,false,imageOut); 237 | 238 | 239 | s = size(image); 240 | b = image; 241 | b(b > asymThreshold) = 0; 242 | if minRangeValue > 1 243 | b(1:minRangeValue-1,:) = 0; 244 | end 245 | if maxRangeValue < length(referenceImage(:,1)) 246 | b(maxRangeValue+1:end,:) = 0; 247 | end 248 | 249 | 250 | q = sum(b) ./ sum(b(:)); 251 | asymValue = symLine - sum(q.*(1:s(1))); 252 | 253 | 254 | if asymValue < 0 255 | 256 | initialPhi = mod(initialPhi+180,360); 257 | 258 | [tempAngle,tempX,tempY,~,~,tempImage] = ... 259 | alignTwoImages(referenceImage,imageOut2,initialPhi,spacing,pixelTol,false,imageOut); 260 | 261 | b = tempImage; 262 | b(b > asymThreshold) = 0; 263 | if minRangeValue > 1 264 | b(1:minRangeValue-1,:) = 0; 265 | end 266 | if maxRangeValue < length(referenceImage(:,1)) 267 | b(maxRangeValue+1:end,:) = 0; 268 | end 269 | 270 | q = sum(b>0)./sum(b(:)>0); 271 | asymValue2 = symLine - sum(q.*(1:s(1))); 272 | 273 | if asymValue2 > asymValue 274 | angle1s(j) = tempAngle; 275 | x1s(j) = tempX; 276 | y1s(j) = tempY; 277 | image = tempImage; 278 | end 279 | 280 | end 281 | 282 | area1s(j) = sum(imageOut(:) ~= 0); 283 | currentPhis(j) = angle1s(j); 284 | images{j} = image; 285 | svdskip1s(j) = 0; 286 | 287 | else 288 | 289 | area1s(j) = sum(imageOut(:) ~= 0); 290 | currentPhis(j) = initialPhi; 291 | angle1s(j) = initialPhi; 292 | svdskip1s(j) = 1; 293 | image = uint8(zeros(size(imageOut2))); 294 | images{j} = image; 295 | 296 | end 297 | 298 | end 299 | 300 | 301 | fprintf(1,'Aligning Images\n'); 302 | 303 | tic 304 | Xs_temp = cell(numProcessors,1); 305 | Ys_temp = cell(numProcessors,1); 306 | Angles_temp = cell(numProcessors,1); 307 | Areas_temp = cell(numProcessors,1); 308 | svdskips_temp = cell(numProcessors,1); 309 | 310 | 311 | parfor i=1:numProcessors 312 | 313 | [Xs_temp{i},Ys_temp{i},Angles_temp{i},Areas_temp{i},svdskips_temp{i}] = ... 314 | align_subroutine_parallel_avi(groupings{i},currentPhis(i),... 315 | segmentationOptions,nDigits,file_path,alignmentFiles{i},readout,i,... 316 | asymThreshold,area1s(i),vidObj,[],areanorm,images{i}); 317 | 318 | 319 | 320 | Xs_temp{i}(1) = x1s(i); 321 | Ys_temp{i}(1) = y1s(i); 322 | Areas_temp{i}(1) = area1s(i); 323 | Angles_temp{i}(1) = angle1s(i); 324 | svdskips_temp{i}(1) = svdskip1s(i); 325 | 326 | close(alignmentFiles{i}); 327 | 328 | end 329 | 330 | 331 | Xs = combineCells(Xs_temp); 332 | Ys = combineCells(Ys_temp); 333 | angles = combineCells(Angles_temp); 334 | areas = combineCells(Areas_temp); 335 | svdskips = combineCells(svdskips_temp); 336 | 337 | 338 | 339 | x = abs(diff(unwrap(angles.*pi/180).*180/pi)); 340 | framesToCheck = find(x > 90) + 1; 341 | svdskipped = find(svdskips == 1); 342 | 343 | 344 | 345 | 346 | 347 | -------------------------------------------------------------------------------- /segmentation_alignment/alignTwoImages.m: -------------------------------------------------------------------------------- 1 | function [rotationAngle,X,Y,finalImage,errors,finalOriginalImage] = ... 2 | alignTwoImages(image1,image2,angleGuess,spacing,... 3 | fractionalPixelAccuracy,noRotation,originalImage) 4 | %alignTwoImages rotationally and translationally aligns an image with a 5 | %background image 6 | % 7 | % Input variables: 8 | % 9 | % image1 -> background image 10 | % image2 -> image to be aligned 11 | % angleGuess -> initial guess to eliminate 180 degree degeneracy 12 | % spacing -> angular spacing in Radon transform 13 | % fractionalPixelAccuracy -> accuracy of translational alignment 14 | % noRotation -> true if only translational alignment used 15 | % originalImage -> full version of image2 (optional) 16 | % 17 | % 18 | % Output variables: 19 | % 20 | % rotationAngle -> rotational alignment angle 21 | % X, Y -> translational alignment values (in pixels) 22 | % finalImage -> aligned version of image2 23 | % errors -> errors in alignment 24 | % finalOriginalImage -> aligned version of originalImage (optional) 25 | % 26 | % 27 | % (C) Gordon J. Berman, 2014 28 | % Princeton University 29 | 30 | 31 | 32 | if nargin < 3 || isempty(angleGuess) == 1 33 | angleGuess = 0; 34 | else 35 | angleGuess = mod(angleGuess,360); 36 | end 37 | 38 | angleGuess = angleGuess*pi/180; 39 | 40 | 41 | if nargin < 4 || isempty(spacing) == 1 42 | spacing = .5; 43 | end 44 | N = 180/spacing; 45 | 46 | 47 | if nargin < 5 || isempty(fractionalPixelAccuracy) == 1 48 | fractionalPixelAccuracy = .25; 49 | end 50 | 51 | 52 | if nargin < 6 || isempty(noRotation) 53 | noRotation = false; 54 | end 55 | 56 | 57 | if nargin < 7 58 | originalImage = []; 59 | finalOriginalImage = []; 60 | end 61 | 62 | errors = zeros(2,1); 63 | 64 | s = size(image1); 65 | 66 | if ~noRotation 67 | 68 | thetas = linspace(0, 180-spacing, N); 69 | 70 | %Find fft of the Radon transform 71 | F1 = abs(fft(radon(image1, thetas))); 72 | F2 = abs(fft(radon(image2, thetas))); 73 | 74 | 75 | 76 | %Find the index of the correlation peak 77 | correlation = sum(fft2(F1) .* fft2(F2)); 78 | peaks = real(ifft(correlation)); 79 | peakIndex = find(peaks==max(peaks)); 80 | 81 | 82 | if length(peakIndex) > 1 83 | peakIndex = peakIndex(1); 84 | end 85 | 86 | 87 | %Find rotation angle via quadratic interpolation 88 | if (peakIndex~=1) && (peakIndex ~= N) 89 | p=polyfit(thetas((peakIndex-1):(peakIndex+1)),peaks((peakIndex-1):(peakIndex+1)),2); 90 | rotationAngle = -.5*p(2)/p(1); 91 | errors(1) = polyval(p,rotationAngle); 92 | else 93 | if peakIndex == 1 94 | p = polyfit([thetas(end)-180,thetas(1),thetas(2)],peaks([N,1,2]),2); 95 | rotationAngle = -.5*p(2)/p(1); 96 | errors(1) = polyval(p,rotationAngle); 97 | if rotationAngle < 0 98 | rotationAngle = 180 + rotationAngle; 99 | end 100 | else 101 | p = polyfit([thetas(end-1),thetas(end),180+thetas(1)],peaks([N-1,N,1]),2); 102 | rotationAngle = -.5*p(2)/p(1); 103 | errors(1) = polyval(p,rotationAngle); 104 | if rotationAngle >= 180 105 | rotationAngle = rotationAngle - 180; 106 | end 107 | end 108 | end 109 | 110 | 111 | %Check to see if rotation angle is in the correct direction 112 | rA = rotationAngle*pi/180; 113 | test = dot([cos(rA),sin(rA)],[cos(angleGuess),sin(angleGuess)]); 114 | if test < 0 115 | rotationAngle = mod(rotationAngle-180,360); 116 | end 117 | rotationAngle = mod(rotationAngle,360); 118 | toRotate = mod(-rotationAngle,360); 119 | 120 | %Rotate Image & Crop to original Size 121 | rotatedImage = imrotate(image2,toRotate,'crop'); 122 | 123 | else 124 | 125 | rotationAngle = mod(angleGuess,360); 126 | toRotate = mod(-rotationAngle,360); 127 | rotatedImage = imrotate(image2,toRotate,'crop'); 128 | 129 | end 130 | 131 | % Take 2D FFT of each image 132 | F1 = fft2(image1); 133 | F2 = fft2(rotatedImage); 134 | 135 | shifts = dftregistration(F1,F2,round(1/fractionalPixelAccuracy)); 136 | X = shifts(4); 137 | Y = shifts(3); 138 | 139 | errors(2) = shifts(1); 140 | 141 | 142 | T = maketform('affine',[1 0 0 ;0 1 0;X Y 1]); 143 | if nargout > 3 144 | finalImage = imtransform(rotatedImage,T,'XData',[1 s(2)],'YData',[1 s(1)]); 145 | end 146 | 147 | if isempty(originalImage) == 0 148 | rotatedImage2 = imrotate(originalImage,toRotate,'crop'); 149 | finalOriginalImage = imtransform(rotatedImage2,T,'XData',[1 s(2)],'YData',[1 s(1)]); 150 | end 151 | 152 | -------------------------------------------------------------------------------- /segmentation_alignment/align_subroutine_parallel_avi.m: -------------------------------------------------------------------------------- 1 | function [Xs,Ys,angles,areas,svdskips] = ... 2 | align_subroutine_parallel_avi(grouping,initialPhi,segmentationOptions,nDigits,file_path,... 3 | image_path,readout,processorNum,asymThreshold,initialArea,vidObj,fid,areanorm,initialImage) 4 | %align_subroutine_parallel_avi is a subroutine used within 5 | %alignImages_Radon_parallel_avi in order to parallelize properly 6 | % 7 | % 8 | % (C) Gordon J. Berman, 2014 9 | % Princeton University 10 | 11 | 12 | 13 | warning off MATLAB:audiovideo:aviread:FunctionToBeRemoved; 14 | L = length(grouping); 15 | Xs = zeros(L,1); 16 | Ys = zeros(L,1); 17 | angles = zeros(L,1); 18 | areas = zeros(L,1); 19 | svdskips = zeros(L,1); 20 | vidChunk = read(vidObj,[grouping(1) grouping(end)]); 21 | 22 | open(image_path); 23 | writeVideo(image_path,initialImage); 24 | 25 | 26 | dilateSize = segmentationOptions.dilateSize; 27 | cannyParameter = segmentationOptions.cannyParameter; 28 | imageThreshold = segmentationOptions.imageThreshold; 29 | spacing = segmentationOptions.spacing; 30 | pixelTol = segmentationOptions.pixelTol; 31 | basis = segmentationOptions.referenceImage; 32 | maxAreaDifference = segmentationOptions.maxAreaDifference; 33 | segmentationOff = segmentationOptions.segmentationOff; 34 | symLine = segmentationOptions.symLine; 35 | minRangeValue = segmentationOptions.minRangeValue; 36 | maxRangeValue = segmentationOptions.maxRangeValue; 37 | 38 | s = size(basis); 39 | currentMinArea = ceil(initialArea*(1-maxAreaDifference)); 40 | 41 | for j=2:L 42 | 43 | if mod(j,readout) == 0 44 | fprintf(1,'\t Processor #%2i, Image #%7i of %7i\n',processorNum,j,L); 45 | end 46 | 47 | 48 | 49 | k = grouping(j); 50 | nn = nDigits - 1 - floor(log(k+1e-10)/log(10)); 51 | zzs = repmat('0',1,nn); 52 | 53 | originalImage = squeeze(vidChunk(:,:,1,j)); 54 | sCurrent = size(originalImage); 55 | 56 | if sCurrent(1) < s(1) || sCurrent(2) < s(2) 57 | zz = uint8(zeros(s)+255); 58 | zz(1:sCurrent(1),1:sCurrent(2)) = originalImage; 59 | originalImage = zz; 60 | end 61 | if ~segmentationOff 62 | imageOut = segmentImage_combo(originalImage,dilateSize,cannyParameter,... 63 | imageThreshold,[],[],currentMinArea,true); 64 | imageOut = rescaleImage(imageOut,areanorm); 65 | else 66 | imageOut = originalImage; 67 | imageOut = rescaleImage(imageOut,areanorm); 68 | end 69 | 70 | 71 | 72 | areas(j) = sum(imageOut(:) ~= 0); 73 | currentMinArea = ceil((1-maxAreaDifference)*areas(j)); 74 | 75 | 76 | imageOut2 = imageOut; 77 | imageOut2(imageOut2 < asymThreshold) = 0; 78 | if max(imageOut2(:)) ~= 0 79 | [angles(j),Xs(j),Ys(j),~,~,loopImage] = ... 80 | alignTwoImages(basis,imageOut2,initialPhi,spacing,pixelTol,false,imageOut); 81 | 82 | 83 | b = loopImage; 84 | b(b > asymThreshold) = 0; 85 | 86 | if minRangeValue > 1 87 | b(1:minRangeValue-1,:) = 0; 88 | end 89 | 90 | if maxRangeValue < length(basis(:,1)) 91 | b(maxRangeValue+1:end,:) = 0; 92 | end 93 | 94 | q = sum(b) ./ sum(b(:)); 95 | 96 | asymValue = symLine - sum(q.*(1:s(1))); 97 | if asymValue < 0 98 | 99 | initialPhi = mod(initialPhi+180,360); 100 | [tempAngle,tempX,tempY,~,~,tempImage] = ... 101 | alignTwoImages(basis,imageOut2,initialPhi,spacing,pixelTol,false,imageOut); 102 | 103 | b = tempImage; 104 | b(b > asymThreshold) = 0; 105 | if minRangeValue > 1 106 | b(1:minRangeValue-1,:) = 0; 107 | end 108 | if maxRangeValue < length(basis(:,1)) 109 | b(maxRangeValue+1:end,:) = 0; 110 | end 111 | 112 | q = sum(b) ./ sum(b(:)); 113 | asymValue2 = symLine - sum(q.*(1:s(1))); 114 | 115 | if asymValue2 > asymValue 116 | angles(j) = tempAngle; 117 | Xs(j) = tempX; 118 | Ys(j) = tempY; 119 | loopImage = tempImage; 120 | end 121 | end 122 | 123 | 124 | 125 | 126 | initialPhi = angles(j); 127 | svdskips(j) = 0; 128 | writeVideo(image_path,loopImage); 129 | 130 | else 131 | 132 | angles(j) = angles(j-1); 133 | svdskips(j) = 1; 134 | loopImage = uint8(zeros(size(imageOut2))); 135 | writeVideo(image_path,loopImage); 136 | 137 | end 138 | 139 | end 140 | -------------------------------------------------------------------------------- /segmentation_alignment/basisImage.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonberman/MotionMapper/1b7e84931beae780ffd765b850a4a7f7378acace/segmentation_alignment/basisImage.tiff -------------------------------------------------------------------------------- /segmentation_alignment/dftregistration.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | function [output Greg] = dftregistration(buf1ft,buf2ft,usfac) 4 | % function [output Greg] = dftregistration(buf1ft,buf2ft,usfac); 5 | % Efficient subpixel image registration by crosscorrelation. This code 6 | % gives the same precision as the FFT upsampled cross correlation in a 7 | % small fraction of the computation time and with reduced memory 8 | % requirements. It obtains an initial estimate of the crosscorrelation peak 9 | % by an FFT and then refines the shift estimation by upsampling the DFT 10 | % only in a small neighborhood of that estimate by means of a 11 | % matrix-multiply DFT. With this procedure all the image points are used to 12 | % compute the upsampled crosscorrelation. 13 | % Manuel Guizar - Dec 13, 2007 14 | 15 | % Portions of this code were taken from code written by Ann M. Kowalczyk 16 | % and James R. Fienup. 17 | % J.R. Fienup and A.M. Kowalczyk, "Phase retrieval for a complex-valued 18 | % object by using a low-resolution image," J. Opt. Soc. Am. A 7, 450-458 19 | % (1990). 20 | 21 | % Citation for this algorithm: 22 | % Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup, 23 | % "Efficient subpixel image registration algorithms," Opt. Lett. 33, 24 | % 156-158 (2008). 25 | 26 | % Inputs 27 | % buf1ft Fourier transform of reference image, 28 | % DC in (1,1) [DO NOT FFTSHIFT] 29 | % buf2ft Fourier transform of image to register, 30 | % DC in (1,1) [DO NOT FFTSHIFT] 31 | % usfac Upsampling factor (integer). Images will be registered to 32 | % within 1/usfac of a pixel. For example usfac = 20 means the 33 | % images will be registered within 1/20 of a pixel. (default = 1) 34 | 35 | % Outputs 36 | % output = [error,diffphase,net_row_shift,net_col_shift] 37 | % error Translation invariant normalized RMS error between f and g 38 | % diffphase Global phase difference between the two images (should be 39 | % zero if images are non-negative). 40 | % net_row_shift net_col_shift Pixel shifts between images 41 | % Greg (Optional) Fourier transform of registered version of buf2ft, 42 | % the global phase difference is compensated for. 43 | 44 | % Default usfac to 1 45 | if exist('usfac')~=1, usfac=1; end 46 | 47 | % Compute error for no pixel shift 48 | if usfac == 0, 49 | CCmax = sum(sum(buf1ft.*conj(buf2ft))); 50 | rfzero = sum(abs(buf1ft(:)).^2); 51 | rgzero = sum(abs(buf2ft(:)).^2); 52 | error = 1.0 - CCmax.*conj(CCmax)/(rgzero*rfzero); 53 | error = sqrt(abs(error)); 54 | diffphase=atan2(imag(CCmax),real(CCmax)); 55 | output=[error,diffphase]; 56 | 57 | % Whole-pixel shift - Compute crosscorrelation by an IFFT and locate the 58 | % peak 59 | elseif usfac == 1, 60 | [m,n]=size(buf1ft); 61 | CC = ifft2(buf1ft.*conj(buf2ft)); 62 | [max1,loc1] = max(CC); 63 | [max2,loc2] = max(max1); 64 | rloc=loc1(loc2); 65 | cloc=loc2; 66 | CCmax=CC(rloc,cloc); 67 | rfzero = sum(abs(buf1ft(:)).^2)/(m*n); 68 | rgzero = sum(abs(buf2ft(:)).^2)/(m*n); 69 | error = 1.0 - CCmax.*conj(CCmax)/(rgzero(1,1)*rfzero(1,1)); 70 | error = sqrt(abs(error)); 71 | diffphase=atan2(imag(CCmax),real(CCmax)); 72 | md2 = fix(m/2); 73 | nd2 = fix(n/2); 74 | if rloc > md2 75 | row_shift = rloc - m - 1; 76 | else 77 | row_shift = rloc - 1; 78 | end 79 | 80 | if cloc > nd2 81 | col_shift = cloc - n - 1; 82 | else 83 | col_shift = cloc - 1; 84 | end 85 | output=[error,diffphase,row_shift,col_shift]; 86 | 87 | % Partial-pixel shift 88 | else 89 | 90 | % First upsample by a factor of 2 to obtain initial estimate 91 | % Embed Fourier data in a 2x larger array 92 | [m,n]=size(buf1ft); 93 | mlarge=m*2; 94 | nlarge=n*2; 95 | CC=zeros(mlarge,nlarge); 96 | CC(m+1-fix(m/2):m+1+fix((m-1)/2),n+1-fix(n/2):n+1+fix((n-1)/2)) = ... 97 | fftshift(buf1ft).*conj(fftshift(buf2ft)); 98 | 99 | % Compute crosscorrelation and locate the peak 100 | CC = ifft2(ifftshift(CC)); % Calculate cross-correlation 101 | [max1,loc1] = max(CC); 102 | [max2,loc2] = max(max1); 103 | rloc=loc1(loc2);cloc=loc2; 104 | CCmax=CC(rloc,cloc); 105 | 106 | % Obtain shift in original pixel grid from the position of the 107 | % crosscorrelation peak 108 | [m,n] = size(CC); md2 = fix(m/2); nd2 = fix(n/2); 109 | if rloc > md2 110 | row_shift = rloc - m - 1; 111 | else 112 | row_shift = rloc - 1; 113 | end 114 | if cloc > nd2 115 | col_shift = cloc - n - 1; 116 | else 117 | col_shift = cloc - 1; 118 | end 119 | row_shift=row_shift/2; 120 | col_shift=col_shift/2; 121 | 122 | % If upsampling > 2, then refine estimate with matrix multiply DFT 123 | if usfac > 2, 124 | %%% DFT computation %%% 125 | % Initial shift estimate in upsampled grid 126 | row_shift = round(row_shift*usfac)/usfac; 127 | col_shift = round(col_shift*usfac)/usfac; 128 | dftshift = fix(ceil(usfac*1.5)/2); %% Center of output array at dftshift+1 129 | % Matrix multiply DFT around the current shift estimate 130 | CC = conj(dftups(buf2ft.*conj(buf1ft),ceil(usfac*1.5),ceil(usfac*1.5),usfac,... 131 | dftshift-row_shift*usfac,dftshift-col_shift*usfac))/(md2*nd2*usfac^2); 132 | % Locate maximum and map back to original pixel grid 133 | [max1,loc1] = max(CC); 134 | [max2,loc2] = max(max1); 135 | rloc = loc1(loc2); cloc = loc2; 136 | CCmax = CC(rloc,cloc); 137 | rg00 = dftups(buf1ft.*conj(buf1ft),1,1,usfac)/(md2*nd2*usfac^2); 138 | rf00 = dftups(buf2ft.*conj(buf2ft),1,1,usfac)/(md2*nd2*usfac^2); 139 | rloc = rloc - dftshift - 1; 140 | cloc = cloc - dftshift - 1; 141 | row_shift = row_shift + rloc/usfac; 142 | col_shift = col_shift + cloc/usfac; 143 | 144 | % If upsampling = 2, no additional pixel shift refinement 145 | else 146 | rg00 = sum(sum( buf1ft.*conj(buf1ft) ))/m/n; 147 | rf00 = sum(sum( buf2ft.*conj(buf2ft) ))/m/n; 148 | end 149 | error = 1.0 - CCmax.*conj(CCmax)/(rg00*rf00); 150 | error = sqrt(abs(error)); 151 | diffphase=atan2(imag(CCmax),real(CCmax)); 152 | % If its only one row or column the shift along that dimension has no 153 | % effect. We set to zero. 154 | if md2 == 1, 155 | row_shift = 0; 156 | end 157 | if nd2 == 1, 158 | col_shift = 0; 159 | end 160 | output=[error,diffphase,row_shift,col_shift]; 161 | end 162 | 163 | % Compute registered version of buf2ft 164 | if (nargout > 1)&&(usfac > 0), 165 | [nr,nc]=size(buf2ft); 166 | Nr = ifftshift([-fix(nr/2):ceil(nr/2)-1]); 167 | Nc = ifftshift([-fix(nc/2):ceil(nc/2)-1]); 168 | [Nc,Nr] = meshgrid(Nc,Nr); 169 | Greg = buf2ft.*exp(i*2*pi*(-row_shift*Nr/nr-col_shift*Nc/nc)); 170 | Greg = Greg*exp(i*diffphase); 171 | elseif (nargout > 1)&&(usfac == 0) 172 | Greg = buf2ft*exp(i*diffphase); 173 | end 174 | return 175 | 176 | function out=dftups(in,nor,noc,usfac,roff,coff) 177 | % function out=dftups(in,nor,noc,usfac,roff,coff); 178 | % Upsampled DFT by matrix multiplies, can compute an upsampled DFT in just 179 | % a small region. 180 | % usfac Upsampling factor (default usfac = 1) 181 | % [nor,noc] Number of pixels in the output upsampled DFT, in 182 | % units of upsampled pixels (default = size(in)) 183 | % roff, coff Row and column offsets, allow to shift the output array to 184 | % a region of interest on the DFT (default = 0) 185 | % Recieves DC in upper left corner, image center must be in (1,1) 186 | % Manuel Guizar - Dec 13, 2007 187 | % Modified from dftus, by J.R. Fienup 7/31/06 188 | 189 | % This code is intended to provide the same result as if the following 190 | % operations were performed 191 | % - Embed the array "in" in an array that is usfac times larger in each 192 | % dimension. ifftshift to bring the center of the image to (1,1). 193 | % - Take the FFT of the larger array 194 | % - Extract an [nor, noc] region of the result. Starting with the 195 | % [roff+1 coff+1] element. 196 | 197 | % It achieves this result by computing the DFT in the output array without 198 | % the need to zeropad. Much faster and memory efficient than the 199 | % zero-padded FFT approach if [nor noc] are much smaller than [nr*usfac nc*usfac] 200 | 201 | [nr,nc]=size(in); 202 | % Set defaults 203 | if exist('roff')~=1, roff=0; end 204 | if exist('coff')~=1, coff=0; end 205 | if exist('usfac')~=1, usfac=1; end 206 | if exist('noc')~=1, noc=nc; end 207 | if exist('nor')~=1, nor=nr; end 208 | % Compute kernels and obtain DFT by matrix products 209 | kernc=exp((-i*2*pi/(nc*usfac))*( ifftshift([0:nc-1]).' - floor(nc/2) )*( [0:noc-1] - coff )); 210 | kernr=exp((-i*2*pi/(nr*usfac))*( [0:nor-1].' - roff )*( ifftshift([0:nr-1]) - floor(nr/2) )); 211 | out=kernr*in*kernc; 212 | return 213 | -------------------------------------------------------------------------------- /segmentation_alignment/segmentImage_combo.m: -------------------------------------------------------------------------------- 1 | function [imageOut,mask] = segmentImage_combo(image,dilateSize,cannyParameter,threshold,alpha,maxIter,minimumArea,chanVeseOff) 2 | %segmentImage_combo segments an image from its background 3 | % 4 | % Input variables: 5 | % 6 | % image -> image to be analyzed 7 | % dilateSize -> initial dilation size for image segmentation 8 | % cannyParameter -> parameter for Canny edge detection 9 | % threshold -> threshold for image segmentation 10 | % minimumArea -> minimum allowed area for segmented image 11 | % alpha, maxIter, chanVeseOff -> not used in this version of the code 12 | % 13 | % 14 | % Output variables: 15 | % 16 | % imageOut -> segmented image 17 | % mask -> binary mask that is 'true' for non-zero pixels in imageOut 18 | % 19 | % 20 | % (C) Gordon J. Berman, 2014 21 | % Princeton University 22 | 23 | 24 | if nargin < 2 || isempty(dilateSize) == 1 25 | dilateSize = 3; 26 | end 27 | 28 | if nargin < 3 || isempty(cannyParameter) == 1 29 | cannyParameter = .1; 30 | end 31 | 32 | if nargin < 4 || isempty(threshold) == 1 33 | threshold = 0; 34 | end 35 | 36 | if nargin < 5 || isempty(alpha) == 1 37 | alpha = .5; 38 | end 39 | 40 | if nargin < 6 || isempty(maxIter) == 1 41 | maxIter = 10; 42 | end 43 | 44 | if nargin < 7 || isempty(minimumArea) == 1 45 | minimumArea = 3500; 46 | end 47 | 48 | if nargin < 8 || isempty(chanVeseOff) 49 | chanVeseOff = true; 50 | else 51 | chanVeseOff = true; 52 | end 53 | 54 | 55 | image(image > 255 - threshold) = 255; 56 | 57 | E = edge(image,'canny',cannyParameter,'nothinning'); 58 | se = strel('square',dilateSize); 59 | E2 = imdilate(E,se); 60 | mask = imfill(E2,'holes'); 61 | 62 | CC = bwconncomp(mask,4); 63 | if length(CC.PixelIdxList) > 1 64 | lengths = zeros(1,length(CC.PixelIdxList)); 65 | for j=1:length(lengths) 66 | lengths(j) = length(CC.PixelIdxList{j}); 67 | end 68 | [~,idx] = max(lengths); 69 | temp = mask; 70 | temp(:) = 0; 71 | temp(CC.PixelIdxList{idx}) = 1; 72 | mask = temp; 73 | end 74 | 75 | 76 | while sum(mask(:)) < minimumArea && dilateSize <= 6 && cannyParameter > 0 77 | 78 | dilateSize = dilateSize + 1; 79 | cannyParameter = .1; 80 | se = strel('square',dilateSize); 81 | E2 = imdilate(E,se); 82 | mask = imfill(E2,'holes'); 83 | 84 | CC = bwconncomp(mask,4); 85 | if length(CC.PixelIdxList) > 1 86 | lengths = zeros(1,length(CC.PixelIdxList)); 87 | for j=1:length(lengths) 88 | lengths(j) = length(CC.PixelIdxList{j}); 89 | end 90 | [~,idx] = max(lengths); 91 | temp = mask; 92 | temp(:) = 0; 93 | temp(CC.PixelIdxList{idx}) = 1; 94 | mask = temp; 95 | end 96 | 97 | 98 | end 99 | 100 | 101 | if mean(image(:)) < 100 102 | imageOut = immultiply(mask,image); 103 | else 104 | imageOut = immultiply(mask,imcomplement(image)); 105 | end -------------------------------------------------------------------------------- /setRunParameters.m: -------------------------------------------------------------------------------- 1 | function parameters = setRunParameters(parameters) 2 | %setRunParameters sets all parameters for the algorithms used here. 3 | % Any parameters not explicitly set will revert to their listed 4 | % default values. 5 | % 6 | % 7 | % (C) Gordon J. Berman, 2014 8 | % Princeton University 9 | 10 | 11 | if nargin < 1 12 | parameters = []; 13 | end 14 | 15 | 16 | 17 | %%%%%%%% General Parameters %%%%%%%% 18 | 19 | %number of processors to use in parallel code 20 | numProcessors = 12; 21 | 22 | %whether or not to close the matlabpool after running a routine 23 | closeMatPool = false; 24 | 25 | 26 | 27 | 28 | 29 | %%%%%%%% Segmentation and Alignment Parameters %%%%%%%% 30 | 31 | %angle spacing for alignement Radon transform 32 | alignment_angle_spacing = 1; 33 | 34 | %tolerance for translational alignment 35 | pixelTol = .1; 36 | 37 | %minimum area for use in image dilation/erosion 38 | minArea = 3500; 39 | 40 | %asymmetry threshold used in eliminating rotational degeneracy (set to -1 for auto) 41 | asymThreshold = 150; 42 | 43 | %line about which directional symmetry is 44 | %determined for eliminating rotational degeneracy 45 | symLine = 110; 46 | 47 | %initial guess for rotation angle 48 | initialPhi = 0; 49 | 50 | %initial dilation size for image segmentation 51 | dilateSize = 5; 52 | 53 | %parameter for Canny edge detection 54 | cannyParameter = .1; 55 | 56 | %threshold for image segmentation 57 | imageThreshold = 40; 58 | 59 | %largest allowed percentage reduction in area from frame to frame 60 | maxAreaDifference = .15; 61 | 62 | %toggle switch for image segmentation (alignment still performed) 63 | segmentationOff = false; 64 | 65 | %threshold for seperating body from background (set to -1 for auto) 66 | bodyThreshold = 150; 67 | 68 | %number of images to test for image size estimation 69 | areaNormalizationNumber = 100; 70 | 71 | %range extension for flipping detector 72 | rangeExtension = 20; 73 | 74 | %path to basis image 75 | basisImagePath = 'segmentation_alignment/basisImage.tiff'; 76 | 77 | 78 | 79 | 80 | 81 | %%%%%%%% PCA Parameters %%%%%%%% 82 | 83 | %number of angles in radon transform 84 | num_Radon_Thetas = 90; 85 | 86 | %image scaling factor 87 | rescaleSize = 10/7; 88 | 89 | %batch size for running online PCA 90 | pca_batchSize = 20000; 91 | 92 | %number of projections to find in PCA 93 | numProjections = 100; 94 | 95 | %number of PCA modes to use in later analyses 96 | pcaModes = 50; 97 | 98 | %number of images to process per file in eignemode calculations 99 | %a value of -1 instructs all images to be processed 100 | pcaNumPerFile = -1; 101 | 102 | 103 | %%%%%%%% Wavelet Parameters %%%%%%%% 104 | 105 | %number of wavelet frequencies to use 106 | numPeriods = 25; 107 | 108 | %dimensionless Morlet wavelet parameter 109 | omega0 = 5; 110 | 111 | %sampling frequency (Hz) 112 | samplingFreq = 100; 113 | 114 | %minimum frequency for wavelet transform (Hz) 115 | minF = 1; 116 | 117 | %maximum frequency for wavelet transform (Hz) 118 | maxF = 50; 119 | 120 | 121 | 122 | 123 | 124 | 125 | %%%%%%%% t-SNE Parameters %%%%%%%% 126 | 127 | 128 | %2^H (H is the transition entropy) 129 | perplexity = 32; 130 | 131 | %relative convergence criterium for t-SNE 132 | relTol = 1e-4; 133 | 134 | %number of dimensions for use in t-SNE 135 | num_tsne_dim = 2; 136 | 137 | %binary search tolerance for finding pointwise transition region 138 | sigmaTolerance = 1e-5; 139 | 140 | %maximum number of non-zero neighbors in P 141 | maxNeighbors = 200; 142 | 143 | %initial momentum 144 | momentum = .5; 145 | 146 | %value to which momentum is changed 147 | final_momentum = 0.8; 148 | 149 | %iteration at which momentum is changed 150 | mom_switch_iter = 250; 151 | 152 | %iteration at which lying about P-values is stopped 153 | stop_lying_iter = 125; 154 | 155 | %degree of P-value expansion at early iterations 156 | lie_multiplier = 4; 157 | 158 | %maximum number of iterations 159 | max_iter = 1000; 160 | 161 | %initial learning rate 162 | epsilon = 500; 163 | 164 | %minimum gain for delta-bar-delta 165 | min_gain = .01; 166 | 167 | %readout variable for t-SNE 168 | tsne_readout = 1; 169 | 170 | %embedding batchsize 171 | embedding_batchSize = 20000; 172 | 173 | %maximum number of iterations for the Nelder-Mead algorithm 174 | maxOptimIter = 100; 175 | 176 | %number of points in the training set 177 | trainingSetSize = 35000; 178 | 179 | %local neighborhood definition in training set creation 180 | kdNeighbors = 5; 181 | 182 | %t-SNE training set stopping critereon 183 | training_relTol = 2e-3; 184 | 185 | %t-SNE training set perplexity 186 | training_perplexity = 20; 187 | 188 | %number of points to evaluate in each training set file 189 | training_numPoints = 10000; 190 | 191 | %minimum training set template length 192 | minTemplateLength = 1; 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 218 | 219 | 220 | if ~isfield(parameters,'numProcessors') || isempty(parameters.numProcessors) 221 | parameters.numProcessors = numProcessors; 222 | end 223 | 224 | 225 | if ~isfield(parameters,'closeMatPool') || isempty(parameters.closeMatPool) 226 | parameters.closeMatPool = closeMatPool; 227 | end 228 | 229 | 230 | 231 | 232 | 233 | 234 | if ~isfield(parameters,'alignment_angle_spacing') || isempty(parameters.alignment_angle_spacing) 235 | parameters.alignment_angle_spacing = alignment_angle_spacing; 236 | end 237 | 238 | 239 | if ~isfield(parameters,'bodyThreshold') || isempty(parameters.bodyThreshold) 240 | parameters.bodyThreshold = bodyThreshold; 241 | end 242 | 243 | 244 | if ~isfield(parameters,'pixelTol') || isempty(parameters.pixelTol) 245 | parameters.pixelTol = pixelTol; 246 | end 247 | 248 | 249 | if ~isfield(parameters,'minArea') || isempty(parameters.minArea) 250 | parameters.minArea = minArea; 251 | end 252 | 253 | 254 | if ~isfield(parameters,'asymThreshold') || isempty(parameters.asymThreshold) 255 | parameters.asymThreshold = asymThreshold; 256 | end 257 | 258 | 259 | if ~isfield(parameters,'symLine') || isempty(parameters.symLine) 260 | parameters.symLine = symLine; 261 | end 262 | 263 | 264 | if ~isfield(parameters,'basisImagePath') || isempty(parameters.basisImagePath) 265 | parameters.basisImagePath = basisImagePath; 266 | end 267 | parameters.basisImage = imread(parameters.basisImagePath); 268 | 269 | 270 | if ~isfield(parameters,'initialPhi') || isempty(parameters.initialPhi) 271 | parameters.initialPhi = initialPhi; 272 | end 273 | 274 | 275 | if ~isfield(parameters,'dilateSize') || isempty(parameters.dilateSize) 276 | parameters.dilateSize = dilateSize; 277 | end 278 | 279 | 280 | if ~isfield(parameters,'cannyParameter') || isempty(parameters.cannyParameter) 281 | parameters.cannyParameter = cannyParameter; 282 | end 283 | 284 | 285 | if ~isfield(parameters,'imageThreshold') || isempty(parameters.imageThreshold) 286 | parameters.imageThreshold = imageThreshold; 287 | end 288 | 289 | 290 | if ~isfield(parameters,'maxAreaDifference') || isempty(parameters.maxAreaDifference) 291 | parameters.maxAreaDifference = maxAreaDifference; 292 | end 293 | 294 | 295 | if ~isfield(parameters,'segmentationOff') || isempty(parameters.segmentationOff) 296 | parameters.segmentationOff = segmentationOff; 297 | end 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | if ~isfield(parameters,'num_Radon_Thetas') || isempty(parameters.num_Radon_Thetas) 307 | parameters.num_Radon_Thetas = num_Radon_Thetas; 308 | end 309 | 310 | 311 | if ~isfield(parameters,'rescaleSize') || isempty(parameters.rescaleSize) 312 | parameters.rescaleSize = rescaleSize; 313 | end 314 | 315 | 316 | if ~isfield(parameters,'pca_batchSize') || isempty(parameters.pca_batchSize) 317 | parameters.pca_batchSize = pca_batchSize; 318 | end 319 | 320 | 321 | if ~isfield(parameters,'numProjections') || isempty(parameters.numProjections) 322 | parameters.numProjections = numProjections; 323 | end 324 | 325 | 326 | if ~isfield(parameters,'pcaModes') || isempty(parameters.pcaModes) 327 | parameters.pcaModes = pcaModes; 328 | end 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | if ~isfield(parameters,'numPeriods') || isempty(parameters.numPeriods) 340 | parameters.numPeriods = numPeriods; 341 | end 342 | 343 | 344 | if ~isfield(parameters,'omega0') || isempty(parameters.omega0) 345 | parameters.omega0 = omega0; 346 | end 347 | 348 | 349 | if ~isfield(parameters,'samplingFreq') || isempty(parameters.samplingFreq) 350 | parameters.samplingFreq = samplingFreq; 351 | end 352 | 353 | 354 | if ~isfield(parameters,'minF') || isempty(parameters.minF) 355 | parameters.minF = minF; 356 | end 357 | 358 | 359 | if ~isfield(parameters,'maxF') || isempty(parameters.maxF) 360 | parameters.maxF = maxF; 361 | end 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | if ~isfield(parameters,'perplexity') || isempty(parameters.perplexity) 372 | parameters.perplexity = perplexity; 373 | end 374 | 375 | 376 | if ~isfield(parameters,'relTol') || isempty(parameters.relTol) 377 | parameters.relTol = relTol; 378 | end 379 | 380 | 381 | if ~isfield(parameters,'num_tsne_dim') || isempty(parameters.num_tsne_dim) 382 | parameters.num_tsne_dim = num_tsne_dim; 383 | end 384 | 385 | 386 | if ~isfield(parameters,'sigmaTolerance') || isempty(parameters.sigmaTolerance) 387 | parameters.sigmaTolerance = sigmaTolerance; 388 | end 389 | 390 | 391 | if ~isfield(parameters,'maxNeighbors') || isempty(parameters.maxNeighbors) 392 | parameters.maxNeighbors = maxNeighbors; 393 | end 394 | 395 | 396 | if ~isfield(parameters,'momentum') || isempty(parameters.momentum) 397 | parameters.momentum = momentum; 398 | end 399 | 400 | 401 | if ~isfield(parameters,'final_momentum') || isempty(parameters.final_momentum) 402 | parameters.final_momentum = final_momentum; 403 | end 404 | 405 | 406 | if ~isfield(parameters,'mom_switch_iter') || isempty(parameters.mom_switch_iter) 407 | parameters.mom_switch_iter = mom_switch_iter; 408 | end 409 | 410 | 411 | if ~isfield(parameters,'stop_lying_iter') || isempty(parameters.stop_lying_iter) 412 | parameters.stop_lying_iter = stop_lying_iter; 413 | end 414 | 415 | 416 | if ~isfield(parameters,'lie_multiplier') || isempty(parameters.lie_multiplier) 417 | parameters.lie_multiplier = lie_multiplier; 418 | end 419 | 420 | 421 | if ~isfield(parameters,'max_iter') || isempty(parameters.max_iter) 422 | parameters.max_iter = max_iter; 423 | end 424 | 425 | 426 | if ~isfield(parameters,'epsilon') || isempty(parameters.epsilon) 427 | parameters.epsilon = epsilon; 428 | end 429 | 430 | 431 | if ~isfield(parameters,'min_gain') || isempty(parameters.min_gain) 432 | parameters.min_gain = min_gain; 433 | end 434 | 435 | 436 | if ~isfield(parameters,'tsne_readout') || isempty(parameters.tsne_readout) 437 | parameters.tsne_readout = tsne_readout; 438 | end 439 | 440 | 441 | if ~isfield(parameters,'embedding_batchSize') || isempty(parameters.embedding_batchSize) 442 | parameters.embedding_batchSize = embedding_batchSize; 443 | end 444 | 445 | 446 | if ~isfield(parameters,'maxOptimIter') || isempty(parameters.maxOptimIter) 447 | parameters.maxOptimIter = maxOptimIter; 448 | end 449 | 450 | 451 | if ~isfield(parameters,'trainingSetSize') || isempty(parameters.trainingSetSize) 452 | parameters.trainingSetSize = trainingSetSize; 453 | end 454 | 455 | 456 | if ~isfield(parameters,'kdNeighbors') || isempty(parameters.kdNeighbors) 457 | parameters.kdNeighbors = kdNeighbors; 458 | end 459 | 460 | 461 | if ~isfield(parameters,'training_relTol') || isempty(parameters.training_relTol) 462 | parameters.training_relTol = training_relTol; 463 | end 464 | 465 | 466 | if ~isfield(parameters,'training_perplexity') || isempty(parameters.training_perplexity) 467 | parameters.training_perplexity = training_perplexity; 468 | end 469 | 470 | 471 | if ~isfield(parameters,'training_numPoints') || isempty(parameters.training_numPoints) 472 | parameters.training_numPoints = training_numPoints; 473 | end 474 | 475 | 476 | if ~isfield(parameters,'minTemplateLength') || isempty(parameters.minTemplateLength) 477 | parameters.minTemplateLength = minTemplateLength; 478 | end 479 | 480 | 481 | if ~isfield(parameters,'pcaNumPerFile') || isempty(parameters.pcaNumPerFile) 482 | parameters.pcaNumPerFile = pcaNumPerFile; 483 | end 484 | 485 | 486 | if ~isfield(parameters,'areaNormalizationNumber') || isempty(parameters.areaNormalizationNumber) 487 | parameters.areaNormalizationNumber = areaNormalizationNumber; 488 | end 489 | 490 | 491 | if ~isfield(parameters,'rangeExtension') || isempty(parameters.rangeExtension) 492 | parameters.rangeExtension = rangeExtension; 493 | end 494 | 495 | 496 | 497 | 498 | -------------------------------------------------------------------------------- /t_sne/calculateKLCost.m: -------------------------------------------------------------------------------- 1 | function out = calculateKLCost(x,ydata,ps) 2 | %calculateKLCost is used by findTDistributedProjections_fmin.m to calculate 3 | %an optimal embedding point 4 | d = sum((ydata-x).^2,2)'; 5 | out = log(sum((1+d).^-1)) + sum(ps.*log(1+d)); 6 | -------------------------------------------------------------------------------- /t_sne/d2p_sparse.m: -------------------------------------------------------------------------------- 1 | function [P, beta] = d2p_sparse(D, u, tol, maxNeighbors) 2 | %D2P Identifies appropriate sigma's to get kk NNs up to some tolerance 3 | % 4 | % [P, beta] = d2p(D, kk, tol) 5 | % 6 | % Identifies the required precision (= 1 / variance^2) to obtain a Gaussian 7 | % kernel with a certain uncertainty for every datapoint. The desired 8 | % uncertainty can be specified through the perplexity u (default = 15). The 9 | % desired perplexity is obtained up to some tolerance that can be specified 10 | % by tol (default = 1e-4). 11 | % The function returns the final Gaussian kernel in P, as well as the 12 | % employed precisions per instance in beta. 13 | % 14 | % Input variables: 15 | % 16 | % D -> NxN distance matrix 17 | % u -> perplexity. 2^H (H is the transition entropy) 18 | % tol -> binary search tolerance for finding pointwise transition 19 | % region 20 | % maxNeighbors -> maximum number of non-zero neighbors in P 21 | % 22 | % 23 | % Output variables: 24 | % 25 | % beta -> list of individual area parameters 26 | % P -> sparse transition matrix 27 | % 28 | % 29 | % (C) Laurens van der Maaten, 2008 30 | % Maastricht University 31 | % 32 | % Modified by Gordon J. Berman, 2014 33 | % Princeton University 34 | 35 | 36 | if nargin < 4 || isempty(maxNeighbors) 37 | maxNeighbors = 150; 38 | end 39 | 40 | 41 | if ~exist('u', 'var') || isempty(u) 42 | u = 15; 43 | end 44 | if ~exist('tol', 'var') || isempty(tol) 45 | tol = 1e-4; 46 | end 47 | 48 | 49 | n = size(D, 1); 50 | if maxNeighbors >= n 51 | maxNeighbors = n - 1; 52 | end 53 | 54 | beta = ones(n, 1); 55 | logU = log(u); 56 | 57 | 58 | jj = zeros(n,maxNeighbors); 59 | vals = zeros(size(jj)); 60 | 61 | % Run over all datapoints 62 | for i=1:n 63 | 64 | if ~rem(i, 500) 65 | disp(['Computed P-values ' num2str(i) ' of ' num2str(n) ' datapoints...']); 66 | end 67 | 68 | % Set minimum and maximum values for precision 69 | betamin = -Inf; 70 | betamax = Inf; 71 | 72 | q = D(i,:); 73 | [sortVals,sortIdx] = sort(q,'ascend'); 74 | sortVals = sortVals(2:(maxNeighbors+1)); 75 | sortIdx = sortIdx(2:(maxNeighbors+1)); 76 | jj(i,:) = sortIdx; 77 | 78 | % Compute the Gaussian kernel and entropy for the current precision 79 | [H, thisP] = Hbeta(sortVals, beta(i)); 80 | 81 | % Evaluate whether the perplexity is within tolerance 82 | Hdiff = H - logU; 83 | tries = 0; 84 | while abs(Hdiff) > tol && tries < 50 85 | 86 | % If not, increase or decrease precision 87 | if Hdiff > 0 88 | betamin = beta(i); 89 | if isinf(betamax) 90 | beta(i) = beta(i) * 2; 91 | else 92 | beta(i) = (beta(i) + betamax) / 2; 93 | end 94 | else 95 | betamax = beta(i); 96 | if isinf(betamin) 97 | beta(i) = beta(i) / 2; 98 | else 99 | beta(i) = (beta(i) + betamin) / 2; 100 | end 101 | end 102 | 103 | % Recompute the values 104 | [H, thisP] = Hbeta(sortVals, beta(i)); 105 | Hdiff = H - logU; 106 | tries = tries + 1; 107 | end 108 | 109 | 110 | vals(i,:) = thisP; 111 | 112 | end 113 | 114 | 115 | ii = repmat((1:n)',1,maxNeighbors); 116 | ii = reshape(ii',[n*maxNeighbors 1]); 117 | jj = reshape(jj',[n*maxNeighbors 1]); 118 | vals = reshape(vals',[n*maxNeighbors 1]); 119 | 120 | 121 | P = sparse(ii,jj,vals,n,n,n*maxNeighbors); 122 | 123 | clear ii jj vals 124 | 125 | disp(['Mean value of sigma: ' num2str(mean(sqrt(1 ./ beta)))]); 126 | disp(['Minimum value of sigma: ' num2str(min(sqrt(1 ./ beta)))]); 127 | disp(['Maximum value of sigma: ' num2str(max(sqrt(1 ./ beta)))]); 128 | end 129 | 130 | 131 | 132 | % Function that computes the Gaussian kernel values given a vector of 133 | % squared Euclidean distances, and the precision of the Gaussian kernel. 134 | % The function also computes the perplexity of the distribution. 135 | function [H, P] = Hbeta(D, beta) 136 | P = exp(-D * beta); 137 | sumP = sum(P); 138 | H = log(sumP) + beta * sum(D .* P) / sumP; 139 | P = P / sumP; 140 | end 141 | 142 | -------------------------------------------------------------------------------- /t_sne/file_embeddingSubSampling.m: -------------------------------------------------------------------------------- 1 | function [yData,signalData,signalIdx,signalAmps] = ... 2 | file_embeddingSubSampling(projectionFile,parameters) 3 | %file_embeddingSubSampling finds the potential training set contributions 4 | %from a single file (called by runEmbeddingSubSampling.m) 5 | % 6 | % Input variables: 7 | % 8 | % projectionFile -> file to be analyzed (should contain a variable 9 | % called 'projections') 10 | % parameters -> struct containing non-default choices for parameters 11 | % 12 | % 13 | % Output variables: 14 | % 15 | % yData -> Nx2 array containing t-SNE embedding 16 | % signalData -> wavelet data corresponding to yData 17 | % signalIdx -> idx used 18 | % signalAmps -> wavelet amplitudes of signalData 19 | % 20 | % (C) Gordon J. Berman, 2014 21 | % Princeton University 22 | 23 | 24 | rtol = parameters.training_relTol; 25 | perplexity = parameters.training_perplexity; 26 | numPoints = parameters.training_numPoints; 27 | 28 | fprintf(1,'\t Loading Projections\n'); 29 | load(projectionFile,'projections'); 30 | 31 | 32 | N = length(projections(:,1)); 33 | numModes = parameters.pcaModes; 34 | skipLength = floor(N / numPoints); 35 | if skipLength == 0 36 | skipLength = 1; 37 | numPoints = N; 38 | end 39 | firstFrame = mod(N,numPoints) + 1; 40 | signalIdx = firstFrame:skipLength:(firstFrame + (numPoints-1)*skipLength); 41 | 42 | fprintf(1,'\t Calculating Wavelets\n'); 43 | [data,~] = findWavelets(projections,numModes,parameters); 44 | amps = sum(data,2); 45 | 46 | signalData = bsxfun(@rdivide,data(signalIdx,:),amps(signalIdx)); 47 | signalAmps = amps(signalIdx); 48 | 49 | clear data amps; 50 | 51 | fprintf(1,'\t Calculating Distances\n'); 52 | [D,~] = findKLDivergences(signalData); 53 | 54 | 55 | fprintf(1,'\t Running t-SNE\n'); 56 | parameters.relTol = rtol; 57 | parameters.perplexity = perplexity; 58 | [yData,~,~,~] = tsne_d(D,parameters); 59 | 60 | 61 | -------------------------------------------------------------------------------- /t_sne/findPointDensity.m: -------------------------------------------------------------------------------- 1 | function [xx,density] = findPointDensity(points,sigma,numPoints,rangeVals) 2 | %findPointDensity finds a Kernel-estimated PDF from a set of 2D data points 3 | %through convolving with a gaussian function 4 | % 5 | % Input variables: 6 | % 7 | % points -> N x 2 array of data points 8 | % sigma -> standard deviation of smoothing gaussian 9 | % numPoints -> number of points in each dimension of 'density' 10 | % rangeVals -> 1 x 2 array giving the extrema of the observed range 11 | % 12 | % 13 | % Output variables: 14 | % 15 | % xx -> 1 x numPoints array giving the x and y axis evaluation points 16 | % density -> numPoints x numPoints array giving the PDF values 17 | % 18 | % 19 | % 20 | % (C) Gordon J. Berman, 2014 21 | % Princeton University 22 | 23 | 24 | 25 | if nargin < 3 || isempty(numPoints) 26 | numPoints = 1001; 27 | else 28 | if mod(numPoints,2) == 0 29 | numPoints = numPoints + 1; 30 | end 31 | end 32 | 33 | if nargin < 4 || isempty(rangeVals) 34 | rangeVals = [-110 110]; 35 | end 36 | 37 | xx = linspace(rangeVals(1),rangeVals(2),numPoints); 38 | yy = xx; 39 | [XX,YY] = meshgrid(xx,yy); 40 | 41 | G = exp(-.5.*(XX.^2 + YY.^2)./sigma^2) ./ (2*pi*sigma^2); 42 | 43 | Z = hist3(points,{xx,yy}); 44 | Z = Z ./ (sum(Z(:))); 45 | 46 | density = fftshift(real(ifft2(fft2(G).*fft2(Z))))'; 47 | density(density<0) = 0; 48 | -------------------------------------------------------------------------------- /t_sne/findTDistributedProjections_fmin.m: -------------------------------------------------------------------------------- 1 | function [zValues,zCosts,zGuesses,inConvHull,meanMax,exitFlags] = ... 2 | findTDistributedProjections_fmin(data,trainingData,... 3 | trainingEmbedding,parameters) 4 | %findTDistributedProjections_fmin is called by runEmbbedings to find the 5 | %optimal embeddings of a set of wavelet amplitudes into a previously 6 | %defined t-SNE embedding 7 | 8 | 9 | readout = 5000; 10 | 11 | perplexity = parameters.perplexity; 12 | sigmaTolerance = parameters.sigmaTolerance; 13 | maxNeighbors = parameters.maxNeighbors; 14 | batchSize = parameters.embedding_batchSize; 15 | maxOptimIter = parameters.maxOptimIter; 16 | 17 | 18 | N = length(data(:,1)); 19 | zValues = zeros(N,2); 20 | zGuesses = zeros(N,2); 21 | zCosts = zeros(N,1); 22 | batches = ceil(N/batchSize); 23 | inConvHull = false(N,1); 24 | meanMax = zeros(N,1); 25 | exitFlags = zeros(N,1); 26 | 27 | options = optimset('Display','off','maxiter',maxOptimIter); 28 | 29 | for j=1:batches 30 | fprintf(1,'\t Processing batch #%4i out of %4i\n',j,batches); 31 | idx = (1:batchSize) + (j-1)*batchSize; 32 | idx = idx(idx <= N); 33 | current_guesses = zeros(length(idx),2); 34 | current = zeros(length(idx),2); 35 | currentData = data(idx,:); 36 | tCosts = zeros(size(idx)); 37 | current_poly = false(length(idx),1); 38 | 39 | D2 = findListKLDivergences(currentData,trainingData); 40 | current_meanMax = zeros(length(idx),1); 41 | 42 | parfor i=1:length(idx) 43 | 44 | if mod(i,readout) == 0 45 | fprintf(1,'\t\t Image #%5i\n',i); 46 | end 47 | 48 | [~,p] = returnCorrectSigma_sparse(D2(i,:),perplexity,sigmaTolerance,maxNeighbors); 49 | idx2 = p>0; 50 | z = trainingEmbedding(idx2,:); 51 | [~,maxIdx] = max(p); 52 | a = sum(bsxfun(@times,z,p(idx2)')); 53 | 54 | guesses = [a;trainingEmbedding(maxIdx,:)]; 55 | 56 | b = zeros(2,2); 57 | c = zeros(2,1) 58 | flags = zeros(2,1); 59 | 60 | q = convhull(z); 61 | q = z(q,:); 62 | 63 | [b(1,:),c(1),flags(1)] = fminsearch(@(x)calculateKLCost(x,z,p(idx2)),guesses(1,:),options); 64 | [b(2,:),c(2),flags(2)] = fminsearch(@(x)calculateKLCost(x,z,p(idx2)),guesses(2,:),options); 65 | polyIn = inpolygon(b(:,1),b(:,2),q(:,1),q(:,2)); 66 | 67 | if sum(polyIn) > 0 68 | pp = find(polyIn); 69 | [~,mI] = min(c(polyIn)); 70 | mI = pp(mI); 71 | current_poly(i) = true; 72 | else 73 | [~,mI] = min(c); 74 | current_poly(i) = false; 75 | end 76 | 77 | exitFlags(i) = flags(mI); 78 | current_guesses(i,:) = guesses(mI,:); 79 | current(i,:) = b(mI,:); 80 | tCosts(i) = c(mI); 81 | current_meanMax(i) = mI; 82 | 83 | end 84 | 85 | 86 | zGuesses(idx,:) = current_guesses; 87 | zValues(idx,:) = current; 88 | zCosts(idx) = tCosts; 89 | inConvHull(idx) = current_poly; 90 | meanMax(idx) = current_meanMax; 91 | 92 | end 93 | 94 | 95 | zValues(~inConvHull,:) = zGuesses(~inConvHull,:); -------------------------------------------------------------------------------- /t_sne/findTemplatesFromData.m: -------------------------------------------------------------------------------- 1 | function [signalData,signalAmps] = findTemplatesFromData(... 2 | signalData,yData,signalAmps,numPerDataSet,parameters) 3 | %findTemplatesFromData finds the training set contributions 4 | %from a single file (called by runEmbeddingSubSampling.m) 5 | 6 | 7 | kdNeighbors = parameters.kdNeighbors; 8 | minTemplateLength = parameters.minTemplateLength; 9 | 10 | plotsOn = false; 11 | 12 | 13 | fprintf(1,'\t Finding Templates\n'); 14 | [templates,~,~,~,templateLengths,~,vals] = ... 15 | returnTemplates(yData,signalData,minTemplateLength,... 16 | kdNeighbors,plotsOn); 17 | 18 | 19 | N = length(templates); 20 | d = length(signalData(1,:)); 21 | selectedData = zeros(numPerDataSet,d); 22 | selectedAmps = zeros(numPerDataSet,1); 23 | 24 | numInGroup = round(numPerDataSet*templateLengths/sum(templateLengths)); 25 | numInGroup(numInGroup == 0) = 1; 26 | sumVal = sum(numInGroup); 27 | if sumVal < numPerDataSet 28 | q = numPerDataSet - sumVal; 29 | idx = randperm(N,min(q,N)); 30 | numInGroup(idx) = numInGroup(idx) + 1; 31 | else 32 | if sumVal > numPerDataSet 33 | q = sumVal - numPerDataSet; 34 | idx2 = find(numInGroup > 1); 35 | Lq = length(idx2); 36 | if Lq < q 37 | idx2 = 1:length(numInGroup); 38 | end 39 | idx = randperm(length(idx2),q); 40 | numInGroup(idx2(idx)) = numInGroup(idx2(idx)) - 1; 41 | end 42 | end 43 | idx = numInGroup > templateLengths; 44 | numInGroup(idx) = templateLengths(idx); 45 | cumSumGroupVals = [0; cumsum(numInGroup)]; 46 | 47 | 48 | for j=1:N 49 | 50 | if cumSumGroupVals(j+1) > cumSumGroupVals(j) 51 | amps = signalAmps(vals == j); 52 | idx2 = randperm(length(templates{j}(:,1)),numInGroup(j)); 53 | selectedData(cumSumGroupVals(j)+1:cumSumGroupVals(j+1),:) = templates{j}(idx2,:); 54 | selectedAmps(cumSumGroupVals(j)+1:cumSumGroupVals(j+1)) = amps(idx2); 55 | end 56 | 57 | end 58 | 59 | signalData = selectedData; 60 | signalAmps = selectedAmps; 61 | 62 | 63 | -------------------------------------------------------------------------------- /t_sne/returnCorrectSigma_sparse.m: -------------------------------------------------------------------------------- 1 | function [sigma,p] = returnCorrectSigma_sparse(ds,perplexity,tol,maxNeighbors) 2 | %returnCorrectSigma_sparse is used by findTDistributedProjections_fmin.m to 3 | %find the correct transition probabilities given a set of distances 4 | 5 | if nargin < 2 || isempty(perplexity) 6 | perplexity = 32; 7 | end 8 | 9 | 10 | if nargin < 3 || isempty(tol) 11 | tol = 1e-5; 12 | end 13 | 14 | s = size(ds); 15 | 16 | highGuess = max(ds); 17 | lowGuess = 1e-10; 18 | 19 | sigma = .5*(highGuess + lowGuess); 20 | [~,sortIdx] = sort(ds); 21 | ds = ds(sortIdx(1:maxNeighbors)); 22 | p = exp(-.5*ds.^2./sigma^2); 23 | p = p./sum(p); 24 | idx = p>0; 25 | H = sum(-p(idx).*log(p(idx))./log(2)); 26 | P = 2^H; 27 | 28 | if abs(P-perplexity) < tol 29 | test = false; 30 | else 31 | test = true; 32 | end 33 | 34 | while test 35 | 36 | if P > perplexity 37 | highGuess = sigma; 38 | else 39 | lowGuess = sigma; 40 | end 41 | 42 | sigma = .5*(highGuess + lowGuess); 43 | 44 | p = exp(-.5*ds.^2./sigma^2); 45 | p = p./sum(p); 46 | idx = p>0; 47 | H = sum(-p(idx).*log(p(idx))./log(2)); 48 | P = 2^H; 49 | 50 | if abs(P-perplexity) < tol 51 | test = false; 52 | end 53 | 54 | end 55 | 56 | 57 | if nargout == 2 58 | if s(1) == 1 59 | p = sparse(1,sortIdx(1:maxNeighbors),p,s(1),s(2)); 60 | else 61 | p = sparse(sortIdx(1:maxNeighbors),1,p,s(1),s(2)); 62 | end 63 | end 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /t_sne/returnTemplates.m: -------------------------------------------------------------------------------- 1 | function [templates,xx,density,sigma,lengths,L,vals2] = ... 2 | returnTemplates(yData,signalData,minTemplateLength,kdNeighbors,plotsOn) 3 | %returnTemplates is used by findTemplatesFromData.m to group wavelets 4 | %mapped to the same region of t-SNE embedded space 5 | 6 | if nargin < 3 || isempty(minTemplateLength) 7 | minTemplateLength = 10; 8 | end 9 | 10 | if nargin < 4 || isempty(kdNeighbors) 11 | kdNeighbors = 10; 12 | end 13 | 14 | if nargin < 5 || isempty(plotsOn) 15 | plotsOn = true; 16 | end 17 | 18 | 19 | maxY = ceil(max(abs(yData(:)))) + 1; 20 | d = length(signalData(1,:)); 21 | 22 | NS = createns(yData); 23 | [~,D] = knnsearch(NS,yData,'K',kdNeighbors+1); 24 | 25 | sigma = median(D(:,kdNeighbors+1)); 26 | 27 | [xx,density] = findPointDensity(yData,sigma,501,[-maxY maxY]); 28 | 29 | 30 | L = watershed(-density,8); 31 | vals = round((yData + max(xx))*length(xx)/(2*max(xx))); 32 | 33 | N = length(D(:,1)); 34 | watershedValues = zeros(N,1); 35 | for i=1:N 36 | watershedValues(i) = diag(L(vals(i,2),vals(i,1))); 37 | end 38 | 39 | maxL = max(L(:)); 40 | templates = cell(maxL,1); 41 | for i=1:maxL 42 | templates{i} = signalData(watershedValues==i,:); 43 | end 44 | lengths = returnCellLengths(templates) / d; 45 | 46 | idx = find(lengths >= minTemplateLength); 47 | vals2 = zeros(size(watershedValues)); 48 | for i=1:length(idx) 49 | vals2(watershedValues == idx(i)) = i; 50 | end 51 | 52 | templates = templates(lengths >= minTemplateLength); 53 | lengths = lengths(lengths >= minTemplateLength); 54 | 55 | 56 | 57 | if plotsOn 58 | imagesc(xx,xx,density); 59 | set(gca,'ydir','normal'); 60 | axis equal tight; 61 | hold on 62 | [ii,jj] = find(L==0); 63 | plot(xx(jj),xx(ii),'k.') 64 | end -------------------------------------------------------------------------------- /t_sne/tsne_d.m: -------------------------------------------------------------------------------- 1 | function [yData,betas,P,errors] = tsne_d(D, parameters) 2 | %TSNE_D Performs symmetric t-SNE on the pairwise Euclidean distance matrix D 3 | % 4 | % [yData,betas,P,errors] = tsne_d(D, parameters) 5 | % 6 | % The function performs symmetric t-SNE on the NxN pairwise 7 | % distance matrix D to construct an embedding with no_dims dimensions 8 | % (default = 2). An initial solution obtained from an other dimensionality 9 | % reduction technique may be specified in initial_solution. 10 | % The perplexity of the Gaussian kernel that is employed can be specified 11 | % through perplexity. 12 | % 13 | % 14 | % Input variables: 15 | % 16 | % D -> NxN distance matrix 17 | % parameters -> structure containing non-default parameters 18 | % 19 | % 20 | % Output variables: 21 | % 22 | % yData -> Nx2 (or Nx3) array of embedded values 23 | % betas -> list of individual area parameters 24 | % P -> sparse transition matrix 25 | % errors -> D_{KL}(P || Q) as a function of iteration 26 | % 27 | % 28 | % (C) Laurens van der Maaten, 2010 29 | % University of California, San Diego 30 | % 31 | % Modified by Gordon J. Berman, 2014 32 | % Princeton University 33 | 34 | 35 | no_dims = parameters.num_tsne_dim; 36 | perplexity = parameters.perplexity; 37 | sigmaTolerance = parameters.sigmaTolerance; 38 | relTol = parameters.relTol; 39 | 40 | 41 | if numel(no_dims) > 1 42 | initial_solution = true; 43 | yData = no_dims; 44 | no_dims = size(ydata, 2); 45 | else 46 | initial_solution = false; 47 | end 48 | 49 | 50 | D = D / max(D(:)); 51 | [P,betas] = d2p_sparse(D .^ 2, perplexity, sigmaTolerance); 52 | P(isnan(P)) = 0; 53 | 54 | clear D 55 | 56 | % Run t-SNE 57 | if initial_solution 58 | [yData,errors] = tsne_p_sparse(P, parameters, yData, relTol); 59 | else 60 | [yData,errors] = tsne_p_sparse(P, parameters, no_dims, relTol); 61 | end 62 | -------------------------------------------------------------------------------- /t_sne/tsne_p_sparse.m: -------------------------------------------------------------------------------- 1 | function [ydata,errors] = tsne_p_sparse(P, parameters, no_dims, relTol) 2 | %TSNE_P Performs symmetric t-SNE on affinity matrix P 3 | % 4 | % [ydata,errors] = tsne_p(P, labels, no_dims, relTol) 5 | % 6 | % The function performs symmetric t-SNE on pairwise similarity matrix P 7 | % to create a low-dimensional map of no_dims dimensions (default = 2). 8 | % The matrix P is assumed to be symmetric, sum up to 1, and have zeros 9 | % on the diagonal. 10 | % The labels of the data are not used by t-SNE itself, however, they 11 | % are used to color intermediate plots. Please provide an empty labels 12 | % matrix [] if you don't want to plot results during the optimization. 13 | % The low-dimensional data representation is returned in mappedX. 14 | % 15 | % 16 | % Input variables: 17 | % 18 | % P -> NxN sparse transition probability matrix 19 | % parameters -> structure containing non-default parameters 20 | % no_dims -> number of dimensions for use in t-SNE (or an initial 21 | % condition if a multi-member array) 22 | % relTol -> relative convergence criterium 23 | % 24 | % 25 | % Output variables: 26 | % 27 | % ydata -> Nx2 (or Nx3) array of embedded values 28 | % errors -> D_{KL}(P || Q) as a function of iteration 29 | % 30 | % 31 | % (C) Laurens van der Maaten, 2010 32 | % University of California, San Diego 33 | % 34 | % Modified by Gordon J. Berman, 2014 35 | % Princeton University 36 | 37 | readout = parameters.tsne_readout; 38 | 39 | 40 | if ~exist('no_dims', 'var') || isempty(no_dims) 41 | no_dims = 2; 42 | end 43 | 44 | if ~exist('relTol', 'var') || isempty(relTol) 45 | relTol = 1e-4; 46 | end 47 | 48 | % First check whether there is an initial solution 49 | if numel(no_dims) > 1 50 | initial_solution = true; 51 | ydata = no_dims; 52 | no_dims = size(ydata, 2); 53 | else 54 | initial_solution = false; 55 | end 56 | 57 | 58 | % Initialize some variables 59 | n = size(P, 1); 60 | 61 | momentum = parameters.momentum; 62 | final_momentum = parameters.final_momentum; 63 | mom_switch_iter = parameters.mom_switch_iter; 64 | stop_lying_iter = parameters.stop_lying_iter; 65 | max_iter = parameters.max_iter; 66 | epsilon = parameters.epsilon; 67 | min_gain = parameters.min_gain; 68 | lie_multiplier = parameters.lie_multiplier; 69 | old_cost = 1e10; 70 | 71 | 72 | % Make sure p-vals are set properly 73 | P(1:(n + 1):end) = 0; 74 | P = 0.5 * (P + P'); 75 | idx = P > 0; 76 | P(idx) = P(idx) ./ sum(P(:)); 77 | idx = P > 0; 78 | 79 | % constant in KL divergence 80 | const = sum(P(idx) .* log2(P(idx))); 81 | 82 | 83 | % lie about the p-vals to find better local minima 84 | if ~initial_solution 85 | P = P * lie_multiplier; 86 | lying_stopped = false; 87 | else 88 | lying_stopped = true; 89 | end 90 | 91 | 92 | % Initialize the solution 93 | if ~initial_solution 94 | ydata = .0001 * randn(n, no_dims); 95 | end 96 | 97 | y_incs = zeros(size(ydata)); 98 | gains = ones(size(ydata)); 99 | 100 | 101 | % Run the iterations 102 | errors = zeros(max_iter,1); 103 | for iter=1:max_iter 104 | 105 | %find distances 106 | Q = 1 ./ (1 + squareform(pdist(ydata)).^2); 107 | Q(1:n+1:end) = 0; 108 | Z = sum(Q(:)); 109 | Q = Q./Z; 110 | 111 | 112 | % Compute the gradients 113 | L = Z * (P - Q) .* Q; 114 | y_grads = 4 * (diag(sum(L, 1)) - L) * ydata; 115 | 116 | 117 | 118 | % Update the solution (note that the y_grads are actually -y_grads) 119 | gains = (gains + .2) .* (sign(y_grads) ~= sign(y_incs)) ... 120 | + (gains * .8) .* (sign(y_grads) == sign(y_incs)); 121 | gains(gains < min_gain) = min_gain; 122 | y_incs = momentum * y_incs - epsilon * (gains .* y_grads); 123 | ydata = ydata + y_incs; 124 | ydata = bsxfun(@minus, ydata, mean(ydata, 1)); 125 | 126 | 127 | %find error value 128 | cost = const - sum(P(idx) .* log2(Q(idx))); 129 | diffVal = (old_cost - cost) / old_cost; 130 | old_cost = cost; 131 | errors(iter) = cost; 132 | 133 | % Update the momentum if necessary 134 | if iter == mom_switch_iter 135 | momentum = final_momentum; 136 | lying_stopped = true; 137 | end 138 | if iter == stop_lying_iter && ~initial_solution 139 | P = P ./ lie_multiplier; 140 | end 141 | 142 | % Print out progress 143 | if ~rem(iter, readout) 144 | 145 | disp(['Iteration ' num2str(iter) ': error is ' num2str(cost) ,', change is ' num2str(diffVal)]); 146 | 147 | if isfield(parameters,'signalLabels') 148 | if length(ydata(1,:)) == 2 149 | scatter(ydata(:,1),ydata(:,2),[],parameters.signalLabels,'filled') 150 | axis equal 151 | else 152 | scatter3(ydata(:,1),ydata(:,2),ydata(:,3),[],parameters.signalLabels,'filled') 153 | axis equal 154 | end 155 | drawnow; 156 | end 157 | 158 | 159 | end 160 | 161 | 162 | if abs(diffVal) < relTol && lying_stopped && iter > 10 163 | break; 164 | end 165 | 166 | end 167 | 168 | 169 | errors = errors(1:iter); 170 | 171 | -------------------------------------------------------------------------------- /utilities/argmax.m: -------------------------------------------------------------------------------- 1 | function idx = argmax(x) 2 | 3 | [~,idx] = max(x); -------------------------------------------------------------------------------- /utilities/argmin.m: -------------------------------------------------------------------------------- 1 | function idx = argmin(x) 2 | 3 | [~,idx] = min(x); -------------------------------------------------------------------------------- /utilities/autoFindThreshold_gmm.m: -------------------------------------------------------------------------------- 1 | function [threshold,obj] = autoFindThreshold_gmm(data,k,replicates) 2 | 3 | if nargin < 3 || isempty(replicates) 4 | replicates = 10; 5 | end 6 | 7 | 8 | if ~isa(class(data),'double') 9 | data = double(data); 10 | end 11 | 12 | obj = gmixPlot(data,k,[],[],true,[],[],[],replicates); 13 | [~,sortIdx] = sort(obj.mu,'descend'); 14 | 15 | minVal = min(data(:)); 16 | maxVal = max(data(:)); 17 | xx = linspace(minVal,maxVal,10000)'; 18 | posts = posterior(obj,xx); 19 | 20 | f = fit(xx,posts(:,sortIdx(1))-posts(:,sortIdx(2)),'linearinterp'); 21 | threshold = fzero(f,.5*(obj.mu(sortIdx(1)) + obj.mu(sortIdx(2)))); 22 | -------------------------------------------------------------------------------- /utilities/close_parpool.m: -------------------------------------------------------------------------------- 1 | function close_parpool 2 | % close the parallel pool in the correct for different versions 3 | % of MATLAB. 4 | % 5 | % function close_parpool 6 | % 7 | % Rob Campbell - TENSS 2017 8 | 9 | 10 | % Is the parallel computing toolbox installed? 11 | if isempty(ver('distcomp')) 12 | fprintf('No parallel computing toolbox installed\n') 13 | return 14 | end 15 | 16 | 17 | % Start the desired number of workers. Delete existing pool with wrong number 18 | % of workers if needed. 19 | if verLessThan('matlab','8.3') 20 | matlabpool close 21 | else 22 | delete(gcp('nocreate')) 23 | end 24 | -------------------------------------------------------------------------------- /utilities/combineCells.m: -------------------------------------------------------------------------------- 1 | function out = combineCells(x,dim,d) 2 | %combines a collection of cells either horizontally or vertically, 3 | %depending on the initial orientation 4 | 5 | 6 | x = x(returnCellLengths(x) > 0); 7 | 8 | if isempty(x) 9 | 10 | out = []; 11 | 12 | else 13 | 14 | L = length(x); 15 | lengths = returnCellLengths(x); 16 | [~,maxIdx] = max(lengths); 17 | s = size(x{maxIdx}); 18 | 19 | if nargin < 2 || isempty(dim) 20 | dim = argmax(s); 21 | end 22 | 23 | if dim == 1 24 | 25 | if nargin < 3 || isempty(d) 26 | d = s(2); 27 | end 28 | lengths = returnCellLengths(x) ./ d; 29 | s2 = size(lengths); 30 | if s2(2) > s2(1) 31 | lengths = lengths'; 32 | end 33 | cVals = [0; cumsum(lengths)]; 34 | 35 | out = zeros(cVals(end),d); 36 | 37 | for i=1:L 38 | if ~isempty(x{i}) 39 | out(cVals(i)+1:cVals(i+1),:) = x{i}; 40 | end 41 | end 42 | 43 | else 44 | 45 | if nargin < 3 || isempty(d) 46 | d = s(1); 47 | end 48 | lengths = returnCellLengths(x) ./ d; 49 | s2 = size(lengths); 50 | if s2(1) > s2(2) 51 | lengths = lengths'; 52 | end 53 | cVals = [0 cumsum(lengths)]; 54 | 55 | 56 | out = zeros(d,cVals(end)); 57 | 58 | for i=1:L; 59 | if ~isempty(x{i}) 60 | out(:,cVals(i)+1:cVals(i+1)) = x{i}; 61 | end 62 | end 63 | 64 | end 65 | 66 | end -------------------------------------------------------------------------------- /utilities/derivative7.m: -------------------------------------------------------------------------------- 1 | % DERIVATIVE5 - 7-Tap 1st and 2nd discrete derivatives 2 | % 3 | % This function computes 1st and 2nd derivatives of an image using the 7-tap 4 | % coefficients given by Farid and Simoncelli. The results are significantly 5 | % more accurate than MATLAB's GRADIENT function on edges that are at angles 6 | % other than vertical or horizontal. This in turn improves gradient orientation 7 | % estimation enormously. 8 | % 9 | % Usage: [gx, gy, gxx, gyy, gxy] = derivative7(im, derivative specifiers) 10 | % 11 | % Arguments: 12 | % im - Image to compute derivatives from. 13 | % derivative specifiers - A comma separated list of character strings 14 | % that can be any of 'x', 'y', 'xx', 'yy' or 'xy' 15 | % These can be in any order, the order of the 16 | % computed output arguments will match the order 17 | % of the derivative specifier strings. 18 | % Returns: 19 | % Function returns requested derivatives which can be: 20 | % gx, gy - 1st derivative in x and y 21 | % gxx, gyy - 2nd derivative in x and y 22 | % gxy - 1st derivative in y of 1st derivative in x 23 | % 24 | % Examples: 25 | % Just compute 1st derivatives in x and y 26 | % [gx, gy] = derivative7(im, 'x', 'y'); 27 | % 28 | % Compute 2nd derivative in x, 1st derivative in y and 2nd derivative in y 29 | % [gxx, gy, gyy] = derivative7(im, 'xx', 'y', 'yy') 30 | % 31 | % See also: DERIVATIVE5 32 | 33 | % Reference: Hany Farid and Eero Simoncelli "Differentiation of Discrete 34 | % Multi-Dimensional Signals" IEEE Trans. Image Processing. 13(4): 496-508 (2004) 35 | 36 | % Copyright (c) 2010 Peter Kovesi 37 | % Centre for Exploration Targeting 38 | % The University of Western Australia 39 | % http://www.csse.uwa.edu.au/~pk/research/matlabfns/ 40 | % 41 | % Permission is hereby granted, free of charge, to any person obtaining a copy 42 | % of this software and associated documentation files (the "Software"), to deal 43 | % in the Software without restriction, subject to the following conditions: 44 | % 45 | % The above copyright notice and this permission notice shall be included in 46 | % all copies or substantial portions of the Software. 47 | % 48 | % The Software is provided "as is", without warranty of any kind. 49 | % 50 | % April 2010 51 | 52 | function varargout = derivative7(im, varargin) 53 | 54 | varargin = varargin(:); 55 | varargout = cell(size(varargin)); 56 | 57 | % 7-tap interpolant and 1st and 2nd derivative coefficients 58 | p = [ 0.004711 0.069321 0.245410 0.361117 0.245410 0.069321 0.004711]; 59 | d1 = [ 0.018708 0.125376 0.193091 0.000000 -0.193091 -0.125376 -0.018708]; 60 | d2 = [ 0.055336 0.137778 -0.056554 -0.273118 -0.056554 0.137778 0.055336]; 61 | 62 | % Compute derivatives. Note that in the 1st call below MATLAB's conv2 63 | % function performs a 1D convolution down the columns using p then a 1D 64 | % convolution along the rows using d1. etc etc. 65 | gx = false; 66 | for n = 1:length(varargin) 67 | if strcmpi('x', varargin{n}) 68 | varargout{n} = conv2(p, d1, im, 'same'); 69 | gx = true; % Record that gx is available for gxy if needed 70 | gxn = n; 71 | elseif strcmpi('y', varargin{n}) 72 | varargout{n} = conv2(d1, p, im, 'same'); 73 | elseif strcmpi('xx', varargin{n}) 74 | varargout{n} = conv2(p, d2, im, 'same'); 75 | elseif strcmpi('yy', varargin{n}) 76 | varargout{n} = conv2(d2, p, im, 'same'); 77 | elseif strcmpi('xy', varargin{n}) | strcmpi('yx', varargin{n}) 78 | if gx 79 | varargout{n} = conv2(d1, p, varargout{gxn}, 'same'); 80 | else 81 | gx = conv2(p, d1, im, 'same'); 82 | varargout{n} = conv2(d1, p, gx, 'same'); 83 | end 84 | else 85 | error(sprintf('''%s'' is an unrecognized derivative option',varargin{n})); 86 | end 87 | end 88 | 89 | -------------------------------------------------------------------------------- /utilities/findAllImagesInFolders.m: -------------------------------------------------------------------------------- 1 | function images = findAllImagesInFolders(folderName,fileType,frontConstraint) 2 | %finds all images within 'folderName' (recursively) whose names end in 3 | %'fileType' and start with 'frontConstraint 4 | 5 | if nargin==1 6 | fileType = '.tiff'; 7 | end 8 | 9 | if nargin < 3 || isempty(frontConstraint) == 1 10 | frontConstraint = ''; 11 | end 12 | 13 | 14 | if folderName(end) ~= '/' 15 | folderName = strcat(folderName, '/'); 16 | end 17 | 18 | [~,temp] = unix(['find ' folderName ' -name ' frontConstraint '*' fileType]); 19 | images = regexp(temp,'\n','split')'; 20 | imageLengths = returnCellLengths(images); 21 | images = images(imageLengths > length(fileType)); 22 | 23 | -------------------------------------------------------------------------------- /utilities/findKLDivergences.m: -------------------------------------------------------------------------------- 1 | function [D,entropies] = findKLDivergences(data) 2 | %finds the KL-divergences (D) and entropies between all rows in 'data' 3 | 4 | N = length(data(:,1)); 5 | logData = log(data); 6 | logData(isinf(logData) | isnan(logData)) = 0; 7 | 8 | entropies = -sum(data.*logData,2); 9 | 10 | D = - data * logData'; 11 | D = bsxfun(@minus,D,entropies); 12 | 13 | D = D ./ log(2); 14 | D(1:(N+1):end) = 0; -------------------------------------------------------------------------------- /utilities/findListKLDivergences.m: -------------------------------------------------------------------------------- 1 | function [D,entropies] = findListKLDivergences(data,data2) 2 | %finds the KL-divergences (D) and entropies between all rows in 'data' and 3 | %all rows in 'data2' 4 | 5 | logData = log(data); 6 | 7 | entropies = -sum(data.*logData,2); 8 | clear logData; 9 | 10 | logData2 = log(data2); 11 | 12 | D = - data * logData2'; 13 | 14 | D = bsxfun(@minus,D,entropies); 15 | 16 | D = D ./ log(2); -------------------------------------------------------------------------------- /utilities/findWatershedRegions.m: -------------------------------------------------------------------------------- 1 | function [watershedRegions,v,obj,pRest] = findWatershedRegions(all_z,... 2 | xx,LL,medianLength,pThreshold,minRest,obj) 3 | 4 | 5 | 6 | if nargin < 4 || isempty(medianLength) 7 | medianLength = 1; 8 | end 9 | 10 | if nargin < 5 || isempty(pThreshold) 11 | pThreshold = [.67 .33]; 12 | end 13 | 14 | if nargin < 6 || isempty(minRest) 15 | minRest = 5; 16 | end 17 | 18 | 19 | restLength = 5; 20 | dt = .01; 21 | numGMM = 2; 22 | numToTest = 50000; 23 | N = length(all_z(:,1)); 24 | 25 | smooth_z = all_z; 26 | if medianLength > 0 27 | smooth_z(:,1) = medfilt1(all_z(:,1),medianLength); 28 | smooth_z(:,2) = medfilt1(all_z(:,2),medianLength); 29 | end 30 | 31 | vx = [0;diff(smooth_z(:,1))]./dt; 32 | vy = [0;diff(smooth_z(:,2))]./dt; 33 | v = sqrt(vx.^2+vy.^2); 34 | 35 | if nargin < 8 || isempty(obj) 36 | figure 37 | obj = gmixPlot(sampleFromMatrix(log10(v(v>0)),numToTest),numGMM,[],200,[],true,[],[],3); 38 | xlabel('log_{10} velocity','fontsize',16,'fontweight','bold') 39 | ylabel('PDF','fontsize',16,'fontweight','bold') 40 | set(gca,'fontsize',14,'fontweight','bold') 41 | drawnow; 42 | end 43 | 44 | [~,maxIdx] = max(obj.mu); 45 | minVal = min(obj.mu); 46 | posts = posterior(obj,log(v)./log(10)); 47 | posts(v==0,maxIdx) = 0; 48 | posts(vlength(xx)) = length(xx); 55 | 56 | 57 | watershedValues = zeros(N,1); 58 | for i=1:N 59 | watershedValues(i) = diag(LL(vals(i,2),vals(i,1))); 60 | end 61 | diffValues = abs([0;diff(watershedValues)]) == 0; 62 | 63 | L = max(LL(:)); 64 | if length(pThreshold) == 1 65 | 66 | CC = largeBWConnComp(pRest > pThreshold & diffValues,minRest); 67 | 68 | else 69 | 70 | minVal = min(pThreshold); 71 | maxVal = max(pThreshold); 72 | 73 | CC = largeBWConnComp(pRest > minVal & diffValues,minRest); 74 | maxInRanges = zeros(CC.NumObjects,1); 75 | for i=1:CC.NumObjects 76 | maxInRanges(i) = max(pRest(CC.PixelIdxList{i})); 77 | end 78 | 79 | CC.NumObjects = sum(maxInRanges >= maxVal); 80 | CC.PixelIdxList = CC.PixelIdxList(maxInRanges >= maxVal); 81 | 82 | end 83 | 84 | segmentAssignments = zeros(size(CC.PixelIdxList)); 85 | watershedRegions = zeros(N,1); 86 | for i=1:CC.NumObjects 87 | segmentAssignments(i) = mode(watershedValues(CC.PixelIdxList{i})); 88 | watershedRegions(CC.PixelIdxList{i}) = segmentAssignments(i); 89 | end 90 | 91 | for i=1:L 92 | CC = largeBWConnComp(watershedValues == i,restLength); 93 | for j=1:length(CC.PixelIdxList) 94 | watershedRegions(CC.PixelIdxList{j}) = i; 95 | end 96 | end 97 | 98 | 99 | -------------------------------------------------------------------------------- /utilities/gaussianfilterdata.m: -------------------------------------------------------------------------------- 1 | function out = gaussianfilterdata(data,sigma) 2 | %convolves a data set with a gaussian of width 'sigma' 3 | 4 | L = length(data); 5 | xx = (1:L) - round(L/2); 6 | if iscolumn(data) 7 | xx = xx'; 8 | end 9 | 10 | g = exp(-.5.*xx.^2./sigma^2)/sqrt(2*pi*sigma^2); 11 | out = fftshift(ifft(fft(data).*fft(g))); -------------------------------------------------------------------------------- /utilities/gmixPlot.m: -------------------------------------------------------------------------------- 1 | function [obj,residuals,Z] = gmixPlot(X,N,MaxIter,bins,plotOFF,plotSubGaussians,obj,xlimits,replicates) 2 | %finds and plots (optional) a gaussian mixture model fit to a 1d data set 3 | % 4 | %Inputs: 5 | %X = column vector of data 6 | %N = number of clusters 7 | %MaxIter = max iterations of GMM fit 8 | %bins = number of bins to display 9 | %plotsOFF = turns plotting off and on 10 | %plotSubGaussians = turn subgaussian plots on and off 11 | %obj = inputted GMM 12 | %xlimits = x limits for plot 13 | %replicates = # of replicates for GMM 14 | 15 | %Outputs: 16 | %obj = GMM object 17 | %residuals = GMM errors 18 | %Z = histogram bins (Z = {Xvalues, Yvalues}) 19 | 20 | 21 | 22 | if nargin < 3 || isempty(MaxIter) 23 | MaxIter = 10000; 24 | end 25 | 26 | if nargin < 4 || isempty(bins) 27 | bins = 50; 28 | end 29 | 30 | if nargin < 5 || isempty(plotOFF) 31 | plotOFF = false; 32 | end 33 | 34 | if nargin < 6 || isempty(plotSubGaussians) 35 | plotSubGaussians = false; 36 | end 37 | 38 | if nargin < 9 || isempty(replicates) 39 | replicates = 1; 40 | end 41 | 42 | if nargin < 7 || isempty(obj) 43 | options = statset('MaxIter',MaxIter,'Robust','on'); 44 | obj = gmdistribution.fit(X,N,'Options',options,'Replicates',replicates,'Regularize',1e-30); 45 | else 46 | N = length(obj.mu); 47 | end 48 | 49 | 50 | 51 | 52 | if nargout > 1 || ~plotOFF 53 | [YY,XX] = hist(X,bins); 54 | YY = YY ./ (sum(YY)*(XX(2) - XX(1))); 55 | g = @(x) pdf(obj,x); 56 | residuals = YY' - g(XX'); 57 | Z = {XX,YY}; 58 | end 59 | 60 | 61 | if ~plotOFF 62 | 63 | %figure 64 | bar(XX,YY) 65 | if nargin < 8 || isempty(xlimits) 66 | xlimits = [XX(1) XX(end)]; 67 | end 68 | xx = linspace(xlimits(1),xlimits(2),1000); 69 | hold on 70 | 71 | if plotSubGaussians && N > 1 72 | g = @(x,mu,sigma,p) p*exp(-.5*(x-mu).^2./sigma^2)./sqrt(2*pi*sigma^2); 73 | for i=1:N 74 | plot(xx,g(xx,obj.mu(i),sqrt(obj.Sigma(i)),obj.PComponents(i)),'g-','linewidth',2) 75 | end 76 | end 77 | 78 | 79 | h = plot(xx,pdf(obj,xx')); 80 | set(h,'linewidth',2) 81 | set(h,'Color','r') 82 | 83 | 84 | 85 | 86 | xlimits = [xlimits 0 max(YY)*1.1]; 87 | axis(xlimits); 88 | 89 | 90 | 91 | end 92 | 93 | -------------------------------------------------------------------------------- /utilities/largeBWConnComp.m: -------------------------------------------------------------------------------- 1 | function CC = largeBWConnComp(x,minLength,vals,minVal) 2 | %returns a structure containing only 1d connceted components above a given 3 | %size (output structure is identical to bwconncomp) 4 | 5 | CC = bwconncomp(x); 6 | lengths = zeros(CC.NumObjects,1); 7 | for i=1:CC.NumObjects 8 | lengths(i) = length(CC.PixelIdxList{i}); 9 | end 10 | 11 | idx = lengths >= minLength; 12 | 13 | CC.NumObjects = sum(idx); 14 | CC.PixelIdxList = CC.PixelIdxList(idx); 15 | 16 | if nargin > 3 17 | 18 | maxVals = zeros(CC.NumObjects,1); 19 | for i=1:CC.NumObjects 20 | maxVals(i) = max(vals(CC.PixelIdxList{i})); 21 | end 22 | 23 | CC.PixelIdxList = CC.PixelIdxList(maxVals >= minVal); 24 | CC.NumObjects = sum(maxVals >= minVal); 25 | 26 | end -------------------------------------------------------------------------------- /utilities/rescaleImage.m: -------------------------------------------------------------------------------- 1 | function imageOut = rescaleImage(image,scale) 2 | %rescales an image 3 | 4 | s = size(image); 5 | s2 = round(s*scale); 6 | 7 | if min(s == s2) == 1 8 | 9 | imageOut = image; 10 | 11 | else 12 | 13 | if scale > 1 14 | 15 | startIdx = floor((s2 - s)/2); 16 | imageOut = imresize(image,s2); 17 | imageOut = imageOut((1:s(1))+startIdx(1),(1:s(2))+startIdx(2)); 18 | 19 | else 20 | 21 | startIdx = floor((s - s2)/2); 22 | image2 = imresize(image,s2); 23 | imageOut = uint8(zeros(s)); 24 | imageOut((1:s2(1)) + startIdx(1),(1:s2(2)) + startIdx(2)) = image2; 25 | 26 | end 27 | 28 | 29 | end -------------------------------------------------------------------------------- /utilities/returnCellLengths.m: -------------------------------------------------------------------------------- 1 | function lengths = returnCellLengths(x) 2 | 3 | L = length(x(:)); 4 | lengths = zeros(size(x)); 5 | 6 | for i=1:L 7 | lengths(i) = length(x{i}(:)); 8 | end 9 | -------------------------------------------------------------------------------- /utilities/sampleFromMatrix.m: -------------------------------------------------------------------------------- 1 | function out = sampleFromMatrix(data,N) 2 | 3 | L = length(data(:,1)); 4 | if L <= N 5 | out = data; 6 | else 7 | q = randperm(L); 8 | out = data(q(1:N),:); 9 | end -------------------------------------------------------------------------------- /utilities/setup_parpool.m: -------------------------------------------------------------------------------- 1 | function setup_parpool(desiredPoolSize) 2 | % Set up a parallel pool of the desired number of workers 3 | % 4 | % function setup_parpool(desiredPoolSize) 5 | % 6 | % Runs the correct parallel pool setup function for different versions 7 | % of MATLAB. 8 | % 9 | % Inputs 10 | % desiredPoolSize - an integer specifying the desired number of workers 11 | % 12 | % 13 | % Rob Campbell - TENSS 2017 14 | 15 | 16 | % Is the parallel computing toolbox installed? 17 | if isempty(ver('parallel')) 18 | fprintf('No parallel computing toolbox installed\n') 19 | return 20 | end 21 | 22 | 23 | % Start the desired number of workers. Delete existing pool with wrong number 24 | % of workers if needed. 25 | if verLessThan('matlab','8.3') 26 | 27 | if matlabpool('size') ~= desiredPoolSize; 28 | matlabpool close force 29 | if desiredPoolSize > 1 30 | matlabpool(desiredPoolSize); 31 | end 32 | end 33 | 34 | else 35 | 36 | g=gcp; 37 | if g.NumWorkers ~= desiredPoolSize 38 | delete(gcp('nocreate')) 39 | if desiredPoolSize > 1 40 | parpool(desiredPoolSize); 41 | end 42 | end 43 | 44 | end 45 | 46 | -------------------------------------------------------------------------------- /utilities/shuffledMatrix.m: -------------------------------------------------------------------------------- 1 | function out = shuffledMatrix(x) 2 | 3 | N = length(x(:,1)); 4 | L = length(x(1,:)); 5 | 6 | out = zeros(N,L); 7 | for i=1:L 8 | q = randperm(N); 9 | out(:,i) = x(q,i); 10 | end -------------------------------------------------------------------------------- /wavelet/fastWavelet_morlet_convolution_parallel.m: -------------------------------------------------------------------------------- 1 | function [amp,W] = fastWavelet_morlet_convolution_parallel(x,f,omega0,dt) 2 | %fastWavelet_morlet_convolution_parallel finds the Morlet wavelet transform 3 | %resulting from a time series 4 | % 5 | % Input variables: 6 | % 7 | % x -> 1d array of projection values to transform 8 | % f -> center bands of wavelet frequency channels (Hz) 9 | % omega0 -> dimensionless Morlet wavelet parameter 10 | % dt -> sampling time (seconds) 11 | % 12 | % 13 | % Output variables: 14 | % 15 | % amp -> wavelet amplitudes (N x (pcaModes*numPeriods) ) 16 | % W -> wavelet coefficients (complex-valued) 17 | % 18 | % 19 | % (C) Gordon J. Berman, 2014 20 | % Princeton University 21 | 22 | N = length(x); 23 | L = length(f); 24 | amp = zeros(L,N); 25 | if mod(N,2) == 1 26 | x(end+1) = 0; 27 | N = N + 1; 28 | test = true; 29 | else 30 | test = false; 31 | end 32 | 33 | 34 | s = size(x); 35 | if s(2) == 1 36 | x = x'; 37 | end 38 | 39 | x = [zeros(1,N/2) x zeros(1,N/2)]; 40 | M = N; 41 | N = length(x); 42 | 43 | scales = (omega0 + sqrt(2+omega0^2))./(4*pi.*f); 44 | Omegavals = 2*pi*(-N/2:N/2-1)./(N*dt); 45 | 46 | xHat = fft(x); 47 | xHat = fftshift(xHat); 48 | 49 | if test 50 | idx = (M/2+1):(M/2+M-1); 51 | else 52 | idx = (M/2+1):(M/2+M); 53 | end 54 | 55 | if nargout == 2 56 | W = zeros(size(amp)); 57 | test2 = true; 58 | else 59 | test2 = false; 60 | end 61 | 62 | parfor i=1:L 63 | 64 | m = morletConjFT(-Omegavals*scales(i),omega0); 65 | q = ifft(m.*xHat)*sqrt(scales(i)); 66 | 67 | q = q(idx); 68 | 69 | amp(i,:) = abs(q)*pi^-.25*exp(.25*(omega0-sqrt(omega0^2+2))^2)/sqrt(2*scales(i)); 70 | 71 | if test2 72 | W(i,:) = q; 73 | end 74 | end 75 | 76 | -------------------------------------------------------------------------------- /wavelet/morletConjFT.m: -------------------------------------------------------------------------------- 1 | function out = morletConjFT(w,omega0) 2 | %morletConjFT is used by fastWavelet_morlet_convolution_parallel to find 3 | %the Morlet wavelet transform resulting from a time series 4 | 5 | out = pi^(-1/4).*exp(-.5.*(w-omega0).^2); --------------------------------------------------------------------------------