├── Ncuts.m └── README.md /Ncuts.m: -------------------------------------------------------------------------------- 1 | % Normalized Cuts and Image Segmentation 2 | % Author : Satyabrat Srikumar 3 | % IIIT Bangalore 4 | % ------------------------------------------------------------------------% 5 | 6 | function Ncuts 7 | I = imread('test.jpg'); 8 | [no_rows, no_cols, c] = size(I); 9 | N = no_rows * no_cols; 10 | 11 | 12 | %-----------------------Parameter speicifications ------------------------% 13 | r = 2; 14 | sigma_I =4; 15 | sigma_X =6; 16 | threshold_Ncut = 0.16; 17 | threshold_Area = 100; 18 | 19 | %-------------------------------------------------------------------------% 20 | %V_node - denotes all pixels as nodes of a graph 21 | 22 | V_node = zeros(N,c); 23 | for k = 1:c 24 | temp = 1; 25 | for i = 1:no_cols 26 | for j = 1:no_rows 27 | V_node(temp,k) = I(j,i,k); 28 | temp = temp + 1; 29 | end 30 | end 31 | end 32 | 33 | %---------------------------SIMILARITY MATRIX CREATION-----------------------------% 34 | %W - similarity matrix 35 | W = sparse(N,N); 36 | 37 | 38 | % X - Spatial location matrix 39 | X_temp = zeros(no_rows, no_cols, 2); 40 | for i = 1:no_rows 41 | for j = 1:no_cols 42 | X_temp(i,j,1) = i; 43 | X_temp(i,j,2) = j; 44 | end 45 | end 46 | 47 | X = zeros(N,1,2); 48 | for k = 1:2 49 | temp = 1; 50 | for i = 1:no_cols 51 | for j = 1:no_rows 52 | X(temp,1,k) = X_temp(j,i,k); 53 | temp = temp + 1; 54 | end 55 | end 56 | end 57 | 58 | %F - Intensity Feature vectors 59 | F = zeros(N,1,c); 60 | for k = 1:c 61 | temp = 1; 62 | for i = 1:no_cols 63 | for j = 1:no_rows 64 | F(temp,1,k) = I(j,i,k); 65 | temp = temp + 1; 66 | end 67 | end 68 | end 69 | F = uint8(F); %uint class required for addition compatibility with spatial 70 | %location matrix. 71 | 72 | % main loop 73 | r1 = floor(r); 74 | for m =1:no_cols 75 | for n =1:no_rows 76 | 77 | %satisfies X(j)-r < X(i) < X(j)+r 78 | range_cols = (m - r1) : (m + r1); 79 | range_rows = ((n - r1) :(n + r1))'; 80 | v_col_index = range_cols >= 1 & range_cols <= no_cols; %valid col. index 81 | v_row_index = range_rows >= 1 & range_rows <= no_rows; %valid row index 82 | 83 | range_cols = range_cols(v_col_index); %range of cols. and rows satisfying euclidean distance metric 84 | range_rows = range_rows(v_row_index); 85 | 86 | %current_vertex index 87 | p_vertex = n + (m - 1) * no_rows; 88 | %-----------------------------------------------------------------------------------------% 89 | 90 | l1 = length(range_rows); 91 | l2 = length(range_cols); 92 | m1 = zeros(l1,l2); 93 | m2 = zeros(l1,l2); 94 | for i = 1:length(range_rows) 95 | for j = 1:length(range_cols) 96 | m1(i,j) = range_rows(i,1); 97 | end 98 | end 99 | 100 | for i = 1:length(range_rows) 101 | for j = 1:length(range_cols) 102 | m2(i,j) = ((range_cols(1,j) -1) .*no_rows); 103 | end 104 | end 105 | n_vertex_temp = m1 + m2; %dimensions l1 * l2 106 | n_vertex = zeros(l1*l2,1); 107 | temp = 1; 108 | for i = 1:l2 109 | for j = 1:l1 110 | n_vertex(temp,1) = n_vertex_temp(j,i); 111 | temp = temp + 1; 112 | end 113 | end 114 | 115 | %spatial location similarity 116 | X_J = zeros(length(n_vertex),1,2); 117 | for k = 1:2 118 | for i = 1:length(n_vertex) 119 | X_J(i,1,k) = X(n_vertex(i,1),1, k); 120 | end 121 | end 122 | 123 | 124 | X_I_temp = X(p_vertex, 1, :); 125 | X_I = zeros(length(n_vertex),1,2); 126 | 127 | for i = 1:length(n_vertex) 128 | for k = 1:2 129 | X_I(i,1,k) = X_I_temp(1,1,k); 130 | end 131 | end 132 | diff_X = X_I - X_J; 133 | diff_X = sum(diff_X .* diff_X, 3); % squared euclid distance 134 | 135 | % |X(i) - X(j)| <= r 136 | valid_index = (sqrt(diff_X) <= r); 137 | n_vertex = n_vertex(valid_index); 138 | diff_X = diff_X(valid_index); 139 | 140 | % feature vector disimilarity 141 | F_J = zeros(length(n_vertex),1,c); 142 | for i = 1:length(n_vertex) 143 | for k = 1:c 144 | a = n_vertex(i,1); 145 | F_J(i,1,k) = F(a,1,k); 146 | end 147 | end 148 | F_J = uint8(F_J); 149 | 150 | FI_temp = F(p_vertex, 1, :); 151 | F_I = zeros(length(n_vertex),1,c); 152 | for i = 1:length(n_vertex) 153 | for k = 1:c 154 | F_I(i,1,k) = FI_temp(1,1,k); 155 | end 156 | end 157 | F_I = uint8(F_I); 158 | 159 | diff_F = F_I - F_J; 160 | diff_F = sum(diff_F .* diff_F, 3); 161 | W(p_vertex, n_vertex) = exp(-diff_F / (sigma_I*sigma_I)) .* exp(-diff_X / (sigma_X*sigma_X)); % for squared distance 162 | 163 | end 164 | end 165 | 166 | % call to partition routine 167 | node_index = (1:N)'; 168 | [node_index Ncut] = NcutPartition(node_index, W, threshold_Ncut, threshold_Area); 169 | 170 | 171 | % node_indexes to images 172 | 173 | for i=1:length(node_index) 174 | Segment_I_temp = zeros(N, c); 175 | Segment_I_temp(node_index{i}, :) = V_node(node_index{i}, :); 176 | %Segment_I_temp1 = zeros(no_rows, no_cols, c); 177 | %size(Segment_I_temp) 178 | Segment_I_temp1{i} = (reshape(Segment_I_temp, no_rows, no_cols, c)); 179 | Segment_I{i} = uint8(Segment_I_temp1{i}); 180 | 181 | end 182 | 183 | 184 | for i=1:length(Segment_I) 185 | figure; 186 | imshow(Segment_I{i}); 187 | imwrite(Segment_I{i}, sprintf('test%d.jpg', i)); 188 | fprintf('Ncut(%d) = %f\n', i, Ncut{i}); 189 | end 190 | end 191 | 192 | function [node_index Ncut] = NcutPartition(I, W, threshold_Ncut, threshold_Area) 193 | N = length(W); 194 | d = sum(W, 2); 195 | D = sparse(N,N); 196 | for i = 1:N 197 | D(i,i) = d(i); 198 | end 199 | 200 | [Y,lambda] = eigs(D-W, D, 2, 'sm'); % (D - W)Y = lambda * D * Y 201 | eig_vector_2 = Y(:, 2); 202 | 203 | split_point = median(eig_vector_2); % starting point for fminsearch 204 | split_point = fminsearch('NcutValue', split_point, split_point, eig_vector_2, W, D); 205 | 206 | Partition_1 = find(eig_vector_2 > split_point); 207 | Partition_2 = find(eig_vector_2 <= split_point); 208 | 209 | Ncut_value = NcutValue(split_point, eig_vector_2, W, D); 210 | if (length(Partition_1) < threshold_Area || length(Partition_2) < threshold_Area || Ncut_value > threshold_Ncut) 211 | node_index{1} = I; 212 | Ncut{1} = Ncut_value; 213 | return; 214 | end 215 | 216 | %recursive partition 217 | [node_index_1 Ncut_1] = NcutPartition(I(Partition_1), W(Partition_1, Partition_1), threshold_Ncut, threshold_Area); 218 | [node_index_2 Ncut_2] = NcutPartition(I(Partition_2), W(Partition_2, Partition_2), threshold_Ncut, threshold_Area); 219 | 220 | node_index = cat(2, node_index_1, node_index_2); 221 | Ncut = cat(2, Ncut_1, Ncut_2); 222 | end 223 | 224 | function value = NcutValue(split_point, eig_vector_2, W, D) 225 | 226 | x = (eig_vector_2 > split_point); 227 | x = (2 * x) - 1; %indicator rv's for Partitions 1 & 2 228 | d = sum(W,2); 229 | k = sum(d(x>0))/sum(d); 230 | b = k/(1 - k); 231 | y = (1 + x) - b*(1 - x); 232 | 233 | value = (y'*(D - W)*y)/(y'*D*y); 234 | 235 | end 236 | 237 | 238 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Normalized-Cuts-and-Image-Segmentation 2 | Jitendra Malik, Jianbo Shi 3 | UC Berkeley 4 | 5 | Normalized cuts is an image segmentation algorithm which uses a graph theoretic framework to solve the problem of perceptual grouping. The algorithm was developed by Jianbo Shi and Jitendra Malik back in 1997, and is one of those rare algorithms that has repeatedly stood the test of time. 6 | 7 | The code written here is a Matlab implementation of the algorithm, written as a partial fulfillment of the Digital Image Processing course at International Institiute of Information Technology, Bangalore. 8 | 9 | --------------------------------------------------------------------------------