先说基础:
Mean Shift 分割是一种局部均匀化技术,对于抑制局部对象中的阴影或色调差异非常有用。一个例子胜过许多话:
动作:用 range-r 邻域中像素的平均值替换每个像素,其值在距离 d 内。
均值偏移通常需要 3 个输入:
- 用于测量像素之间距离的距离函数。通常是欧几里得距离,但可以使用任何其他明确定义的距离函数。曼哈顿距离有时是另一个有用的选择。
- 一个半径。该半径内的所有像素(根据上述距离测量)将被计算在内。
- 价值差异。从半径 r 内的所有像素中,我们将只取那些值在这个差值范围内的像素来计算平均值
请注意,算法在边界处没有很好地定义,因此不同的实现会在那里给你不同的结果。
我不会在这里讨论血淋淋的数学细节,因为如果没有适当的数学符号,它们是不可能显示的,在 StackOverflow 中不可用,而且还因为它们可以从其他地方的好资源中找到。
让我们看看矩阵的中心:
153 153 153 153
147 96 98 153
153 97 96 147
153 153 147 156
通过合理选择半径和距离,四个中心像素将获得 97(它们的平均值)的值,并且与相邻像素不同。
让我们在Mathematica中计算它。我们将显示颜色编码,而不是显示实际数字,以便更容易理解正在发生的事情:
矩阵的颜色编码是:

然后我们采取合理的 Mean Shift:
MeanShiftFilter[a, 3, 3]
我们得到:

所有中心元素都相等(等于 97,顺便说一句)。
您可以使用 Mean Shift 进行多次迭代,以尝试获得更均匀的颜色。经过几次迭代后,您会得到一个稳定的非各向同性配置:

这时候应该清楚了,在应用 Mean Shift 之后,你无法选择得到多少个“颜色”。因此,让我们展示如何做到这一点,因为这是您问题的第二部分。
您需要能够提前设置输出集群的数量类似于Kmeans clustering。
它以这种方式为您的矩阵运行:
b = ClusteringComponents[a, 3]
{{1, 1, 1, 1, 1, 1, 1, 1},
{1, 2, 2, 3, 2, 3, 3, 1},
{1, 3, 3, 3, 3, 3, 3, 1},
{1, 3, 2, 1, 1, 3, 3, 1},
{1, 3, 3, 1, 1, 2, 3, 1},
{1, 3, 3, 2, 3, 3, 3, 1},
{1, 3, 3, 2, 2, 3, 3, 1},
{1, 1, 1, 1, 1, 1, 1, 1}}
或者:

这与我们之前的结果非常相似,但是如您所见,现在我们只有三个输出级别。
!