Thresholded Subspace Clustering (TSC) Algorithm Demo on Hyperspectral Datasets

This Live Script lets you:

Dropdown to select desired dataset

% % Dataset Configuration
 
this_script_path = matlab.desktop.editor.getActiveFilename;
this_script_folder = fileparts(this_script_path);
proj_root = fileparts(this_script_folder);
addpath(fullfile(proj_root, "TSC_MATLAB"));
 
clear; clc;
 
DATASETS = struct( ...
'Pavia', struct( ...
'data_file', "Pavia.mat", ...
'gt_file', "Pavia_gt.mat", ...
'data_key', "pavia", ...
'gt_key', "pavia_gt"), ...
'PaviaUni', struct( ...
'data_file', "PaviaUni.mat", ...
'gt_file', "PaviaU_gt.mat", ...
'data_key', "paviaU", ...
'gt_key', "paviaU_gt"), ...
'Salinas', struct( ...
'data_file', "Salinas_corrected.mat", ...
'gt_file', "Salinas_gt.mat", ...
'data_key', "salinas_corrected", ...
'gt_key', "salinas_gt"), ...
'Indian_pines', struct( ...
'data_file', "Indian_pines.mat", ...
'gt_file', "Indian_pines_gt.mat", ...
'data_key', "indian_pines", ...
'gt_key', "indian_pines_gt") ...
);
 
 
ds_name = "Pavia";

Function to run TSC on remote sensing datasets

function run_tsc_hsi(ds_name, DATASETS)
cfg = DATASETS.(ds_name);
 
% Load Data and Ground Truth
 
data_struct = load(fullfile("MAT Files", cfg.data_file));
gt_struct = load(fullfile("GT Files", cfg.gt_file));
 
data_cube = data_struct.(cfg.data_key);
gt_data = gt_struct.(cfg.gt_key);
 
[H, W, B] = size(data_cube);
 
% Mask to remove the background pixels
 
mask_fg = gt_data ~= 0;
mask_vec = mask_fg(:);
 
% Determine K from unique non-zero labels
 
gt_labels = unique(gt_data);
gt_labels(gt_labels == 0) = [];
K = numel(gt_labels);
 
% Reshape the data cube to a matrix (D x N)
% D = Bands; N=pixels
X_full = reshape(data_cube, [], B);
X_full = X_full.';
X = X_full(:, mask_vec);
 
% Run TSC on the filtered out pixels
[~, ~, ~, c, K_used] = tsc(X, K, 'Verbose', true, 'MaxNZ', 50);
% Map cluster labels back to image grid (H x W)
c_image_vec = zeros(H*W, 1);
c_image_vec(mask_vec) = c; % fill only foreground pixels
c_image = reshape(c_image_vec, H, W);
gt_image = gt_data;
 
% Visualize clustering result
figure('Color', 'w', 'Position', [100 100 900 800]);
t = tiledlayout(2,2, ...
'TileSpacing','compact', ...
'Padding','compact');
% -------------------------
% Shared colormap
% -------------------------
colors = lines(K);
cmap = [0 0 0; colors];
colormap(cmap);
% -------------------------
% LEFT: Ground Truth
% -------------------------
ax1 = nexttile(1);
imagesc(gt_data);
axis image off;
title('Ground Truth', 'FontWeight','bold');
clim([-0.5 K+0.5]);
% -------------------------
% RIGHT: Clustering
% -------------------------
ax2 = nexttile(2);
imagesc(c_image);
axis image off;
title(sprintf('TSC Clustering (%s, K = %d)', ds_name, K_used), 'FontWeight','bold');
clim([-0.5 K+0.5]);
% -----------
% Colorbars
% -----------
cb1 = colorbar(ax1, 'southoutside');
cb1.Ticks = 0:K;
cb2 = colorbar(ax2, 'southoutside');
cb2.Ticks = 0:K;
end

Run TSC button

