如何将谱聚类的分割运行组合成一个巨大的亲和度矩阵

时间:2018-05-21 10:01:35

标签: machine-learning computer-vision cluster-analysis linear-algebra image-segmentation

导致问题

我有一个具有一系列短值的2D复值图像。我想聚类相似像素/分割图像。存在一个或多或少具有叠加图像的静态图像,其中具有一些斑点,其具有在短序列上的变化值(主要是复数的角度)。它们在图像的标准中也略微可辨别。

我的第一次尝试是k-means,但是根据手段真正聚集(平均值有所区别,特别是与周围像素相比,但时间和角度信息更大)。我的第二次尝试是ICA,然后查看具有最大幅度的k个分量,并且成功识别出我的图像中的某些区域是不同的,但没有识别我感兴趣的像素组(视觉上并不难认识他们,但他们很小。)

现状

因为我的前两次尝试没有成功,我用谷歌环顾四周,似乎spectral clustering可能是合适的。但是在使用该方法时我遇到了一些严重问题,主要是因为有限的可用内存。然后我想,因为我有这么多的像素,我可以只使用谱聚类来分离数据。

有人here建议首先对平板进行聚类,然后将它们组合起来,然后他说,最后你会遇到重新组合它们的问题,这个问题可以很容易地解决。指定为' easy'的位在解释中当然不容易。他链接到this论文,但该方法不处理平板中的所有数据。它排除了不接近主成分的向量。

问题

我的问题有两部分:

1 即可。如何组合单独的段的结果?特征向量不同,簇数不同。结果看起来像在单独的板块中起作用。

2 即可。在单独的板中的像素之间没有考虑距离/亲和力。我可以在平板之间制作平板吗?对于那些平板L和A不对称,没有线索如何执行该方法。也许我可以在某种程度上比较/合并所有特征向量?

(3。是否有类似或更好的方法,不需要太多的内存。计算时间也是可接受的边界,容易爆炸)

Matlab代码示例

%% generate data
% get some outer region without data
tempdisk = strel('disk',922/2); tempdisk = double(repmat((1+sqrt(-1)).*tempdisk.Neighborhood,[1 1 15]));
% make some noise
tempnoise = (rand(921,921,15)+sqrt(-1).*rand(921,921,15))./10;
% 'background signal'
tempim1 = double(imresize(mean(imread('cameraman.tif'),3),[921,921])); tempim1 = repmat(tempim1./max(tempim1(:)),[1 1 15]);
% 'target signal'
tempim2 = double(rgb2hsv(imread('fabric.png'))); tempim2 = imresize(tempim2(:,:,2),[921,921]); tempim2 = repmat(tempim2./max(tempim2(:)),[1 1 15]);
sin1 = repmat(permute(sin(2.*pi.*(0:14)./15),[1 3 2]),[921 921 1]);
% combine into data
complexdata = (sin1.*(1.0.*tempim1+0.5.*tempim2.^2).*exp(-sqrt(-1).*2.*pi.*sin1.*(tempim2.^2)).*tempdisk+tempnoise)./1.5;

%this is what the mean data looks like
meannorm = mean(abs(complexdata),3);
meanangle = mean(angle(complexdata),3);
figure; subplot(1,2,1); imshow(meannorm,[]); title('mean norm'); subplot(1,2,2); imshow(meanangle,[]); title('mean angle')

生成的数据如下所示:

mean data

右图中明亮的斑点是我追随的。它们随时间变化也最强(并且在时间上是相关的)。

然后设置群集:

%% perform spectral clustering in seperate slabs 
% method from http://ai.stanford.edu/~ang/papers/nips01-spectral.pdf
%get all pixel vectors in a single matrix
complexrows = reshape(permute(complexdata, [3,1,2]), [15, 921*921]);
%k means and eigs dont accept complex, so convert to real here?
complexrowsTranspose = [real(complexrows);imag(complexrows)]'; 

%lets say 10000 by 10000 matrices are still ok
npix = 10000;
nslabpix = floor(length(complexrowsTranspose)/npix);
nrestpix = rem(length(complexrowsTranspose), npix);

在适合内存的平板中执行光谱聚类:

