今天早些时候,我正在研究基于http://www.mathworks.com/products/demos/image/color_seg_k/ipexhistology.html和Matlab答案的脚本:
clc;
clear;
close all;
input_im=imread('C:\Users\Udell\Desktop\T2.jpg');
sz_im=size(input_im);
cform = makecform('srgb2lab');
lab_he = applycform(input_im,cform);
ab = double(lab_he(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', 'Replicates',3);
pixel_labels = reshape(cluster_idx,nrows,ncols);
%imshow(pixel_labels,[]), title('image labeled by cluster index');
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:nColors
color = input_im;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
for k=1:nColors
%figure
title_string=sprintf('objects in cluster %d',k);
%imshow(segmented_images{k}), title(title_string);
end
finalSegmentedImage=segmented_images{1};
%imshow(finalSegmentedImage);
close all;
Icombine = [input_im finalSegmentedImage];
imshow(Icombine);
在多次运行脚本的同时,我注意到当组合图像(Icombine)的finalSegmentedImage = segmented_images {1}时,我得到了不同的图像。 为什么?如何解决结果重复的问题(例如,segmented_images {1}图像将始终相同)?
非常感谢。
图片:
答案 0 :(得分:7)
您获得不同结果的原因是您的颜色分割算法使用k-means clustering。我会假设你不知道这是什么,熟悉它如何运作的人会立刻告诉你这就是你每次都得到不同结果的原因。事实上,每次运行此代码后得到的不同结果都是 k -means聚类的自然结果,我将解释原因。
它的工作原理是,对于您拥有的某些数据,您希望将它们分组到 k 组中。您最初在数据中选择 k 随机点,这些点将包含来自1,2,...,k
的标签。这些就是我们所说的质心。然后,确定其余数据与这些点之间的接近程度。然后,您将这些点分组,以便无论哪个点最接近这些 k 点中的任何一个,您都可以将这些点指定为属于该特定组(1,2,...,k
)。之后,对于每个组的所有点,您更新质心,实际上将其定义为每个组的代表点。对于每个组,您计算每个 k 组中所有点的平均值。这些成为下一次迭代的新质心。在下一次迭代中,您可以确定数据中每个点与每个质心的接近程度。你继续迭代并重复这种行为,直到质心不再移动,或者移动很少。
这适用于上述代码的方法是您正在拍摄图像,并且您希望仅使用 k 可能的颜色来表示图像。因此,这些可能的颜色中的每一种都是质心。找到每个像素所属的聚类后,您可以使用像素所属的聚类的质心替换像素的颜色。因此,对于图像中的每个颜色像素,您需要确定哪个 k 可能的颜色,这个像素最好用哪个颜色表示。这是一个颜色分割的原因是因为您分割图像只属于 k 可能的颜色。在更一般的意义上,这就是所谓的无监督分割。
现在,回到 k - 意思。如何选择初始质心是您获得不同结果的原因。您以默认方式调用 k -means,它自动确定算法将从中选择哪些初始点。因此,每次调用算法时,无法保证都会生成相同的初始点。如果您想要重复相同的细分,无论您拨打kmeans
多少次,都需要自己指定初始点。因此,您需要修改 k -means调用,使其看起来像这样:
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates', 3, 'start', seeds);
请注意,该调用是相同的,但我们在 k -means调用中添加了两个附加参数。标记start
表示您指定了初始点,seeds
是k x p
数组,其中 k 是您想要的组数。在这种情况下,这与nColors
相同,即{3}。p
是数据的维度。由于您正在转换和重塑数据的方式,这将是2.因此,您最终指定了3 x 2
矩阵。但是,那里有一个Replicate
标志。这意味着 k -means算法将运行您指定的特定次数,并将输出具有最小错误量的分段。因此,我们将使用此标志指定的次数重复kmeans
次调用。 seeds
的上述结构将不再是k x p
,而是k x p x n
,其中n
是您要运行细分的次数。现在这是一个3D矩阵,其中每个2D切片确定算法的每次运行的初始点。请记住这一点。
您如何选择这些积分取决于您。但是,如果您想随机选择这些并且不想让它,但每次调用此函数时想要重现相同的结果,则应将random seed generator设置为已知数字,例如{{1 }}。这样,当您生成随机点时,它将始终生成相同的点序列,因此是可重现的。因此,我会在调用123
之前将其添加到您的代码中。
kmeans
请记住,您指定了rng(123); %// Set seed for reproducibility
numReplicates = 3;
ind = randperm(size(ab,1), numReplicates*nColors); %// Randomly choose nColors colours from data
%// We are also repeating the experiment numReplicates times
%// Make a 3D matrix where each slice denotes the initial centres for each iteration
seeds = permute(reshape(ab(ind,:).', [2 nColors numReplicates]), [2 1 3]);
%// Now call kmeans
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates', numReplicates, 'start', seeds);
标志,我们希望重复此算法一定次数。这是Replicates
。因此,我们需要做的是为每次运行算法指定初始点。因为我们将有3个点集群,并且我们将运行此算法3次,所以我们总共需要9个初始点(或3
)。每组初始点必须是3D数组中的切片,这就是您在nColors * numReplicates
调用之前看到复杂语句的原因。
我将重复次数作为一个变量,以便您可以更改此内容以及您心中的内容,并且它仍然可以正常工作。使用permute
和reshape
的复杂语句使我们可以非常轻松地创建这个3D点阵。
请记住,MATLAB中对randperm
的调用仅接受了最近的第二个参数。如果以上对kmeans
的调用无效,请执行以下操作:
randperm
现在使用上面的代码,您应该每次都能生成相同的颜色分割结果。
祝你好运!