run_tsc_hsi(ds_name, DATASETS);
Running TSC with K=9, max_nz=50, chunk_size=1024, n_init=100, max_iter=100 Building chunked affinity matrix | N=148152, q=50, chunk_size=1024, n_chunks=145 Processed chunk 1 / 145 (columns 1:1024) Processed chunk 2 / 145 (columns 1025:2048) Processed chunk 3 / 145 (columns 2049:3072) Processed chunk 4 / 145 (columns 3073:4096) Processed chunk 5 / 145 (columns 4097:5120) Processed chunk 6 / 145 (columns 5121:6144) Processed chunk 7 / 145 (columns 6145:7168) Processed chunk 8 / 145 (columns 7169:8192) Processed chunk 9 / 145 (columns 8193:9216) Processed chunk 10 / 145 (columns 9217:10240) Processed chunk 11 / 145 (columns 10241:11264) Processed chunk 12 / 145 (columns 11265:12288) Processed chunk 13 / 145 (columns 12289:13312) Processed chunk 14 / 145 (columns 13313:14336) Processed chunk 15 / 145 (columns 14337:15360) Processed chunk 16 / 145 (columns 15361:16384) Processed chunk 17 / 145 (columns 16385:17408) Processed chunk 18 / 145 (columns 17409:18432) Processed chunk 19 / 145 (columns 18433:19456) Processed chunk 20 / 145 (columns 19457:20480) Processed chunk 21 / 145 (columns 20481:21504) Processed chunk 22 / 145 (columns 21505:22528) Processed chunk 23 / 145 (columns 22529:23552) Processed chunk 24 / 145 (columns 23553:24576) Processed chunk 25 / 145 (columns 24577:25600) Processed chunk 26 / 145 (columns 25601:26624) Processed chunk 27 / 145 (columns 26625:27648) Processed chunk 28 / 145 (columns 27649:28672) Processed chunk 29 / 145 (columns 28673:29696) Processed chunk 30 / 145 (columns 29697:30720) Processed chunk 31 / 145 (columns 30721:31744) Processed chunk 32 / 145 (columns 31745:32768) Processed chunk 33 / 145 (columns 32769:33792) Processed chunk 34 / 145 (columns 33793:34816) Processed chunk 35 / 145 (columns 34817:35840) Processed chunk 36 / 145 (columns 35841:36864) Processed chunk 37 / 145 (columns 36865:37888) Processed chunk 38 / 145 (columns 37889:38912) Processed chunk 39 / 145 (columns 38913:39936) Processed chunk 40 / 145 (columns 39937:40960) Processed chunk 41 / 145 (columns 40961:41984) Processed chunk 42 / 145 (columns 41985:43008) Processed chunk 43 / 145 (columns 43009:44032) Processed chunk 44 / 145 (columns 44033:45056) Processed chunk 45 / 145 (columns 45057:46080) Processed chunk 46 / 145 (columns 46081:47104) Processed chunk 47 / 145 (columns 47105:48128) Processed chunk 48 / 145 (columns 48129:49152) Processed chunk 49 / 145 (columns 49153:50176) Processed chunk 50 / 145 (columns 50177:51200) Processed chunk 51 / 145 (columns 51201:52224) Processed chunk 52 / 145 (columns 52225:53248) Processed chunk 53 / 145 (columns 53249:54272) Processed chunk 54 / 145 (columns 54273:55296) Processed chunk 55 / 145 (columns 55297:56320) Processed chunk 56 / 145 (columns 56321:57344) Processed chunk 57 / 145 (columns 57345:58368) Processed chunk 58 / 145 (columns 58369:59392) Processed chunk 59 / 145 (columns 59393:60416) Processed chunk 60 / 145 (columns 60417:61440) Processed chunk 61 / 145 (columns 61441:62464) Processed chunk 62 / 145 (columns 62465:63488) Processed chunk 63 / 145 (columns 63489:64512) Processed chunk 64 / 145 (columns 64513:65536) Processed chunk 65 / 145 (columns 65537:66560) Processed chunk 66 / 145 (columns 66561:67584) Processed chunk 67 / 145 (columns 67585:68608) Processed chunk 68 / 145 (columns 68609:69632) Processed chunk 69 / 145 (columns 69633:70656) Processed chunk 70 / 145 (columns 70657:71680) Processed chunk 71 / 145 (columns 71681:72704) Processed chunk 72 / 145 (columns 72705:73728) Processed chunk 73 / 145 (columns 73729:74752) Processed chunk 74 / 145 (columns 74753:75776) Processed chunk 75 / 145 (columns 75777:76800) Processed chunk 76 / 145 (columns 76801:77824) Processed chunk 77 / 145 (columns 77825:78848) Processed chunk 78 / 145 (columns 78849:79872) Processed chunk 79 / 145 (columns 79873:80896) Processed chunk 80 / 145 (columns 80897:81920) Processed chunk 81 / 145 (columns 81921:82944) Processed chunk 82 / 145 (columns 82945:83968) Processed chunk 83 / 145 (columns 83969:84992) Processed chunk 84 / 145 (columns 84993:86016) Processed chunk 85 / 145 (columns 86017:87040) Processed chunk 86 / 145 (columns 87041:88064) Processed chunk 87 / 145 (columns 88065:89088) Processed chunk 88 / 145 (columns 89089:90112) Processed chunk 89 / 145 (columns 90113:91136) Processed chunk 90 / 145 (columns 91137:92160) Processed chunk 91 / 145 (columns 92161:93184) Processed chunk 92 / 145 (columns 93185:94208) Processed chunk 93 / 145 (columns 94209:95232) Processed chunk 94 / 145 (columns 95233:96256) Processed chunk 95 / 145 (columns 96257:97280) Processed chunk 96 / 145 (columns 97281:98304) Processed chunk 97 / 145 (columns 98305:99328) Processed chunk 98 / 145 (columns 99329:100352) Processed chunk 99 / 145 (columns 100353:101376) Processed chunk 100 / 145 (columns 101377:102400) Processed chunk 101 / 145 (columns 102401:103424) Processed chunk 102 / 145 (columns 103425:104448) Processed chunk 103 / 145 (columns 104449:105472) Processed chunk 104 / 145 (columns 105473:106496) Processed chunk 105 / 145 (columns 106497:107520) Processed chunk 106 / 145 (columns 107521:108544) Processed chunk 107 / 145 (columns 108545:109568) Processed chunk 108 / 145 (columns 109569:110592) Processed chunk 109 / 145 (columns 110593:111616) Processed chunk 110 / 145 (columns 111617:112640) Processed chunk 111 / 145 (columns 112641:113664) Processed chunk 112 / 145 (columns 113665:114688) Processed chunk 113 / 145 (columns 114689:115712) Processed chunk 114 / 145 (columns 115713:116736) Processed chunk 115 / 145 (columns 116737:117760) Processed chunk 116 / 145 (columns 117761:118784) Processed chunk 117 / 145 (columns 118785:119808) Processed chunk 118 / 145 (columns 119809:120832) Processed chunk 119 / 145 (columns 120833:121856) Processed chunk 120 / 145 (columns 121857:122880) Processed chunk 121 / 145 (columns 122881:123904) Processed chunk 122 / 145 (columns 123905:124928) Processed chunk 123 / 145 (columns 124929:125952) Processed chunk 124 / 145 (columns 125953:126976) Processed chunk 125 / 145 (columns 126977:128000) Processed chunk 126 / 145 (columns 128001:129024) Processed chunk 127 / 145 (columns 129025:130048) Processed chunk 128 / 145 (columns 130049:131072) Processed chunk 129 / 145 (columns 131073:132096) Processed chunk 130 / 145 (columns 132097:133120) Processed chunk 131 / 145 (columns 133121:134144) Processed chunk 132 / 145 (columns 134145:135168) Processed chunk 133 / 145 (columns 135169:136192) Processed chunk 134 / 145 (columns 136193:137216) Processed chunk 135 / 145 (columns 137217:138240) Processed chunk 136 / 145 (columns 138241:139264) Processed chunk 137 / 145 (columns 139265:140288) Processed chunk 138 / 145 (columns 140289:141312) Processed chunk 139 / 145 (columns 141313:142336) Processed chunk 140 / 145 (columns 142337:143360) Processed chunk 141 / 145 (columns 143361:144384) Processed chunk 142 / 145 (columns 144385:145408) Processed chunk 143 / 145 (columns 145409:146432) Processed chunk 144 / 145 (columns 146433:147456) Processed chunk 145 / 145 (columns 147457:148152) Affinity construction finished | nnz(A)=11264260 Computing spectral embedding | nev=9, mode=fixed K=9
Warning: Ignoring issym field in the options structure since the first input is not a function handle.
Running k-means on embedding of size 148152 x 9 with K=9
Warning: Failed to converge in 100 iterations during replicate 97.
Finished TSC with K_used=9