% function par = imncut_sp; or
% [Sp,Seg,V,S,W] = imncut_sp(I,par)
%
% Compute "superpixels."
% An intial segmentation into K1=par.nv segments is performed using cncut.
% These initial segments are then subdivided into K2=par.sp "superpixels"
% by running kmeans on the cncut eigenvector coordinates, followed by cleanup.
%
% Input:
% I = image
% par = parameters
% par.nb_r = neighbour hood radius
% par.sample_rate = sampling rate
% par.mask = mask for bias, label matrix of image size
% par.sig_ic = sigma for computing affinity from intervening contour
% par.rep = offset for repulsion
% par.reg = offset for regularization
% par.nv = number of eigenvectors
% Output:
% Sp = K2-way partition matrix, same size as I, after forcing K2=par.sp segments
% Seg = initial K1-way partition matrix, same size as I
% [V,S] = eigenvector and eigenvalues from constrained ncuts
% W = affinity matrix
% Reference:
% www.cs.berkeley.edu/~stellayu/thesis.html
% Examples:
% par = imncut_sp; % return the default parameters
% imncut_sp(I); % ncuts using the default parameters
% Stella X. Yu, July 13 2003.
% Modified by Greg Mori, April 2005.
function [Sp,Seg,V,S,W] = imncut_sp(I,par,varargin)
if nargin==0,
par.nb_r = 8;
par.nb_r = 24;
par.sample_rate = 0.2;
% par.nb_r = 30;
% par.sample_rate = 0.2;
par.mask = [];
par.sig_ic = 0.4;
par.sig_pb_ic = 0.2;
par.sig_int = 0.15;
par.sig_p = 10;
par.rep = 0;
par.reg = 0;
par.nv = 3;
par.hwx = 1;
par.hwy = 1;
par.pb_ic = 1;
par.ic = 0;
par.int = 0;
par.prox = 0;
par.count = 0;
par.verbose = 0;
par.visualize = 0;
par.pb_timing = 1;
par.sp = 3;
Sp = par;
return;
end
if nargin<2,
par = ncutim;
end
if nargin<3
visualize=1;
end
mask = par.mask;
nv = par.nv;
VERBOSE = par.verbose;
visualize = par.visualize;
sz = size(I); sz=sz(1:2);
np = prod(sz);
[W,samp] = computeW(I,par);
% constraints
p = find(samp);
if isempty(mask),
U = [];
else
U = pargrp(double(mask & samp));
U = U(p,:);
end
% cuts on samples; and then interpolate to the rest pixels
if VERBOSE
fprintf('cncutting... ');
end
[Vp,S] = cncut(W(p,p),U,nv);
if VERBOSE
fprintf('done\n');
end
if VERBOSE
fprintf('interpolating... ');
end
q = find(not(samp));
if isempty(q),
Vq = [];
else
C = W(q,p);
C = spmd(C,1./double(sum(C,2)+eps),[]);
Vq = C * Vp;
end
V = zeros(np,nv);
V([p;q],:) = [Vp; Vq];
for j=1:nv,
z = reshape(V(:,j),sz);
z = medfilt2(z,[7,7],'symmetric');
V(:,j) = z(:);
end
if VERBOSE
fprintf('done\n');
end
% discretization
if VERBOSE
fprintf('discretizing... ');
end
X = getbinsol(V);
if VERBOSE
fprintf('done\n');
end
% visualization
if visualize
figure;
range = [min(V(:)),max(V(:))];
for j=1:nv,
z = reshape(V(:,j),sz);
subplot(nv,2,j+j-1); imagesc(z,range); axis image; axis off;
colormap(gray);
title(sprintf('%5.4f',S(j)));
z = reshape(X(:,j),sz);
subplot(nv,2,j+j); imagesc(im2double(rgb2gray(I)).*z+not(z),[0,1]); axis image; axis off;
colormap(gray);
end
end
[mv,C] = max(X,[],2);
% TO DO:: Possibly need to do connected components cleanup on Seg as well.
Seg = reshape(C,[size(I,1) size(I,2)]);
% Force par.sp clusters by running kmeans on clusters from C
Sp = zeros(size(C));
N_clusters = par.sp;
cc = unique(C)';
c_off=0;
for c_i=cc
inds_use = find(C==c_i);
V_use = V(inds_use,:);
% This segment should contribute its fair share, at least 1 though.
N_this = max(1,round(N_clusters * length(inds_use)/np));
if N_this>1
Sp_this = kmeans(V_use,N_this,'Start','sample','Replicates',5,'EmptyAction','singleton');
else
Sp_this = ones(size(V_use,1),1);
end
Sp(inds_use) = Sp_this + c_off;
c_off = c_off + max(Sp_this);
end
Sp = reshape(Sp,[size(I,1) size(I,2)]);
% Connected components analysis, cut apart disconnected clusters
% Clean up Sp. Merge small segments, break disconnected clusters.
MIN_SIZE = 30;
min_c = min(Sp(:)); max_c = max(Sp(:));
new_num = max_c+1;
for c_i=min_c:max_c
[L,num] = bwlabel(Sp==c_i,4);
if num > 1 | sum(L(:)) < MIN_SIZE
for n_i=1:num
the_inds = find(L==n_i);
if length(the_inds) < MIN_SIZE
% Merge each small segment with a nearby one.
the_perim = bwperim(imdilate(L==n_i,strel('diamond',1)));
the_perim(the_inds)=0; % bwperim has errors on boundary.
nhbs = find(the_perim);
the_dists = dist2(V(the_inds,:),V(nhbs,:));
the_dists = min(the_dists,[],1);
[mind,mind] = min(the_dists);
Sp(the_inds) = Sp(nhbs(mind));
else
% Renumber large segments.
Sp(the_inds) = new_num;
new_num = new_num+1;
end
end
end
end
% Renumber segments.
Spv = Sp';
Spv = Spv(:);
uu = unique(Spv);
N_seg = length(uu);
the_map(uu) = 1:N_seg;
Spv = the_map(Spv);
Sp = reshape(Spv,[size(I,2) size(I,1)])';