% spectral clustering 
keig = 50;%how many eigenvectors needed? more is better
affinity_sigma = 1;% i dont understand how to calculate this from the paper
tic
% start with last slab (dynamically preallocate)
for islabpix = (nslabpix+1):-1:1;
    %print progress
    islabpix/nslabpix
    toc
    if islabpix>nslabpix
        pixrange = (1:nrestpix) + ((islabpix-1)*npix);;
    else
        pixrange = (1:npix) + ((islabpix-1)*npix);
    end
    %calculate affinity between all voxels in slab
    Aff = exp( -squareform(pdist(complexrowsTranspose(pixrange,:))).^2/(2*affinity_sigma^2) ); % affinity matrix
    %calculate degree matrix for normalization
    Dsq = sparse(size(Aff,1),size(Aff,2)); %degree matrix
    for idiag=1:size(Aff,1)
        Dsq(idiag,idiag) = sum(Aff(idiag,:))^(1/2);
    end
    %normalize affinity matrix
    Lap = Dsq * Aff * Dsq; %normalize affinity matrix
    %calculate eigenvectors of affinity matrix
    [eigVectors(pixrange,1:keig), eigValues] = eigs(Lap, keig); %eigenvectors of normalized aff mat
    normEigVectors(pixrange,1:keig) = eigVectors(pixrange,1:keig)./repmat(sqrt(sum(abs(eigVectors(pixrange,1:keig)).^2,2)), [1 keig]); %normalize rows of eigen vectors, normr only works on real numbers
    % perform k means clustering on weights for eigenvectors
    [idx,C,sumd,D] = kmeans([real(normEigVectors(pixrange,1:keig)),imag(normEigVectors(pixrange,1:keig))], 5); %k means on normalized eigenvecotrs

    idxval(pixrange) = idx;
end
%reshape into image
idxim = reshape(idxval, [921, 921]);
figure; imshow(idxim,[])
toc

结果聚类:

k means clusters on spectral slabs

结果看起来该方法在每个板块内都有一定程度的作用;目标是聚集所有具有略高的范数和更强角度变化的斑点(来自tempim2的高饱和度斑点),这在结果中似乎是可识别的。现在它主要是单独的板块,这是问题,没有跨板块。这花了大约15分钟。我为这个例子减少了特征值的数量和图像大小,因此它在可接受的时间内运行。我认为这说明了我的一部分问题。

2 个答案:

答案 0 :(得分:1)

我真的没有给你答案,但我认为这些指针可以帮助你找到答案:

  1. 您声称存在内存问题。你确定你的亲和力矩阵是稀疏的吗?似乎只有对角度矩阵在您的代码中是稀疏的。通常在像素/体素上运行光谱聚类时,设计亲和度矩阵非常稀疏(8连接或26连接)。

  2. 您将群集描述为“它们很小”。光谱聚类具有known issues,具有非常不同尺度的聚类。你确定你得到了满意的结果吗?

  3. 如何计算相邻体素之间的亲和力(相似度)?你能测量相异性吗?也就是说,对于某些体素,你能说属于同一个集群吗?如果是,您是否考虑过使用correlation clustering?此方法对于不同的群集比例更加健壮,并且可以自动检测群集的数量。

  4. 您是否考虑过使用多尺度/ multigrid方法来粗化数据而不是将其粗暴地切成“平板”?

  5. 你看过spectralNet了吗?如果我没有弄错的话,这种方法应该让你“学习”部分点上的谱聚类,然后使用网络将聚类“外推”到新的点。

  6. <强> Upadate:
    根据{{​​3}},我要说的是,当涉及非常大的数据的谱聚类时,将数据粗暴地切成“平板”然后试图将结果“缝合”在一起可能不是最好的粗略动作(不是我认为这是不可能的)。解决问题的更好方法是通过显着稀疏亲和度矩阵:计算每个点仅与其邻居的成对关联性,从而产生大多数稀疏的亲和度矩阵。这样,可以一次处理所有点而无需“切片”和“缝合”。

    光谱聚类和相关聚类之间的区别:
    为什么频谱聚类能够聚集所有点,即使输入亲和度矩阵太稀疏?它如何告诉那个点a和一个远点{即使在它们之间没有计算亲和力,{1}}也应该属于同一个集群? 简单的答案是Leo's comment亲和力:如果ca相似且bb相似,那么c和{{1}应该聚集在一起。
    捕获的位置?在谱聚类中,亲和度矩阵中的所有条目都是非负的,这意味着除非绝对没有连接ac的路径(很少)有一些“传递亲和力”表明ac应该属于同一个群集。因此,如果看一下光谱聚类的数学,你会注意到“平凡的解决方案”,即将所有点放在同一个聚类中,为问题提供全局最优。人们必须人为地迫使解决方案拥有a簇,以避免重要的解决方案 可以做什么?如果你只考虑正相关性,那么0值是模糊的:它意味着“我没有费心去计算这些点之间的亲和力”,但它也可能意味着“我认为这两点应该在同一个集群中“。为了克服这种歧义,我们可以通过这种方式引入负面关联,如果c表示点k且点A(i, j) > 0应该在确定性i的同一群集中},如果j表示A(i, j)A(i, j) < 0 应位于同一群集中(确定性为i)。引入负面的亲和力打破了可能链接远点的“传递链”,并不是将所有点放在同一个集群中也不再是微不足道的。
    如何利用负面亲和力?当您的亲和力矩阵同时具有正(吸引)和负(排斥)值时,您可以使用相关聚类对点进行聚类,这基本上会尝试最大化两者之间的亲和力/吸引力每个群集内的点,同时最大化不同群集中的点之间的排斥力。相关聚类的一个很好的属性是它“自动”发现底层的聚类数量,参见sec。 transitivity中的2个。

