AMOEBASUPERPIX_BASE - Base function for AMOEBASUPERPIX.
Contents
Syntax
[Q, Ck, ColCk] = AMOEBASUPERPIX_BASE(I, K, isLab, alpha, T, n, k, maxiter);
See also
Ressembles: AMOEBASUPERPIX, SLICSUPERPIX_BASE, GEOSUPERPIX_BASE. Requires: RGB2LAB, DIJKADVANCED, DIJKSTRAPROPAGATION_MEX, IM2POTENTIAL, POTENTIAL2FRONT, GSTDECOMP, GRDMASK_BASE, GSTFEATURE_BASE, NEIPOSKERNEL.
Function implementation
function [Q, Ck, ColCk, D] = amoebasuperpix_base(I, K, isLab, alpha, T, n, k, maxiter)
checking/setting parameters
if nargin<8, maxiter = Inf; if nargin<7, k = 3; if nargin<6, n = 2; if nargin<5, T = eps; if nargin<4, alpha = 1; end end end end end if ~exist('dijkstrapropagation_mex','file') warning('amoebasuperpix_base:methodwarning', ... ['!!!very slow matlab implementation of Disjkstra-like algorithm - use ' ... 'C implemented version instead (see function dijkstrapropagation_mex)!!!']) handle_dijkstra = @(G,start) dijkadvanced(G>0, G, start);; %#ok % transform the input weight matrix and create an appropriate adjacency % matrix for DIJKADVANCED_BASE else handle_dijkstra = @(G,start) ... dijkstrapropagation_mex(G, start-1, -1, 1.2*numel(G)); %#ok % use C-implemented priority queues end % note: using a function handle in a loop will slower the program anyway [X,Y,C] = size(I); if isLab if C~=3 warning('amoebasuperpix_base:inputwarning','RGB image required in input'); if C==1, I = repmat(I, [1 1 3]); else I = I(:,:,1:3); end C = 3; end I = RGB2Lab(I(:,:,1), I(:,:,2), I(:,:,3)); end
for an image with N=X*Y pixels, the approximate size of each superpixel is N/K pixels; therefore, for roughly equally sized superpixels there would be a superpixel center at every grid interval S
S = floor(sqrt(X*Y/K)); if mod(n,2)~=0, n = n+1; end; win = S * n; pad = win / 2; win = win + 1; % L1 and L2 distance functions % L1 distance distL1 = @(v0, v1) sum(abs(v1-v0), 2); %#ok distL2sqr = @(v0, v1) sum((v1-v0).^2, 2); distL2 = @(v0, v1) sqrt(distL2sqr(v0,v1));
main calculation
we begin by sampling K regularly spaced cluster centers
[Ck, ColCk] = initcenters(I, S);
since the spatial extent of any superpixel is approximately S^2 (the area of a superpixel), we can safely assume that pixels that are associated with this cluster center lie within a (nS,nS) window around the superpixel center on the X-Y plane
nk = size(Ck,1); % %---------------------------------------------------------------------- function [Ck, ColCk] = initcenters(I, S) % [X,Y] = size(Lab(:,:,1)); xk = round(X / S); if xk==0, xk = floor(X/2); else xk = floor(S * (0:xk-1) + S/2); end yk = round(Y / S); if yk==0, yk = floor(X/2); else yk = floor(S * (0:yk-1) + S/2); end ColCk = reshape(I(xk,yk,:), [length(xk)*length(yk) C]); [xk yk] = meshgrid(xk, yk); Ck = [xk(:), yk(:)]; % Ck = sub2ind([X,Y], xk(:), yk(:)); end
and we move the centers to seed locations corresponding to the lowest gradient position in a (k,k) neighborhood.
if k>0 [Ck, ColCk] = movecenters(I, Ck, k); end % %---------------------------------------------------------------------- function [Ck, ColCk] = movecenters(I, Ck, k) [gx, gy] = grdmask_base(I,'matlab','ij'); G = sum(gx.^2+gy.^2,3); % I0 = I([2:X X], (1:Y)); I1 = I([1 1:(X-1)], (1:Y)); % G = distL2sqr(I0(:),I1(:)); % I0 = I((1:X), [2:Y Y]); I1 = I((1:X), [1 1:(Y-1)]); % G = G + distL2sqr(I0(:),I1(:)); % G = reshape(G,[X,Y]); [ind, ix, iy] = neiposkernel(k,X); ind = ind(:); ix = ix(:); iy = iy(:); cind = sub2ind([X,Y], Ck(:,1), Ck(:,2)); ind = repmat(cind, [1 numel(ind)]) + repmat(ind', [length(cind) 1]); ind(ind>X*Y) = X*Y; ind(ind<=0) = 1; [~,pos] = min(G(ind), [], 2); Ck = [Ck(:,1) + ix(pos), Ck(:,2) + iy(pos)]; % check that the Ck are not outside the image domain's limits Ck(:,1) = min([max([Ck(:,1), ones(nk,1)],[],2), X*ones(nk,1)], [], 2); Ck(:,2) = min([max([Ck(:,2), ones(nk,1)],[],2), Y*ones(nk,1)], [], 2); cind = sub2ind([X,Y], Ck(:,1), Ck(:,2)); cind = repmat(cind, [1 C]) + (X*Y) * meshgrid(0:C-1, 1:length(cind)); ColCk = reshape(I(cind), [nk C]); end % %----------------------------------------------------------------------
pad the original image
A = padarray(I, [pad pad 0], 'both', 'replicate'); [M,N] = size(A(:,:,1));
possibly define an additional cost function when propagating the amoeba: a gradient magnitude map
if alpha(2) rho = 1; sigma=0.7; samp = 1; int = 'fast'; der = 'fast'; eign = 'zen'; P = gstsmooth_base(A, rho, sigma, der, int, samp, ... [], false, false, 8, .4); grd = gstfeature_base(P(:,:,1,1), P(:,:,2,2), P(:,:,1,2), ... 'norm', eign, [], []); grd = rescale(grd); clear P; else % dgxy = zeros(win^2,1); grd = zeros(size(A)); % we want to avoid further 'if' tests end
reshape for easier manipulations
A = reshape(A,[M*N C]); I = reshape(I,[X*Y C]);
initial labels and distances matrices
Q0 = zeros(M,N); D0 = Inf(M,N);
define some utility matrices
% general indices pixindex = reshape(1:M*N,M,N); % relative indices of the image pixels w.r.t. the paded image pixin = pixindex(pad+1:pad+X,pad+1:pad+Y); % relative indices of the pixels inside the centered analyzing window w.r.t. % the paded image ind2D = neiposkernel(pad, M); ind2D = ind2D(:); % 2D: spatial position %indnD = repmat(ind2D,[1 C]); % nD: spatial/spectral position % relative indice of the centroid pixel w.r.t. the analyzing window cwin = [pad+1; pad+1]; cwin = sub2ind([win,win],cwin(1),cwin(2)); % = (pad+1) + (pad+1)*(win); % list of neighbour connections within the analyzing window: we compute it % once for all conn = 8; [ic,icd] = ixneighbours(true(win,win), [], conn); % note that ic is of size close to (but <) 8*win^2 % compute the spatial distance once for all dxy = distL2(ind2rc(win,ic,'rc'), ind2rc(win,icd,'rc')); % the local cost of traveling from one pixel to any of its neighbours is % the standard Euclidean distance between them
start 'looping'
niter = 1; err = Inf(nk,1); % % ierr = 1:nk; while niter<=maxiter
% % if ~any(err>T), break; end ierr = find(err>T); if isempty(ierr), break; end
update distance and labels
[D0,Q0] = updatedistance(ierr, D0, Q0, Ck, ColCk); Q = Q0(pixin); D = D0(pixin);
update centroids
[nCk, nColCk] = updatecentroids(ierr, Q);
update error
% % ierr = 1:nk;
err = updaterror(ierr, D, Q, Ck, nCk, ColCk, nColCk);
update amoeba
Ck(ierr,:) = nCk; ColCk(ierr,:) = nColCk; niter = niter + 1;
end % %---------------------------------------------------------------------- function [D, Q, err ] = updatedistance(ierr, D, Q, Ck, ColCk) %#ok % in that context, A, M, N, win, pixin, ind2D, indnD, win2D, lambda % pad, and dxy are all 'global' variables in the sense that they are % either passed to the program, or computed prior to the algorithm % running and they are not modified throughout the algorithm; on the % contrary, ierr, D, Q, Ck and ColCk are. % err = zeros(length(ierr),1); for l=1:length(ierr) % separable estimation ll = ierr(l); % ll = l; % we recompute all of them, even those unchanged % retrieve the coordinates of the cluster centroid (also center % of the analyzing window) w.r.t. the paded image, then the indices % of the analyzing window (in 2D) w.r.t. the paded image c2D = pixin(Ck(ll,1),Ck(ll,2)); cind2D = c2D + ind2D; % % retrieve the position in color space % cnD = c2D + (M*N) * (0:C-1); % cindnD = repmat(cnD,[win^2 1]) + indnD; % extract labels and distances within the current neighbourhood q = Q(cind2D); d = D(cind2D); % F = A(cindnD); % F(cwin + wind2D) = ColCk(ll,:); F = A(cind2D,:); F(cwin,:) = ColCk(ll,:); dI = distL2(F(ic,:),F(icd,:)); % distL2(F(icnD),F(icdnD)); % the cost of traveling from ic to icd is the distance between the % spectral values taken by the image on those points: the closer % their spectral values, the higher the probability they belong % to the same amoeba % compute the cost induced by the gradient magnitude of the image % (it may be null) dgxy = (grd(ic) + grd(icd)) / 2; % the cost of traveling from ic to icd is the average of their % gradient values: the lower the gradient at those points, the % higher the probability they belong to the same amoeba; high % gradient pixels act like barriers in the amoeba propagation % method 1 % start = sub2ind([win,win], pad+1, pad+1); W = dxy + alpha(1) * dI + alpha(2) * dgxy; % construct a sparse adjacency matrix G G = sparse(ic, icd, W, win^2, win^2); % Ds = handle_dijkstra(G, cwin); Ds = dijkstrapropagation_mex(G, cwin-1, -1, 1.2*numel(G)); % % method 2 % W = reshape(dfeat(F, repmat(F(cwin+wind2D),[win^2 1])), [win win]); % W = im2potential(W, 'pixinv', lambda); % d = potential2front(W, [pad+1;pad+1]); % find closest [d, r] = min(cat(2,d(:),Ds(:)), [], 2); q(r==2) = ll; % update labels Q(cind2D) = q; % Qll = find(Q==ll); % ck = floor(sum(ind2rc(M,Qll,'rc')) / length(Qll)); % c2D = ind2rc(M,c2D,'rc'); pos = pad+1 + ck - c2D; % Ds = reshape(Ds,[win,win]); % err(l) = Ds(pos(1), pos(2)); % update distances D(cind2D) = d; end end % %---------------------------------------------------------------------- function [Ck, ColCk] = updatecentroids(ierr, Q) labels = cellfun(@(k) find(Q==k), num2cell(ierr(:)), 'UniformOutput', false); % note that we choose the color value of the (point closest to the) % centroid point as a representative value ColCk = cellfun(@(x) sum(I(x,:))/length(x), labels, 'UniformOutput', false); % if we sum the Lab values over the component with same label % ColCk = cellfun(@(x) sum(I([x x+X*Y x+2*X*Y]),1) / length(x), ... % labels, 'UniformOutput', false); labels = cellfun(@(x) ind2rc(X,x,'rc'), labels, 'UniformOutput', false); Ck = cellfun(@(x) floor(sum(x)/size(x,1)), labels, 'UniformOutput', false); Ck = cell2mat(Ck); ColCk = cell2mat(ColCk); end % %---------------------------------------------------------------------- function err = updaterror(ierr, D, Q, Ck, nCk, ColCk, nColCk) %#ok % % - error type 1: % err = distL1(Ck(ierr,:), nCk); % % - error type 2: ddxy = distL2(Ck(ierr,:), nCk); ddrange = distL2(ColCk(ierr,:), nColCk); err = ddxy + alpha(1) * ddrange; % + alpha(2) * ddgxy; % - error type 3: % find the centroids' neighbours within their own superpixel % region (connected component with same label) % [i,j] = ixneighbours(true(X,Y), sub2ind([X Y],nCk(ierr,1),nCk(ierr,2)), conn); % ii = Q(j)~=ierr; % Q(j)~=Q(i); the centroid may have a different label % i(ii) = []; j(ii) = []; % % spatial distance between a centroid and ist nearest neighbours % ii = (ind2rc(X,i,'r')~=ind2rc(X,j,'r')) & ... % (ind2rc(X,i,'c')~=ind2rc(X,j,'c')); % W = sqrt(2)*ii + ~ii; % % add the spectral distance between a centroid and any of its nearest % % neighbours to the already computed distance between those neighbours % % and the previous centroids % W = W + (D(j) + lambda * distL2(nColCk(Q(i),:),I(j,:))); % err = accumarray(i, W, [], @(x){x}, {NaN}); % err(cellfun(@(x)isnan(x(1)),err)) = []; % err = cellfun(@min,err); end % %----------------------------------------------------------------------
end % end of amoebasuperpix_base