spm_vb_graphcut.m 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. function labels = spm_vb_graphcut(labels,index,I,W,depth,grnd_type,CUTOFF,DIM)
  2. % Recursive bi-partition of a graph using the isoperimetric algorithm
  3. %
  4. % FORMAT labels = spm_vb_graphcut(labels,index,I,W,depth,grnd_type,CUTOFF,DIM)
  5. %
  6. % labels each voxel is lableled depending on whihc segment is belongs
  7. % index index of current node set in labels vector
  8. % I InMask XYZ voxel (node set) indices
  9. % W weight matrix i.e. adjacency matrix containing edge weights
  10. % of graph
  11. % depth depth of recursion
  12. % grnd_type 'random' or 'max' - ground node selected at random or the
  13. % node with maximal degree
  14. % CUTOFF minimal number of voxels in a segment of the partition
  15. % DIM dimensions of data
  16. %__________________________________________________________________________
  17. %
  18. % Recursive bi-partition of a graph using the isoperimetric algorithm by
  19. % Grady et al. This routine is adapted from "The Graph Analysis Toolbox:
  20. % Image Processing on Arbitrary Graphs", available through Matlab Central
  21. % File Exchange. See also Grady, L. Schwartz, E. L. (2006) "Isoperimetric
  22. % graph partitioning for image segmentation",
  23. % IEEE Trans Pattern Anal Mach Intell, 28(3),pp469-75
  24. %__________________________________________________________________________
  25. % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
  26. % Lee Harrison
  27. % $Id: spm_vb_graphcut.m 2923 2009-03-23 18:34:51Z guillaume $
  28. try, grnd_type; catch, grnd_type = 'random'; end
  29. %-Initialize
  30. s = rand('twister'); rand('seed',0);
  31. N = length(index);
  32. terminate = 0;
  33. %-Partition current graph
  34. if N > CUTOFF
  35. reject = 1;
  36. d = sum(W,2); % "degree" of each node
  37. switch grnd_type
  38. case 'max'
  39. id = find(d==max(d));
  40. ground = id(ceil(rand(1)*length(id)));
  41. case 'random'
  42. ground = ceil(rand(1)*N);
  43. end
  44. while reject == 1,
  45. if N < 1e5, method = 'direct'; else, method = 'cg'; end
  46. parts = bipartition(W,CUTOFF,ground,method);
  47. nparts = [length(parts{1}),length(parts{2})];
  48. if min(nparts) < CUTOFF, terminate = 1; break, end
  49. for k = 1:2, % check if partitions are contiguous
  50. bw = zeros(DIM(1),DIM(2),DIM(3));
  51. bw(I(parts{k})) = 1;
  52. [tmp,NUM] = spm_bwlabel(bw,6);
  53. if NUM > 1
  54. reject = 1;
  55. ground = ceil(rand(1)*N); % re-select ground node
  56. fprintf('depth %1.0f, partition %1.0f of 2, reject ',depth,k); fprintf('\n')
  57. break
  58. else
  59. reject = 0;
  60. fprintf('depth %1.0f, partition %1.0f of 2, accept ',depth,k);
  61. fprintf('\n')
  62. end
  63. end
  64. end
  65. else
  66. terminate = 1;
  67. end
  68. if terminate
  69. labels = labels;
  70. fprintf('depth %1.0f, end of branch ',depth);
  71. fprintf('\n')
  72. rand('twister',s);
  73. else
  74. %Accept partition and update labels
  75. tmpInd = find(labels>labels(index(1)));
  76. labels(tmpInd) = labels(tmpInd) + 1; %Make room for new class
  77. labels(index(parts{2})) = labels(index(parts{2})) + 1; %Mark new class
  78. %Continue recursion on each partition
  79. if nparts(1) > CUTOFF
  80. labels = spm_vb_graphcut(labels,index(parts{1}),I(parts{1}),...
  81. W(parts{1},parts{1}),depth + 1,grnd_type,CUTOFF,DIM);
  82. end
  83. if nparts(2) > CUTOFF
  84. labels = spm_vb_graphcut(labels,index(parts{2}),I(parts{2}),...
  85. W(parts{2},parts{2}),depth + 1,grnd_type,CUTOFF,DIM);
  86. end
  87. end
  88. %==========================================================================
  89. % function parts = bipartition(W,CUTOFF,ground,method)
  90. %==========================================================================
  91. function parts = bipartition(W,CUTOFF,ground,method)
  92. % Computes bi-partition of a graph using isoperimetric algorithm.
  93. % FORMAT parts = bipartition(W,CUTOFF,ground,method)
  94. % parts 1x2 cell containing indices of each partition
  95. % W weight matrix
  96. % CUTOFF minimal number of voxels in a segment of the partition
  97. % ground ground node index
  98. % method used to solve L0*x0=d0. Options are 'direct' or 'cg', which
  99. % x0 = L0\d0 or preconditioned conjugate gradients (see Matlab
  100. % rountine pcg.m)
  101. try, method; catch, method = 'direct'; end
  102. %-Laplacian matrix
  103. d = sum(W,2);
  104. L = diag(d) - W;
  105. N = length(d);
  106. %-Compute reduced Laplacian matrix, i.e. remove ground node
  107. index = [1:(ground-1),(ground+1):N];
  108. d0 = d(index);
  109. L0 = L(index,index);
  110. %-Solve system of equations L0*x0=d0
  111. switch method
  112. case 'direct'
  113. x0 = L0\d0;
  114. case 'cg'
  115. x0 = pcg(L0,d0,[],N,diag(d0));
  116. end
  117. %-Error catch if numerical instability occurs (due to ill-conditioned or
  118. %singular matrix)
  119. minVal = min(min(x0));
  120. if minVal < 0
  121. x0(find(x0 < 0)) = max(max(x0)) + 1;
  122. end
  123. %-Re-insert ground point
  124. x0 = [x0(1:(ground-1));0;x0((ground):(N-1))];
  125. %-Remove sparseness of output
  126. x0 = full(x0);
  127. %-Determine cut point (ratio cut method)
  128. indicator = sparse(N,1);
  129. %-Sort values
  130. sortX = sortrows([x0,[1:N]'],1)';
  131. %-Find total volume
  132. totalVolume = sum(d);
  133. halfTotalVolume = totalVolume/2;
  134. %-Calculate denominators
  135. sortedDegree = d(sortX(2,:))';
  136. denominators = cumsum(sortedDegree);
  137. tmpIndex = find(denominators > halfTotalVolume);
  138. denominators(tmpIndex) = totalVolume - denominators(tmpIndex);
  139. %-Calculate numerators
  140. L = L(sortX(2,:),sortX(2,:)) - diag(sortedDegree);
  141. numerators = cumsum(sum((L - 2*triu(L)),2))';
  142. if min(numerators) < 0
  143. %Line used to avoid negative values due to precision issues
  144. numerators = numerators - min(numerators) + eps;
  145. end
  146. %-Calculate ratios for Isoperimetric criteria
  147. sw = warning('off','MATLAB:divideByZero');
  148. [constant,minCut] = min(numerators(CUTOFF:(N-CUTOFF))./ ...
  149. denominators(CUTOFF:(N-CUTOFF)));
  150. minCut = minCut + CUTOFF - 1;
  151. warning(sw);
  152. %-Output partitions
  153. parts{1} = sortX(2,1:(minCut))';
  154. parts{2} = sortX(2,(minCut+1):N);