答案 1 :(得分:1)

Shai's answer之后,我切换到仅计算相邻像素(在4个像素的半径内)和使用稀疏矩阵之间的亲和度。然后,我得到整个图像的相等聚类。为了建立一个稀疏的邻接矩阵,我使用了Shai的函数sparse_adj_matrix,否则内存仅由邻接矩阵填充。

tic
complexrowsTranspose = [real(complexrows);imag(complexrows)]';
indexnonzero = find(mean(tempdisk,3) > 0);
idxval = zeros(size(complexrowsTranspose, 1),1);

[irow jcol] = sparse_adj_matrix([size(meannorm,1), size(meannorm,2)], 4, 2);
keep = ismember(irow, indexnonzero);
irow(~keep) = [];
jcol(~keep) = [];
clear keep

sigma = 1;
Avect = exp(-sum((complexrowsTranspose(irow,:)-complexrowsTranspose(jcol,:)).^2,2)/(2*sigma^2));
iAval = find([Avect>0].*[Avect<Inf]);
Aff = sparse(irow(iAval),jcol(iAval),Avect(iAval),length(complexrowsTranspose),length(complexrowsTranspose));
Dvector = sum(Aff,2).^(1/2);
Dindex = find(Dvector);
D = sparse(Dindex, Dindex, Dvector(Dindex),size(Aff,1),size(Aff,2));
L = D * Aff * D;

keig = 25;
[Vect, Val] = eigs(L, keig);
normVect = Vect./repmat(sqrt(sum(abs(Vect).^2,2)), [1 keig]);
[kidx,kC,ksumd,kD] = kmeans(normVect, 5);

kmeansim = reshape(kidx, [921, 921]);
figure; imshow(kmeansim,[])
toc

这就是生成的集群的样子:

k means after only local affinity

看起来好多了。然而,我感兴趣的聚类不会出现(在'角度'图像中,在摄影师的黑色外套内部具有高值的斑点)。尤其是具有相似均值范数值的像素被聚类,而不是在短序列上也没有类似的变化,也没有相似的角度(复数值)。

我会尝试调整输入值和邻接半径来计算亲和力。

<强>更新

我尝试只放入角度,整个复杂值(并调整代码以适应复杂值),改变计算亲和力的半径,放入1相关而不是距离,但我没有得到摄影师大衣中的小亮角blob聚集在一起。

然后我下载了this代码并尝试如下:

complexrowsTranspose = complexrows';
[icol irow] = sparse_adj_matrix([921, 921], 1, Inf);

complexrowsTminmean = complexrowsTranspose -repmat(mean(complexrowsTranspose , 2), [1, 15]);
complexrowsTstd = sqrt( std(real(complexrowsTranspose), [], 2).^2+std(imag(complexrowsT), [], 2).^2 );
complexrowsTcorr = sum(real(complexrowsTminmean(icol).*complexrowsTminmean(irow)), 2)./complexrowsTstd(irow)./complexrowsTstd(icol)./(15-1);

Asparse = sparse(irow, icol, 1-complexrowsTcorr, 921*921, 921*921);
Asparse(isnan(Asparse)) = 0;

K = AL_ICM(Asparse);

但我不会让它超越第一次迭代。我计算这些复杂向量的相关性的方法可能不满足函数的要求。