O básico primeiro:
A segmentação por deslocamento médio é uma técnica de homogeneização local muito útil para amortecer diferenças de sombreamento ou tonalidade em objetos localizados. Um exemplo é melhor do que muitas palavras:
Ação: substitui cada pixel pela média dos pixels em uma vizinhança de alcance r e cujo valor está dentro de uma distância d.
A mudança média leva geralmente 3 entradas:
- Uma função de distância para medir distâncias entre pixels. Normalmente a distância euclidiana, mas qualquer outra função de distância bem definida pode ser usada. A distância de Manhattan é outra escolha útil às vezes.
- Um raio. Todos os pixels dentro deste raio (medidos de acordo com a distância acima) serão contabilizados para o cálculo.
- Uma diferença de valor. De todos os pixels dentro do raio r, tomaremos apenas aqueles cujos valores estão dentro desta diferença para calcular a média
Observe que o algoritmo não está bem definido nas bordas, portanto, diferentes implementações fornecerão resultados diferentes lá.
NÃO discutirei os detalhes matemáticos sangrentos aqui, pois eles são impossíveis de mostrar sem a notação matemática adequada, não disponível no StackOverflow, e também porque podem ser encontrados em boas fontes em outros lugares .
Vejamos o centro de sua matriz:
153 153 153 153
147 96 98 153
153 97 96 147
153 153 147 156
Com opções razoáveis de raio e distância, os quatro pixels centrais obterão o valor de 97 (sua média) e serão diferentes dos pixels adjacentes.
Vamos calcular no Mathematica . Em vez de mostrar os números reais, exibiremos um código de cores, para que seja mais fácil entender o que está acontecendo:
O código de cores para sua matriz é:

Em seguida, tomamos uma mudança média razoável:
MeanShiftFilter[a, 3, 3]
E nós temos:

Onde todos os elementos centrais são iguais (a 97, BTW).
Você pode iterar várias vezes com Mean Shift, tentando obter uma coloração mais homogênea. Depois de algumas iterações, você chega a uma configuração não isotrópica estável:

Neste momento, deve ficar claro que você não pode selecionar quantas "cores" deseja obter após aplicar o deslocamento médio. Então, vamos mostrar como fazer, porque essa é a segunda parte da sua pergunta.
O que você precisa para ser capaz de definir o número de clusters de saída com antecedência é algo como cluster de Kmeans .
Funciona assim para sua matriz:
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}}
Ou:

Que é muito semelhante ao nosso resultado anterior, mas como você pode ver, agora temos apenas três níveis de saída.
HTH!