├── .gitattributes ├── CalculateMetrics9.m ├── ImsAndSegs ├── ImsAndTruths100075.mat ├── ImsAndTruths100080.mat ├── ImsAndTruths100098.mat ├── ImsAndTruths103041.mat ├── ImsAndTruths104022.mat ├── ImsAndTruths105019.mat ├── ImsAndTruths105053.mat ├── ImsAndTruths106020.mat ├── ImsAndTruths106025.mat ├── ImsAndTruths108041.mat ├── ImsAndTruths108073.mat ├── ImsAndTruths109034.mat ├── ImsAndTruths112082.mat ├── ImsAndTruths113009.mat ├── ImsAndTruths113016.mat ├── ImsAndTruths113044.mat ├── ImsAndTruths117054.mat ├── ImsAndTruths118020.mat ├── ImsAndTruths118035.mat ├── ImsAndTruths12003.mat ├── ImsAndTruths12074.mat ├── ImsAndTruths122048.mat ├── ImsAndTruths124084.mat ├── ImsAndTruths126039.mat ├── ImsAndTruths130034.mat ├── ImsAndTruths134008.mat ├── ImsAndTruths134052.mat ├── ImsAndTruths135037.mat ├── ImsAndTruths135069.mat ├── ImsAndTruths138032.mat ├── ImsAndTruths138078.mat ├── ImsAndTruths140055.mat ├── ImsAndTruths140075.mat ├── ImsAndTruths144067.mat ├── ImsAndTruths145014.mat ├── ImsAndTruths145053.mat ├── ImsAndTruths147021.mat ├── ImsAndTruths147062.mat ├── ImsAndTruths15004.mat ├── ImsAndTruths15088.mat ├── ImsAndTruths151087.mat ├── ImsAndTruths153077.mat ├── ImsAndTruths153093.mat ├── ImsAndTruths155060.mat ├── ImsAndTruths156079.mat ├── ImsAndTruths157036.mat ├── ImsAndTruths159029.mat ├── ImsAndTruths159045.mat ├── ImsAndTruths159091.mat ├── ImsAndTruths16052.mat ├── ImsAndTruths161062.mat ├── ImsAndTruths163014.mat ├── ImsAndTruths163062.mat ├── ImsAndTruths164074.mat ├── ImsAndTruths166081.mat ├── ImsAndTruths169012.mat ├── ImsAndTruths170054.mat ├── ImsAndTruths172032.mat ├── ImsAndTruths173036.mat ├── ImsAndTruths176019.mat ├── ImsAndTruths176035.mat ├── ImsAndTruths176039.mat ├── ImsAndTruths178054.mat ├── ImsAndTruths181018.mat ├── ImsAndTruths181079.mat ├── ImsAndTruths181091.mat ├── ImsAndTruths183055.mat ├── ImsAndTruths183087.mat ├── ImsAndTruths187003.mat ├── ImsAndTruths187029.mat ├── ImsAndTruths187039.mat ├── ImsAndTruths187071.mat ├── ImsAndTruths187083.mat ├── ImsAndTruths188005.mat ├── ImsAndTruths188063.mat ├── ImsAndTruths188091.mat ├── ImsAndTruths189003.mat ├── ImsAndTruths189011.mat ├── ImsAndTruths196015.mat ├── ImsAndTruths198004.mat ├── ImsAndTruths198023.mat ├── ImsAndTruths198054.mat ├── ImsAndTruths20008.mat ├── ImsAndTruths202012.mat ├── ImsAndTruths207056.mat ├── ImsAndTruths209070.mat ├── ImsAndTruths2092.mat ├── ImsAndTruths216041.mat ├── ImsAndTruths216053.mat ├── ImsAndTruths216066.mat ├── ImsAndTruths22013.mat ├── ImsAndTruths22090.mat ├── ImsAndTruths22093.mat ├── ImsAndTruths225017.mat ├── ImsAndTruths227040.mat ├── ImsAndTruths227046.mat ├── ImsAndTruths23025.mat ├── ImsAndTruths23080.mat ├── ImsAndTruths23084.mat ├── ImsAndTruths231015.mat ├── ImsAndTruths232038.mat ├── ImsAndTruths236017.mat ├── ImsAndTruths238011.mat ├── ImsAndTruths239007.mat ├── ImsAndTruths239096.mat ├── ImsAndTruths24004.mat ├── ImsAndTruths24063.mat ├── ImsAndTruths242078.mat ├── ImsAndTruths245051.mat ├── ImsAndTruths246016.mat ├── ImsAndTruths246053.mat ├── ImsAndTruths247085.mat ├── ImsAndTruths249061.mat ├── ImsAndTruths249087.mat ├── ImsAndTruths25098.mat ├── ImsAndTruths253036.mat ├── ImsAndTruths254033.mat ├── ImsAndTruths260081.mat ├── ImsAndTruths26031.mat ├── ImsAndTruths268002.mat ├── ImsAndTruths27059.mat ├── ImsAndTruths271008.mat ├── ImsAndTruths271031.mat ├── ImsAndTruths274007.mat ├── ImsAndTruths277095.mat ├── ImsAndTruths28075.mat ├── ImsAndTruths28096.mat ├── ImsAndTruths285036.mat ├── ImsAndTruths286092.mat ├── ImsAndTruths292066.mat ├── ImsAndTruths293029.mat ├── ImsAndTruths299091.mat ├── ImsAndTruths301007.mat ├── ImsAndTruths302003.mat ├── ImsAndTruths309004.mat ├── ImsAndTruths310007.mat ├── ImsAndTruths311068.mat ├── ImsAndTruths311081.mat ├── ImsAndTruths314016.mat ├── ImsAndTruths317080.mat ├── ImsAndTruths323016.mat ├── ImsAndTruths326038.mat ├── ImsAndTruths33066.mat ├── ImsAndTruths35008.mat ├── ImsAndTruths35010.mat ├── ImsAndTruths35058.mat ├── ImsAndTruths35070.mat ├── ImsAndTruths35091.mat ├── ImsAndTruths353013.mat ├── ImsAndTruths361084.mat ├── ImsAndTruths365025.mat ├── ImsAndTruths365073.mat ├── ImsAndTruths368016.mat ├── ImsAndTruths368078.mat ├── ImsAndTruths370036.mat ├── ImsAndTruths372047.mat ├── ImsAndTruths374020.mat ├── ImsAndTruths374067.mat ├── ImsAndTruths376001.mat ├── ImsAndTruths376020.mat ├── ImsAndTruths385028.mat ├── ImsAndTruths388016.mat ├── ImsAndTruths41004.mat ├── ImsAndTruths41025.mat ├── ImsAndTruths42044.mat ├── ImsAndTruths42078.mat ├── ImsAndTruths43070.mat ├── ImsAndTruths43083.mat ├── ImsAndTruths45077.mat ├── ImsAndTruths46076.mat ├── ImsAndTruths48055.mat ├── ImsAndTruths54005.mat ├── ImsAndTruths55067.mat ├── ImsAndTruths55075.mat ├── ImsAndTruths56028.mat ├── ImsAndTruths59078.mat ├── ImsAndTruths60079.mat ├── ImsAndTruths61060.mat ├── ImsAndTruths61086.mat ├── ImsAndTruths65010.mat ├── ImsAndTruths65019.mat ├── ImsAndTruths65074.mat ├── ImsAndTruths65132.mat ├── ImsAndTruths66039.mat ├── ImsAndTruths66075.mat ├── ImsAndTruths67079.mat ├── ImsAndTruths68077.mat ├── ImsAndTruths71046.mat ├── ImsAndTruths76002.mat ├── ImsAndTruths78019.mat ├── ImsAndTruths80099.mat ├── ImsAndTruths8049.mat ├── ImsAndTruths87065.mat ├── ImsAndTruths90076.mat ├── ImsAndTruths92059.mat ├── ImsAndTruths94079.mat ├── ImsAndTruths95006.mat └── ImsAndTruths97017.mat ├── MyClust9.m ├── MyClustEvalHyper9.m ├── MyClustEvalRGB9.m ├── MyFCM9.m ├── MyGMM9.m ├── MyKmeans9.m ├── MyMartinIndex9.m ├── MySOM9.m ├── MySpectral9.asv ├── MySpectral9.m ├── Readme.txt ├── TestImage9.m └── helpers ├── ConnectedComponents.m ├── PCAbyDG.m ├── SimGraph_NearestNeighbors.m ├── SpectralClustering.m ├── convertClusterVector.m ├── distEuclidean.m ├── normalizeData.m └── simGaussian.m /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /CalculateMetrics9.m: -------------------------------------------------------------------------------- 1 | function [output] = CalculateMetrics9() 2 | addpath(genpath('helpers')) 3 | % Provide local path for ImsAndSegs folder 4 | Images = dir('C:\Users\FoxRiver-Yoga\Documents\ImsAndSegs3'); 5 | Images(1:2,:) = []; 6 | numberOfImages = max(size(Images)); 7 | output = zeros(1, numberOfImages); 8 | numberOfImages 9 | for i = 1:numberOfImages 10 | minimum = 1; 11 | i 12 | LoadedImage = load(strcat(Images(i,1).folder, '/', Images(i,1).name)); 13 | for j = 2:7 14 | % Change to algorithm for which metric has to be calculated 15 | %[ClusterIm, CCIm] = MySpectral9(LoadedImage.Im, 'RGB', j); 16 | [ClusterIm, CCIm] = MyClust9(LoadedImage.Im,'Algorithm', 'Spectral', 'ImType', 'RGB', 'NumClusts', j); 17 | 18 | a = MyMartinIndex9(CCIm, LoadedImage.Seg1); 19 | b = MyMartinIndex9(CCIm, LoadedImage.Seg2); 20 | c = MyMartinIndex9(CCIm, LoadedImage.Seg3); 21 | index = min(min(a,b),c); 22 | 23 | if index= 2 44 | Data = (squeeze(Data))'; 45 | end 46 | 47 | % convert to double and normalize to [0,1] 48 | Data = double(Data); 49 | Data = normalizeData(Data); 50 | 51 | % Find unique colors 52 | if isequal(roundColors, 1) 53 | fac = 10^roundDigits; 54 | rData = round(Data * fac) / fac; 55 | else 56 | rData = Data; 57 | end 58 | 59 | [~, ind, order] = unique(rData', 'rows', 'R2012a'); 60 | 61 | % crop data 62 | Data = Data(:, ind); 63 | 64 | % now for the clustering 65 | fprintf('Creating Similarity Graph...\n'); 66 | SimGraph = SimGraph_NearestNeighbors(Data, Neighbors, 1); 67 | 68 | try 69 | comps = graphconncomp(SimGraph, 'Directed', false); 70 | fprintf('- %d connected components found\n', comps); 71 | end 72 | 73 | fprintf('Clustering Data...\n'); 74 | C = SpectralClustering(SimGraph, k, 3); 75 | 76 | %ConnImg = SpectralClustering(SimGraph, k, 2); 77 | 78 | % convert and restore full size 79 | D = convertClusterVector(C); 80 | D = D(order); 81 | 82 | % reshape indicator vector into m-by-n 83 | S = reshape(D, m, n); 84 | 85 | % choose colormap 86 | %if k == 2 87 | % map = [0 0 0; 1 1 1]; 88 | %else 89 | % map = zeros(3, k); 90 | 91 | % for ii = 1:k 92 | % ind = find(D == ii, 1); 93 | % map(:, ii) = rData(:, ind); 94 | % end 95 | % 96 | % map = map'; 97 | %end 98 | 99 | % plot image 100 | set(gca, 'Position', [0 0 1 1], 'Units', 'Normalized'); 101 | ClusterIm = S; 102 | 103 | %imshow(S, map, 'Border', 'tight'); 104 | %imshow(S,map); 105 | %hold on; 106 | 107 | %axis off; 108 | %truesize; 109 | %hold off; 110 | %pause; 111 | 112 | IDX=reshape(ClusterIm,[m*n,1]); 113 | CCIm = ConnectedComponents(IDX,NumClusts,m,n); 114 | 115 | return -------------------------------------------------------------------------------- /MySpectral9.m: -------------------------------------------------------------------------------- 1 | function [ClusterIm, CCIm] = MySpectral9(Im, ImageType, NumClusts); 2 | 3 | %% 4 | disp('Running Spectral Clustering...') 5 | ClusterIm = []; 6 | CCIm = []; 7 | %% 8 | 9 | k = NumClusts; % Number of Clusters 10 | Neighbors = 10; % Number of Neighbors 11 | 12 | roundColors = 1; % Round color values for less strict uniqueness 13 | roundDigits = 2; % Precision for Uniqueness 14 | saveData = 0; % Save Dataset 15 | markEdges = 0; % Outline edges 16 | 17 | % ============= 18 | 19 | %%%% Used to read .jpg files as test %%%% 20 | %FileName = 'RainbowDash.jpg'; 21 | %FileName = fullfile(FileName); 22 | Img = Im; %imread(FileName); 23 | 24 | %%%% Used to read .mat files from the given folder %%%% 25 | %matData = load('C:\Users\FoxRiver-Yoga\OneDrive\Academic\Spring 2018\CAP6610\project1\PaviaRGB.mat'); 26 | %imshow(input_data.PaviaRGB); 27 | %FileName = 'C:\Users\FoxRiver-Yoga\OneDrive\Academic\Spring 2018\CAP6610\project1\ImsAndSegs\ImsAndTruths100075.mat'; 28 | %ImsAndSegs = load(FileName); 29 | %Img = ImsAndSegs.Im; 30 | %Img = matData.PaviaRGB; 31 | 32 | [m, n, d] = size(Img); 33 | 34 | if(strcmp('Hyper',ImageType)==1) 35 | b = 20; 36 | [Y, U, Lambda, Mu] = PCAbyDG(Img,b); 37 | Data = Y; 38 | Data = reshape(Data, 1, m * n, []); 39 | else 40 | % convert into list of data points 41 | Data = reshape(Img, 1, m * n, []); 42 | end 43 | 44 | 45 | if d >= 2 46 | Data = (squeeze(Data))'; 47 | end 48 | 49 | % convert to double and normalize to [0,1] 50 | Data = double(Data); 51 | Data = normalizeData(Data); 52 | 53 | % Find unique colors 54 | if isequal(roundColors, 1) 55 | fac = 10^roundDigits; 56 | rData = round(Data * fac) / fac; 57 | else 58 | rData = Data; 59 | end 60 | 61 | [~, ind, order] = unique(rData', 'rows', 'R2012a'); 62 | 63 | % crop data 64 | Data = Data(:, ind); 65 | 66 | % now for the clustering 67 | fprintf('Creating Similarity Graph...\n'); 68 | SimGraph = SimGraph_NearestNeighbors(Data, Neighbors, 1); 69 | 70 | try 71 | comps = graphconncomp(SimGraph, 'Directed', false); 72 | fprintf('- %d connected components found\n', comps); 73 | end 74 | 75 | fprintf('Clustering Data...\n'); 76 | C = SpectralClustering(SimGraph, k, 3); 77 | 78 | %ConnImg = SpectralClustering(SimGraph, k, 2); 79 | 80 | % convert and restore full size 81 | D = convertClusterVector(C); 82 | D = D(order); 83 | 84 | % reshape indicator vector into m-by-n 85 | S = reshape(D, m, n); 86 | 87 | % choose colormap 88 | %if k == 2 89 | % map = [0 0 0; 1 1 1]; 90 | %else 91 | % map = zeros(3, k); 92 | 93 | % for ii = 1:k 94 | % ind = find(D == ii, 1); 95 | % map(:, ii) = rData(:, ind); 96 | % end 97 | % 98 | % map = map'; 99 | %end 100 | 101 | % plot image 102 | set(gca, 'Position', [0 0 1 1], 'Units', 'Normalized'); 103 | ClusterIm = S; 104 | 105 | %imshow(S, map, 'Border', 'tight'); 106 | %imshow(S,map); 107 | %hold on; 108 | 109 | %axis off; 110 | %truesize; 111 | %hold off; 112 | %pause; 113 | 114 | IDX=reshape(ClusterIm,[m*n,1]); 115 | CCIm = ConnectedComponents(IDX,NumClusts,m,n); 116 | 117 | return -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | addpath(genpath('helpers')) 2 | addpath(genpath('ImsAndSegs')) 3 | 4 | These two lines are added in MyClust9.m and TestImage9.m which assumes the following directory structure; 5 | 6 | / 7 | - ImsAndSegs/ 8 | - helpers/ 9 | - CalculateMetrics9.m 10 | - MyClust9.m 11 | - MyClustEvalHyper9.m 12 | - MyClustEvalRGB9.m 13 | - MyFCM9.m 14 | - MyGMM9.m 15 | - MyKmeans9.m 16 | - MyMartinIndex9.m 17 | - MySOM9.m 18 | - MySpectral9.m 19 | - TestImage9.m 20 | 21 | PaviaHyperIm.mat, PaviaGrTruth.mat and PaviaGrTruthMask.mat are assumed to be inside ImsAndSegs 22 | 23 | The two main functions to run are CalculateMetrics9 and TestImage9. Make sure ImsAndSegs with all RGB and HyperSpectral mat files are copied to the working directory (root) as shown in the directory structure above. 24 | 25 | 1. CalculateMetrics9: 26 | Calculates the mean and standard deviation to populate Table 2. The local path to image directory should be provided to the script. 27 | 28 | 2. TestImage9: 29 | Runs one algorithm on one image and displays the segmentation. Name of the image to run should be provided to the script. Evaluation of HyperSpectral images is also done here. Comments are added to show which lines are used for RGB or HyperSpectral or both. 30 | 31 | All other helper functions are defined in "helpers". Comments are added in each script to explain its functionality. 32 | 33 | -------------------------------------------------------------------------------- /TestImage9.m: -------------------------------------------------------------------------------- 1 | close all;clear all; 2 | 3 | addpath(genpath('helpers')) %use for both 4 | addpath(genpath('ImsAndSegs')) %use for both 5 | 6 | %matData = load('ImsAndTruths22090.mat'); %use for RGB 7 | matData = load('PaviaHyperIm.mat'); %use for Pavia 8 | 9 | %Img = matData.Im; %use for RGB 10 | Img = matData.PaviaHyperIm; %use for Pavia 11 | GroundTruthMatData = load('PaviaGrTruth.mat'); %use for Pavia 12 | GroundTruth = GroundTruthMatData.PaviaGrTruth; %use for Pavia 13 | MaskMatData = load('PaviaGrTruthMask.mat'); %use for Pavia 14 | Mask = MaskMatData.PaviaGrTruthMask; %use for Pavia 15 | 16 | [ClusterIm, CCIm] = MyClust9(Img,'Algorithm', 'Spectral', 'ImType', 'Hyper', 'NumClusts', 9); %use for Pavia 17 | %[ClusterIm, CCIm] = MyClust9(Img,'Algorithm', 'SOM', 'ImType', 'RGB','NumClusts', 3); %use for RGB 18 | 19 | index = MyClustEvalHyper9(ClusterIm,GroundTruth,Mask) %use for Pavia 20 | 21 | [m,n] = size(CCIm); %use for both 22 | ClusterIm = reshape(ClusterIm, [m,n]); %use for both 23 | 24 | imagesc(ClusterIm); %use for both -------------------------------------------------------------------------------- /helpers/ConnectedComponents.m: -------------------------------------------------------------------------------- 1 | function[CCIm] = ConnectedComponents(clusterIm,clustNum,m,n) 2 | disp('getting conn comp'); 3 | CCIm = zeros(m*n,1); 4 | mask = gausswin(6); 5 | mask = mask*mask'; 6 | mask = mask/sum(mask); 7 | %connected component count 8 | count = 1; 9 | for clust = 1:clustNum 10 | bw = zeros(m*n,1); 11 | % converting each clsuter to bw image 12 | for itr = 1:size(clusterIm,1) 13 | if clusterIm(itr) == clust 14 | bw(itr) = 1; 15 | end 16 | end 17 | 18 | bw = reshape(bw,m,n); 19 | cc = bwconncomp(bw); 20 | 21 | componentsFound = size(cc.PixelIdxList,2); 22 | for itr = 1:componentsFound 23 | pointsInComponent = size(cc.PixelIdxList{itr},1); 24 | cc.PixelIdxList{itr} 25 | for jtr = 1:pointsInComponent 26 | imageIndex = cc.PixelIdxList{itr}(jtr); 27 | %imageIndex 28 | CCIm(imageIndex) = count; 29 | end 30 | %CCIm 31 | count = count + 1; 32 | end 33 | 34 | end 35 | %CCIm 36 | CCIm = reshape(CCIm,m,n); 37 | end -------------------------------------------------------------------------------- /helpers/PCAbyDG.m: -------------------------------------------------------------------------------- 1 | function [Y, U, Lambda, Mu] = PCAbyDG(X, NComps); 2 | %function [Y, U, Lambda, Mu] = PCAbyDG(X, NComps); 3 | % 4 | %%% To compute transform of N x 1 vector x, use U'*(x-Mu) 5 | % 6 | %INPUTS: 7 | % 8 | % X is either: 9 | % (1) a B x N Matrix 10 | % and the columns of X are spectra 11 | % or 12 | % (2) an NRows x NCols X B Spectral Data Cube 13 | % where 14 | % B = Number of Bands 15 | % N = Number of Spectra 16 | % 17 | % NComps is the number of components to keep. Must be >=1. 18 | % 19 | %OUTPUTS: 20 | % Y = first NComps Principal Components sorted by decreasing variance 21 | % U = B x B matrix of eigenvectors of the covariance matrix 22 | % Lambda = B x 1 vector of eigenvalues of the covariance matrix 23 | % Mu = mean of columns of X 24 | % 25 | %%%%%%%%%%%%%%%%%%%%%%%%%%%% 26 | %%% Author: Darth Gader %%% 27 | %%%%%%%%%%%%%%%%%%%%%%%%%%%% 28 | 29 | %% 30 | %%% REFORMAT X AS A BxN MATRIX IF IT IS NRows x NCols x B %%% 31 | %%% THROW AN ERROR IF X IS 1D OR >3D %%% 32 | Sx = size(X); 33 | NDims = min(4,length(Sx)); 34 | switch NDims 35 | case 1 36 | error('Error: Not enough Dimensions'); 37 | case 3 38 | N = Sx(1)*Sx(2); 39 | B = Sx(3); 40 | X = shiftdim(X, 2); 41 | X = reshape(X, [B, N]); 42 | case 4 43 | error('Error: Too many Dimensions'); 44 | end 45 | 46 | %%% CALCULATE MEAN AND SUBTRACT IT %%% 47 | [B,N] = size(X); 48 | Mu = mean(X, 2); 49 | BigMu = repmat(Mu, [1, N]); 50 | Xz = X-BigMu; 51 | 52 | %% 53 | %%% CALCULATE COVARIANCE MATRIX %%% 54 | C = (1/(N-1))*Xz*Xz'; 55 | %% 56 | %%% GET EIGENVALUES AND EIGENVECTORS OF COVARIANCE MATRIX %%% 57 | [U, Lambda] = eig(C); 58 | 59 | %%% REVERSE ORDER OF EIGENVALUES FROM INCREASING TO DECREASING %%% 60 | % PermMat = fliplr(eye(B)); 61 | % Lambda = PermMat*Lambda*PermMat; 62 | % U = PermMat*U'; 63 | Lambda = diag(Lambda); 64 | [Lambda,Index]= sort(Lambda,'descend'); % to sort eigenvalues in decresing order 65 | U= U(:,Index); 66 | U=U'; 67 | %%% STORE EIGENVALUES IN VECTOR INSTEAD OF DIAGONAL MATRIX %%% 68 | Lambda = diag(Lambda); 69 | 70 | %%% COMPUTE TRANSFORMATION AND REDUCE DIMENSIONALITY 71 | Y = U*Xz; 72 | Y = Y(1:NComps, :); 73 | 74 | %%% MAKE MATRIX SIZE CONSISTENT WITH MNFbyDG %%% 75 | Y = Y'; 76 | 77 | %%% THE END %%% 78 | end -------------------------------------------------------------------------------- /helpers/SimGraph_NearestNeighbors.m: -------------------------------------------------------------------------------- 1 | function W = SimGraph_NearestNeighbors(M, k, Type, sigma) 2 | % SIMGRAPH_NEARESTNEIGHBORS Returns kNN similarity graph 3 | % Returns adjacency matrix for an k-Nearest Neighbors 4 | % similarity graph 5 | % 6 | % 'M' - A d-by-n matrix containing n d-dimensional data points 7 | % 'k' - Number of neighbors 8 | % 'Type' - Type if kNN Graph 9 | % 1 - Normal 10 | % 2 - Mutual 11 | % 'sigma' - Parameter for Gaussian similarity function. Set 12 | % this to 0 for an unweighted graph. Default is 1. 13 | 14 | if nargin < 3 15 | ME = MException('InvalidCall:NotEnoughArguments', ... 16 | 'Function called with too few arguments'); 17 | throw(ME); 18 | end 19 | 20 | if ~any(Type == (1:2)) 21 | ME = MException('InvalidCall:UnknownType', ... 22 | 'Unknown similarity graph type'); 23 | throw(ME); 24 | end 25 | 26 | n = size(M, 2); 27 | 28 | % Preallocate memory 29 | indi = zeros(1, k * n); 30 | indj = zeros(1, k * n); 31 | inds = zeros(1, k * n); 32 | 33 | for ii = 1:n 34 | % Compute i-th column of distance matrix 35 | dist = distEuclidean(repmat(M(:, ii), 1, n), M); 36 | 37 | % Sort row by distance 38 | [s, O] = sort(dist, 'ascend'); 39 | 40 | % Save indices and value of the k 41 | indi(1, (ii-1)*k+1:ii*k) = ii; 42 | indj(1, (ii-1)*k+1:ii*k) = O(1:k); 43 | inds(1, (ii-1)*k+1:ii*k) = s(1:k); 44 | end 45 | 46 | % Create sparse matrix 47 | W = sparse(indi, indj, inds, n, n); 48 | 49 | clear indi indj inds dist s O; 50 | 51 | % Construct either normal or mutual graph 52 | if Type == 1 53 | % Normal 54 | W = max(W, W'); 55 | else 56 | % Mutual 57 | W = min(W, W'); 58 | end 59 | 60 | if nargin < 4 || isempty(sigma) 61 | sigma = 1; 62 | end 63 | 64 | % Unweighted graph 65 | if sigma == 0 66 | W = (W ~= 0); 67 | 68 | % Gaussian similarity function 69 | elseif isnumeric(sigma) 70 | W = spfun(@(W) (simGaussian(W, sigma)), W); 71 | 72 | else 73 | ME = MException('InvalidArgument:NotANumber', ... 74 | 'Parameter epsilon is not numeric'); 75 | throw(ME); 76 | end 77 | 78 | end -------------------------------------------------------------------------------- /helpers/SpectralClustering.m: -------------------------------------------------------------------------------- 1 | function [C, L, U] = SpectralClustering(W, k, Type) 2 | %SPECTRALCLUSTERING Executes spectral clustering algorithm 3 | % Executes the spectral clustering algorithm defined by 4 | % Type on the adjacency matrix W and returns the k cluster 5 | % indicator vectors as columns in C. 6 | % If L and U are also called, the (normalized) Laplacian and 7 | % eigenvectors will also be returned. 8 | % 9 | % 'W' - Adjacency matrix, needs to be square 10 | % 'k' - Number of clusters to look for 11 | % 'Type' - Defines the type of spectral clustering algorithm 12 | % that should be used. Choices are: 13 | % 1 - Unnormalized 14 | % 2 - Normalized according to Shi and Malik (2000) 15 | % 3 - Normalized according to Jordan and Weiss (2002) 16 | % 17 | % References: 18 | % - Ulrike von Luxburg, "A Tutorial on Spectral Clustering", 19 | % Statistics and Computing 17 (4), 2007 20 | 21 | % calculate degree matrix 22 | degs = sum(W, 2); 23 | D = sparse(1:size(W, 1), 1:size(W, 2), degs); 24 | 25 | % compute unnormalized Laplacian 26 | L = D - W; 27 | 28 | % compute normalized Laplacian if needed 29 | switch Type 30 | case 2 31 | % avoid dividing by zero 32 | degs(degs == 0) = eps; 33 | % calculate inverse of D 34 | D = spdiags(1./degs, 0, size(D, 1), size(D, 2)); 35 | 36 | % calculate normalized Laplacian 37 | L = D * L; 38 | case 3 39 | % avoid dividing by zero 40 | degs(degs == 0) = eps; 41 | % calculate D^(-1/2) 42 | D = spdiags(1./(degs.^0.5), 0, size(D, 1), size(D, 2)); 43 | 44 | % calculate normalized Laplacian 45 | L = D * L * D; 46 | end 47 | 48 | % compute the eigenvectors corresponding to the k smallest 49 | % eigenvalues 50 | diff = eps; 51 | [U, ~] = eigs(L, k, diff); 52 | 53 | % in case of the Jordan-Weiss algorithm, we need to normalize 54 | % the eigenvectors row-wise 55 | if Type == 3 56 | U = bsxfun(@rdivide, U, sqrt(sum(U.^2, 2))); 57 | end 58 | 59 | % now use the k-means algorithm to cluster U row-wise 60 | % C will be a n-by-1 matrix containing the cluster number for 61 | % each data point 62 | C = kmeans(U, k, 'start', 'cluster', ... 63 | 'EmptyAction', 'singleton'); 64 | 65 | % now convert C to a n-by-k matrix containing the k indicator 66 | % vectors as columns 67 | C = sparse(1:size(D, 1), C, 1); 68 | 69 | end -------------------------------------------------------------------------------- /helpers/convertClusterVector.m: -------------------------------------------------------------------------------- 1 | function indMatrix = convertClusterVector(M) 2 | % CONVERTCLUSTERVECTOR 3 | % Converts between row vector with cluster number and indicator vector 4 | % matrix 5 | 6 | if size(M, 2) > 1 7 | indMatrix = zeros(size(M, 1), 1); 8 | for ii = 1:size(M, 2) 9 | indMatrix(M(:, ii) == 1) = ii; 10 | end 11 | else 12 | indMatrix = sparse(1:size(M, 1), M, 1); 13 | end -------------------------------------------------------------------------------- /helpers/distEuclidean.m: -------------------------------------------------------------------------------- 1 | function [ dist ] = distEuclidean( M, N ) 2 | %DISTEUCLIDEAN Calculates Euclidean distances 3 | % distEuclidean calculates the Euclidean distances between n 4 | % d-dimensional points, where M and N are d-by-n matrices, and 5 | % returns a 1-by-n vector dist containing those distances. 6 | 7 | dist = sqrt(sum((M - N) .^ 2, 1)); 8 | 9 | end 10 | 11 | -------------------------------------------------------------------------------- /helpers/normalizeData.m: -------------------------------------------------------------------------------- 1 | function normalizedData = normalizeData(Data) 2 | % NORMALIZEDATA Normalized data matrix 3 | % normalizeData(Data) normalizes the d-by-n matrix Data, so that 4 | % the minimum value of each dimension and for all data points is 0 and 5 | % the maximum value respectively is 1. 6 | 7 | a = 0; 8 | b = 1; 9 | 10 | minData = min(Data, [], 2); 11 | maxData = max(Data, [], 2); 12 | 13 | r = (a-b) ./ (minData - maxData); 14 | s = a - r .* minData; 15 | 16 | normalizedData = repmat(r, 1, size(Data, 2)) .* Data + repmat(s, 1, size(Data, 2)); -------------------------------------------------------------------------------- /helpers/simGaussian.m: -------------------------------------------------------------------------------- 1 | function [ M ] = simGaussian( M, sigma ) 2 | %SIMGAUSSIAN Calculates Gaussian similarity on matrix 3 | % simGaussian(M, sigma) returns a matrix of the same size as 4 | % the distance matrix M, which contains similarity values 5 | % that are computed by using a Gaussian similarity function 6 | % with parameter sigma. 7 | 8 | M = exp(-M.^2 ./ (2*sigma^2)); 9 | 10 | end 11 | --------------------------------------------------------------------------------