⚠️ Este é um site de tradução não oficial, sem relação com a ImageMagick Studio LLC. Para informações oficiais, consulte a página original (https://usage.imagemagick.org/morphology/index.html).

Exemplos do ImageMagick -- Morfologia de Formas

Exemplos do ImageMagick: Prefácio e Índice
Introdução à Morfologia

A morfologia modifica uma imagem de várias maneiras com base na «vizinhança» próxima dos outros pixels que a cercam. Isso, por sua vez, pode proporcionar uma enorme variedade de efeitos, da expansão e contração de formas (dilatação/erosão), à distância da borda, ao afinamento até um esqueleto, ou eixo de linha média. Até mesmo o método mais antigo das técnicas de «convolução», que fornecem técnicas de desfoque e aguçamento (próxima seção), é, de certa forma, um tipo de método de morfologia. Essencialmente, a morfologia serve para a modificação, determinação e descoberta das formas dos objetos encontrados dentro de uma imagem.


Introdução à Morfologia

A morfologia foi originalmente desenvolvida como um método pelo qual a estrutura das formas dentro de uma imagem podia ser limpa e estudada. Ela funciona comparando cada pixel da imagem com seus vizinhos de várias maneiras, de modo a adicionar ou remover, clarear ou escurecer esse pixel. Aplicada sobre uma imagem inteira, talvez de forma repetida, formas específicas podem ser encontradas e/ou removidas e modificadas. Por exemplo, se um pixel é branco e está completamente cercado por outros pixels brancos, então esse pixel obviamente não está na borda da imagem. Você pode então querer tornar esse pixel preto, de modo a deixar apenas os pixels de borda ativados. Um método conhecido como '[EdgeIn](#edgein)' (veja abaixo). Todo o processo na verdade depende da definição de um 'Elemento Estruturante' ou 'Núcleo', que define quais pixels devem ser classificados como 'vizinhos' para cada método morfológico específico. Exatamente qual o tamanho e a forma dessa 'vizinhança' muitas vezes depende do que você está tentando alcançar, ou do que você está procurando especificamente dentro da imagem. Aqui estão alguns exemplos de vários núcleos que foram convertidos em imagens (usando um script especial "[kernel2image"](../static/img/scripts/kernel2image)") mostrando algumas das 'vizinhanças' ao redor de um pixel central, a 'origem'.

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

As imagens foram escalonadas para destacar os elementos individuais do 'núcleo', e, como você pode ver, os núcleos típicos costumam ser muito pequenos. Na verdade, o núcleo 'Disk' mostrado acima é, na realidade, "[Raw Disk Kernel Image]", e esse é um dos maiores núcleos mostrados acima. No entanto, os 'núcleos' não são realmente imagens. Apenas um arranjo de valores de ponto flutuante com um elemento especificado como a 'origem' do núcleo. Esse elemento especial é a localização do pixel que será 'afetado' pela vizinhança definida, e é tipicamente, embora nem sempre, o pixel central de um núcleo simétrico. Observe que estes são apenas alguns exemplos de vizinhanças possíveis. Alguns núcleos podem ser feitos maiores, tipicamente aumentando um argumento de 'raio' específico daquele núcleo, enquanto outros usados para fins especiais têm tamanho fixo. Para núcleos simples, como os dois primeiros, o método morfológico pode ser repetido (iterado) para aumentar o 'tamanho' efetivo do núcleo, de modo a afetar mais pixels mais distantes da 'origem' (conforme marcado). No entanto, isso nem sempre funciona e pode produzir resultados inesperados; ainda assim, às vezes é mais rápido do que usar diretamente um núcleo maior, mas, novamente, nem sempre é esse o caso. O tamanho e a forma finais de um 'Elemento Estruturante', ou 'SE', como um núcleo é denominado nos artigos de pesquisa sobre morfologia, são importantes como meio de localizar e realçar ou eliminar elementos da imagem que sejam maiores ou menores do que essa forma. É isso que torna a morfologia extremamente poderosa como meio de separar vários elementos dentro das imagens. Contudo, quanto maior o núcleo, mais tempo os métodos morfológicos levarão, por isso é melhor manter os núcleos pequenos. Todos os núcleos mostrados, exceto o último, têm de fato uma forma. As partes que são transparentes não fazem parte da 'vizinhança' definida do núcleo. Ou seja, elas não têm nenhum valor válido e não participarão de nenhum dos cálculos de morfologia. Observe como o penúltimo núcleo 'Corner #0' não tem apenas valores 'ligados', mas também valores 'desligados', como parte de sua 'forma'. Ambos os valores, bem como aqueles que são transparentes (não fazem parte da forma), são importantes para os métodos Hit-n-Miss e relacionados (veja abaixo). Esse núcleo específico é apenas o primeiro de uma série de núcleos destinados a localizar os pixels de 'canto' de formas binárias dentro de uma imagem. O último 'núcleo' mostrado acima é totalmente definido sobre uma grande área retangular (quadrada). Além disso, ao contrário dos outros núcleos, que usam apenas valores de 1 (branco), 0 (preto) ou um valor 'indefinido' especial, os valores desse núcleo na verdade variam de quase-zero (quase-preto) nas bordas até um valor máximo (branco-puro) no centro. No entanto, tais núcleos também podem usar valores negativos, ou mesmo valores muito grandes, bem além da faixa normal dos outros núcleos. Lembre-se de que um núcleo é, na verdade, apenas um arranjo de valores, e estes poderiam ter qualquer valor, não apenas uma faixa de 0 a 1. Esse tipo de núcleo é especialmente importante nas 'Operações de Convolução', um método especial que existe há muito mais tempo do que a própria morfologia. Como resultado, o IM tem um número muito grande de núcleos deste tipo internos, ou 'Nomeados'. Isso será visto em mais detalhes na próxima seção dos Exemplos de IM, Convolução de Imagens'. Agora, como já mencionei, os núcleos não são realmente imagens. Eles são simplesmente um arranjo de valores de ponto flutuante. Veremos esses valores reais (que foram convertidos em uma imagem para visualização, acima) mais adiante.

Operador de Morfologia

O operador "[-morphology](https://imagemagick.org/command-line-options/#morphology)" é muito complexo, pois oferece ao usuário muitos controles sobre suas ações.

  -morphology {_method_}[:{_iterations_}]   {_kernel_}[:[_k_args_}]

Observe que você precisa fornecer pelo menos dois itens, o 'method ' da morfologia, que informa ao operador o tipo de operação que você deseja aplicar à imagem, e um 'kernel ' que especifica quais pixels 'vizinhos' devem afetar o resultado final. Ambos são igualmente importantes e ambos podem ter consequências de longo alcance. Você pode obter uma lista dos métodos disponíveis usando "-list morphology ". Uma lista dos núcleos internos que incluímos no IM pode ser vista com "-list kernel ". Passaremos pelos vários métodos, e pelos núcleos que esses métodos podem usar, mais adiante. | _O operador "[-morphology](https://imagemagick.org/command-line-options/#morphology)" (métodos básicos) e o conjunto inicial de núcleos foram adicionados ao ImageMagick versão 6.5.9-0 por mim mesmo, enquanto eu estava de férias na China. Dezembro de 2009 a janeiro de 2010.

No entanto, é possível realizar uma morfologia simplificada com núcleo 'quadrado' usando o método mais antigo e intimamente relacionado "[-convolve](https://imagemagick.org/command-line-options/#convolve)". Veja Técnicas Alternativas de Morfologia Básica abaixo.

_
---|---

Núcleos de Forma Internos Básicos

Como o núcleo é comum a todos os métodos de morfologia, e os resultados dos vários métodos dependem fortemente do núcleo efetivamente selecionado, veremos primeiro como você pode definir ou selecionar um núcleo para usar. Uma boa seleção de núcleos já está predefinida para você e, muitas vezes, você não precisa procurar além desses. Você pode obter uma lista dos núcleos internos predefinidos usando "-list kernel". Todos os núcleos têm um tamanho específico, tipicamente um quadrado com um número ímpar de pixels por lado, cujo centro é a 'origem' do núcleo. No entanto, como você verá, o operador "[-morphology](https://imagemagick.org/command-line-options/#morphology)" não está restrito a essa limitação. O k_argument mais comum usado para os núcleos internos, e geralmente o primeiro argumento fornecido, é um 'radius '. Isso define quão grande será a típica vizinhança quadrada de tamanho ímpar do núcleo. O tamanho final do núcleo geralmente será o dobro do raio mais um (para o pixel central). Ou seja, um 'radius ' de '2' criará um núcleo de 5×5 pixels quadrado. Embora um 'radius ' tipicamente defina o tamanho do núcleo final e, portanto, a velocidade geral da operação morfológica sobre as imagens, ele pode não ser o fator mais importante, especialmente para os Núcleos de Convolução, onde os valores têm um efeito maior sobre os resultados do que o tamanho do núcleo. Se um 'radius ' for definido como 0, ou deixado indefinido, o 'radius ' assumirá automaticamente algum valor razoável ou mais comumente usado, dependendo do núcleo envolvido. [IM Output]

Unity

Este é um núcleo especial usado especificamente quando você precisa de um núcleo 'No-Op' (sem operação). A maioria dos métodos morfológicos que usam este núcleo ou reproduz a imagem original ou gera um resultado em branco. O núcleo não tem argumentos. Esse mesmo núcleo de elemento único também pode ser gerado usando '[Disk:0.5](#disk)', que também permite especificar um argumento de escalonamento como parte da geração do núcleo. [IM Output]

Diamond

O núcleo mais minimalista, embora talvez não o mais simples, é o núcleo interno 'Diamond '. Uma maneira simples de observar o núcleo básico é usar um método de morfologia Dilate em uma imagem contendo um único pixel branco sobre um fundo preto. Isso basicamente expande o único pixel para a 'forma' da vizinhança do núcleo. Aqui está o resultado de usar 'Dilate' com o núcleo interno mínimo 'Diamond', escalonando o resultado para maior a fim de torná-lo mais visível.

  magick xc: -bordercolor black -border 5x5 pixel.gif
  magick pixel.gif -scale 800% pixel_mag.gif
  magick pixel.gif -morphology Dilate Diamond \
                    -scale 800% k_diamond.gif

[IM Output] [IM Output]

| Lembre-se de que todos os resultados de imagem de núcleo nesta área dos exemplos de IM foram ampliados para permitir que você veja os pixels individuais. Na realidade, todos os núcleos e os resultados que estamos mostrando são muito pequenos, como deveriam ser. Neste caso, a imagem sendo dilatada tem apenas 11×11 pixels de tamanho e foi escalonada 8 vezes para exibição.
---|---
Este é, na verdade, um núcleo bastante bom para operações morfológicas e basicamente define a vizinhança prática mais mínima: o pixel original, mais os quatro pixels em contato direto. Outro nome para esse tipo de núcleo é elemento estruturante 'Z4'. Ele se parece bastante com um pequeno sinal de 'mais'. A forma de losango só se torna aparente à medida que o raio aumenta. O k_arg opcional para este núcleo pode assumir dois valores, assim...

     Diamond[:{_radius_}[,{_scale_}]]

Para todos os núcleos de forma, o argumento mais importante é radius e, como mencionado antes, é um inteiro que representa a distância da 'origem' central até a borda mais próxima. Assim, o núcleo 'Diamond' final é um quadrado (2 vezes radius mais 1) contendo a forma de losango. Aqui estão os resultados de usar um radius maior para gerar um núcleo grande.

  for r in 1 2 3 4; do
    magick pixel.gif -morphology Dilate Diamond:$r -scale 800% k_diamond:$r.gif
  done

[IM Output]
Diamond:1
(padrão) | [IM Output]
Diamond:2 | [IM Output]
Diamond:3 | [IM Output]
Diamond:4
---|---|---|---

O outro k_argument é scale, cujo valor padrão é 1.0. Tipicamente, ele é usado para alterar os valores efetivamente usados pelo núcleo para formar a forma. Isso geralmente só é importante para métodos especiais como Convolve e Morfologia de Tons de Cinza. [IM Output]

Square

O 'Square ' é o núcleo mais comumente usado para morfologia, pois é o mais fácil de aplicar usando outras técnicas alternativas. No entanto, não é o núcleo mais mínimo (veja '[Diamond](#diamond)' acima). Por padrão, o núcleo 'Square' usa uma vizinhança de 3x3 pixels ao redor do 'centro'. |

  magick pixel.gif  -morphology Dilate Square -scale 800% k_square.gif

[IM Output]
Basicamente, isso significa que todos os 8 vizinhos do pixel original serão classificados como parte da vizinhança desse pixel. Como resultado, é um bom núcleo para calcular a média de pixels, ou expandir/encolher alguma forma em um pixel. Como todos os núcleos de forma, ele aceita os mesmos k_arguments mostrados para o Núcleo Diamond acima, sendo o primeiro argumento radius o mais importante.

  for r in 1 2 3 4; do
    magick pixel.gif  -morphology Dilate Square:$r -scale 800% k_square:$r.gif
  done

[IM Output]
Square:1
(padrão) | [IM Output]
Square:2 | [IM Output]
Square:3 | [IM Output]
Square:4
---|---|---|---

O padrão (radius=1) para este núcleo, como mencionado, é um quadrado 3×3, e é comumente conhecido como um elemento estruturante 'Z8' (pelo número de vizinhos imediatos envolvidos). [IM Output]

Octagon

O núcleo 'Octagon ' é um núcleo com forma de 8 lados. E foi projetado especificamente para corresponder à '[Octagonal Distance Metric](../static/img/morphology/octagonal)'. Não confunda os dois, pois são núcleos muito diferentes. Aqui estão os núcleos resultantes para raios pequenos...

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Observe que, no raio 1, você obtém o mesmo núcleo que um núcleo "Diamond". Por causa disso, o tamanho padrão do octógono é de raio '2'. | _Deste ponto em diante, usarei um script especial kernel2image para gerar imagens dos núcleos, pois elas são muito mais claras do que usar um método bruto de "dilatar-escalonar" (como acima). Lembre-se, porém, de que os núcleos são geralmente muito pequenos, embora os núcleos Octagon e Disk (veja a seguir) possam se tornar muito grandes para usos específicos.


---|---
| _O núcleo "Octagon" foi adicionado no IM v6.6.9-4, junto com o núcleo de distância "[Octagonal](#octagonal)".

---|---
[IM Output]

Disk

O núcleo 'Disk' é, como você esperaria, uma forma circular. E é comumente usado quando um núcleo morfológico muito grande é necessário. Observe, porém, que é um círculo booleano com serrilhado (aliased). No entanto, o argumento radius para um disco pode ser um número de ponto flutuante, o que permite produzir uma boa variedade de formas, usando raios pequenos.

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

O núcleo 'Disk:4.3' é o padrão e o que considero a primeira verdadeira forma de disco. Discos desse tamanho ou maiores são especialmente bons para, de modo geral, arredondar e suavizar as formas da imagem. O tamanho final do núcleo que contém o disco é o valor de 'radius ' arredondado para baixo, vezes 2 mais 1. Assim, o núcleo padrão 'Disk:4.3' tem um raio de tamanho de núcleo de 4, tornando o tamanho final do núcleo 4 vezes 2 mais 1, e gerando um núcleo 9×9 para conter a forma de disco. Observe que um valor menor que um (mas não zero) sempre produzirá um núcleo de um único pixel, embora isso não seja muito útil. Depois disso, o núcleo tende, na maior parte das vezes, a produzir núcleos que também podem ser gerados usando os tipos de núcleo anteriores. É somente à medida que o raio fica grande que verdadeiros núcleos em forma de disco começam a surgir. A coisa mais importante a observar é que um disco com raio fracionário funciona muito melhor do que usar um raio inteiro. Adicionar uma fração de cerca de 0.3 a 0.5 é geralmente recomendado, para evitar gerar um único pixel de aparência estranha nas laterais do disco. [IM Output]

Plus

O núcleo 'Plus' é, na verdade, um pouco diferente dos outros núcleos de forma morfológicos, no sentido de que é projetado para representar uma 'forma' específica em vez de uma simples 'vizinhança' ao redor de um pixel. Usar um 'radius ' maior com este núcleo não simplesmente aumenta o tamanho do núcleo, mas alonga os braços do sinal de mais resultante. A espessura dos braços, contudo, não aumenta.

[IM Output] [IM Output] [IM Output] [IM Output]

O tamanho padrão de um núcleo 'Plus' é um raio de 2, produzindo 'braços' de 2 pixels ao redor da 'origem' central. Um núcleo 'Plus:1' acaba sendo o mesmo que o núcleo padrão 'Diamond'. Observe que um núcleo 'Plus' geralmente não é usado para métodos morfológicos normais e deve ser evitado para tais fins. No entanto, é muito útil se você quiser encontrar e destacar pontos individuais em uma imagem, como faço mais adiante para exibir Informações do Esqueleto. Basicamente, ele fornece um método para Desenhar Símbolos, sem precisar saber exatamente onde os 'pontos' individuais estão localizados na imagem. [IM Output]

Cross

O núcleo 'Cross' é exatamente como '[Plus](#plus)', mas rotacionado 45 graus. Ele também é apenas uma forma de núcleo especial adequada para expandir pixels a fim de marcar as localizações de vários pontos

[IM Output] [IM Output] [IM Output] [IM Output]

[IM Output]

Ring

O núcleo 'Ring', como o núcleo '[Plus](#plus)', também é projetado como um núcleo de 'forma' especial para marcar pixels e gerar padrões em imagens. No entanto, ele não aceita apenas um raio, pode aceitar dois raios e é definido da mesma forma que os Núcleos Disk...

     Ring[:{_radius1_}[,{_radius2_}[,{_scale_}]]]

O que ele faz é ativar qualquer pixel que caia entre os dois raios, independentemente da ordem dos dois raios fornecidos. Se nenhum raio for fornecido, o padrão é raios de '2.5' e '3.5', produzindo um 'Ring:2.5,3.5', que se parece com um anel octogonal oco, ideal para circundar um pixel. Variando os dois raios, você pode criar um 'anel' de qualquer tamanho e espessura. Pequenas mudanças nos raios adicionarão e removerão números muito pequenos de pixels ao redor das bordas, permitindo um controle fino da aparência do anel. Se os dois raios estiverem a menos de 1 pixel um do outro, você também pode gerar um anel constituído de pontos esparsamente separados, o que pode ser útil como uma vizinhança de propósito especial. Raios pequenos também gerarão núcleos semelhantes a caixas, que também podem ser úteis. Se o segundo raio não for fornecido, ele assumirá o valor padrão de '0.5', o que define efetivamente um disco completo, mas sem o pixel de 'origem' central. Em outras palavras, um núcleo de disco, mas excluindo o pixel de 'origem'. Aqui estão exemplos de muitos dos núcleos 'Ring' que podem ser gerados...

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Como você pode ver, você tem muitas possibilidades ao ajustar cuidadosamente os dois raios, e isso fornece uma boa maneira de mostrar locais de interesse em uma imagem. [IM Output]

Rectangle

O núcleo 'Rectangle' está intimamente relacionado ao núcleo '[Square](#k_square)' acima e, por padrão, produz o mesmo núcleo quadrado 3x3. Mas, em vez de um simples argumento de raio, você pode fornecer um argumento 'geometry ' para especificar o tamanho exato do núcleo retangular desejado. Aqui estão algumas especificações e uma imagem dos núcleos que elas produzem.

[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]

Por padrão, o núcleo tentará definir a 'origem' da vizinhança como o 'centro' exato do núcleo. Mas, para um retângulo de tamanho par, ele escolherá o ponto imediatamente acima e/ou à esquerda do centro, conforme apropriado. No entanto, você também pode especificar origens fora do centro. Este núcleo em particular também é bom para definir longas linhas horizontais e verticais, permitindo que você procure por tais objetos dentro das imagens. Mais sobre isso adiante. Neste momento, você não pode fornecer um fator scale para um retângulo. Todos os seus valores de núcleo serão definidos apenas como 1.0.

Núcleos DIY Definidos pelo Usuário

Você não está restrito apenas aos núcleos internos, mas também pode especificar seu próprio núcleo, fornecendo os valores exatos que deseja que o núcleo use...

   "[{_geometry_}:] {_value_}, {_value_}, {_value_},....."

A especificação 'geometry ' é basicamente exatamente como o argumento do núcleo '[Rectangle](#k_rectangle)' anterior. Ela fornece o tamanho do núcleo e, opcionalmente, o 'deslocamento' da 'origem' da vizinhança. Se apenas um número for fornecido, ele será assumido como as dimensões de um núcleo quadrado. Lembre-se de que o valor de geometria NÃO é um argumento de 'raio', mas o tamanho geral do núcleo.
Se nenhum 'geometry ' ou ':' for especificado, então você está usando a especificação de estilo 'antigo'. Um núcleo quadrado de tamanho ímpar grande o suficiente para conter todos os valores fornecidos será gerado. Isso não é recomendado e é fornecido apenas para compatibilidade retroativa com versões mais antigas do ImageMagick. Após o ':' (que é obrigatório depois de uma especificação de 'geometry '), você então fornece width × height valores de ponto flutuante separados por vírgulas e/ou espaços em branco. Um valor especial de 'NaN' (que significa "Not a Number", ou "Não é um Número") ou um '-' isolado pode ser usado para especificar que este ponto no núcleo não faz parte da vizinhança morfológica. Por exemplo, aqui está uma especificação para um núcleo quadrado de largura 3, que pode ser usado para desfoque por convolução da imagem de um único pixel.
  magick pixel.gif   -morphology Convolve \
            "3:  0.3,0.6,0.3   0.6,1.0,0.6   0.3,0.6,0.3" \
                                         -scale 800%  k_user_3.gif

[IM Output]
Com um único pixel, Convolve funciona quase da mesma forma que Dilate; no entanto, Convolve usa os valores do núcleo, expandindo e somando os valores vizinhos. Dilate, por outro lado, geralmente funciona usando uma forma ligado/desligado (booleana) e o máximo de todos os vizinhos. No entanto, quando aplicado em um único pixel isolado com uma forma booleana, você obtém o mesmo resultado. Observe como você pode adicionar espaçamento extra (ou até quebras de linha) à string de entrada para separar as linhas individuais da definição do núcleo retangular. E aqui eu defini uma área retangular 5×3, mas uso os valores especiais 'nan' (não é um número) para cortar os cantos e fazer um núcleo em forma oval... |

  magick pixel.gif   -morphology Dilate \
            "5x3: nan,1,1,1,nan   1,1,1,1,1   nan,1,1,1,nan " \
                                    -scale 800%   k_user_5x3.gif

[IM Output]
E, finalmente, aqui está um exemplo de especificação de uma vizinhança retangular que forma uma forma de 'L' ao redor da 'origem'. Usei '-' em vez de 'nan' para especificar as partes que não fazem parte do núcleo. Observe que a origem deste núcleo nem sequer faz parte de sua própria vizinhança; ela pode estar localizada em qualquer lugar dentro dos limites retangulares do núcleo. |

  magick pixel.gif   -morphology Dilate \
            "2x3+1+1:   1,-   1,-   1,1   "  -scale 800% k_lman.gif

[IM Output]
Como você pode ver, a especificação de núcleo do usuário é muito flexível, permitindo que você especifique praticamente qualquer tipo de núcleo que quiser, seja um núcleo de convolução com muitas frações, ou um núcleo com forma com elementos 'fora da vizinhança', para métodos morfológicos.

Converter uma Imagem em um Núcleo do Usuário

Para facilitar a geração de núcleos DIY, você pode usar o script "[image2kernel](../static/img/scripts/image2kernel)" para criar núcleos. Por exemplo, aqui eu converto uma pequena bandeira ( ) em um arquivo de dados de núcleo do usuário ("[flag_kernel.dat](../static/img/morphology/flag_kernel.dat)") e, em seguida, o uso para dilatar uma imagem com alguns pixels nela.

  magick -size 80x80 xc:black -fill white \
          -draw 'point 20,15 point 55,30 point 40,60'  points_pixels.gif
  image2kernel -qgm flag.gif flag_kernel.dat

  magick points_pixels.gif \
             -morphology Dilate @flag_kernel.dat \
           flagged_points.gif

[IM Output] [IM Output] [IM Output]

Veja também Gerando uma Imagem do Núcleo abaixo, que pode gerar imagens (ou gerar versões ampliadas e bonitas) de um núcleo. Essa técnica também é discutida em Alternativas para Desenhar Símbolos.

Iterando (Repetindo) Operações de Morfologia

Como você viu, você pode gerar um núcleo maior, de modo a aplicar uma morfologia sobre uma vizinhança maior. No entanto, na maioria dos casos, uma alternativa mais rápida do que usar um núcleo maior é simplesmente repetir (iterar ou fazer um laço) o operador de morfologia várias vezes. Isso significa que o efeito desse operador será levado mais adiante, tendo o mesmo efeito básico que usar um núcleo maior, mas sem o custo computacional adicional de usar um núcleo maior. Por exemplo, aqui está uma dilatação de um único pixel usando um núcleo 'Diamond:3'... |

  magick pixel.gif  -morphology Dilate Diamond:3 -scale 800% k_diamond_x3.gif

[IM Output]
Mas você também pode obter o mesmo resultado usando um núcleo 'Diamond' menor (raio 1) três vezes... |

  magick pixel.gif  -morphology Dilate Diamond \
                     -morphology Dilate Diamond \
                     -morphology Dilate Diamond  -scale 800% k_diamond_x3.gif

[IM Output]
Você ainda está usando apenas um núcleo 3x3 muito pequeno, mas repetindo a operação morfológica básica três vezes para produzir o mesmo efeito que se estivesse usando um núcleo maior. Na verdade, repetir núcleos pequenos assim é bem mais rápido do que usar o núcleo muito maior. | _Um grande núcleo 'Diamond:3' tem 81 elementos a serem processados por pixel na imagem. Mas repetir um núcleo 'Diamond' menor 3 vezes tem 3×9, ou 27 elementos de núcleo para processar por pixel na imagem. Neste caso, é 3 vezes mais rápido.

Esse aumento de velocidade não é muito neste caso, mas a economia é muito maior à medida que o tamanho dos núcleos aumenta._
---|---
Como repetir uma operação morfológica é muito comum, em vez de repetir a operação várias vezes, você pode simplesmente pedir ao IM para fazer o laço ou iterar a operação, esse número de vezes. |

  magick pixel.gif   -morphology Dilate:3 Diamond -scale 800%  k_diamond_3.gif

[IM Output]
Observe a diferença entre este e o primeiro exemplo. Tudo o que aconteceu é que movemos o ':3' de ser o raio do núcleo 'Diamond' para o número de vezes que o método 'Dilate' deve ser usado. Usar uma 'iteration ' para tornar a vizinhança efetiva maior funciona para a maioria dos núcleos 'circulares' ou 'convexos', como um 'Square' e um 'Diamond'. Mas não funciona para todos os tipos de núcleo. Por exemplo, para um núcleo não convexo como um 'Plus' (que não é uma forma 'côncava'), produzirá resultados muito incomuns. Por exemplo, isto não é o mesmo que passar de 'Plus' (raio 2) para um núcleo 'Plus:4' com o dobro do tamanho... |

  magick pixel.gif   -morphology Dilate:2 Plus  -scale 800%  k_plus_2.gif

[IM Output]
Observe que, se você usar uma contagem de 'iteration ' de '0', a morfologia não fará nada. Esta é uma maneira útil de 'desligar' o operador quando você não quer que ele faça nada, mas não quer removê-lo da linha de comando. Veja Exibição de Saída Detalhada, abaixo, para outro uso de uma contagem de iteração zero. Usar um valor especial de '-1' repetirá a operação até que nenhuma mudança seja mais vista na imagem. Ou seja, a imagem atinge um ponto de 'convergência'. Isso, no entanto, é perigoso, pois em algumas situações pode levar a operações de execução muito longa. Para uma operação como 'Dilate', por exemplo, ela simplesmente repetiria a dilatação até que toda a imagem estivesse completamente preenchida de branco. Basicamente produzindo uma espécie de 'preenchimento por inundação' descontrolado (veja o próximo exemplo abaixo). Iterar um núcleo 'Disk' para produzir um efeito de vizinhança maior também não é geralmente recomendado. Isso porque o núcleo 'Disk' se torna uma forma de disco mais precisa à medida que o raio aumenta, ao passo que um disco iterado ampliará não apenas a forma, mas também os erros (forma não circular) do núcleo. Assim, pode ser melhor usar um raio maior (o que é mais lento) do que iterar a operação (o que produz um disco mais distorcido). No entanto, à medida que o raio de um 'Disk' se torna realmente grande, uma combinação de raio e múltiplas iterações poderia produzir um resultado mais rápido, mas ainda aceitável. Cautela e alguma experimentação com sua situação específica podem ser necessárias.

Saída Detalhada das Mudanças

Se você quiser ver os resultados de iterar (repetir) uma operação morfológica, você pode definir a opção "[-define debug=True](https://imagemagick.org/command-line-options/#define)", que ativa o Controle Operacional Detalhado. À medida que o operador de morfologia itera, ele relatará uma contagem crescente da iteração e quantos pixels na imagem foram alterados por cada passo iterado. A saída vai para o erro padrão, de modo que você ainda pode canalizar (pipe) os resultados da imagem.. Por exemplo, vamos aplicar 'Dilate' na imagem de um único pixel usando o maior núcleo 'Octagon' até que toda a imagem tenha sido preenchida de branco e nenhuma mudança adicional possa ser feita na imagem. Lembre-se de que um limite de iteração de '-1' significa iterar para sempre, ou até que nenhuma mudança seja mais vista. | |

  MAGICK_THREAD_LIMIT=1 \
    magick pixel.gif -define debug=true -morphology Dilate:-1 Octagon \
            -scale 800% iterate_infinite.gif

[IM Output]
| [IM Text]


Observe o número de mudanças feitas em cada iteração. Inicialmente, havia 20 pixels convertidos de preto para branco. Depois, mais 48 na iteração seguinte, e assim por diante. Esse número geralmente cresce à medida que a borda da forma resultante fica maior, mas depois começou a diminuir novamente à medida que a forma atinge o limite da imagem. Na quarta dilatação, os últimos 4 pixels (nos cantos da imagem) foram preenchidos. Na última dilatação (iteração 5), a imagem já estava completamente preenchida, de modo que nenhuma mudança adicional em qualquer pixel foi realizada. Como nenhuma mudança foi feita, a morfologia aborta automaticamente, fornecendo um número final de mudanças para esta etapa da operação. Usar uma iteração infinita de '-1' tem, sim, um limite interno. Atualmente, ele é definido como a largura ou altura máxima da imagem. Isso é feito para evitar que o ImageMagick entre em um laço sem fim. Tipicamente, no entanto, as operações terminam muito antes de esse limite interno ser atingido. Alguns métodos de morfologia são, na verdade, definidos em termos de métodos mais simples e primitivos. Por exemplo, um método '[Smooth](#smooth)' é um desses métodos compostos. A saída de "[-define](https://imagemagick.org/command-line-options/#debug)" que é gerada ao usar este método mostra os múltiplos passos internos que compõem o seu processamento.

  MAGICK_THREAD_LIMIT=1 \
    magick man.gif -define debug=true -morphology Smooth:2 Diamond null:

[IM Text]

Se você observar, poderá ver que o '[Smooth](#smooth)' na verdade itera 4 métodos mais primitivos e, assim, processa internamente a imagem 8 vezes para realizar a operação solicitada. Cada linha consiste em...

Smooth:_i_._s_ isto mostra o método de morfologia de alto nível que está sendo aplicado à imagem, e a contagem de iteração 'i ' e o 'estágio' primitivo 's ', que o IM está processando. Para o método 'Smooth', esse primeiro número é sempre '1', pois a 'contagem de iteração' fornecida pelo usuário é aplicada no método primitivo de nível inferior. Em outros métodos, a iteração fornecida pelo usuário pode ser aplicada neste nível superior em vez de no nível inferior. O segundo número de 'estágio' é a contagem de 'estágio' primitivo que está sendo aplicada. O próprio 'Smooth' é composto de quatro desses estágios, pois implementa os métodos compostos '[Open](#open)' e '[Close](#close)'. Dilate*:_i_._k_ Este é o método primitivo que está sendo aplicado. O primeiro número i é novamente a contagem de iteração fornecida pelo usuário (se estiver sendo aplicada aqui). O segundo número 'k ' é o núcleo que está sendo aplicado pelo método de morfologia primitivo. Como há apenas um núcleo, ele é sempre zero neste caso. (Veja Tratamento de Múltiplos Núcleos abaixo) O '*' indica que o núcleo foi refletido (ou rotacionado 180 graus em torno da origem) antes de ser aplicado pela primitiva morfológica. Isso é necessário para alguns métodos morfológicos compostos; neste caso, o método '[Close](#close)' sempre usa um núcleo refletido em seu uso dos métodos primitivos '[Dilate](#dilate)' e '[Erode](#erode)'. #6 => Changed 311 Total 637 Este é um relatório dos resultados de aplicar a primitiva de morfologia à imagem. O número 'hash' é uma contagem incremental do número de passagens primitivas pela imagem. Isso dá uma boa ideia de quão computacionalmente intensivo é um operador de morfologia composto. Você então obtém o número real de pixels que foram alterados de alguma forma durante essa passagem. Se esta for a última de várias iterações para esta primitiva e núcleo específicos, uma contagem total de modificações de pixels também é exibida. Isso, no entanto, não reflete o número total de pixels alterados do início ao fim, apenas as mudanças causadas pela iteração de baixo nível da operação específica de primitiva e núcleo. Alguns pixels podem mudar várias vezes por algumas primitivas morfológicas.

A partir do que foi dito acima, você pode ver que, internamente, o IM pode ter quatro laços de processamento sendo aplicados para processar totalmente um dado método de morfologia. No entanto, tipicamente, a maioria desses laços é aplicada apenas uma vez. | _Atenção: o número de pixels que mudam pode não estar correto em máquinas que executam um ambiente multithread em máquinas modernas de múltiplos núcleos! Ele só tem precisão garantida quando executado em um ambiente de thread única. Classifico isso como um bug, mas não um vital.

Se isso for um problema, então certifique-se de definir a variável de ambiente "MAGICK_THREAD_LIMIT" com um valor de '1' para essa execução específica do ImageMagick, como fiz nos dois últimos exemplos acima.

A partir do IM v6.8.4, você não precisa mais da configuração de ambiente "MAGICK_THREAD_LIMIT", pois as contagens são tratadas corretamente em um ambiente multithread.

_
---|---

Exibindo o Núcleo Gerado (para fins de depuração)

Se você quiser realmente ver os valores que foram usados para definir um núcleo específico que foi gerado, você pode definir uma configuração especial...

    -define morphology:showkernel=1
    -define convolve:showkernel=1

Qualquer um dos defines acima faz com que o IM produza (no 'erro padrão') todas as informações sobre um núcleo gerado, depois que o núcleo tiver sido completamente processado em preparação para seu uso. (Veja Escalonamento do Núcleo de Convolução). Por exemplo, aqui estão os valores reais do núcleo interno '[Disk](#disk)'...

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 Disk null:

[IM Text]

Observe que, como eu só queria mostrar o núcleo, na verdade não me importo nem um pouco com o processamento da imagem. Assim, defini a 'iteration ' da morfologia como '0' (não fazer nada) e também descarto qualquer resultado de imagem usando um formato de arquivo de saída null:. O valor especial de ponto flutuante 'nan' acima tem o mesmo significado que ao inserir um Núcleo Definido pelo Usuário. Ele significa 'Not A Number' (Não é um Número) e marca as partes de um núcleo que não fazem parte da vizinhança. Esses valores são ignorados por todas as operações morfológicas. Aqui está outro exemplo. Desta vez, de um núcleo de convolução '[Comet](convolve.html#comet)'.

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 Comet:0x2  null:

[IM Text]

Isto é, na verdade, metade de uma Curva Gaussiana Unidimensional (sigma de 1.0), e pode ser uma boa maneira de extrair tal curva do ImageMagick. Observe também que a 'origem' deste núcleo específico (o pixel que ele afeta) está fora do centro (localizada em +0+0), o que não é muito comum. O tamanho e o espaçamento dos valores na saída podem ser controlados pelo especial Controle Operacional de Precisão. Ele foi adicionado ao IM aproximadamente na mesma época que o operador de morfologia. Por exemplo, aqui está uma repetição do exemplo anterior, mas usando "[-precision](https://imagemagick.org/command-line-options/#precision)" para limitar o número de dígitos significativos do padrão de 6 para 3.

  magick xc: -define morphology:showkernel=1 -precision 3 \
          -morphology Dilate:0 Comet:0x2  null:

[IM Text]

| A opção "[-precision](https://imagemagick.org/command-line-options/#precision)" foi adicionada ao ImageMagick versão 6.5.9-1 durante o ciclo de desenvolvimento da morfologia. Assim, se a morfologia estiver disponível, a precisão também pode ser considerada disponível.
---|---

Gerando uma Imagem do Núcleo

Para facilitar a visualização dos núcleos, em vez de usar Dilatação ou Convolução em uma imagem de um único pixel para ver o que ela produz, criei um script especial chamado "[kernel2image](../static/img/scripts/kernel2image)". Este script extrai a saída exata de Show Kernel e a converte em uma imagem do núcleo. O script "[kernel2image](../static/img/scripts/kernel2image)" tem muitas opções, desde produzir a imagem bruta do núcleo (o padrão) até especificar a quantidade de escalonamento, os espaços entre pixels, a montagem, a rotulagem e até a coloração da 'imagem de núcleo' resultante. O script torna muito mais fácil visualizar e entender os vários núcleos, e é usado extensivamente para gerar as imagens de núcleo exibidas nestas páginas de exemplo. Por exemplo, aqui está como gerei a imagem do núcleo "[Octagon](#octagon)". |

  kernel2image -10.1  -m "Octagon"  kernel_octagon.gif

[IM Output]
A opção especial '-10.1' significa escalonar todos os pixels para 10 pixels de tamanho, mas também incluir um espaço de 1 pixel entre esses pixels. Se o núcleo for escalonado o suficiente, a 'origem' do núcleo será marcada com alguns círculos desenhados. O '-m' então especifica que eu quero criar uma Montagem da imagem com um rótulo de identificação do núcleo "[Octagon](#octagon)" extraído, e efeitos de sombra. E aqui eu gero uma 'imagem de núcleo' do núcleo definido pelo usuário em forma de 'L' que usei acima. |

  kernel2image -20.2 -ml 'L-Shape'  "3: 1,-,-  1,-,-  1,1,- " kernel_lman.gif

[IM Output]
Se você quiser criar um núcleo a partir de uma imagem existente, um script "[image2kernel](../static/img/scripts/image2kernel)" pode ser usado para criar um arquivo de dados de núcleo a partir de uma imagem. Este script normalmente aceita uma imagem em tons de cinza, mas se uma imagem multicolorida for fornecida, cada canal da imagem é convertido como um arquivo de dados de núcleo separado. Aqui eu crio os dados de núcleo do usuário a partir de uma pequena imagem de bandeira ( ) e, em seguida, uso "[kernel2image](../static/img/scripts/kernel2image)" para converter esses dados novamente em uma 'imagem de núcleo' ampliada para exibição. |

   image2kernel -qgm flag.gif  flag_kernel.dat
   kernel2image -6.1 -m  -ml "Flag"  @flag_kernel.dat  kernel_flag.gif

[IM Output]
OBSERVAÇÃO: eu poderia ter gerado a versão 'ampliada' da imagem pequena de forma mais direta com um script semelhante "[enlarge_image](../static/img/scripts/enlarge_image), mas isso estaria exibindo a imagem, e não os Dados de Núcleo, "[flag_kernel.dat](../static/img/morphology/flag_kernel.dat)".

Tratamento de Lista de Múltiplos Núcleos

Gerando Múltiplos Núcleos

A partir do IM v6.6.2-0, você pode especificar múltiplos núcleos que serão aplicados à imagem um de cada vez. Para especificar múltiplos núcleos, você simplesmente anexa cada definição de núcleo, separada por um ponto e vírgula ';'. Um ponto e vírgula final no fim é opcional. Por exemplo, aqui defino uma lista de núcleos especial contendo uma lista que pode ser usada para a 'correspondência de padrões' de pixels de canto.

     3: 0,0,- 0,1,1 -,1,-  ;
     3: -,0,0 1,1,1 -,1,-  ;
     3: -,1,- 1,1,0 -,0,0  ;
     3: -,1,- 0,1,1 0,0,-  ;

Pontos e vírgulas extras (';') não importam, desde que pelo menos um seja fornecido entre as especificações de núcleo. Nem o espaço em branco extra (incluindo quebras de linha) em qualquer especificação de núcleo. Aqui está uma Saída de Show Kernel desta definição.

  magick xc: -define morphology:showkernel=1 -morphology Dilate:0 \
             " 3: 0,0,- 0,1,1 -,1,-  ;
               3: -,1,- 1,1,0 -,0,0  ;
               3: -,0,0 1,1,1 -,1,-  ;
               3: -,1,- 0,1,1 0,0,-  ; " null:

[IM Text]

E aqui está uma Imagem de Núcleo desses quatro núcleos usando o script especial "[kernel2image](../static/img/scripts/kernel2image)".

   kernel2image -20.2 -ml '' -mt x1 \
             " 3: 0,0,- 0,1,1 -,1,-  ;
               3: -,1,- 1,1,0 -,0,0  ;
               3: -,0,0 1,1,0 -,1,-  ;
               3: -,1,- 0,1,1 0,0,-  ; "  kernel_multi.gif

[IM Text]

Agora, esta definição na verdade consiste em apenas um núcleo que foi expandido para formar um conjunto de 4 núcleos, cada um rotacionado em 90 graus. NOTA: Esta definição é quase equivalente ao padrão especial de correspondência de padrões '[Corners](#corners)' (veja abaixo), exceto que se limita aos cantos da forma real, e não a qualquer canto, seja de fundo ou de primeiro plano.

Expandindo para uma Lista de Núcleos Rotacionados

A partir do IM v6.2.2-0 você pode pedir ao IM que expanda um único núcleo em uma lista de núcleos rotacionados usando uma de três flags especiais, tanto em núcleos nomeados quanto definidos pelo usuário. As três flags especiais são...

'@ ' Rotaciona ciclicamente núcleos 3x3 em incrementos de 45 graus, produzindo uma lista de até 8 núcleos rotacionados. (mnemônico: '@' é circular)
'> ' Rotaciona (apenas núcleos quadrados ou lineares) em incrementos de 90 graus. (mnemônico: o '>' é um ângulo reto).
'< ' Também produz rotações de 90 graus, mas em uma sequência 'espelhada' (ângulos de rotação de 0, 180, -90, +90 ). Esta forma especial de expansão de rotação funciona melhor para métodos de morfologia como '[Thinning](#thinning)'. (mnemônico: '<' é um espelho de um ângulo reto).

Por exemplo, aquele mesmo núcleo acima pode ser especificado de forma mais simples como...

    ' 3>:  0,0,-  0,1,1  -,1,- '

Isto define um núcleo, e a flag '>' então diz ao IM que o expanda em uma lista rotacionada de 90 graus. E aqui está uma imagem da lista multi-núcleo resultante

   kernel2image -20.2 -ml '' -mt x1 \
                '3>: 0,0,- 0,1,1 -,1,- '  kernel_rotated_list.gif

[IM Text]

E aqui eu rotaciono um núcleo 3x3 em uma rotação 'cíclica' de 45 graus, expandindo-o para uma lista de 8 núcleos.

   kernel2image -20.2 -ml '' -mt x1 \
                '3@: -,1,- -,0,- 1,1,1 '  kernel_rotated_list2.gif

[IM Text]

Você também pode fazer o mesmo para qualquer núcleo nomeado 'único' embutido no IM, usando as mesmas flags na seção de argumentos desses núcleos. Por exemplo, aqui eu pego um núcleo '[Blur](convolve.html#blur)' simétrico e o expando em uma lista rotacionada de 90 graus usando uma flag '>'.

   kernel2image -12.1 -n -ml ''   "Blur:0x1>"  blur_kernels.gif

[IM Text]

Observe que apenas 2 núcleos foram gerados, pois um terceiro núcleo apenas reproduziria exatamente o primeiro núcleo. Isso é detectado e a geração de núcleos rotacionados é interrompida. No entanto, se a 'origem' estiver descentralizada, então a sequência completa de 4 núcleos rotacionados teria sido gerada, pois embora a 'forma' do núcleo coincida, a localização da origem não seria a mesma. Muitas definições de núcleo embutidas geram automaticamente uma lista multi-núcleo, de modo que você não precisa especificar nenhuma flag para esse fim. Ou seja, a expansão de rotação também é 'embutida' na definição específica do núcleo. Tais núcleos normalmente também fornecem 'subtipos' da definição de núcleo único original, de modo que você pode escolher núcleos específicos para propósitos específicos.

Mesclagem de Resultados de Múltiplos Núcleos: Reiterar ou Compor

Quando você definiu múltiplos núcleos, o método de morfologia também precisa saber como deve mesclar os resultados gerados por múltiplos núcleos. Isso pode ser controlado pelo uso de um Define global...

    -define morphology:compose={_método_de_composição_}

O padrão para a maioria dos métodos de morfologia é uma configuração de 'None'. Isso significa que, após cada núcleo ter sido aplicado usando o método de morfologia fornecido, a imagem resultante deve ser usada como fonte para o próximo núcleo. Ou seja, simplesmente 'reitera ' ou reutiliza a imagem resultante da aplicação de um núcleo, para o próximo núcleo. Por exemplo, se eu fizer uma Convolve usando 2 núcleos '[Blur](convolve.html#blur)' rotacionados de 90 graus, obtemos o seguinte.

  magick pixel.gif  -morphology Convolve "Blur:0x1>" \
          -auto-level  blur_re-iterate.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Como você pode ver, ambos os núcleos foram aplicados à imagem um após o outro, de modo que cada núcleo trabalha com o resultado do núcleo anterior. Ou seja, ele 'reitera ' o resultado de um núcleo com o próximo núcleo, em sequência. Isto é equivalente a fazer os dois passos assim.

  magick pixel.gif -morphology Convolve "Blur:0x1" -auto-level blur_1.gif
  magick blur_1.gif -morphology Convolve "Blur:0x1+90" \
          -auto-level blur_re-iterate.gif

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Na verdade, é assim que o Operador Blur realmente funciona, para gerar desfoques de imagem mais rapidamente. Veja Núcleos Gaussian vs Blur, que demonstra esse uso de forma mais completa.
Ao definir o '{_método_de_composição_}' para qualquer método diferente de 'None', a operação NÃO será reiterada. Em vez disso, cada núcleo será aplicado à imagem original , e as imagens resultantes serão então Compostas juntas usando o método '{_método_de_composição_}' especificado. Por exemplo, se eu usar um método de morfologia '[Lighten](compose.html#lighten)' para gerar uma União dos resultados separados, obteríamos..

  magick pixel.gif -define morphology:compose=Lighten \
                     -morphology Convolve "Blur:0x1>" \
          -auto-level blur_union.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Isto foi equivalente a fazer...

  magick pixel.gif -morphology Convolve "Blur:0x1"  -auto-level blur_1.gif
  magick pixel.gif -morphology Convolve "Blur:0x1+90" -auto-level blur_2.gif
  magick blur_1.gif blur_2.gif -compose Lighten -composite \
          -auto-level blur_union.gif

[IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output]

Se você não tem certeza do que o IM está realmente fazendo durante uma morfologia, ative a Saída Verbosa de Mudanças. Por exemplo, aqui está a saída verbosa de reiterar com cada núcleo...

  magick pixel.gif -define morphology:compose=None \
         -define debug=true -morphology Convolve "Blur:0x1>" null:

[IM Text]

E aqui está a saída verbosa de uma União (Composição Lighten) de cada resultado de núcleo....

  magick pixel.gif -define morphology:compose=Lighten \
         -define debug=true -morphology Convolve "Blur:0x1>" null:

[IM Text]

Ambas mostram claramente o que o ImageMagick está fazendo para gerar a imagem final. O número após o ponto decimal representa o número do núcleo que está sendo aplicado, em cada passo. Seguido, ao final, de como ele compõe as imagens juntas de acordo com a configuração 'morphology:compose'. Muitos dos Métodos de Composição Matemática e suas operações equivalentes do tipo Teoria dos Conjuntos também podem ser usados para mesclar os resultados da aplicação de cada núcleo à imagem original. Em resumo, esta configuração define como os núcleos individuais de uma lista multi-núcleo serão aplicados à imagem dada. O padrão é o valor de composição 'None', o que significa simplesmente 'reiterar' os resultados; caso contrário, ele mesclará todos os resultados com base no método de composição fornecido.


Métodos Básicos de Morfologia

Os Métodos Morfológicos são uma técnica de processamento de imagem para a localização e análise de formas de objetos dentro de uma imagem. Expandir, encolher, localizar formas específicas, e assim por diante. Foi originalmente desenvolvido com imagens binárias (preto e branco puros) em mente e, por causa disso, é mais comumente aplicado a imagens Limiarizadas contendo formas simples em preto e branco. Por convenção, o branco em uma imagem binária representa o primeiro plano, enquanto o preto representa o fundo. Os nomes dos métodos são, portanto, descritos de acordo com esta convenção. Ou seja, isto não quer dizer que os operadores não funcionem com imagens em tons de cinza ou, em alguns casos, com imagens coloridas, mas seu propósito original era lidar com formas binárias. Os Núcleos de Forma básicos já vistos acima são as 'formas' de definição de vizinhança mais comumente usadas para métodos morfológicos. Tais núcleos são frequentemente chamados de 'Elementos Estruturantes', pois são normalmente usados para determinar a estrutura das formas dentro da imagem.

Erode ( )

Como o nome indica, o método '**Erode**' 'corrói' a forma branca, a partir de qualquer pixel de fundo, tornando-a menor. Você também pode pensar nele como expandindo as áreas pretas da imagem. Por exemplo, aqui está uma forma binária simples semelhante a um 'homem' que foi erodida usando um núcleo '[Octagon](#octagon)'.

  magick man.gif   -morphology Erode Octagon  erode_man.gif

[IM Output] [IM Output] [IM Output]

Seu efeito básico é tornar mais finas quaisquer protuberâncias ou pontas que a imagem possa ter, ou removê-las completamente, mas também torna maiores quaisquer buracos que estejam presentes (como o causado pelo 'braço' desta imagem) na imagem. Em geral, o tamanho do núcleo determina quantos pixels são removidos.

Dilate ( )

O método '**Dilate**' é o dual do 'Erode'. Ele expande as formas brancas, tornando uma forma maior de acordo com o núcleo (e o número de iterações) especificado. Claro que isso também significa que ele 'erodirá' as áreas pretas da imagem.

  magick man.gif   -morphology Dilate Octagon  dilate_man.gif

[IM Output] [IM Output] [IM Output]

Observe como a forma não apenas se torna maior, mas seu contorno se torna mais suave. A grande reentrância entre as 'pernas' foi preenchida, assim como o pequeno 'buraco' de um único pixel que a imagem continha. O tamanho e a forma do núcleo determinam quantos pixels são adicionados ao redor das bordas da imagem. O 'Dilate' e o 'Erode' são duais. Ou seja, (pelo menos com um núcleo simétrico) ao inverter a imagem antes e depois de aplicar o método morfológico, você na verdade realizará a outra forma do operador. Por exemplo, aqui eu realizo uma erosão usando 'Dilate' nas Imagens Invertidas. |

  magick man.gif -negate \
             -morphology Dilate Octagon   -negate dilate_man_neg.gif

[IM Output]

Open ( )

Aqui está o efeito do método '**Open**', mas desta vez usando um núcleo '[Disk](#disk)' muito maior.

  magick man.gif   -morphology Open Disk  open_man.gif

[IM Output] [IM Output] [IM Output]

Como resultado, você verá que o 'Open' suavizou o contorno, arredondando quaisquer pontas afiadas e removendo quaisquer partes que sejam menores que a forma usada. Ele também desconectará ou 'abrirá' quaisquer pontes finas. No entanto, ele não remove nenhum 'buraco' ou lacuna que possa estar presente na imagem, como entre as 'pernas' das formas. Além disso, ele não torna o tamanho básico do 'núcleo' da forma maior ou menor. Em termos reais e concretos, o que ele faz é '[Erode](#erode)' uma imagem e depois '[Dilate](#dilate)' novamente usando o mesmo núcleo que foi fornecido

  magick man.gif         -morphology Erode  Disk  open_erode.gif
  magick open_erode.gif  -morphology Dilate Disk  open_man_2.gif

[IM Output] [IM Output] [IM Output]

Observe que realizar um 'Open' em uma forma que já foi aberta, com o mesmo núcleo, não resultará em nenhuma mudança adicional na forma. Por exemplo...

  magick open_man.gif  -morphology Open Disk  open_man_twice.gif

[IM Output] [IM Output] [IM Output]

Ou seja, repetir uma operação 'Open', com o mesmo núcleo, não tem efeito sobre o resultado. Por causa disso, qualquer contagem de iteração fornecida será aplicada aos submétodos individuais de dilatação e erosão, e não ao método como um todo, de modo que a iteração possa ser usada para 'expandir' o núcleo efetivo, em vez de repetir inutilmente a operação composta. Ou seja, uma iteração 'Open:2 ' será na verdade aplicada como um 'Erode:2', seguido de um 'Dilate:2' à imagem. Isto tem o efeito geral de tornar maior a 'vizinhança' efetiva definida pelo núcleo. |

  magick man.gif   -morphology Open:2  Disk  open_man_x2.gif

[IM Output]
Aqui você pode ver que a vizinhança maior resultante fez com que tanto a 'cabeça' quanto os 'pés' do homem, suas extremidades, fossem removidas. O corpo principal da forma permanece basicamente intacto, embora também com aparência mais suave, enquanto a lacuna entre as pernas permanece intocada. Este é o mesmo efeito de dobrar o tamanho do núcleo, embora sua forma exata possa não ser exatamente a mesma de um núcleo com o dobro do raio.

Close ( )

O uso básico do método '**Close**' é reduzir ou remover quaisquer 'buracos' ou 'lacunas' com cerca do tamanho do 'Elemento Estruturante' do núcleo. Ou seja, 'fechar' partes do fundo que tenham aproximadamente esse tamanho.

  magick man.gif    -morphology Close Disk   close_man.gif

[IM Output] [IM Output] [IM Output]

O efeito básico deste operador é suavizar o contorno da forma, preenchendo (fechando) quaisquer buracos e reentrâncias. Ele também formará 'pontes' de conexão com outras formas que estejam próximas o suficiente para que o núcleo toque ambas simultaneamente. Mas ele não torna o tamanho básico do 'núcleo' da forma maior ou menor. Em termos reais e concretos, o que ele faz é '[Dilate](#dilate)' a imagem e depois '[Erode](#erode)' novamente usando o mesmo núcleo que foi fornecido, fazendo com que a imagem se torne primeiro maior, depois menor. Esta é a ordem oposta do que o '[Open](#open)' faz.

  magick man.gif           -morphology Dilate Disk  close_dilate.gif
  magick close_dilate.gif  -morphology Erode  Disk  close_man_2.gif

[IM Output] [IM Output] [IM Output]

O resultado é que os pontos externos da imagem serão deixados como estão, mas quaisquer 'baías' serão suavizadas e engrossadas, e 'buracos' e 'lacunas' serão fechados. Objetos desconectados que estão muito próximos podem se tornar ligados. Assim como com o '[Open](#open)', repetir o método '[Close](#close)' com o mesmo núcleo não faz nenhuma mudança adicional na imagem. Usar uma 'iteração ' com o operador irá, no entanto, repetir os submétodos internos, de modo a produzir um efeito de arredondamento mais forte, semelhante ao uso de um núcleo maior. E assim como com os métodos '[Dilate](#dilate)' e '[Erode](#erode)', os métodos '[Open](#open)' e '[Close](#close)' são duais. Você pode reproduzir o efeito do outro 'dual' Invertendo a imagem antes e depois da operação. |

  magick man.gif   -negate -morphology Close Disk -negate   close_man_neg.gif

[IM Output]

Smooth

O método '**Smooth**' aplica um '[Open](#open)' seguido de um '[Close](#close)' da forma, o que primeiro remove quaisquer 'objetos pequenos' e depois preenche quaisquer 'buracos' ou 'lacunas' com cerca do tamanho do 'Elemento Estruturante' do núcleo. Aqui suavizamos a imagem usando um núcleo '[Octagon:3](#octagon)' de tamanho médio. |

  magick man.gif  -morphology Smooth  Octagon:3  smooth_man.gif

[IM Output]
Como você pode ver, todas as 'reentrâncias', 'lacunas', 'buracos' e 'pontas' foram suavizadas e arredondadas de acordo com o tamanho e a forma do núcleo. O operador '[Smooth](#smooth)' também é frequentemente repetido com Elementos Estruturantes de tamanho lentamente crescente, de modo a remover lentamente o ruído das imagens. Se as partes removidas forem preservadas, você obtém uma 'decomposição' morfológica da imagem que pode ser usada para estudos adicionais. Veja Granularidade abaixo. O método é particularmente bom para limpar documentos digitalizados. Observe que isto está na verdade aplicando 4 operações 'primitivas' separadas à imagem original. É, portanto, 4 vezes mais lento do que apenas um simples '[Erode](#erode)' ou '[Dilate](#dilate)'.

Morfologia em Tons de Cinza Plana

Embora essencialmente todos os quatro Métodos Morfológicos Básicos, e os posteriores que são definidos em termos desses quatro métodos, sejam especificamente projetados para funcionar com imagens binárias, eles podem ser aplicados tanto a imagens em tons de cinza quanto a imagens coloridas (embora imagens coloridas possam gerar alguns efeitos de cor estranhos). Exemplo Prático de Operação em Tons de Cinza Desejado Aqui No entanto, o próprio núcleo sempre será considerado como uma vizinhança simples 'ligada' ou 'desligada'. Qualquer valor de núcleo que seja 'nan' ou menor que '0.5' será considerado fora da 'vizinhança' que ele define. Em resumo, os operadores acima aplicam um núcleo 'plano' sem qualquer 'altura' ou características '3-dimensionais', mas ainda podem ser aplicados a imagens em tons de cinza.

Morfologia Verdadeira em Tons de Cinza ou 3-dimensional

A morfologia verdadeira em tons de cinza ou 3-dimensional (como uma biblioteca colocou) na verdade adicionará ou subtrairá os valores encontrados no núcleo dos pixels vizinhos na imagem, antes de procurar pelos valores máximo/mínimo como resultado. O que isso significa é que ela trata uma imagem em tons de cinza como um 'campo de altura' de um objeto de morfologia 3-dimensional e a forma em tons de cinza do núcleo como a forma de suavização para ajustar esse campo de altura. Embora os detalhes de implementação da morfologia verdadeira em tons de cinza sejam bem documentados, seu uso em situações práticas não é. Ou seja, eu não encontrei nenhum exemplo útil de uso da morfologia verdadeira em tons de cinza além de 'núcleos de forma plana', a não ser um comentário sobre seu uso em processamento 'fotométrico'. Por causa disso, eu não implementei a morfologia verdadeira 3-dimensional em tons de cinza. No entanto, se as pessoas realmente precisarem de tais operadores morfológicos não planos em tons de cinza, por favor me avisem, e eu implementarei os operadores apropriados. Observe que o método especial '[Distance](#distance)' (veja abaixo) é na verdade semelhante ao modo como a morfologia verdadeira em tons de cinza funciona, no sentido de que ele adiciona o valor do núcleo a cada valor de pixel, antes de tomar o menor valor 'mínimo'. No entanto, este método não corresponde nem à definição de erosão 3D (subtrair e tomar o mínimo) nem à de dilatação (adicionar e tomar o máximo). Ele é, no entanto, muito intimamente relacionado, e provavelmente poderia ser implementado usando esses métodos.

Variante de Intensidade para Imagens Coloridas

Como os quatro métodos acima são métodos de Canal em tons de cinza, usá-los em imagens coloridas pode gerar efeitos de cor deslocados, onde um canal é modificado, mas outro não. Eles realmente não são projetados para uso com imagens coloridas multicanal, apenas com imagens em tons de cinza e binárias. O resultado é que, para imagens coloridas, as cores ficam distorcidas, tornando-se um tom mais claro ou mais escuro dependendo da operação. Com isso em mente, criei versões 'de Intensidade' desses métodos. 'ErodeIntensity', 'DilateIntensity', 'OpenIntensity', 'CloseIntensity'. Estas comparam os pixels dentro da 'vizinhança' definida e substituem a cor do pixel atual de acordo com a intensidade dos pixels. Ou seja, o pixel de cor inteiro é copiado, e não apenas os valores de canal individuais. Como resultado...

As Variantes de Intensidade não geram nenhuma cor 'nova' nas imagens.

Por causa de sua natureza, os Métodos de Intensidade ignorarão completamente a configuração atual de "[-channel](https://imagemagick.org/command-line-options/#channel)". Por exemplo, aqui eu uso as variantes binária e de intensidade da Morfologia '[Dilate](#dilate)' (expandir áreas brilhantes), na imagem embutida "rose:".

  magick rose: -morphology Dilate          Octagon:3  rose_dilate.gif
  magick rose: -morphology DilateIntensity Octagon:3  rose_dilate_intensity.gif

[IM Output] [IM Output] [IM Output]

Como você pode ver, o método '[Dilate](#dilate)' normal pode gerar diferentes tons em cada uma das grandes manchas dilatadas, pois cada canal é tratado separadamente. A segunda dilatação por intensidade, no entanto, preserva a cor completa das manchas mais brilhantes, expandindo-as de acordo com a forma booleana do núcleo. Os métodos de intensidade também possuem um esquema de nomenclatura abreviada, substituindo a palavra 'Intensity' apenas por um 'I'. Assim, aqui eu uso um método 'CloseIntensity', mas uso o nome abreviado 'CloseI'. Por exemplo, aqui estão os resultados do uso de cada uma das quatro variantes 'de Intensidade' na imagem embutida rose. |

  magick rose: -morphology ErodeI Octagon:3 rose_erode_intensity.gif

[IM Output]
|

  magick rose: -morphology DilateI Octagon:3 rose_dilate_intensity.gif

[IM Output]
|

  magick rose: -morphology OpenI Octagon:3 rose_open_intensity.gif

[IM Output]
|

  magick rose: -morphology CloseI Octagon:3 rose_close_intensity.gif

[IM Output]
Os dois últimos podem ser particularmente adequados como operador substituto do Operador Paint. Estes métodos são classificados como experimentais , e comentários ou problemas com seu uso são bem-vindos. Se eu não ouvir comentários, nada mais será adicionado!

Técnicas Alternativas de Morfologia Básica

Para pessoas com versões do IM anteriores à v6.5.9-0, você ainda pode implementar
alguns métodos básicos de morfologia.

Você pode gerar um núcleo que é todo composto de uns. Por exemplo, um array 7x7 de 1's
(raio=3), usando um sigma extremamente grande e especificando o raio apropriado,
usando um desfoque Gaussiano.

Assim
    -convolve 1,1,1,1,1,.....
para um total de 49 uns é equivalente a
    -gaussian-blur 3x65535

Isto permite que você gere um núcleo quadrado simples para métodos
morfológicos binários.

'Dilate'   para um núcleo quadrado 3x3 (raio=1) é, portanto,
    -gaussian-blur 1x65535 -threshold 0
'Erode'  é, portanto,
    -gaussian-blur 1x65535 -threshold 99.999%

Como mostrado anteriormente acima
'Open' é um 'Dilate' seguido de um 'Erode'
'Close' é um 'Erode' seguido de um 'Dilate'
e Smooth é um 'Open' seguido de um 'Close'

Núcleos quadrados maiores podem ser especificados usando raios maiores.

Infelizmente, as outras formas de núcleo embutidas não estão disponíveis,
sem usar o operador convolve para definir manualmente sua forma.

Isto também só funciona verdadeiramente para morfologia binária. Para implementar uma
morfologia plana em tons de cinza, você precisará usar uma técnica diferente de
gerar uma imagem separada para cada pixel no núcleo, e deslocá-la
para a posição do pixel.

Ambos os métodos de composição de convolução-limiarizada e deslocamento-por-rolagem foram
implementados no script "morphology" de Fred Weinhaus, que foi criado muito
antes de o operador "-morphology" ser adicionado ao ImageMagick.

Veja e Baixe o Script "Morphology" de Fred Weinhaus em
  http://www.fmwconcepts.com/imagemagick/morphology/index.php

Métodos de Morfologia de Diferença

O próximo nível de métodos morfológicos é algo que eu chamo de morfologia de diferença. Ou seja, os resultados desses métodos de morfologia são a diferença entre um dos métodos básicos de morfologia anteriores e a imagem original, ou algum outro método morfológico. Essencialmente, eles retornam as mudanças que foram feitas na imagem original por um dos métodos mais simples, dando a você os contornos, as adições ou subtrações entre as imagens. Eles são essencialmente composições de imagem '[Difference](compose.html#difference)' ou '[Minus](compose.html#minus)' dos resultados da imagem.

EdgeIn

O método '**EdgeIn**', também chamado de 'Gradiente Interno ', encontra os pixels que a Erosão remove do original. Como resultado, os pixels que estão mais próximos da borda, mas que faziam parte da forma original, são retornados.

  magick man.gif   -morphology EdgeIn Octagon  edgein_man.gif

[IM Output] [IM Output] [IM Output]

A borda resultante tem cerca da metade do tamanho do núcleo fornecido, o que, para um núcleo '[Octagon](#octagon)', é bastante espesso. Mais tipicamente, você usaria um núcleo '[Diamond](#diamond)' ou '[Square](#square)' muito menor, para produzir um contorno de um único pixel da forma. Um exemplo de uso do '[EdgeIn](#edgein)' com o canal alfa, para extrair pixels de borda, é mostrado em Sparse Color como um Operador de Preenchimento.

EdgeOut

O método '**EdgeOut**', também chamado de 'Gradiente Externo ', encontra os pixels que foram adicionados à imagem original por uma Dilatação dessa imagem. Como resultado, os pixels de fundo imediatamente adjacentes à forma são retornados.

  magick man.gif   -morphology EdgeOut Octagon  edgeout_man.gif

[IM Output] [IM Output] [IM Output]

Um exemplo de uso do '[EdgeOut](#edgeout)' com o canal alfa é mostrado em Contorno ou Transparência de Halo.

Edge ou Gradiente Morfológico

O método '**Edge**' retorna um 'Gradiente Morfológico ', que pode ser descrito ou como a soma dos dois últimos métodos de 'borda', ou mais especificamente como a diferença entre a forma Erodida e sua forma Dilatada.

  magick man.gif   -morphology Edge Octagon  edge_man.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Como antes, o tamanho e a forma do núcleo definem a espessura da imagem erodida. Sua espessura é essencialmente equivalente àquele tamanho de núcleo, menos o pixel central. Assim, um núcleo de raio 3 geralmente produzirá uma 'Edge' com 6 pixels de espessura (o tamanho do núcleo é de 7 pixels de espessura) Aqui, por exemplo, está o contorno 'Edge' da forma usando o núcleo mínimo '[Diamond](#diamond)'. |

  magick man.gif  -morphology Edge Diamond  man_outline.gif

A borda tem dois pixels de espessura, pois contém os pixels que ficam de cada lado da 'borda de pixel' real da forma original. A única maneira de tornar essa borda mais fina é, na verdade, deslocar a imagem inteira diagonalmente em meio pixel. [IM Text]
Para mais detalhes sobre como obter contornos de formas de várias maneiras, veja a seção sobre Detecção de Bordas. Futuro: gerar a borda usando uma 'linha diagonal'.

Top-Hat

O método '**TopHat**', ou mais especificamente 'White Top Hat ', retorna os pixels que foram removidos por uma Abertura da forma, ou seja, os pixels que foram removidos para arredondar as pontas e as pontes de conexão entre as formas.

  magick man.gif   -morphology TopHat Disk  tophat_man.gif

[IM Output] [IM Output] [IM Output]

Como você pode ver, os pixels frequentemente formam pequenas ilhas altamente disjuntas, sem nenhum conjunto de pixels mais espesso que o núcleo usado. O nome do método 'Top Hat ' na verdade se refere ao uso dos operadores quando aplicados usando o método de morfologia 3-dimensional em tons de cinza, e não com imagens binárias como fizemos aqui. Este operador é mais comumente usado com imagens em tons de cinza. FUTURO: Exemplo de top-hat em tons de cinza

Bottom-Hat

O método '**BottomHat**', também conhecido como 'Black TopHat ', são os pixels que um Fechamento da forma adiciona à imagem. Ou seja, os pixels que foram usados para preencher os 'buracos', 'lacunas' e 'pontes'.

  magick man.gif   -morphology BottomHat Disk  bottomhat_man.gif

[IM Output] [IM Output] [IM Output]

Novamente, você pode ver que ele também resulta em 'ilhas' de pixels altamente disjuntas, nenhuma das quais é mais espessa que o núcleo usado. No entanto, elas são sempre um conjunto de ilhas completamente diferente do método anterior. FUTURO: Exemplo de bottom-hat em tons de cinza


Usando Métodos de Morfologia de Baixo Nível

Morfologia Básica e Canais

Todos os métodos básicos de morfologia acima são métodos de canal; como tal, eles são aplicados aos canais individuais de uma imagem de acordo com a configuração atual de "[-channel](https://imagemagick.org/command-line-options/#channel)". Isto significa que você pode aplicar esses métodos a imagens coloridas, desde que não seja muito exigente quanto ao 'vazamento de cor' de áreas transparentes indefinidas. Por exemplo, vamos '[Erode](#erode)' o canal alfa da imagem original da 'figura do homem', sem modificar os canais de cor.

  magick figure.gif -channel A  -morphology Erode Diamond:3 \
          +channel   figure_erode.gif

[IM Output] [IM Output] [IM Output]

Como você pode ver, funciona bem. Para outros exemplos, veja Sparse Color como um Operador de Preenchimento, usando o método '[EdgeIn](#edgein)' para encontrar os pixels de borda de uma imagem. Também Contorno ou Transparência de Halo usando '[EdgeOut](#edgeout)' para expandir as bordas de uma imagem com uma cor específica.

Busca por Formas Específicas

O conhecimento sobre um objeto depende da maneira pela qual o sondamos (observamos).
                    -- Georges Matheron, O Pai da Morfologia

Usar Erode para localizar formas específicas a partir de uma grande coleção de formas. Levado
ao extremo, isto cria [Esqueletos](#skeletons), veja também [Afinamento de Esqueletos](#thinning_skeleton).

Restaurar objetos usando Open (resultado suavizado) ou [Dilatação Condicional](#dilate_conditional).

Precisa de algum tipo de Análise de Componentes Conectados (Segmentação) para contar
objetos encontrados dentro de uma imagem adequadamente.

Granularidade de uma coleção de Formas

Usando uma série de operações '[Open](#open)' em uma imagem com elementos estruturantes de tamanho lentamente crescente, e medindo a área resultante, você pode obter rapidamente um resumo do número de tais formas que podem ser encontradas na imagem. Ao tomar a derivada (inclinação) desse resultado, você obtém um 'espectro' do número e tamanho daquelas formas que compõem a imagem. Este gráfico é a 'granularidade ' da imagem para alguma forma particular. Veja Granulometria (morfologia), Wikipédia. As diferenças de um tamanho para o próximo também permitirão que você separe e conte elementos específicos com base no tamanho e, por sua vez, separe áreas contendo elementos de tamanhos e formas diferentes. O resultado é um método de segmentação de textura. Demonstração da determinação do número e tamanho de uma coleção de formas. No entanto, isto requer um método de 'contagem' (a ser adicionado) para implementar completamente. Nota histórica... Este uso foi de fato a força motriz original por trás da criação original dos métodos de morfologia, em uma empresa de mineração de Paris, na década de 1960. Ele permitiu que os criadores criassem um sistema automatizado para analisar a estrutura de grãos de fotos microscópicas de amostras minerais para determinar sua adequação para a mineração. Ou seja, localizar e contar o tamanho e a quantidade de mineral nas amostras. Por exemplo: Dois minérios podem ter a mesma quantidade de mineral desejado (geralmente como grãos ou cristais na rocha), mas apenas o minério com grãos maiores poderia ser efetivamente minerado, pois permitia separar mais facilmente o mineral puro grande da rocha portadora de minério circundante. Esta era uma tarefa muito trabalhosa, que a morfologia tornou muito mais fácil.

Efeitos de Núcleo Assimétrico (Testes de Métodos Básicos)

Vamos ver como esses métodos básicos funcionam quando usados com um núcleo que não é simétrico. Por exemplo, aqui aplico um formato 'L' definido pelo usuário contra uma imagem especial de teste morfológico (ampliada para visualizar os pixels individuais). |

  for method in  erode dilate open close; do
    magick test_morphology.gif \
             -morphology $method  '2x3+1+1: 1,-  1,-  1,1 '  test_$method.gif
  done

[IM Text]
O que produz os seguintes resultados...

[IM Text] '[Erode](#erode)' resulta em qualquer correspondência exata do formato do núcleo, tornando-se um único pixel branco no ponto de correspondência, a 'origem'. Também expandirá qualquer 'buraco' de um único pixel para esse mesmo formato, mas 'refletido' em torno da 'origem', isto é, como se o núcleo tivesse sido rotacionado 180 graus.

[IM Text] '[Dilate](#dilate)' Como esperado, produz esse mesmo resultado, mas para uma forma 'negativa' e 'refletida' da imagem ou do núcleo. Um único pixel branco expande-se para o formato do núcleo, enquanto qualquer buraco com o formato 'refletido' correspondente encolhe até um 'buraco' de um único pixel.
Note também que a fronteira entre as metades positiva e negativa da imagem de teste realmente se move como consequência da aplicação dos métodos morfológicos básicos acima. Isso é esperado. Isso levanta um ponto específico sobre esses dois métodos. Para converter um método '[Erode](#erode)' em um '[Dilate](#dilate)' ou vice-versa, você precisa não apenas Inverter as imagens antes e depois, mas também precisa rotacionar ou refletir o núcleo em torno da origem. Normalmente, esse segundo aspecto pode ser ignorado, pois a maioria dos núcleos é 'simétrica'. Só se torna importante com núcleos assimétricos definidos pelo usuário. [IM Text] '[Open](#open)' como mencionado antes, geralmente não remove quaisquer 'buracos' da imagem, no entanto uma forma que corresponda exatamente permanecerá inalterada. Formas maiores (como a metade negativa da imagem de teste) também podem permanecer, mas talvez ligeiramente modificadas.
[IM Text] '[Close](#close)' é um resultado negativo exato do anterior, mas é definido de tal forma que não precisa que o núcleo seja refletido (pois já é refletido por sua definição interna), apenas que a imagem seja invertida.


Casamento de Padrões Hit And Miss (HMT)

Hit-And-Miss ( )

O método de morfologia 'Hit-And-Miss', também comumente conhecido como "HMT " na literatura de ciência da computação, é um método de morfologia de alto nível projetado especificamente para encontrar e localizar padrões específicos em imagens. Ele faz isso procurando por uma configuração específica de pixels de 'primeiro plano' e 'fundo' em torno da 'origem'. A partir do IM v6.6.9-4, você pode usar qualquer um dos nomes de método 'HitAndMiss', 'Hit_N_Miss' ou simplesmente 'HMT', e as variantes, para especificar esse método de morfologia. Antes dessa versão, apenas o nome de método 'HitAndMiss' podia ser usado.
Por exemplo, poderíamos procurar por um pixel de 'primeiro plano' que tenha um pixel de 'fundo' imediatamente à sua direita.
  magick man.gif   -morphology Hit-and-Miss '2x1:1,0'  hmt_right.gif

[IM Output] [IM Output] [IM Output]

Como você pode ver, o pequeno núcleo de 2 elementos correspondeu apenas aos pixels que estavam no lado direito da imagem. Isto é, o método retornou apenas um pixel específico que correspondeu ao padrão dado. O 'Núcleo' ou 'Elemento Estruturante' usado pode conter um padrão de apenas 3 tipos de elementos: um valor '1' significando 'primeiro plano', um valor '0' significando 'fundo', e também um terceiro elemento que pode ser especificado como 'Nan', ou '-' ou um valor '0.5' que significa 'Não Importa' ou 'Qualquer Pixel'. O valor que você usa para a 'origem' é muito importante, pois definirá se você quer apenas 'acertar' a forma de primeiro plano ou o padrão de fundo. Mas se você definir especificamente o valor da 'origem' como 'Não Importa', então poderá corresponder tanto a pixels de primeiro plano quanto de fundo que tenham a vizinhança adjacente correta. Por exemplo, se eu usar um elemento estruturado como...

  magick man.gif   -morphology Hit-and-Miss '3x1:1,-,0'  hmt_right2.gif

[IM Output] [IM Output] [IM Output]

Você obtém quaisquer pixels de borda direita que estejam por dentro ou por fora. Assim, você agora está marcando ambos os lados da fronteira da forma e extraindo uma borda de 2 pixels de largura. No entanto, nem todos os pixels correspondem ao padrão, então nem todo pixel é duplicado, mas em geral é isso que você obtém. O uso de um valor 'Não Importa' para a 'origem' é na verdade muito comum, especialmente quando examinamos mais adiante os métodos Thicken e Thinning, que se restringem a adicionar ou remover pixels. Ao 'Não Importar', a mesma definição de núcleo poderia ser usada para qualquer operação, pois a própria operação define que tipo de 'acertos' interessam a você.
Aqui está outro exemplo, mas desta vez limito novamente meus 'acertos' aos pixels que caem dentro da forma mas que formam um canto voltado para o Noroeste.

  magick man.gif   -morphology HMT "3:0,0,- 0,1,1 -,1,-" hmt_nw_corner.gif

[IM Output] [IM Output] [IM Output]

Ao expandir esse único canto para um conjunto de Cantos Rotacionados a 90 graus adicionando uma flag '>', podemos encontrar todos os cantos que aparecem dentro da forma. |

  magick man.gif  -morphology HMT "3>:0,0,- 0,1,1 -,1,-" hmt_corners.gif

[IM Output] [IM Output]
Como você pode ver, o método '[Hit-And-Miss](#hmt)' localiza e retorna TODAS as posições de pixel que correspondem a qualquer um dos padrões de núcleo fornecidos. | _Se você examinasse aSaída Detalhada da operação "[-morphology](https://imagemagick.org/command-line-options/#morphology)" acima, descobriria que o '[Hit-And-Miss](#hmt)' usa um método de composição '[Lighten](compose.html#set_theory)' para criar uma 'união' de todos os pixels que correspondem a cada um dos núcleos de padrão fornecidos.

Infelizmente, a contagem de pixels 'alterados' é de todos os pixels que são desativados por cada aplicação de núcleo. Em outras palavras, o número de pixels na forma, menos o número de pixels que foram correspondidos por cada núcleo.

_
---|---
| _Da mesma forma, repetir oMétodo Hit-And-Miss com os resultados de si mesmo é geralmente inútil, pois a imagem terá mudado tanto que você provavelmente acabará sem correspondências depois.

Você pode, e como vê, usar os resultados para modificar a imagem original de modo a gerar uma imagem ligeiramente diferente._
---|---
Você pode usar um conjunto de núcleos que sejam mais seletivos quanto ao que especificamente lhe interessa. Por exemplo, suponha que você esteja interessado nos pontos onde três linhas se encontram. Então você pode usar o conjunto de núcleos '[LineJunctions](#linejunctions)', projetado especificamente para esse propósito.

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif

[IM Output] [IM Output]

Como você pode ver, apenas uma pequena dispersão de localizações corresponde a qualquer um dos núcleos desse conjunto. No entanto, os resultados podem tornar muito difícil ver de fato onde estavam as localizações correspondentes na imagem original. Isso é especialmente ruim se você estiver lidando com uma imagem em escala de cinza. Uma solução é expandir as correspondências usando '[Dilate](#dilate)' com algum Núcleo de Forma, como um '[Ring](#ring)'. Por exemplo... |

  magick lines.gif \( +clone \
             -morphology HMT LineJunctions \
             -morphology Dilate Ring \
             -background red -alpha shape \
          \) -composite              hmt_junctions_rings.gif

[IM Output]
Agora você pode ver claramente as localizações onde esse conjunto específico de núcleos encontrou Junções de 3 ou mais linhas. Cada um dos núcleos em '[LineJunctions](#linejunctions)' pode corresponder apenas a algumas localizações específicas; assim, o casamento de padrões dessa forma pode ser lento. Ainda assim, é muito preciso e funciona muito bem. Outro conjunto de núcleos '[Hit-And-Miss](#hitmiss)' semelhante é o núcleo '[LineEnds](#lineend)', que pode ser usado para encontrar as extremidades livres de todas as linhas da imagem. |

  magick lines.gif \( +clone \
             -morphology HMT LineEnds \
             -morphology Dilate Ring \
             -background red -alpha shape \
          \) -composite                  hmt_lineends_rings.gif

[IM Output]
HitandMiss - apenas com pixels de primeiro plano - > erode HitandMiss - apenas com fundo - > dilate invertido

Hit And Miss com Imagens em Escala de Cinza

Quando o método '[Hit-And-Miss](#hitmiss)' é aplicado a uma imagem em escala de cinza, o valor realmente retornado será a diferença entre o valor mínimo de 'primeiro plano' e o valor máximo de 'fundo'. Se ocorrer um resultado negativo (sem matemática), o resultado é 'limitado a zero', pois valores negativos não têm significado real. Em outras palavras, ele retorna a 'separação mínima ' de valores entre os dois conjuntos de pixels. Para formas booleanas, isso será '0.0' (preto) ou '1.0' (branco). Mas para imagens em escala de cinza, isso equivale ao 'gradiente' dos pixels correspondentes. Pode, por exemplo, ser usado para identificar exatamente quanto contraste está presente entre um determinado primeiro plano e fundo no padrão correspondente. Se você realmente quer apenas um resultado booleano (ligado/desligado) de quais pixels de fato correspondem ao padrão em uma imagem em escala de cinza, você deve adicionar uma opção "[-threshold](https://imagemagick.org/command-line-options/#threshold) 0" após o comando.

Thicken (Adicionando Pixels a uma Forma)

O método 'Thicken' adicionará pixels à forma original em cada localização correspondente. Por exemplo, aqui procuro por um pixel de fundo que esteja a dois pixels de distância da borda direita da forma.

  magick man.gif   -morphology Thicken '3x1+2+0:1,0,0'  thick_right.gif

[IM Output] [IM Output] [IM Output]

Como você pode ver, você acabou com uma linha de pixels logo fora da fronteira original da forma. Você pode Iterar esse método 'Thicken' algumas vezes para continuar a sequência. |

  magick man.gif   -morphology Thicken:4 '3x1+2+0:1,0,0'  thick_right2.gif

[IM Output]
No entanto, como os pixels estão sendo adicionados, a origem do núcleo de casamento de padrões NÃO deve corresponder a um pixel de primeiro plano, ou você estará essencialmente adicionando um pixel onde já existe um. No conjunto acima, defini o pixel de origem para um padrão de fundo, de modo que apenas padrões de fundo realmente correspondam. Uma alternativa é sempre definir a origem para um valor de elemento 'Não Importa'. Ao fazer isso, você poderá usar o mesmo padrão de núcleo tanto para o afinamento '[Thicken](#thicken)', quanto, como verá mais adiante, para o '[Thinning](#thinning)' também. Então a melhor regra é definir a origem como 'Não Importa'. | _Outra maneira de gerar uma operação '[Thicken](#thicken)' é gerar uma União dos resultados do '[Hit-And-Miss](#hitmiss)' desse núcleo com o núcleo especial '[Unity](#unity)' de modo a incluir a imagem original nos resultados.

Por exemplo..._ |

  magick man.gif -define morphology:compose=Lighten \
                  -morphology HitAndMiss 'Unity ; 3x1+2+0:1,0,0' hmt_thicken.gif

[IM Output] [IM Output]

_Na verdade, aConfiguração de Composição Multi-Núcleo no exemplo acima não é necessária, pois o método '[Hit-And-Miss](#hitmiss)' define especificamente essa configuração de composição por padrão, quando não definida pelo usuário.

_

Tipicamente, o '[Thicken](#thicken)' é usado para ampliar formas como linhas, mas sem tornar as linhas mais longas. Um conjunto especial de núcleos conhecido como núcleo '[ConvexHull](#convexhull)' permite que você faça isso. Por exemplo...

  magick -size 80x80 xc:black -fill none -stroke white \
          +antialias   -draw 'line 10,20 70,60'     man_line.gif
  magick man_line.gif   -morphology Thicken ConvexHull  thick_line.gif

[IM Output] [IM Output]

Thicken - Envoltória Convexa Octogonal

O núcleo '[ConvexHull](#convexhull)' propriamente dito foi realmente projetado para trabalhar com formas de imagem, e expandirá uma forma em uma 'Envoltória Convexa Octogonal '. Isto é, ele tentará preencher todas as lacunas entre os extremos até produzir um objeto de 'formato octogonal'.

  magick man.gif -morphology Close Diamond \
                  -morphology Thicken:-1 ConvexHull \
                  -morphology Close Diamond       man_hull_full.gif

[IM Output] [IM Output]
Veja a definição do núcleo '[ConvexHull](#convexhull)' para mais detalhes, e por que os dois métodos '[Close](#close)' são necessários.

Você pode observar as iterações sendo executadas ativando a Configuração de Saída Detalhada. No entanto, isso mostrará que o procedimento acima é muito, muito lento. Cada iteração '[Thicken](#thicken)' só adicionará de fato alguns poucos pixels à forma a cada iteração. Assim, pode levar muitas iterações antes que a 'envoltória' completa seja concluída. Neste caso específico, a imagem exigiu 80 iterações '[Thicken](#thicken)', com uma '[ConvexHull](#convexhull)' de 8 núcleos. Isso significa que o procedimento acima na verdade exigiu 640 iterações primitivas, além de outras 4 iterações primitivas necessárias para realizar os dois métodos '[Close](#close)'. Isso pode consumir uma quantidade de tempo bastante grande. Basicamente, iterar usando Casamento de Padrões Hit And Miss pode ser muito, muito 'lento ', e se uma técnica alternativa puder ser encontrada, ela deve ser usada em vez disso. Você pode usar isso também para encontrar quais pontos da imagem original causaram a criação dessa forma octogonal, obtendo uma interseção (Composição Darken) entre a borda da envoltória convexa e a forma original.

  magick man_hull_full.gif \
              -morphology EdgeIn Diamond man_convex_edge.gif
  magick man.gif man_convex_edge.gif \
          -compose Darken -composite man_extremities.gif

[IM Output] [IM Output] [IM Output]

Qualquer forma conectada que caiba dentro da envoltória convexa, mas que também inclua ao menos um pixel em cada borda da envoltória convexa acima, gerará a mesma envoltória convexa octogonal.

Thicken com Imagens em Escala de Cinza

Ao lidar com uma imagem em escala de cinza, o '[Thicken](#thicken)' irá adicionar o resultado da separação de primeiro plano e fundo do '[Hit-And-Miss](#hitmiss)' ao pixel de origem. Isso pode, portanto, ser usado para tornar os pixels correspondentes mais brilhantes, mesmo quando o pixel de 'origem' não está no conjunto de 'fundo'. Por exemplo, vamos repetir o exemplo de busca de cantos de cima, mas com uma versão da forma em cinza a 50%.

  magick man.gif   -evaluate multiply 0.5   man_grey.gif
  magick man_grey.gif  -morphology Thicken Corners  thick_corners.gif

[IM Output] [IM Output]

Ao usar uma versão HDRI do Imagemagick com '[Thicken](#thicken)', provavelmente é uma boa ideia aplicar "[-clamp](https://imagemagick.org/command-line-options/#clamp)" ou "[-auto-level](https://imagemagick.org/command-line-options/#auto-level)" nos resultados para evitar que eles ultrapassem os limites da faixa de valores de pixel da imagem.

Thinning ( ) (Subtraindo Pixels de uma Forma)

O método 'Thinning' é o dual do '[Thicken](#thicken)'. Em vez de adicionar pixels, esse método os subtrai da imagem original. Por exemplo, vamos remover qualquer pixel que esteja a 4 pixels da borda direita.

  magick man.gif   -morphology Thinning '5x1+0+0:1,1,1,1,0' thin_right.gif

[IM Output] [IM Output] [IM Output]

Para que o 'Thinning' funcione corretamente, o núcleo de casamento de padrões deve ter uma origem contendo um pixel de primeiro plano, caso contrário o método não terá pixel correspondente para remover da forma. | _Outra maneira de gerar uma operação '[Thinning](#thinning)' é aplicar o Complemento Relativo (usando uma composição MinusSrc) dos resultados do '[Hit-And-Miss](#hitmiss)' a partir da imagem original. Você pode incluir essa imagem no início da lista de núcleos (para 'subtrair' dela) usando um núcleo '[Unity](#unity)'.

Por exemplo..._ |

  magick man.gif -define morphology:compose=MinusSrc \
          -morphology HMT 'Unity ; 5x1+0+0:1,1,1,1,0' hmt_thinning.gif

[IM Output] [IM Output]

_Este é um estilo de afinamento de 'interseção', removendo todos os pixels especificados de todos os núcleos em uma única etapa, em vez do estilo 'iterativo', que remove os pixels de cada núcleo em sequência. VejaEstilo de Thinning para mais informações.

_

Conectividade de Linhas

FUTURO: linhas 4-conectadas versus 8-conectadas Veja a discussão nos fóruns do IM, From 8-connected to 4-connected lines.

Saída de Detector de Bordas Afinada

Um dos usos mais comuns do afinamento é reduzir a saída limiarizada de um Detector de Bordas, como a Convolução Sobel, a linhas de espessura de um único pixel, preservando o comprimento total dessas linhas. Exemplo usando uma Imagem de Gradiente de Distância.

Afinando até um Esqueleto

O '[Thinning](#thinning)' de imagens é na verdade mais comumente usado que o '[Thicken](#thicken)', pois é usado para reduzir as formas a formatos mais gerenciáveis, como Esqueletos. Estes, como será discutido mais adiante, destinam-se a ser a linha central de pixels entre duas (ou mais) bordas da forma. Um esqueleto é importante porque fornece uma descrição muito boa de uma forma bastante complexa. Por exemplo, processar a imagem para descobrir o número de laços, segmentos de linha e como eles estão dispostos lhe dirá muito sobre a forma que você tem. Então, vamos produzir um 'Esqueleto Afinado ' aplicando repetidamente o '[Thinning](#thinning)' nas bordas da forma do homem, até que restem apenas as linhas centrais.

  magick man.gif  -morphology Thinning:-1 Skeleton  man_raw_thinned.gif

[IM Output] [IM Output]

Um relatório Detalhado do procedimento acima teria mostrado 18 iterações, com 8 núcleos, totalizando 144 iterações primitivas no total. Isso é na verdade muito mais rápido do que encontrar sua Envoltória Convexa (acima), pois os núcleos de afinamento removem linhas e colunas inteiras de pixels a cada iteração, e não apenas alguns de cada vez. Note como o conjunto de núcleos '[Skeleton](#skeleton)' falhou em expandir o buraco, de modo que não encontrou a linha central entre o buraco e a borda externa. Essa é uma falha séria desse núcleo específico de afinamento de esqueleto, e é causada porque os núcleos exigem todos ao menos pixels de fundo antes de fazerem qualquer correspondência de afinamento. Você pode usar conjuntos de núcleos de afinamento de esqueleto para resolver esse problema. Uma solução mais simples é aplicar Erode ligeiramente à imagem para dar aos núcleos algo com que trabalhar. Também vou aplicar erode e afinamento apenas aos canais 'Vermelho' e 'Verde', de modo a deixar a forma original em azul.

  magick man.gif -channel RG -morphology Erode Diamond  man_erode.gif
  magick man_erode.gif -channel RG \
          -morphology Thinning:-1 Skeleton +channel  man_skeleton.gif

[IM Output] [IM Output]

Você também pode ver que qualquer buraco na imagem agora se expandiu para produzir um laço contínuo maior de pixels ao seu redor. Aqui está um close-up do laço ao redor do buraco erodido. |

  magick man_skeleton.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_skeleton_zoom.gif

[IM Output]
Note que ele não produziu uma linha central exata entre o buraco e a borda. Além disso, como a forma foi erodida, as linhas não vão até a borda da forma original mas param um pixel antes. Isto é, as extremidades das linhas foram ligeiramente 'podadas'. Essa é a desvantagem da solução com 'erode'. O esqueleto também está limitado a linhas octogonais, o que significa que está perdendo muitos detalhes, embora neste caso essa simplificação possa ser algo bom. Veja a seção sobre Esqueletos abaixo. Este é um núcleo '[Skeleton](#skeleton)' tradicional, que, como você pode ver, produz linhas diagonais 'grossas', de modo que todas as partes do esqueleto são '4-conectadas' ou 'conectadas por diamante'. Existem outras variações de núcleos '[Skeleton](#skeleton)', que produzirão outras variações no 'Esqueleto Afinado ' resultante. Esqueleto Mais Fino, 8-Conectado Este esqueleto 'tradicional', como mencionado, tem diagonais grossas. Mas frequentemente isso não é 'fino' o suficiente. Em algumas situações, o que você quer é um esqueleto ligeiramente mais fino. Isto é, você quer um esqueleto '8-conectado' em vez de um esqueleto '4-conectado'. Uma solução é usar uma variante diferente de geração de esqueleto, como a gerada usando um núcleo '[Skeleton:2](#skeleton2)', (encontrado no Site do Tutorial Gráfico HIPR2). Por exemplo... |

  magick man.gif   -channel RG  -morphology Erode Diamond \
          -morphology Thinning:-1 Skeleton:2 +channel  man_skeleton_hipr.gif

[IM Output]
E aqui está um zoom da área do laço, mostrando como o esqueleto resultante é 8-conectado, com diagonais mais finas. |

  magick man_skeleton_hipr.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_skeleton_hipr_zoom.gif

[IM Output]
No entanto, descobri que tais esqueletos não são tão precisos quanto o esqueleto 'tradicional'. Basicamente, em casos de teste descobri que as diagonais eram 'afinadas' no lado errado. Basicamente porque o lado das diagonais que é removido é controlado puramente pela ordem do núcleo de afinamento de 'canto' no conjunto de núcleos, e não por qualquer decisão devida à natureza da forma.
A alternativa é pegar um esqueleto 'tradicional' e afiná-lo de modo que as diagonais sejam sempre afinadas no lado 'externo' da diagonal, conforme definido pelos pontos extremos da diagonal. O núcleo de afinamento especial '[Diagonals](#diagonals)' foi projetado para fazer isso, com um núcleo '[Corners](#corners)' sendo usado depois para 'finalizar'. Então vamos afinar ainda mais o esqueleto 'tradicional' anterior...

  magick man_skeleton.gif -channel RG \
          -morphology Thinning:-1 Diagonals \
          -morphology Thinning Corners   man_thin_skeleton.gif

[IM Output] [IM Output]

Essa técnica de afinar um esqueleto 4-conectado tradicional é ligeiramente mais lenta do que simplesmente usar diretamente a variante '[Skeleton:2](#skeleton2)'. O afinamento extra exigiu 8 iterações de afinamento dos 8 núcleos, ou 64 iterações primitivas. Alternativamente, você pode simplesmente usar apenas o núcleo '[Corners](#corners)', embora isso apenas gere a variante 'HIPR', com apenas uma escolha 'aleatória' de qual lado das diagonais foi afinado. No entanto, isso levará apenas 1 passagem de todos os 4 núcleos, e assim é muito, muito mais rápido do que usar '[Diagonals](#diagonals)'. De qualquer forma, começando com um esqueleto 4-conectado 'tradicional', você pode então gerar uma versão 8-conectada (de algum tipo) muito facilmente.

Informações do Esqueleto

Quando você tem um esqueleto (talvez até ambas as versões, 4 e 8 conectadas), o próximo passo geralmente é descobrir mais informações sobre o esqueleto. Por exemplo, quantas 'extremidades livres de linhas', 'junções de linha' e 'laços de linha' estão presentes. Número de Extremidades de Linha Aqui uso uma Busca Hit And Miss para '[LineEnds](#lineends)' no esqueleto que geramos anteriormente (extraindo-o do canal 'vermelho'). Em seguida, aplico Dilate nessas extremidades de linha transformando-as em Anéis e as colorindo antes de mesclar com o esqueleto original, para tornar suas localizações bem visíveis.

  magick man_skeleton.gif -channel R -separate +channel \
          -morphology HMT LineEnds man_ends.gif
  magick man_ends.gif -morphology Dilate Ring -background Red -alpha Shape \
          man_skeleton.gif +swap -composite man_ends_marked.gif

[IM Output] [IM Output] [IM Output]

Note que as linhas todas se conectam umas às outras, ou ao laço de pixels que não foi encontrado. Apenas as extremidades livres de linha foram indicadas. Se você fizesse uma contagem de pixels (usando uma Saída de Histograma), veria que este esqueleto gerou 12 extremidades de linha. Número de Junções de Linha Você pode obter uma contagem aproximada do número de junções de linha em uma imagem usando o núcleo '[LineJunctions](#linejunctions)' com um esqueleto 8-conectado , preferencialmente um que tenha sido afinado a partir do esqueleto original usado para contar extremidades de linha. Não misture duas variantes diferentes de geração de esqueleto.

  magick man_thin_skeleton.gif -channel R -separate +channel \
            -morphology HMT LineJunctions  man_junctions.gif
  magick man_junctions.gif -morphology Dilate Ring \
          -background Red -alpha Shape \
            man_thin_skeleton.gif +swap -composite man_junctions_marked.gif

[IM Output] [IM Output] [IM Output]

Se você tentar usar esse núcleo diretamente com um esqueleto 4-conectado tradicional, obterá múltiplas correspondências para algumas das junções 'T', tornando a contagem muito imprecisa. O resultado, como você pode ver, são 12 junções de linha, o que para esta forma específica está correto. No entanto, para algumas junções o núcleo '[LineJunctions](#linejunctions)' é impreciso. Por exemplo, uma junção diagonal 'X' de 4 linhas produzirá apenas 1 correspondência, enquanto uma junção ortogonal '+' produzirá 4 correspondências. Ambas essas junções especiais deveriam produzir 2 correspondências, para manter a contagem de junções de linha correta. Assim, para obter uma contagem precisa, você precisará adicionar 1 valor a mais para cada junção 'X', e subtrair 2 da contagem para cada junção '+'.
Para um esqueleto que não tem laços, o número de junções deve ser 2 a menos que o número de extremidades de linha. No entanto, se o número de extremidades de linha for igual ao número de junções de linha, isso significa que você tem um ou mais laços no esqueleto. Ora, este esqueleto tem 12 extremidades de linha e 12 junções, portanto contém pelo menos um laço contínuo de pixels em algum lugar da imagem. Número de Laços FUTURO: Rotulação de Objetos Conectados

Podando Linhas

Então você sabe que esta imagem tem pelo menos um laço. Suponha que você queira simplificar a forma apenas para aquele(s) laço(s). A solução é 'Podar ' todas as extremidades de linha repetidamente até que você as tenha removido todas. Para um esqueleto 4-conectado como este, você pode até usar um conjunto menor de núcleos '[LineEnds](#lineends_subtypes)' para tornar o processo cerca de duas vezes mais rápido.

  magick man_skeleton.gif -channel G \
          -morphology Thinning:-1 'LineEnds:1>' man_loop.gif

[IM Output] [IM Output]

Um relatório Detalhado disso teria mostrado que isso levou 75 iterações com 4 núcleos, resultando em 300 integrações primitivas para 'Podar ' todas as linhas com extremidades livres da imagem. Isto é, cerca de duas vezes mais operações do que as usadas para encontrar o esqueleto, o que mostra quão mais intensiva essa operação pode ser. Usar um conjunto completo de núcleos '[LineEnds](#lineends)' (8 núcleos) também teria levado 75 iterações, mas com o dobro de núcleos, tornando isso 600 iterações primitivas.

Poda Rápida de Linhas

Técnica de poda completa rápida..

  1/  Encontre as extremidades de linha e as junções de linha.
  2/  Apague as junções de linha para desconectar completamente todos os segmentos de linha.
  3/  Preencha por inundação, ou use dilatação condicional para remover os segmentos de 'extremidade de linha'.
  4/  Restaure as junções de linha.
  5/  use isso como um mapa na imagem original para restaurar os 'laços'.

Já cobrimos o primeiro passo... resultando em... |

  magick man_skeleton.gif -channel R -separate +channel \
          -morphology HMT LineEnds man_ends.gif

[IM Output]
Para desconectar (ou separar) todos os segmentos de linha, você pode usar um núcleo '[LineJunctions](#linejunctions)'. No entanto, o conjunto de núcleos padrão não desconectará completamente as junções 'T' (apenas as localizará). Para desconectar corretamente todos os segmentos de linha, você também precisará adicionar núcleos 'T' ortogonais ao conjunto de núcleos, e também é melhor incluir uma junção '+'. Por exemplo. |

  magick man_skeleton.gif -channel R -separate +channel \
      -morphology HMT 'LineJunctions;LineJunctions:3>;LineJunctions:5' \
      man_disconnect.gif

[IM Output]
Aplicar afinamento com essas correspondências desconectará de fato os segmentos, no entanto você deve fazer isso tudo em uma única etapa, (veja Estilo de Thinning), ou não funcionará corretamente. |

  magick man_skeleton.gif -channel R -separate +channel \
      -define morphology:compose=Darken \
      -morphology Thinning 'LineJunctions;LineJunctions:3>;LineJunctions:5' \
      man_line_segments.gif

[IM Output]
Aqui está um zoom do 'laço' mostrando os segmentos desconectados. |

  magick man_line_segments.gif -crop 22x22+47+29 +repage \
          -scale 120x120    man_line_segments_zoom.gif

[IM Output]
Neste ponto, podemos agora remover qualquer segmento de linha que contenha uma correspondência com a 'extremidade de linha' previamente descoberta. Isso pode ser feito 'preenchendo por inundação' a partir daqueles pontos 'semente', para apagá-los. No entanto, isso só funciona para um esqueleto 4-conectado, que é o que o preenchimento por inundação pressupõe. Exemplo Aqui Alternativamente, podemos usar Dilatação Condicional para encontrar todos os pontos simultaneamente e removê-los. Exemplo Aqui - quando Dilatação ou Erosão Condicional estiver disponível. Se você agora restaurar as junções de linha, fizer uma poda e remover quaisquer pixels isolados que restem, terá então removido todos os segmentos de linha rapidamente. Sim, isso parece muitos passos, mas acredite, ainda é muito mais rápido do que ter que 'podar as extremidades das linhas ' 300 vezes para obter o mesmo resultado.

Estilo de Thinning - Sequencial ou Simultâneo

Se você fizesse uma única 'poda' das extremidades dos segmentos de linha, e a comparasse com a imagem original, descobriria que na maioria das vezes um segmento de linha foi podado de 2 a 4 vezes, dependendo da forma e orientação exatas das linhas. Por exemplo (imagem resultante ampliada) este é um afinamento de extremidades de linha padrão

  magick -size 10x10 xc:black -fill white \
          +antialias  -draw 'line 1,7 8,3' line.gif
  magick line.gif -channel GB \
          -morphology Thinning LineEnds  line_seqential.gif

[IM Output] [IM Output]

Isso ocorre porque, por padrão, cada um dos núcleos '[Thinning](#thinning)' é aplicado contra os resultados do núcleo anterior, em sequência. Isto é, ele remove todos os pixels selecionados por um núcleo, antes de aplicar o próximo núcleo a esse resultado, que pode (e de fato) selecionar mais pixels da mesma extremidade de linha. Em outras palavras, por padrão ele afinará as extremidades das linhas múltiplas vezes em uma 'iteração' completa por todos os núcleos fornecidos. Isso significa que você não pode confiar na Saída Detalhada para obter uma ideia exata de quão longas eram todas as linhas contando o número de pixels removidos por uma única iteração desse operador. No entanto, você pode modificar como o '[Thinning](#thinning)' funciona, de modo que ele remova apenas o conjunto de pixels que uma única iteração '[Hit-And-Miss](#hitmiss)' por todos os núcleos encontraria. Em outras palavras, aplique todos os núcleos à mesma imagem no início da iteração, mescle-os e então remova apenas esses pixels, uma única vez para todos os núcleos. Isto é, remova todos os pixels selecionados pelo HMT simultaneamente. Basicamente, você define a Configuração de Composição Multi-Núcleo para usar um método de composição '[Darken](compose.html#darken)', que fará exatamente isso. Especificamente, mesclando todos os pixels selecionados para uma única remoção dos pixels selecionados. Por exemplo... |

  magick line.gif -channel GB -define morphology:compose=darken \
          -morphology Thinning LineEnds  line_simultaneous.gif

[IM Output]
O que aconteceu aqui é que cada núcleo dos Núcleos de Casamento de Padrões será aplicado apenas à imagem original. Quaisquer pixels que corresponderem à original serão então coletados juntos. Isto é, removeremos apenas uma 'interseção' dos resultados de todos os núcleos contra a original, usando uma composição 'darken'. Mas a remoção é feita toda em uma etapa para qualquer iteração por todos os núcleos. O resultado é que uma extremidade de linha só será correspondida uma vez, mesmo que múltiplos núcleos pudessem corresponder a essa extremidade de linha. E assim apenas o único pixel na extremidade será removido, em vez de 2 ou mais pixels, por núcleos diferentes. Em resumo, adicionar uma Configuração de Composição Multi-Núcleo '[Darken](compose.html#darken)' garantirá que o método '[Thinning](#thinning)' faça 'Afinamento Simultâneo ' (todos os núcleos simultaneamente), em vez de 'Afinamento Sequencial ' (um núcleo por vez - o padrão).
No entanto, embora isso torne a poda de extremidades de linha mais bem comportada, ela a tornará mais lenta e pode alterar o resultado geral de um afinamento. Considere o caso de aplicar '[Thinning](#thinning)' a algumas caixas afinando simultaneamente as bordas esquerda e direita.

  magick -size 10x10 xc:black -fill white -draw 'rectangle 4,1 5,7' rect.gif
  magick rect.gif -channel GB -define morphology:compose=darken \
          -morphology Thinning Edges  rect_simultaneous.gif

[IM Output] [IM Output]

O 'Afinamento Simultâneo' na verdade apagou completamente o retângulo central! O que está acontecendo é que a forma foi afinada até uma espessura de dois pixels, e então ambos os lados do 'grosso' retângulo central corresponderam ao padrão e ambos os lados foram 'afinados'. A mesma coisa acontecerá se você fizer isso ao Afinar Esqueletos. O 'Afinamento Sequencial' padrão, por outro lado, produziu... |

  magick rect.gif -channel GB \
          -morphology Thinning Edges rect_seqential.gif

[IM Output]
Como você pode ver, ele preservou um dos pixels (à direita) para ser uma linha central do esqueleto. Isso ocorre porque um conjunto de núcleos afinou primeiro um lado de uma 'linha central grossa', mas os núcleos posteriores não corresponderam a essa linha 'mais fina', de modo que ela não foi removida. Essencialmente, existem situações em que o 'Afinamento Sequencial ' (o padrão) é melhor que o especial 'Afinamento Simultâneo ', e vice-versa.

Núcleos de Casamento de Padrões

Como mencionado, um núcleo de 'Casamento de Padrões' ou '[Hit-And-Miss](#hitmiss)' pode conter 3 tipos diferentes de elementos: primeiro plano, fundo e 'não importa'. Um valor '1.0' ou (branco) corresponde a pixels de primeiro plano. Um valor '0.0' ou (preto) corresponde a pixels de fundo. Você pode usar um valor '0.5' ou o valor especial 'Nan' ou '-' para representar elementos de pixel que não fazem parte da vizinhança e sobre os quais você 'não se importa'. O '[Hit-And-Miss](#hitmiss)' só corresponderá aos locais onde o menor (mínimo) pixel de primeiro plano for maior que o maior (máximo) pixel de fundo. Ele então retornará a diferença entre esses dois valores, ou zero. [IM Output]

Peaks

O núcleo 'Peaks' é uma extensão do núcleo '[Ring](#ring)' mostrado anteriormente. Dois argumentos de raio gerarão um 'anel' de pixels de fundo, cercando um único pixel de primeiro plano na 'origem' central. Aqui estão alguns exemplos de alguns dos núcleos 'Peak' mais úteis...

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Os núcleos acima podem ser usados tanto para localizar definitivamente um único pixel de valor de 'pico' em um mar de pixels mais escuros, quanto para encontrar qualquer forma pequena que caiba completamente dentro do anel maior. Eles são especialmente úteis para melhorar o contraste de uma Busca de Casamento de Padrões por Correlação.

Edges

O conjunto de núcleos 'Edges' corresponderá a qualquer pixel em uma borda plana de uma forma. Ele não corresponde a pixels em um canto agudo de noventa graus, embora corresponda a um pixel de canto em uma forma octogonal.

[IM Output]

Como você pode ver, todas as rotações de 90 graus são geradas, mas elas são ordenadas em uma ordenação de espelho 'alternada' que geralmente produz melhores resultados. Tipicamente, esse núcleo é usado como um tipo de núcleo de '[Thinning](#thinning)' de imagem, no entanto, do jeito que está, ele falhará em afinar bordas diagonais, ou em gerar um esqueleto adequado de uma imagem. Por exemplo...

  magick man.gif -channel RG \
          -morphology Thinning:-1 Edges   thin_edges.gif

[IM Output] [IM Output]

Veja os núcleos '[Skeleton](#skeleton)' abaixo.

Corners

Os núcleos 'Corner' localizam qualquer pixel de canto diagonal ao redor das bordas de uma imagem. Veja '[Hit-And-Miss](#hitmiss)' acima para um exemplo de seu uso.

[IM Output]

Aqui, por exemplo, eu o usei para tentar afinar todas as bordas diagonais... |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Corners  thin_corners.gif

Ele pode ser combinado com o núcleo '[Edges](#edges)' para produzir um afinamento de esqueleto de um único método. Veja os núcleos '[Skeleton](#skeleton)' abaixo, para um exemplo disso. [IM Output]

Diagonals

O núcleo 'Diagonals' é uma alternativa a simplesmente usar um núcleo '[Corners](#corners)' para afinar linhas diagonais 4-conectadas até linhas diagonais 8-conectadas. Isso pode ser usado para afinar linhas 4-conectadas, removendo o conjunto externo de pixels de um canto em direção ao centro até completar.

[IM Output]

Note que os resultados devem ser completados usando um núcleo '[Corners](#corners)', para localizar e afinar cantos de 90 graus. Veja Esqueleto Mais Fino para um exemplo de uso. Subtipos de Diagonals Ao fornecer um argumento 'tipo[,ângulo]' ao núcleo, você pode selecionar subtipos específicos que foram usados para compor o conjunto de núcleos acima.

[IM Output] [IM Output]

Isso lhe permitirá especificar seu próprio conjunto específico de núcleos, para afinar diagonais exatamente da maneira que você deseja. Por exemplo, você poderia afinar separadamente cada um dos quatro tipos de diagonais (usando ambos os núcleos acima com o mesmo valor de ângulo). Ao fazer isso, você pode fazer uma redução iterativa de cada tipo de diagonal, um de cada vez, abortando assim que todas aquelas diagonais específicas tiverem sido afinadas, reduzindo assim o número geral de 'passos primitivos de morfologia ' que são executados. exemplo necessário Do jeito que é dado, o conjunto de núcleos padrão simplesmente tentará afinar todas as diagonais simultânea e repetidamente até que todas tenham sido afinadas. Isso significa que todos os núcleos serão aplicados até que todas as diagonais tenham sido afinadas, em vez de apenas as diagonais que precisam de afinamento. Isso significa que ele executa muitos 'passos primitivos de morfologia ' que não são mais necessários, com a maioria dos núcleos não fazendo alterações na imagem durante cada laço. exemplo completo necessário Lembre-se de que cada uma das quatro diagonais ainda deve ser executada usando ambos os pares de núcleos (para cada ângulo específico), de modo que ambas as extremidades de cada diagonal específica sejam afinadas juntas, como quando a diagonal faz parte de um 'arco'. Há uma discussão relacionada sobre esse tipo de operação de afinamento/espessamento no fórum do IM, From 8-connected to 4-connected lines.

LineEnds

O conjunto de núcleos 'LineEnds', como mostrado em Podando Extremidades de Linhas acima, é projetado para localizar as extremidades de linhas. Mais especificamente, ele encontra as extremidades de pontas afiadas.

[IM Output]

Como você pode ver, ele só corresponderá a linhas que tenham pelo menos dois pixels, com o pixel correspondente 'coberto' ou 'cercado' por pixels de fundo. Por exemplo, aqui usamos '[Hit-And-Miss](#hitmiss)' para encontrar todas as extremidades de linhas.

  magick lines.gif -morphology HMT LineEnds  hmt_lineends.gif

[IM Output] [IM Output] [IM Output]

Sim, há muitas extremidades de linhas nesta imagem. Mas você deve notar que linhas que terminam em algum tipo de 'laço' não produzirão correspondência. Note que, se você estiver '[Afinando](#thinning)' uma imagem usando este núcleo em um estilo de 'afinamento iterativo' (o padrão), núcleos sucessivos poderiam corresponder à mesma extremidade de uma linha duas ou mais vezes, encurtando assim a linha muitas vezes durante uma única iteração de todo o método de '[Afinamento](#thinning)'. Veja Afinamento - Sequência vs Simultâneo para mais detalhes. Subtipos de Extremidades de Linha Você também pode dar a este núcleo argumentos 'type[,angle]', que retornarão uma das definições de núcleo único que foi usada para gerar o conjunto de núcleos '[LineEnds](#lineends)' acima.

[IM Output] [IM Output] [IM Output] [IM Output]

Estes podem então ser Expandidos em uma Lista de Núcleos Rotacionados conforme sua necessidade, ou rotacionados para um 'angle ' específico, conforme necessário. O conjunto '[LineEnds](#lineends)' padrão, na verdade, usa a definição de núcleo.

'LineEnds:1> ; LineEnds:2>'

O 'LineEnds:3' é o equivalente ortogonal ao diagonal 'LineEnds:2', que só encontrará as extremidades de linha bem longe de qualquer canto ou junção diagonal. O 'LineEnds:4' é um núcleo de extremidade de linha tradicional, que é rotacionado de forma cíclica para produzir 8 núcleos (por exemplo 'LineEnds:4@). No entanto, ele falhará em localizar o último pixel de uma linha que se conecta a uma junção 'T' ortogonal. O conjunto '[LineEnds](#lineends)' padrão, como definido acima, no entanto, encontra esse pixel final em junções 'T', usando o mesmo número de núcleos.

LineJunctions

Onde '[LineEnds](#lineends)' encontra as extremidades de um grupo de linhas, 'LineJunctions' encontrará pontos que formam uma junção de 3 ou mais linhas.

[IM Output]

Por exemplo, aqui usamos '[Hit-And-Miss](#hitmiss)' para encontrar todas as junções de linhas.

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif

[IM Output] [IM Output] [IM Output]

O núcleo '[LineJunctions](#linejunctions)' é geralmente usado para dois propósitos.

  • Contar o número de junções de linhas em uma imagem e, assim, trabalhar em direção a uma contagem do número de segmentos de linha no esqueleto.
  • Desconectar todos os segmentos de linha uns dos outros.

Note, no entanto, que nas junções 'T' e '+' na imagem acima, o núcleo de junção 'Y' corresponde a pontos que estão a um pixel de distância da interseção real. Por causa disso, as contagens de junções podem não ser exatamente como esperado, especialmente no '+' onde quatro correspondências foram encontradas em vez de apenas as duas necessárias para uma contagem de junção. Recomenda-se cautela. Veja Informação do Esqueleto, e Poda Rápida de Linhas para mais detalhes desses dois aspectos. O núcleo na verdade define apenas os pixels de primeiro plano, e como tal pode ser aplicado simplesmente como um método '[Erode](#erode)', em vez de como um método '[Hit-and-Miss](#hitmiss)'. Subtipos de Junção de Linha Este núcleo também fornece acesso aos vários subtipos, especificando argumentos 'type[,angle]'. Isso pode ser usado para buscar tipos específicos de junções de linha.

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Os núcleos 'LineJunctions:2' também podem ser especificados usando 'LineJunctions:3,45', e da mesma forma 'LineJunctions:5' e 'LineJunctions:4,45' são equivalentes. O conjunto de núcleos '[LineJunctions](#linejunctions)' padrão usa apenas as duas primeiras definições de junção (as junções 'Y' e 'T' diagonal), da seguinte maneira...

'LineJunctions:1@ ; LineJunctions:2>'

Isto é apropriado para junções de linha 8-conectadas. Como discutido nos Fóruns do IM "Kernels used by LineJunctions", se você quiser testar apenas junções de linha 4-conectadas, precisaria procurar junções 'T' ortogonais e junções '+'.

'LineJunctions:3> ; LineJunctions:5'

No entanto, como os núcleos 'T' também atingirão um '+', você pode reduzir o acima para apenas...

'LineJunctions:3>'

Um teste de imagem separado apenas para junções '+' de 4 vias pode ser usado para separá-las das junções 'T' de 3 vias, se isso for necessário para determinar contagens de segmentos de linha.

Ridges

Os núcleos 'Ridges' são usados para localizar cristas e linhas finas de pixels, como em uma imagem de Gradiente de Distância. Estes núcleos são experimentais e podem mudar. O padrão é projetado para localizar linhas de crista com espessura de um único pixel.

[IM Output]

Ridges:2 Um subtipo expandido especial projetado para encontrar linhas de crista com espessura de dois pixels. A complexidade é causada pela necessidade de localizar e marcar uma linha inclinada desse tipo, incluindo espelhamentos dessas linhas.

[IM Output]

Este conjunto de núcleos é importante porque um 'Esqueleto Morfológico' na verdade consiste tanto de linhas com espessura de 1 quanto de 2 pixels.

ConvexHull

O conjunto de núcleos 'ConvexHull' é projetado para engrossar formas de modo a produzir uma 'Envoltória Convexa Octagonal' da forma. Ou seja, a menor forma octagonal que pode conter toda a forma.

[IM Output]

Há dois conjuntos de núcleos rotacionados em 90 graus, um sendo a imagem espelhada do outro. Como a origem é na verdade um elemento de 'fundo', ela realmente só deve ser usada como um núcleo de padrão '[Thicken](#thicken)'. No entanto, o núcleo falhará para imagens que contenham 'fendas' horizontais ou verticais, como as que temos na forma 'man'.

  magick man.gif -channel R \
          -morphology Thicken:-1 ConvexHull  man_hull.gif

[IM Output] [IM Output]

A solução é '[Fechar](#close)' essas fendas (e o buraco central) antes de usar '[ConvexHull](#convexhull)'. |

  magick man.gif -morphology Close Diamond \
                  -morphology Thicken:-1 ConvexHull \
                  -morphology Close Diamond       man_hull_full.gif

[IM Output]
Note que no exemplo acima eu também repeti o '[Close](#close)' após usar '[ConvexHull](#convexhull)'. A razão é que quaisquer 'buracos' grandes em uma imagem também serão reduzidos pelo '[Thicken](#thicken)' até pixels únicos, ou 'fendas' ortogonais. Repetir o '[Close](#close)' remove esses buracos sem afetar a forma final. Aqui está outro exemplo, onde a forma original (branca) foi expandida usando um engrossamento de envoltória convexa (vermelho). |

  magick circles.gif -channel R \
          -morphology Thicken:-1 ConvexHull  circles_hull.gif

[IM Output]
Como você pode ver, o resultado é uma forma octagonal, enquanto o buraco central foi reduzido a uma fenda de dois pixels, pronta para ser fechada.

Skeleton

Gerar 'esqueletos' por meio do afinamento de uma forma específica não é uma tarefa fácil. Mesmo com o mesmo conjunto de núcleos, reordenar os núcleos pode gerar uma variação diferente no 'esqueleto' final. Por causa disso, eu não implementei apenas um conjunto de núcleos 'Skeleton', mas vários deles, que podem ser selecionados fornecendo um número de argumento 'type '.

Skeleton:1

O primeiro conjunto, e o padrão, '**Skeleton:1**', é um núcleo de afinamento tradicional, como o que foi usado primeiro. Este é basicamente exatamente igual ao núcleo '[Edges](#edges)' acima, mas rotacionado ciclicamente em incrementos de 45 graus. [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton   thin_skeleton1.gif

[IM Output]
O resultado é um 'esqueleto afinado' razoável de uma forma, embora as diagonais tendam a permanecer um pouco espessas em um lado. Basicamente, o esqueleto produzido é 4-conectado, o que permitirá que você use uma técnica de Poda Rápida. Note também que este conjunto de núcleos não expande corretamente o buraco de pixel único na imagem. Em outras palavras, o esqueleto ao redor daquele buraco não está nem perto da linha central entre o buraco e o restante da imagem. Para mais detalhes veja Afinando Até um Esqueleto.

Skeleton:2

A variante '**Skeleton:2**' é quase exatamente igual à versão tradicional 'Skeleton:1'. Ela foi encontrada na documentação dos Recursos de Processamento de Imagem HIPR2. [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton:2   thin_skeleton2.gif

[IM Output]
Se você comparar isto com o conjunto anterior, notará que o pixel interno dos cantos foi removido. Isso então permitirá que a operação de afinamento remova o engrossamento extra das diagonais. No entanto, esse afinamento diagonal não é simétrico, e é altamente dependente da forma da imagem, e da ordem em que os núcleos são aplicados. A variante 'Skeleton:2' está muito intimamente relacionada a simplesmente usar uma lista de núcleos combinada '**Edges;Corners**'. [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 'Edges;Corners' thin_edge-corner.gif

[IM Output]
A única diferença entre isto e o que 'Skeleton:2' usa é a ordenação dos núcleos na lista. Note como o esqueleto resultante também difere, mesmo que o mesmo conjunto de núcleos tenha sido usado. Isto mostra que gerar esqueletos por afinamento é na verdade bastante frágil, pois uma simples mudança de ordem pode produzir resultados diferentes no esqueleto conectado.

Skeleton:3

O '**Skeleton:3**' foi desenvolvido em um estudo formal sobre o uso de Núcleos de Afinamento (Veja Núcleos ThinSE abaixo), em um artigo de pesquisa "Connectivity-Preserving Morphological Image Transformations" de Dan S. Bloomberg, 1991. Ele desenvolveu uma boa quantidade desses esqueletos, e tabulou os resultados do estudo. O seguinte é o melhor que ele conseguiu apresentar, que gera um esqueleto 4-conectado. No entanto, ao contrário dos esqueletos anteriores, este requer o uso de 3 núcleos rotacionados (12 no total). [IM Output] |

  magick man.gif -channel RG \
          -morphology Thinning:-1 Skeleton:3   thin_skeleton3.gif

[IM Output]
Deve-se notar que o primeiro grupo de núcleos rotacionados contém apenas um único pixel de fundo. Isso significa que este esqueleto foi capaz de abrir o buraco de pixel único que está presente na forma 'man', e produzir um esqueleto orientado pela linha central. Ele não gera muitos ramos, produz linhas limpas e suaves, e também afina completamente. No geral, este é um dos melhores núcleos de afinamento de esqueleto.

ThinSE

O mesmo artigo de pesquisa "Connectivity-Preserving Morphological Image Thansformations" de Dan S. Bloomberg, na verdade desenvolveu a partir dos primeiros princípios uma gama completa de 'Elementos Estruturantes de Afinamento' 3x3 mínimos, todos projetados para preservar ou linhas 4-conectadas ou linhas 8-conectadas. O conjunto de núcleos '**ThinSE:**{_type_}' é uma lista de todos esses elementos estruturantes, e estão listados abaixo ordenados em grupos com base na conectividade e na força de preservação. O '{_type_}' é um número baseado nos números de elemento sobrescrito (grau de conexão) e subscrito usados no artigo de pesquisa. Como tal, o núcleo '**ThinSE:41**' é o primeiro dos elementos que preservam linhas 4-conectadas. Você também pode adicionar um ângulo de rotação, ou gerar um conjunto de flags rotacionados ou espelhados-rotacionados para a definição de núcleo dada.

[IM Output] [IM Output]
[IM Output] [IM Output]
[IM Output] [IM Output]

O último 'Núcleo Geral de Afinamento , '**ThinSE:482**', você pode reconhecer como sendo o mesmo núcleo usado para definir o conjunto de Núcleos de Detecção de Bordas. Este núcleo geral é na verdade o núcleo central a partir do qual todos os outros núcleos de afinamento mostrados acima foram desenvolvidos. Ele é o núcleo padrão do conjunto. Note que ambos os núcleos gerais 'ThinSE:481' e 'ThinSE:482' são os únicos núcleos relacionados por rotação. Ou seja, 'ThinSE:481x45' é equivalente a 'ThinSE:482'. Muitos dos outros conjuntos de núcleos HMT embutidos são na verdade definidos internamente em termos desses núcleos. Por exemplo, o conjunto de núcleos '**ThinSE:41 ; ThinSE:42 ; ThinSE:43**', e sua expansão rotacionada, produzirá os 12 núcleos usados para criar o conjunto '[Skeleton:3](#skeleton3)'. Este esqueleto foi listado no artigo como sendo o melhor conjunto de núcleos encontrado para produzir um bom esqueleto afinado. Os outros núcleos de afinamento geradores de esqueleto também são definidos usando os núcleos acima.
No entanto, esteja avisado de que alguns núcleos, como 'ThinSE:44', que embora projetado para preservar a 'conectividade', na verdade não preserva as extremidades de linha, e como tal fará com que um esqueleto seja podado até um único ponto, ou um conjunto de anéis conectados. Todos os núcleos não definem o valor de origem central, o que significa que você pode usar estes 'núcleos de afinamento' não apenas para 'Afinar Formas', mas também para 'Engrossar Formas', para gerar SKIZ (zonas de influência). Se você olhar com atenção, provavelmente notará que cada um dos núcleos 4-conectados está na verdade também presente em uma forma invertida e rotacionada em 180 no conjunto 8-conectado, e vice-versa. Por exemplo, 'ThinSE:41' e 'ThinSE:84' são rotações invertidas um do outro. A razão é que a conectividade 4 e 8 está intimamente relacionada uma à outra por meio da dualidade dos métodos morfológicos de afinamento e engrossamento (usando imagens invertidas). Essencialmente, um 'núcleo de afinamento' que preserva a conexão 4, que é então usado para engrossar uma imagem, resultará em um esqueleto de fundo 8-conectado (SKIZ não podado) ao redor da forma, e vice-versa. Assim, usando as formas invertidas (de modo que os métodos de engrossar e afinar são trocados), você pode gerar a outra forma de conectividade para a mesma operação.


Morfologia de Gradiente de Distância

O método morfológico 'Distance' é o primeiro dos muitos métodos especializados que são possíveis. O que ele faz é usar um núcleo especializado para medir a distância de cada pixel de primeiro plano da 'borda' da forma. Mais especificamente, ele mede a distância do pixel a um valor de cor 'zero' ou 'preto'. No entanto, ele só funciona com formas puramente binárias (branco sobre preto), embora, como você verá mais adiante, seja possível modificar uma forma com suavização de serrilhado para funcionar com o método de distância. E apenas com Núcleos de Distância especialmente projetados. O núcleo de distância é aplicado à imagem de modo que cada pixel receba o menor valor de pixel mais o valor do núcleo para aquela distância. Isto é aplicado por toda a imagem simultaneamente, usando um algoritmo que não requer múltiplas iterações, como vimos nos métodos morfológicos anteriores. Por causa disso, ele é quase tão rápido quanto uma única operação morfológica primitiva, o que é absurdamente rápido comparado, digamos, a um método morfológico de Esqueleto por Afinamento. Como ele é aplicado por toda a imagem, nenhum argumento de 'iteration ' é necessário, pois repetir (iterar) a mesma operação de núcleo não resultará em nenhuma mudança adicional no resultado. Antes do IM v6.6.9-4, uma contagem de iteração '-1' era necessária, pois o núcleo era aplicado usando uma técnica semelhante a um Erode normal. Isso não é mais necessário, e qualquer argumento de 'iteração' dado, diferente de zero (sem ação), é agora simplesmente ignorado.
Aqui está um exemplo de uso do método 'Distance', em nossa forma 'man'.
  magick man.gif -threshold 50% \
          -morphology Distance Euclidean:4 \
          +depth  distance.png

[IM Output] [IM Output]

Bem, isso foi realmente empolgante, NÃO! O problema é que a cor das imagens finais é muito, muito escura. Mas se você tiver um bom monitor, e puder olhar de perto, poderá ver uma forma muito escura, tipo 'fantasma', onde estava o 'man'. O que aconteceu foi que, pelo menos para esta imagem pequena, todos os pixels estão 'próximos' da borda, e assim não recebem um valor de 'distância' muito grande. | _Uma imagem PNG é recomendada para qualquer uso do método 'Distance'. Isso porque ela pode fornecer uma 'profundidade' de valor de saída maior do que, por exemplo, GIF, sem qualquer perda de cor como o JPEG.

É também a razão pela qual a Configuração de Profundidade "+depth" foi usada para garantir que a saída seja redefinida para profundidade de 16 bits (para minha versão Q16 do IM), mesmo tendo lido uma imagem de origem GIF de 8 bits.

Para usuários com uma versão Q8 do IM, sugiro que leiam sobre a opção de núcleo de distância 'scale' em Núcleos de Distância (abaixo) para ajustar os 'valores de escala' usados (veja a próxima seção abaixo). Usar versões Q8 do IM com núcleos de distância não inteiros (como este Núcleo de Distância Euclidiana) não é recomendado, embora produza um resultado menos preciso.

Veja a seção IM Examples sobre Qualidade e Profundidade, para uma melhor compreensão desses dois aspectos.


---|---
Por padrão, os Núcleos de Distância embutidos aplicarão um valor de cor de "100 × {_pixel_distance
}" a cada pixel. Se um pixel for mais brilhante que isso, ele é ajustado para esse valor de modo que a menor distância de um pixel a qualquer borda seja atribuída. O resultado é que os pixels ao longo da própria borda de uma forma receberão um valor de 100 unidades a mais que a cor de fundo. O próximo pixel mais interno receberá 100 unidades a mais. Exatamente quantas unidades serão atribuídas é dado pelo Núcleo de Distância que é usado. Então vamos ver o maior valor de cor que foi definido na imagem acima.

  magick identify -verbose distance.png | grep max:

[IM Text]

Ou seja, o maior valor de cor na imagem resultante foi '1616', tornando o pixel 'mais brilhante' da imagem um cinza muito escuro de 2,5%, e sua distância da borda mais próxima, 16,16 pixels de distância. Em outras palavras, vemos uma imagem muito escura, mas não realmente completamente preta. Vamos usar o matemático "[-auto-level](https://imagemagick.org/command-line-options/#auto-level)" para ajustar os valores de cor resultantes de modo que o pixel mais brilhante, ou mais distante de uma borda, seja definido como branco. Desta forma, podemos realmente ver o efeito completo do 'gradiente de distância' gerado. |

  magick distance.png -auto-level  distance_man.gif

| Como não nos importamos mais com os valores exatos de 'distância' gerados para esta imagem, apenas com o efeito visível da distância, a imagem pode agora ser salva e exibida usando o formato de arquivo de imagem GIF.
---|---
[IM Output]
Isto é o que o método 'Distance' faz. Gera um gradiente ao longo da forma dada, definindo o quão longe cada pixel está da borda mais próxima, de acordo com o Núcleo de Distância específico usado. Outra maneira de tornar a imagem de 'distância' resultante mais brilhante é na verdade usar um valor de 'scale ' de núcleo de distância maior, por exemplo um valor de 3000 unidades (usuários Q8 provavelmente podem usar um valor de 20). |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,3000     distance_scaled.gif

[IM Output]
Note que o gradiente de distância não cobriu de preto a branco, atingindo um pico em algum valor de escala de cinza. Como já sabemos a 'distância' do pico, podemos calcular que esse pico máximo seja 16.16 * 3000 => 48480 ou cerca de 74% cinza. Você também pode usar um fator de escala percentual, por exemplo, usar um valor de faixa de cor de 8% para cada pixel de distância da borda. |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,8%    distance_scale_percent.gif

[IM Output]
Como você pode ver, desta vez atingimos nosso limite de valor máximo antes de alcançar a distância máxima. Você pode calcular que a distância máxima que o gradiente de distância pode cobrir é (100% na faixa máxima) / (8% por pixel) => 12.5 pixel_distance. Claro que, se você estivesse usando uma versão HDRI do ImageMagick, os valores completos de distância seriam mantidos na memória, pelo menos até você Fixar seu valor, ou salvá-lo em um formato de arquivo de imagem de ponto não flutuante. Você também pode especificar diretamente a distância máxima de pixel na qual está interessado usando o especial Flag de Escala de Distância, '!'. Como já sabemos que nossa forma tem uma distância máxima da borda de 16,16, vamos ao menos solicitar um limite de 18 pixels. |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4,'18!'   distance_range.gif

[IM Output]
O flag '!' escalonará a distância de modo a dar 'n' valores de escala de cinza antes que o limite da faixa de cor seja atingido. Como tal, um valor de 1 apenas 'suavizará' (ou tornará cinza) apenas os pixels que são vizinhos diretos da borda da imagem. Como você pode ver, todos os métodos de escalonamento, no entanto, dependem fortemente do tamanho real da forma na qual você está executando o método 'Distance'. Muito pequena e ela fica muito escura e pode não ser precisa para suas necessidades. Muito grande e a distância pode ser 'cortada' pelo valor de cor máximo possível da Qualidade de Tempo de Compilação do seu ImageMagick. Para mais detalhes sobre o fator 'scale ' no núcleo, veja a seção Núcleo de Distância abaixo. Gostaria de fazer uma última observação sobre a 'forma' semelhante a um homem usada nesses exemplos. A forma contém um 'buraco' de pixel único que criou uma espécie de 'poço de gradiente' ao seu redor. Isso resulta em um efeito muito forte na metade superior da imagem de 'gradiente de distância' resultante. Uma solução para isso é remover esse buraco, usando '[Close](#close)', de modo a tornar a forma 'limpa e suave'. Por exemplo...

  magick man.gif -morphology Close Diamond  man_clean.gif
  magick man_clean.gif   -morphology Distance Euclidean \
                                    -auto-level   distance_clean.gif

[IM Output] [IM Output] [IM Output]

Claro que isso também tem o efeito de também 'fechar' a lacuna entre as 'pernas' da forma, o que afeta a metade inferior do resultado final. Uma solução alternativa é usar um método de Preenchimento por Inundação para extrair a parte externa da imagem, e transformar isso em uma nova máscara. O resultado é que quaisquer buracos foram fechados, mas a fronteira externa da imagem foi preservada. Por exemplo...

  magick man.gif -gamma 0,1,1 -bordercolor black -border 1x1 \
          -fill red -floodfill +0+0 black -shave 1x1 \
          -channel R -separate +channel -negate  man_floodfill.gif
  magick man_floodfill.gif    -morphology Distance Euclidean \
                                    -auto-level   distance_floodfill.gif

[IM Output] [IM Output] [IM Output]

Núcleos de Distância

O núcleo dado é muito especial, pois é usado para definir as medidas reais de distância que serão atribuídas a cada pixel. Por exemplo, aqui está a saída de Mostrar Núcleo de um dos 'Núcleos de Distância' embutidos.

  magick xc: -define morphology:showkernel=1 -precision 3 \
          -morphology Distance:0 Chebyshev:3     null:

[IM Text]

O importante a notar é que a 'origem' (neste caso o centro exato do núcleo) tem um valor de zero. Isto é muito importante. Essa 'origem' é então cercada por valores maiores, que aumentam linearmente com maior distância dessa 'origem'. Se o núcleo não for definido dessa maneira específica, efeitos inesperados e estranhos podem resultar. O valor dado no núcleo é o 'valor' real que será adicionado a uma distância já 'conhecida', atribuída a um pixel se esse valor for menor do que o já atribuído. O resultado é que os pixels 'brancos' ficam mais escuros quanto mais próximos estão de uma borda, e linearmente mais brilhantes (somando aos valores previamente atribuídos) quanto mais longe ficam da borda. Todos os Núcleos de Distância embutidos fornecidos podem receber dois k_argumentos opcionais...

     {_distance_kernel_}[:{_radius_}[,{_scale_}[%][!]]]

O primeiro argumento, como todos os Núcleos de Forma, é o radius dos núcleos, que define o tamanho a ser dado ao núcleo gerado. Por padrão, o radius é definido como '1' para os núcleos de distância embutidos, resultando em um núcleo muito pequeno de 3 por 3, o que na maioria dos casos funciona bastante bem. O segundo argumento 'scale ' define a escala de distância usada para representar a distância de um comprimento de pixel. Como mostrado no exemplo acima, ele assume por padrão um valor de '100'. Ou seja, um pixel que recebe um valor final de pixel ou escala de cinza de, digamos, '300' deve estar exatamente a '3 pixels' de distância da borda. Escalonamento de Distância Como mencionado anteriormente, um valor grande de 'scale ' é usado para que você possa usar distâncias 'fracionárias' para medidas de distância mais 'exatas'. No entanto, apenas o núcleo de distância '[Euclidean](#euclidean)' fornecido usa tais valores 'fracionários'. Nos exemplos anteriores, o valor de 'maior distância' atribuído foi '1700', o que estouraria uma versão Q8 do ImageMagick (Veja Qualidade, profundidade de bits em memória). Um IM Q8 só permite que valores de cor atinjam um valor máximo de 255 (2Q => 28 => 256 valores de cor, variando de 0 a 255). Como tal, usar um scale menor como '10' ou '20' funcionará melhor para usuários que utilizam a variante de tempo de compilação IM Q8. Embora seja muito menos preciso quando usado com um núcleo '[Euclidean](#euclidean)'. Por causa disso, recomenda-se que usuários com versões Q8 do IM restrinjam-se a usar os outros núcleos de distância 'inteiros', com um fator de escala de '1'. Você também pode especificar o escalonamento de distância como uma porcentagem da faixa de cor completa, incluindo um '%' no fator de escala. Isso significa que, se você usar uma escala de '12.5%' da faixa de valores de cor, então será capaz de obter uma métrica de distância de cerca de 8 pixels antes que a distância estoure os limites da faixa de cor da versão do IM que você está usando. Alternativamente, você pode usar um '!', o que significa que a escala é um divisor da faixa de cor. Ou seja, se você especificar uma escala de '20!', o escalonamento de distância será definido de modo que o limite da faixa de cor seja atingido a 20 pixels da borda da imagem. No entanto, mesmo com esses 'flags de escala especiais', você ainda terá uma limitação severa de precisão de faixa nas versões Q8 do IM. Ela simplesmente não tem a faixa para os valores de dados necessários para muitas operações de distância. Claro que qualquer scale (incluindo ponto flutuante completo) pode ser usado com precisão em versões HDRI do IM, pois os valores de cor resultantes também são armazenados como valores de ponto flutuante. Apenas certifique-se de reescalonar a faixa de cor apropriadamente antes de tentar salvar tal imagem em formatos de arquivo de imagem de ponto não flutuante.
Uma série de diferentes núcleos de medição de distância é fornecida, com um que pode ser usado de duas maneiras diferentes. Cada núcleo fornece diferentes 'métricas de distância' resultantes para especificar a distância do pixel à borda, e basicamente define o que deve ser considerado a 'borda mais próxima'.

Núcleo de Distância de Chebyshev (Tabuleiro de Xadrez)

O núcleo de distância '**Chebyshev**' é o mais simples, e especifica que todos os pixels ao redor da 'origem' estão simplesmente a 1 unidade de distância de seus vizinhos. Ou seja, todos os 8 vizinhos estão 'ao lado' um do outro. Como tal, não apenas os quatro vizinhos imediatos estão a uma distância de 1 unidade, mas os vizinhos diagonais também estão exatamente a 1 unidade de distância. Isto é frequentemente comparado à distância em casas que uma peça de xadrez 'Rei' ou 'Rainha' se move em um tabuleiro de xadrez, e por isso também é frequentemente conhecido como uma métrica de distância de 'Tabuleiro de Xadrez '. Note, no entanto, que os núcleos de distância usam um fator {scale} padrão de 100 unidades de distância, por pixel de distância. Como tal, a distância é de 100 unidades para cada passo para longe da origem. Este também foi o núcleo usado nos exemplos anteriores acima. Aqui está o núcleo real que ele gera...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Chebyshev       null:

[IM Text]

O nome deste núcleo é o do matemático russo Pafnuty Chebyshev, que primeiro descreveu matematicamente esta forma de medição de distância. Você pode descobrir mais sobre esta medida na Wikipedia, Chebyshev Distance. Usando uma medida de distância 'Chebyshev', a distância final de um pixel é o maior valor X ou Y até a borda mais próxima. No entanto, como a distância diagonal é de apenas 1 unidade, a distância máxima dentro de uma imagem é geralmente menor do que você esperaria. Vamos gerar um 'gradiente de distância' usando esta 'métrica' de núcleo. No entanto, para que possamos ver o que está acontecendo, vamos usar um método morfológico mais lento 'Iterative Distance', usando uma contagem de iteração infinita. | |

  magick man.gif -threshold 50% +depth \
          -define debug=true -morphology IterativeDistance:-1 Chebyshev \
          chebyshev_gradient.png


  magick identify -format 'Maximum Distance = %[max]' chebyshev_gradient.png
  magick chebyshev_gradient.png -auto-level chebyshev_gradient.gif
  rm chebyshev_gradient.png

[IM Output]
| [IM Text]
[IM Text]


| _O método morfológico 'Iterative Distance' calcula a distância aplicando o núcleo de distância repetidamente até que nenhuma mudança adicional de valor seja vista.

Isto é muito mais lento que o método 'Distance' mais normal, que usa um método de duas passagens para definir a distância pela imagem como um todo. No entanto, a saída detalhada do método 'Distance' é muito menos interessante.


---|---
Eu ativei o flag Verbose para que o comando gere quantos pixels foram alterados (todos os pixels brancos) pela operação, durante cada iteração (passagem) pela imagem. Então eu extraí a distância 'máxima' gerada ('1400'), antes de ajustar o resultado (normalizando) em uma imagem onde você pode ver o gradiente resultante. A distância máxima '1400' é o valor dos pixels mais brilhantes na imagem (na verdade é um agrupamento de 4 desses pixels). Esta informação é o resultado mais importante deste núcleo de distância (métrica), pois representa o tamanho do maior quadrado que caberá dentro desta forma. Especificamente, um raio de 14 pixels ou um quadrado de aproximadamente (R-1)*2+1 => 27 pixels por lado, centralizado nesses 4 pixels máximos. Como todas as unidades de distância neste núcleo são sempre múltiplos de '100', então este valor final de distância deve sempre ser um múltiplo de '100', e nunca terá qualquer componente fracionário. Basicamente, este núcleo produzirá uma distância inteira, e você pode usar um _scale
simples de '1 unidade' com este núcleo sem perda de qualquer informação de distância. Isto é recomendado se você estiver usando uma versão Q8 do ImageMagick, ou estiver aplicando isso a imagens muito, muito grandes. Aqui está uma ampliação do gradiente entre as 'pernas' da forma, que destaca as características do gradiente de distância gerado. |

  magick chebyshev_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% chebyshev_magnify.gif

[IM Output]
Como você pode ver, o núcleo de distância '[Chebyshev](#chebyshev)' produz um gradiente muito semelhante a um quadrado. Esta é uma característica específica desta forma simples de métrica de distância, e reflete diretamente a natureza quadrada do próprio núcleo de distância. O acima também mostra os 4 pixels de distância máxima na 'barriga' da figura, próximos ao topo da imagem. Centralizando um quadrado em qualquer um desses 4 pontos, você pode gerar o maior quadrado de tamanho ímpar que está totalmente contido dentro da figura. No entanto, esteja avisado de que pode haver uma série de tais 'picos'.

Núcleo de Distância de Manhattan (Táxi)

O núcleo de distância '**Manhattan**' mede a distância somando os valores X e Y até a borda mais próxima. É basicamente a distância que você precisa percorrer quando está restrito apenas a movimentos em grade, como um táxi nas ruas de grandes cidades como Manhattan, Nova York. Por causa disso, outros nomes mais comuns para esta medida são a métrica de distância 'Táxi ' ou 'Quarteirão de Cidade '. Você pode descobrir mais na Wikipedia, Manhattan Distance. Aqui está o núcleo real que ele gera...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Manhattan     null:

[IM Text]

Note que as diagonais agora têm um valor de '200' ou 2 unidades do centro. Ou seja, para alcançar um pixel diagonal você teria que percorrer dois pixels nos movimentos em grade mencionados. Como resultado disso, as diagonais tendem a ser maiores do que o esperado, e como tal as medidas finais de distância também tendem a ser maiores. Vamos novamente extrair a distância máxima e a imagem de 'gradiente de distância' usando esta 'métrica'. | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Manhattan      manhattan_gradient.png


  magick identify -format 'Maximum Distance = %[max]' manhattan_gradient.png
  magick manhattan_gradient.png -auto-level manhattan_gradient.gif
  rm manhattan_gradient.png

[IM Output]
| [IM Text]


Eu não usei 'Iterative Distance' desta vez, e mesmo que tivesse usado, a contagem total de pixels alterados não seria precisa. Apenas o núcleo '[Chebyshev](#chebyshev)' anterior definirá uma distância de pixel uma vez e apenas uma vez. Note como a distância máxima final para a imagem é muito maior, em '1700' unidades de distância, tornando o(s) pixel(s) máximo(s) dentro da forma a 17 pixels da borda. Este núcleo de distância também é um núcleo 'inteiro', e como tal você pode definir o scale como apenas '1 unidade' sem perda de informação. Aqui está uma ampliação do gradiente. |

  magick manhattan_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% manhattan_magnify.gif

[IM Output]
Como você pode ver, o núcleo de distância '[Manhattan](#manhattan)' gerou um gradiente semelhante a um diamante, que é basicamente o que esta métrica de distância simples representa, como refletido pelos valores reais do núcleo.

Núcleo de Distância Octagonal

O núcleo de distância '**Octagonal**' é um pouco diferente dos outros dois. Ele é criado gerando primeiro uma distância de Manhattan para os pixels na própria borda, depois usando Chebyshev para os pixels que estão a 2 unidades de distância da borda. Em seguida, ele repete usando a distância de Manhattan para os pixels a 3 unidades de distância, e assim por diante. O resultado é um 'entrelaçamento' ou 'média' de distância resultante do uso dos dois núcleos mais simples. Como este núcleo é baseado em um entrelaçamento de dois núcleos de distância inteiros, ele também é um núcleo de distância inteiro. Como tal, um scale de '1 unidade' pode ser usado para produzir valores menores, para versões de menor qualidade do ImageMagick, ou medidas de distância muito grandes. A forma da distância também é uma mistura dos dois núcleos e como tal produz o equivalente ao núcleo em forma de '[Octagon](#octagon)'. Aqui está o núcleo real que ele gera...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Octagonal     null:

[IM Text]

Note que o núcleo tem um tamanho mínimo e padrão de raio 2, formando um núcleo de 5x5 pixels. Este núcleo ligeiramente maior é necessário para gerar o 'entrelaçamento' dos núcleos. A distância geral será geralmente um pouco menor que uma distância verdadeira. Aqui calculamos novamente a distância máxima... | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Octagonal  octagonal_gradient.png


  magick identify -format 'Maximum Distance = %[max]' octagonal_gradient.png
  magick octagonal_gradient.png -auto-level octagonal_gradient.gif
  rm octagonal_gradient.png

[IM Output]
| [IM Text]


O resultado de '1500' é uma distância 'inteira', e na verdade fica entre a Distância de Chebyshev, muito pequena, e a Distância de Manhattan, muito grande. No entanto, em geral, ela deve ser razoavelmente próxima da distância real ao centro da forma, permanecendo um valor 'inteiro'. Aqui está uma ampliação do gradiente. |

  magick octagonal_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% octagonal_magnify.gif

[IM Output]
Você pode ver claramente as distâncias 'octagonais' que se desenvolveram ao redor do topo da lacuna das pernas. Você também pode ver que a diagonal foi gerada usando um entrelaçamento de linhas diagonais grossas e finas.

Núcleo de Distância Octagonal Fracionário

Um núcleo de distância nomeado não foi fornecido. Mas ele se encaixa bem na sequência de núcleos de distância que estamos estudando neste ponto. Você pode gerar outro tipo de núcleo de distância inteiro usando uma forma octagonal. No entanto, a distância inteira neste caso usa um valor unitário de 2 por pixel, então na verdade os valores de distância gerados precisam ser divididos pela metade, gerando um valor fracionário a partir dos pequenos inteiros que são gerados. Daí o nome "Octagonal Fracionário". Para fazer isso, usamos uma distância inteira de 2 entre pixels vizinhos, e 3 para a diagonal.

'3: 3,2,3
    2,0,2
    3,2,3'

Como 'meios inteiros' podem ser gerados, a menor escala mínima que pode ser usada é '2 unidades'. E embora não seja tão preciso quanto um 'movimento de cavalo', ele funciona bem. O octógono deste núcleo tem 'pontas' na direção ortogonal, em vez de 'lados planos' como o núcleo anterior gera. Ele está relacionado, mas não é exatamente igual ao próximo núcleo 'Movimento de Cavalo', e poderia ser considerado uma espécie de forma 'quase inteira' do núcleo 'knights'. Se você quiser escaloná-lo da mesma forma que os núcleos de distância anteriores do IM, você pode usar este núcleo.

'3: 150,100,150
    100, 0 ,100
    150,100,150'

Aqui está um exemplo | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance '3:3,2,3 2,0,2 3,2,3' \
          fractional_gradient.png


  magick identify -format 'Maximum Distance = %[max]' fractional_gradient.png
  magick fractional_gradient.png -auto-level fractional_gradient.gif
  rm fractional_gradient.png

[IM Output]
| [IM Text]


O resultado de '34' é uma distância 'inteira', mas precisa ser dividido por 2 para produzir um resultado de distância máxima real de 17. No entanto, embora este também seja um inteiro, ele poderia igualmente resultar em uma distância fracionária de 16,5. Este aspecto fracionário dos resultados de distância é por que a maioria dos núcleos é definida usando unidades de 100, e se tornará mais prevalente em núcleos posteriores à medida que nos afastamos dos núcleos de distância puramente inteiros. Aqui está uma ampliação do gradiente. |

  magick fractional_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% fractional_magnify.gif

[IM Output]
O gradiente (se você estudar os resultados cuidadosamente) é uma forma octagonal. Mas é difícil ver os pixels que têm valores de distância comuns. Para ver a forma mais claramente, peguei a imagem acima e colori um conjunto de pixels com o mesmo valor de cor, vermelho. |

  magick fractional_magnify.gif -fill red -opaque gray53 \
          fractional_magnify_shape.gif

[IM Output]
Como você pode ver, pixels do mesmo valor são geralmente separados em um padrão de 'movimento de cavalo', mas formam linhas que geram uma forma octagonal. O octógono, no entanto, é rotacionado em 45 graus a partir do Núcleo de Distância Octagonal. É também essa diferença de forma que faz com que a distância máxima final seja maior. Essencialmente, um octógono maior rotacionado desta forma se encaixa melhor na forma, resultando assim em uma distância máxima maior. Outro núcleo de distância 'inteiro' fracionário que pode ser usado é este, embora a distância seja em termos de 3 unidades em vez de 2. Ou seja, os resultados precisam ser divididos por 3 para obter a distância em termos de tamanho de pixel, o que não é realmente um ótimo divisor para usar. É, no entanto, outra métrica de distância do tipo octagonal.

'3: 4,3,4
    3,0,3
    4,3,4'

O Núcleo de Distância Euclidiana (Movimento de Cavalo) abaixo também gera um estilo octagonal de forma (todos os núcleos de distância 3x3 o fazem), mas tenta ser o mais preciso possível ao longo das diagonais. Isto pode ou não ser a melhor ideia, mas é o núcleo de distância octagonal mais logicamente matemático deste tipo.

Núcleos de Distância de Chanfro

Um núcleo de distância nomeado não foi fornecido. Mas ele se encaixa bem na sequência de núcleos de distância que estamos estudando neste ponto. Um núcleo de Distância 'Chanfro' (ainda não implementado), é definido usando apenas os números (tipicamente inteiros) que serão usados para preencher a matriz de distância. Você pode, por exemplo, dar a ele 2 números para definir qualquer núcleo de distância do tipo 'octagonal' 3x3, como descrito acima. Aqui estão as definições dos núcleos inteiros anteriores, Chebyshev Chamfer:1,1
Manhattan Chamfer:1,2
Octagonal Fracionário Chamfer:2,3
Octagonal Fracionário Alternativo Chamfer:3,4
--- ---
Todos esses núcleos são simples núcleos de raio 1. Os valores dados podem ser considerados como os valores reais de 'escalonamento de distância' que ele deveria estar usando. Note, no entanto, que o núcleo Inteiro Octagonal anterior requer um Núcleo de Chanfro de raio 2 com 3 números para defini-lo. O núcleo de Chanfro mais conhecido é como núcleo de raio 2, 'Chamfer:5,7,11', que gera uma distância muito precisa, e também gera valores de distância inteiros, tornando-o bem adequado para usuários Q8. Tradicionalmente, o núcleo (chanfro 5,7,11) tem a forma...
'5:  -   11   -   11   -
    11    7   5   7    11
     -    5   0   5    -
    11    7   5   7    11
     -   11   -   11   -'

OU multiplique o acima por 20, para produzir o mesmo escalonamento de distância de pixel (100) usado normalmente pelo ImageMagick para núcleos de distância....

'5:  -   220   -   220   -
    220  140  100  140  220
     -   100   0   100   -
    220  140  100  140  220
     -   220   -   220   -'
Observe como o núcleo não preenche de fato TODAS as distâncias do núcleo. Isso ocorre porque esses valores obterão suas distâncias a partir dos outros valores já fornecidos. Ou seja, você não precisa de fato preencher todo o array bidimensional para definir completamente um núcleo de distância, embora isso seja tipicamente feito para facilitar o processamento. Aqui está uma lista de outros núcleos Chamfer conhecidos (usando apenas valores inteiros) que encontrei em minha pesquisa. Chamfer:3,4 /3
Chamfer:5,7,11 /5
Chamfer:99,141,221 /100
Chamfer:987,1414,2206 /1000
Chamfer:12,17,27,38,43 /12

[diagram]
Como 5 valores são posicionados para definir um núcleo Chamfor de raio 3

O núcleo destacado na tabela acima é o Núcleo de Distância Chamfor mais conhecido e comumente utilizado. Ele gera a imagem usando apenas pequenos valores inteiros, de modo que as grandes imagens de gradiente de distância podem ser armazenadas sem perda de precisão. Ele também é muito preciso, ao menos o suficiente para praticamente qualquer propósito imaginável. Como bônus, os resultados de distância não criam casas decimais recursivas, apenas uma fração de um único dígito quando normalizados. Este é outro motivo pelo qual ele é frequentemente selecionado por muitos pacotes de processamento de imagem. O "Chamfer:5,7,11" deve ser considerado o núcleo de Distância "Chamfor" padrão.

Núcleo de Distância Euclidiano (Movimento de Cavalo)

O núcleo '**Euclidean**' é gerado usando números de distância exatos em ponto flutuante. Mas para que isso funcione com versões não-HDRI do ImageMagick é necessário o uso de distâncias diagonais fracionárias. Como a diagonal, que tem um valor igual à raiz quadrada de 2, um valor de cerca de 1,4142 unidades de distância. Para permitir que isso funcione, as distâncias são escaladas por um valor de 100 (como em todos os núcleos acima), para produzir uma distância percentual fracionária. Aqui está o núcleo padrão que ele gera...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Euclidean    null:

[IM Text]

Agora, usando o raio padrão de 1, embora seja uma grande melhoria em relação aos núcleos anteriores em termos de precisão, ainda há algumas limitações. Basicamente, ele fornece uma distância em termos de apenas diagonais de 45 graus e movimentos ortogonais (X e Y). Ou seja, as distâncias se assemelham de certo modo a um 'Movimento de Cavalo ' no jogo de xadrez. Aqui está a distância máxima e a imagem de 'gradiente de distância' que foi criada usando o núcleo 'Euclidean' ou 'Movimento de Cavalo' padrão. | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean    knight_gradient.png


  magick identify -format 'Maximum Distance = %[max]' knight_gradient.png
  magick knight_gradient.png -auto-level knight_gradient.gif
  rm knight_gradient.png

[IM Output]
| [IM Text]


Como você pode ver para esta forma específica, você também obtém um valor de distância de '1700' unidades de distância. Normalmente o resultado seria alguma distância fracionária, entre a menor distância '[Chebyshev](#chebyshev)', ou a maior distância '[Manhattan](#manhattan)'. Foi pura sorte que tenha resultado em um múltiplo simples de '100' e que também tenha calhado de ser igual à distância '[Manhattan](#manhattan)'. A distância real até um pixel é, na verdade, a soma da distância diagonal com a distância ortogonal (dos eixos). Ou seja, não é exatamente uma distância euclidiana perfeita, mas é a mais próxima que se pode obter usando o menor núcleo de distância possível (de raio 1). Aqui está uma ampliação do gradiente entre as 'pernas' da forma. |

  magick knight_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% knight_magnify.gif

[IM Output]
Como você pode ver, o gradiente tem um aspecto muito mais arredondado, sem o efeito de 'níveis' ou 'terraços' semelhante a uma cebola que se obtém com um núcleo de distância 'inteiro'. Isso ocorre porque cada pixel tem mais probabilidade de receber uma distância fracionária individual a partir da borda. A forma final do gradiente, no entanto, é na verdade aproximadamente 'octogonal', embora com pontas como os pontos de uma bússola, em vez de topos e bases planos como se obtém com o núcleo de distância '[Octagonal](#octagonal)' anterior. Para trabalhos gerais de distância (como 'esfumaçar'), este núcleo 'Euclidean' ou 'Movimento de Cavalo' padrão fornece um bom resultado. No entanto, como você não obtém distâncias 'inteiras', não é possível usá-lo com um fator de escala de distância de '1', tornando-o menos útil para versões Q8 do ImageMagick.

Núcleo de Distância Euclidiano Maior

Ao aumentar o 'raio ' do núcleo 'Euclidean' gerado, você produz uma métrica de distância 'Pitagórica' ou 'Euclidiana' verdadeira ainda mais precisa. Quanto maior o raio, mais preciso o resultado, mas o método morfológico '[Distance](#distance)' levará mais tempo para executar, embora sejam necessárias menos iterações. Além de um raio de 4, no entanto, você não obterá muito mais precisão, mas terá uma perda de velocidade muito maior. Veja Distância com uma Forma com Anti-Serrilhamento abaixo para alguns exemplos de uso de núcleos 'Euclidean' muito grandes para melhorar a precisão. Aqui está um verdadeiro núcleo 'Euclidean' usando o raio recomendado de 4, que gera um núcleo 9×9 maior...

  magick xc: -define morphology:showkernel=1  -precision 4 \
          -morphology Distance:0 Euclidean:4     null:

[IM Text]

A vantagem adicional de usar um raio de 4 é que o núcleo também contém o Triângulo Pitagórico, que tem lados 3,4,5, ou, com a escala padrão do núcleo, unidades de 300,400,500. Embora isso possa reduzir o número de componentes fracionários na imagem resultante, é realmente apenas um efeito menor. Ainda assim, é uma escolha lógica para maior precisão. Aqui está a sua aplicação... | |

  magick man.gif -threshold 50% +depth \
          -morphology Distance Euclidean:4     euclidean_gradient.png


  magick identify -format 'Maximum Distance = %[max]' euclidean_gradient.png
  magick euclidean_gradient.png -auto-level euclidean_gradient.gif
  rm euclidean_gradient.png

[IM Output]
| [IM Text]


Como resultado do uso deste núcleo 'Euclidean' de raio maior, a distância máxima final é a medição de distância máxima mais precisa até agora. Isso também torna improvável que você obtenha mais de um pixel 'mais brilhante' na imagem, a menos que a forma seja muito regular. Aqui está uma ampliação do gradiente entre as 'pernas' da forma. |

  magick euclidean_gradient.gif -crop 25x20+39+69 +repage \
          -scale 500% euclidean_magnify.gif

[IM Output]
Como você pode ver, o gradiente produz um gradiente quase perfeitamente circular ao redor da extremidade do 'vão entre as pernas'. O custo de usar este núcleo é, como eu disse acima, um tempo de execução marginalmente mais lento.

Comparação dos Núcleos de Distância

Aqui está novamente uma comparação lado a lado das ampliações. Isso mostra claramente os gradientes bem diferentes gerados por cada uma das quatro métricas de distância utilizadas.

[IM Output]
Chebyshev
(Tabuleiro de Xadrez) | [IM Output]
Manhattan
(Táxi) | [IM Output]
Octagonal
(Misto) | [IM Output]
Euclidean
(Movimento de Cavalo) | [IM Output]
Euclidean
(raio=4)
---|---|---|---|---

Aqui está outra comparação, desta vez obtendo a distância a partir de um único pixel preto próximo ao canto inferior esquerdo, sem qualquer ampliação dos pixels.

  magick -size 100x100 xc: -draw 'point 20,80'  distance_start.png

  for kernel in chebyshev manhattan octagonal euclidean euclidean:2 euclidean:4
  do
    magick distance_start.png    -morphology Distance $kernel \
            -auto-level  point_$kernel.png
  done

[IM Output]
Chebyshev
(Tabuleiro de Xadrez) | [IM Output]
Manhattan
(Táxi) | [IM Output]
Octagonal
(Misto) | [IM Output]
Euclidean
(Movimento de Cavalo) | [IM Output]
Euclidean
(raio=2) | [IM Output]
Euclidean
(raio=4)
---|---|---|---|---|---

Essas imagens mostram claramente as linhas ao longo das quais os pixels são considerados mais próximos do pixel inicial do que você provavelmente esperaria, e como os vários núcleos se tornam mais suaves à medida que ficam mais complexos. Apenas o último não mostra linhas visíveis de 'pixels mais próximos', mas mesmo com raio 4 elas estão presentes. Para este núcleo, as linhas só aparecem a uma grande distância da origem. Um raio 7 produz resultados ainda melhores, mas a um grande custo em velocidade, embora às vezes tal precisão seja necessária para evitar artefatos na imagem resultante. Lembre-se de que apenas os três primeiros núcleos produzirão distâncias inteiras, que podem ser usadas em uma versão Q8 do ImageMagick (com o ajuste de escala apropriado, veja a descrição de cada núcleo individual). E são estes que são tipicamente o que muitos pacotes de processamento de imagem usarão. O cálculo da distância a partir de um único ponto será examinado novamente mais adiante nos exemplos de Distância Restringida abaixo.

Núcleos de Distância Especiais Definidos pelo Usuário

Você não está limitado aos núcleos de distância que foram fornecidos para você. Desde que você siga as regras de usar um valor zero na 'origem' e um valor de distância crescente ao seu redor, você pode gerar outros efeitos de distância muito interessantes. Por exemplo, aqui eu aplico um Núcleo Definido pelo Usuário muito pequeno que simplesmente diz para tornar maior o valor de qualquer pixel à direita. |

  magick man.gif -threshold 50% +depth \
          -morphology Distance  '2x1+0+0: 0,100 ' \
          -auto-level    distance_linear.gif

[IM Output]
Observe o efeito do vão entre as pernas, que 'reinicia' o gradiente que aumenta lentamente por ele gerado. E aqui eu crio um gradiente de distância a partir apenas dos dois lados, mas com escalas diferentes para cada lado! |

  magick man.gif -threshold 50% +depth \
          -morphology Distance  '3x1: 50,0,100 ' \
          -auto-level    distance_sides.gif

[IM Output]
Estes são apenas alguns exemplos de variantes de núcleo de distância que são possíveis. Você consegue pensar em outros? Por favor, me avise. Observe que, se sua imagem sair ruim, provavelmente a configuração da origem do seu núcleo está errada, ou a origem não tinha um valor 'zero'. Isso não é verificado pela função de distância morfológica.

Distância com uma Forma com Anti-Serrilhamento

O método Distance funciona muito bem. Mas o melhor teste de sua funcionalidade é aplicar a função de distância a um círculo e, em seguida, aplicar Shade para destacar até mesmo o menor erro que possa ser gerado pela função.

  magick -size 129x129 xc: -draw 'circle 64,64 60,4' \
          -negate  circle_shape.png

  magick circle_shape.png  -morphology Distance Euclidean:4 \
          -auto-level cone_distance.png

  magick cone_distance.png -shade 135x30 -auto-level \
          +level 10,90%  cone_distance_shade.png

[IM Output] [IM Output] [IM Output]

Você pode ver acima que, embora obtenha um resultado com aparência 'cônica', ele está longe de ser um 'cone' suave. Ele é coberto por uma rede de cristas radiais que começam nas bordas. Se você olhar de perto a borda do cone sombreado, verá que o cone não tem uma base circular suave da forma original. Ela é altamente 'serrilhada' ou 'escalonada', e são esses 'degraus' que estão sendo refletidos pela função de distância para formar as cristas radiais que se veem. O problema é que o método de distância não tem ideia dos pequenos pixels 'cinza' de anti-serrilhamento que o círculo usa ao redor da borda para lhe dar aquela aparência suave. De fato, qualquer pixel 'cinza' é geralmente considerado como um pixel inteiro em vez do pixel de borda parcial com anti-serrilhamento que ele representa. O que precisamos fazer é de alguma forma incluir esses valores de borda cinza no resultado, e isso é feito usando uma etapa de pré-processamento antes de o método de distância ser aplicado. |

  magick circle_shape.png  -gamma 2 +level 0,100 -white-threshold 99 \
          -morphology Distance Euclidean:4   -auto-level \
          -shade 135x30 -auto-level +level 10,90%   cone_antialiased.png

[IM Output]
O que foi feito foi primeiro converter todos aqueles pixels cinza de uma representação de quanto do pixel estava dentro do limite do círculo para uma representação de quão longe o pixel estava da borda do círculo. Como você pode ver pelo resultado, quase todos os erros de borda escalonada foram corrigidos. Os erros finais que são visíveis só ocorrem afastados da borda, e se tornam mais visíveis em direção ao centro do 'cone'. Eles são causados pela iteração da função de distância, a cada 4 pixels (o tamanho do núcleo de distância euclidiano) repetidamente. Assim, as pequenas imprecisões se acentuam à medida que nos afastamos da borda. Isso normalmente não é um problema na maioria das situações, mas você pode reduzir, ou possivelmente até eliminar, mesmo esses pequenos erros usando um núcleo Euclidiano maior, de modo a produzir um resultado muito mais preciso e suave. No entanto, isso leva mais tempo para gerar. |

  magick circle_shape.png  -gamma 2 +level 0,100 -white-threshold 99 \
          -morphology Distance Euclidean:7   -auto-level \
          -shade 135x30 -auto-level +level 10,90%   cone_improved.png

[IM Output]
O resultado é uma função de distância quase perfeita para uma forma com anti-serrilhamento ou suave. Aqui está outro exemplo, desta vez usando os dois Núcleos de Distância Definidos pelo Usuário da seção anterior.

   magick circle_shape.png -gamma 2 +level 0,100 -white-threshold 99 \
           -morphology Distance  '2x1+0+0:0,100'  -auto-level \
           circle_gradient.png

   magick circle_shape.png -gamma 2 +level 0,100 -white-threshold 99 \
           -morphology Distance  '3x1:50,0,100'  -auto-level \
           circle_ridge.png

[IM Output] [IM Output]

Sem o tratamento especial para pixels com anti-serrilhamento, o exemplo acima não produziria um gradiente tão suave por toda a imagem. Mesmo assim, ainda precisamos restaurar a 'forma' da forma original.

Esfumaçando Formas usando Distância

A técnica acima pode ser aplicada ao Canal Alfa de uma forma de modo a 'esfumaçar' o objeto adequadamente. Por exemplo, aqui está um esfumaçado 'suavizado' de 10 pixels ao redor de um objeto em forma.

   magick rose_orig.png \
           \( +clone -fill black -colorize 100% \
              -fill white -draw 'circle 114,75 110,2' \
           \) -alpha off -compose CopyOpacity -composite \
           -trim +repage rose_shape.png

   magick rose_shape.png \
           \( +clone -alpha extract -virtual-pixel black \
              -gamma 2 +level 0,100 -white-threshold 99 \
              -morphology Distance Euclidean:4,10! \
              -sigmoidal-contrast 3,0% \
           \) -compose CopyOpacity -composite \
           rose_feathered.png

[IM Output] [IM Output]

Isso preservará TODAS as bordas exatamente, ao contrário da técnica mais simples de Esfumaçado por Desfoque. Eu poderia ter aplicado o procedimento acima diretamente sobre o canal alfa, exceto que alguns operadores não tratam o canal de transparência como 'valores alfa', mas como 'valores de opacidade' (especificamente o operador "[-white-threshold](https://imagemagick.org/command-line-options/#white-threshold)"). Por isso, extraí o canal alfa de modo a manipulá-lo como uma imagem em tons de cinza, antes de mesclá-lo de volta na imagem final. O núcleo de distância especial fará três iterações de um Núcleo Euclidiano de 4 pixels, para gerar um gradiente de distância suficiente próximo à borda da forma. O operador "[-level](https://imagemagick.org/command-line-options/#level)" então converte isso em uma forma de gradiente linear da borda ('0') a 10 pixels ('1000' unidades) para dentro da forma. A configuração "[-virtual-pixel](https://imagemagick.org/command-line-options/#virtual-pixel)" também é fornecida para garantir que qualquer forma que toque a borda do contêiner de imagem retangular também seja considerada como cercada por transparência. O resultado da função de distância neste caso é uma 'rampa linear' ou 'bisel', que pode produzir alguns efeitos de aparência nítida. Por isso, uma pequena modificação com "[-sigmoidal-contrast](https://imagemagick.org/command-line-options/#sigmoidal-contrast)" suavizará essa transição de transparência para opaco. Quanto maior a intensidade ('3' no exemplo acima), mais nítido será o esfumaçado na borda. Se você preferir que o esfumaçado 'afunile' mais suavemente para a transparência, substitua o '0%' no código acima por '50%' para posicionar o 'ombro' da curva sigmoidal no meio do esfumaçado de 10 pixels. Esfumaçado de Forma Bitmap Se a forma for um bitmap, como de uma imagem GIF, ou uma Máscara de Imagem, então você pode simplificar a operação de esfumaçado acima. Por exemplo...

  magick figure.gif -channel A -virtual-pixel transparent \
          -morphology Distance Euclidean:4,3!  boolean_feathered.png

[IM Output] [IM Output]

As mudanças-chave são que você tem muito menos pré e pós-processamento da função de distância; você pode simplesmente especificar uma unidade de distância especial usando '3!'. O que gerará um gradiente linear de 3 pixels ao redor da borda da forma. Outro exemplo desse tipo de esfumaçado (um 'esfumaçado linear' maior) pode ser visto em Miniaturas, Bordas Suaves. Você pode usar o operador "[-sigmoidal-contrast](https://imagemagick.org/command-line-options/#sigmoidal-contrast)" no exemplo acima para suavizar esfumaçados maiores, mas esteja ciente de que no momento ele processa a transparência como valores 'matte' em vez de valores alfa. Por isso, um valor de '100%' deve ser usado em vez de '05' na solução anterior. Para formas bitmap, pode ser melhor aplicar um "-blur 1x0.7" ao canal alfa, para suavizá-lo levemente, antes de aplicar o esfumaçado de distância anterior, mais complexo, a esses resultados.


Morfologia Condicional ou Restringida

Aqui examinamos técnicas em que as operações repetidas de morfologia são restringidas ou limitadas a uma área ou região específica de uma imagem. Basicamente técnicas que podem ser usadas para garantir que você não 'transborde' ou cresça além de algum limite ou área de interesse. Isso geralmente requer uma imagem 'máscara' de algum tipo, e é tipicamente feito usando uma Máscara de Proteção de Escrita, para limitar quais pixels são atualizados.

Dilatação Condicional

O Método de Morfologia Dilate, como você sabe, expandirá uma forma específica de acordo com uma dada vizinhança do núcleo. A 'Dilatação Condicional ' é essencialmente a mesma coisa, mas estabelece um limite para o quanto a dilatação pode se espalhar quando aplicada repetidamente a uma imagem. Um Preenchimento por Inundação de Draw é, em certo sentido, a 'Dilatação Condicional' definitiva. Ele simplesmente preencherá qualquer vizinhança ortogonal (vizinhança do Núcleo Diamond) que por acaso seja da mesma cor que o ponto inicial. Por exemplo, podemos selecionar um único ponto em um de vários discos e dilatar condicionalmente (preencher por inundação) até que esse disco tenha sido completamente recolorido, separando-o das outras formas.

  magick disks.gif -fill red -draw 'color 60,60 floodfill' \
          cond_dilate_draw.gif

[IM Output] [IM Output]

Da mesma forma, você pode usar o Operador Floodfill para fazer a mesma coisa, mas somente se o ponto inicial também corresponder a uma 'cor condicional' fornecida pelo usuário. |

  magick disks.gif \
          -fill green -floodfill +10+40 white \
          -fill blue  -floodfill +30+50 white \
          cond_dilate_floodfill.gif

[IM Output]
Neste caso, o preenchimento por inundação 'verde' 'atingiu um disco' (e o preencheu), enquanto a operação de preenchimento por inundação 'azul' não correspondeu, de modo que nenhum disco foi preenchido. O problema com tais métodos de 'preenchimento por inundação' é que você só pode dilatar a partir de um único ponto fornecido pelo usuário. No entanto, ele é muito rápido e funciona na imagem como um todo. O Dilate repetido ou iterado é o mesmo que o preenchimento por inundação, mas pode ter múltiplos pontos iniciais, embora não tenha compreensão de limites ou fronteiras para a operação de preenchimento que fornece. Para limitar seus efeitos, precisamos fornecer não apenas os 'pontos iniciais', mas também as 'fronteiras condicionais' do preenchimento. Para fazer isso, criamos uma Máscara de Proteção de Escrita (quais partes da imagem estão protegidas contra escrita).

  magick disks.gif disks.gif -morphology Erode:7 Diamond disks_big_center.gif

  magick disks.gif -negate disks_mask.gif

  magick disks_big_center.gif -write-mask disks_mask.gif \
          -morphology Dilate:15 Diamond +write-mask disks_big_found.gif

[IM Output] [IM Output] [IM Output] [IM Output]

No exemplo acima, primeiro usamos um Método Erode para localizar qualquer disco que seja maior que um raio de 7 (diâmetro 7x2+1 => 15 pixels). Em seguida, 'Dilatamos Condicionalmente' os pontos descobertos na mesma quantidade de modo a restaurar 'perfeitamente' o objeto encontrado. Observe que a 'Dilatação Condicional' é muito diferente de usar um Método Open para restauração de objeto. Aquele método teria gerado a forma interna de 'diamante' do núcleo, em vez da forma exata do objeto original. Ele também não lidará com pontos-semente de 'forma irregular' ou 'descentrados'. O número de iteração '15' não é crítico, mas deve ser grande o suficiente para restaurar completamente o objeto. | _Lembre-se de que é melhor usar um núcleo pequeno, como umDiamond ou Square com uma Contagem de Iterações ao realizar Operações Básicas de Morfologia do que usar um núcleo muito maior, como um Disk com um raio grande.

Isso se torna especialmente importante ao fazer uma Dilatação Condicional, pois núcleos grandes poderiam, na prática, 'saltar' sobre vãos que separam múltiplos objetos.

_
---|---
| _Não use uma contagem de iteração de '-1' ou (quase) infinita com uma máscara de escrita. A Morfologia do IMv7 atualmente não perceberá que os pixels não são graváveis e, por isso, não abortará quando não vir mais mudanças na imagem, pois sempre vê mudanças (que nunca são gravadas) ao redor das bordas da forma.

Isso será corrigido com o IMv7, que forneceu uma grande reestruturação interna que permitirá ao operador ser um pouco mais inteligente em relação aos pixels protegidos contra escrita.

_
---|---
Aqui está outro exemplo da versatilidade de usar uma Máscara de Proteção de Escrita. Encontrar os discos que serão atingidos por uma linha diagonal através da imagem.

  magick -size 80x80 xc:black -fill white \
                        -draw 'line 0,0 79,79'   disks_line.gif

  magick disks_line.gif disks.gif \
          -compose Multiply  -composite    disks_line_find.gif

  magick disks_line_find.gif -write-mask disks_mask.gif \
          -morphology Dilate:15 Diamond +write-mask disks_line_found.gif

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Observe a etapa extra de mascaramento (usando uma Composição Multiply), que garante que apenas os objetos pelos quais a linha realmente passa serão 'encontrados'. Sem esta etapa, objetos que também estejam próximos à linha, ou seja, dentro do raio do núcleo dos 'pontos-semente' (apenas tocando no exemplo acima), também seriam 'dilatados'. Claro que, se você quiser incluir 'objetos próximos', então dilate a linha (tornando-a mais larga) com um núcleo de disco do raio apropriado, antes de fazer a etapa inicial de mascaramento. Isso lhe dará mais controle de 'proximidade' do que confiar no raio do núcleo quadrado. Em resumo, uma Dilatação Condicional poderia ser considerada um Preenchimento por Inundação de Draw de múltiplos pontos, que, embora mais lento, pode ser mais versátil na seleção exata do que deve ser preenchido, ou 'descoberto'.

Distância Restringida

O método de morfologia Distance pode ser facilmente usado para descobrir quão longe um ponto dentro de um objeto está de uma borda. Mas ele também pode ser usado para descobrir quão distante cada ponto dentro do objeto está de outro ponto. Por exemplo, aqui eu descubro quão longe cada ponto está de um único ponto 'semente' (em linha reta)...

  magick -size 100x100 xc: -draw 'point 20,80'  distance_start.png

  magick distance_start.png -morphology Distance Euclidean \
          -auto-level  distance_point.png

  magick -font Casual -pointsize 140 label:D \
          -trim +repage -gravity center -extent 100x100 \
          -threshold 20% distance_bounds.png

  magick distance_point.png \( distance_bounds.png -negate \)  \
          -compose multiply -composite  -auto-level distance_direct.png

[IM Output] [IM Output] [IM Output] [IM Output]

A distância a partir de um ponto é mascarada pela forma do objeto, pois esses são os únicos pontos que nos interessam. O problema é que o gradiente de distância acima representa uma distância 'em linha reta' ou direta até o 'ponto inicial'. Simplesmente mascarar esse gradiente pelo objeto não muda isso. Infelizmente, isso normalmente não é o que um usuário deseja em termos de uma "distância a partir do ponto inicial". Se a forma representasse uma ilha, você ficaria bem molhado se quisesse tomar a 'rota direta' de uma extremidade desta ilha à outra. O que você realmente quer é a distância que seja limitada a caminhos 'dentro do objeto '. Ou seja, você quer que a distância seja 'restringida' pelo próprio objeto e siga o menor caminho possível, dentro do objeto. Para fazer isso, podemos configurar uma Máscara de Proteção de Escrita para que, à medida que o gradiente de distância é calculado, ele não cruze (grave em) as áreas de 'passagem proibida' ou fundo da imagem.

  magick distance_start.png -write-mask distance_bounds.png \
          -morphology IterativeDistance:150 Euclidean \
          +write-mask -fill black -opaque white -auto-level \
          distance_constrained.png

[IM Output] [IM Output] [IM Output]

O resultado, como você pode ver, é um gradiente de 'distância através da imagem' correto, que mostra claramente que a maior distância (branco) a partir do ponto inicial é a outra extremidade da ilha, que fica a apenas 'um pulo' através do vão no objeto.
Observe que eu não usei simplesmente um Método Distance normal, mas um método de morfologia de nível mais baixo 'Iterative_Distance'. O Método Distance normal é um método de distância RÁPIDO especial de 2 passagens que é aplicado à imagem como um todo. Por causa disso, a máscara de escrita não restringirá suas ações ao longo de uma 'linha' de pixels e, por isso, a máscara de escrita terá pouco efeito. O resultado é que o 'Distance' terá a tendência de 'saltar' sobre vãos horizontais, independentemente da máscara de escrita. Ou seja, o Método Distance normal não é 'restringido' adequadamente. O método 'Iterative_Distance', no entanto, funciona mais como um Método de Morfologia Básico mais simples e é aplicado apenas incrementalmente à vizinhança local. Ele é, na verdade, mais parecido com uma forma de gradiente de 'dilate', e está de fato intimamente relacionado a um método de Morfologia de Tons de Cinza Verdadeira. Como ele processa a imagem em 'passos incrementais' menores, o método 'Iterative_Distance' será 'restringido' pela máscara de escrita. Infelizmente, ele também é muito mais lento. Em vez de 2 passagens pela imagem, o exemplo acima realiza 150 passagens, conforme fornecido pela Contagem de Iterações ao método de morfologia. É melhor tentar manter essa contagem de iterações a menor possível, mas grande o suficiente para cobrir a maior distância que será encontrada dentro da imagem. | _Não use uma contagem de iteração de '-1' ou (quase) infinita com uma máscara de escrita. A Morfologia do IMv7 não entende que alguns pixels não são graváveis e, por isso, não abortará quando não vir mais mudanças na imagem, pois sempre vê mudanças nos 'pixels não graváveis' ao redor das bordas da forma.

Isso será corrigido, com sorte, com o IMv7, que fornece uma grande reestruturação interna que permitirá ao operador ser um pouco mais inteligente, entendendo que alguns pixels não são graváveis e, assim, evitar calculá-los, ou contá-los como tendo sido 'alterados'.

_
---|---
Por fim, você notará que usei um Núcleo de Distância que tem apenas um raio de 1, embora tais núcleos não sejam tão precisos. Isso é importante, pois um núcleo maior poderia resultar no gradiente de distância saltando sobre qualquer vão que seja menor que seu raio. Veja Dilatação Condicional acima. Se for necessária mais precisão, então você precisará garantir que não haja nenhum vão menor que o Núcleo de Distância que você deseja usar. Isso inclui vãos devido a uma curva acentuada na borda da imagem.


Gerando Esqueletos de formas.

Em Construção

De HIPR2 Morphology
http://homepages.inf.ed.ac.uk/rbf/HIPR2/morops.htm


O esqueleto/MAT pode ser produzido de duas maneiras principais. A primeira é usar algum
tipo de afinamento morfológico que erode sucessivamente os pixels da
fronteira (enquanto preserva os pontos finais dos segmentos de linha) até que nenhum
afinamento adicional seja possível, momento em que o que resta se aproxima do esqueleto.

O método alternativo é primeiro calcular a transformada de distância da
imagem. O esqueleto então se situa ao longo das singularidades (ou seja, dobras ou
descontinuidades de curvatura) na transformada de distância. Esta última abordagem é
mais adequada para calcular a MAT, já que a MAT é a mesma que a transformada de
distância, mas com todos os pontos que não fazem parte do esqueleto suprimidos a zero.

Nota: A MAT é frequentemente descrita como sendo o 'lugar geométrico dos máximos locais' na
transformada de distância. Isso não é realmente verdadeiro em nenhum sentido normal da expressão
'máximo local'. Se a transformada de distância for exibida como um gráfico de superfície 3-D
com a terceira dimensão representando o valor de cinza, a MAT pode ser imaginada
como as cristas na superfície 3-D.



Definição??

Esqueleto Morfológico (por erosão?), (por afinamento)

Os esqueletos são calculados seja por afinamento repetido, seja por transformada de
distância, e encontrando as 'dobras', ou cristas na superfície 3d (transformada de
watershed?).

   mat.gif -morphology HMT Ridges           -threshold 0
   mat.gif -morphology HMT LineEnds         -threshold 0
   mat.gif -morphology HMT Ridges\;LineEnds -threshold 0

   mat.gif -morphology HMT Ridges\;Ridges2  -threshold 0

   mat.gif -morphology TopHat Diamond              -threshold 0

   mat.gif -define morphology:compose=Lighten \
              -morphology TopHat '3@:-,1,- -,1,- -,-,-' -threshold 0


Uma definição de transformada de eixo medial (MAT) usa a intensidade de cada ponto
para representar a distância até a fronteira.  Aquele esqueleto foi usado como
uma máscara para a transformada de distância. O método da transformada de distância é mais
adequado para isso, e provavelmente é mais rápido de calcular do que por afinamento.

SKIZ (Skeleton by Influence Zones - Esqueleto por Zonas de Influência) é um esqueleto do fundo, o
inverso da operação.  Ou seja, dividindo as regiões mais próximas de cada
objeto do primeiro plano.  (gerado por espessamento)

Geralmente, um SKIZ é podado até áreas simples, ou bacias, também erodindo o
final dos segmentos de linha, a menos que estejam ligados a uma borda da imagem.

Identificando a forma por seus esqueletos.
   distância entre os pontos 'finais' mais afastados,
   número de 'laços' ou regiões na imagem,
   número de pontos triplos.

Distância para Esqueleto

Uma maneira rápida e simplificada de gerar um 'esqueleto morfológico' bruto a partir de uma imagem é aplicando o método '[TopHat](#tophat)' ao gradiente de distância. Por exemplo, aqui está um esqueleto da forma depois de ela ter sido Aberta um pouco para suavizar levemente seu contorno. |

  magick man.gif \
          -morphology Open  Diamond \
          -morphology Distance  Chebyshev \
          -morphology TopHat Diamond \
          -auto-level    chebyshev_dist_skel.gif

[IM Output]
Este é basicamente um esqueleto morfológico. Ele só mostra os pixels onde um 'quadrado' maximal (mais comumente conhecido como 'Bola Maximal') pôde ser encontrado, razão pela qual parece incompleto. No entanto, ainda é um resultado muito bruto com muitos pixels isolados. Surpreendentemente, ele funciona. Sem o '[Open](#open)', o resultado é muito ruim, devido ao fato de a forma ter um contorno tão áspero. Usar uma medida de distância euclidiana produz um esqueleto melhor da forma. |

  magick man.gif \
          -morphology Open  Diamond \
          -morphology Distance Euclidean:4 \
          -morphology TopHat Diamond \
          -auto-level    euclidean_dist_skel.gif

[IM Output]
Mas como você pode ver, você também obtém mais ruído e o esqueleto, embora mais completo, também está muito sujo com muitos valores em tons de cinza. Aqui está uma ampliação da 'cabeça' do esqueleto, mostrando como ele permanece desconexo. |

  magick euclidean_dist_skel.gif -crop 35x28+30+13 +repage \
          -scale 400%   euclidean_dist_skel_mag.gif

[IM Output]
Claro que o resultado acima poderia ser limiarizado e usado como uma máscara com o gradiente de distância real que foi usado para gerá-lo. Isso lhe permitirá consultar o tamanho real (raio de distância) dos discos maximais que compõem o esqueleto, permitindo que você recrie a forma original.

Esqueleto usando Autotrace

Outra alternativa para a geração de esqueleto é usar o programa "[AutoTrace](http://autotrace.sourceforge.net/)" e sua opção especial de linha central (centerline). Observe que ele assume preto sobre branco para seu processamento, devido ao seu envolvimento com impressão e conversão de fontes. Por exemplo...

  magick man.gif -negate man_at_prep.pgm
  autotrace -centerline -output-format svg man_at_prep.pgm |\
      magick SVG:-  man_centerline.gif
  magick man.gif man_centerline.gif \
          -compose multiply -composite man_at_skeleton.gif

[IM Output] [IM Output] [IM Output] [IM Output]

Observe que a linha central gerada tem a forma de uma curva suave devido à natureza vetorial do processo. Ela também é desconexa, com vãos nos laços do esqueleto e ramos desconectados. No entanto, não examinei como o "autotrace" realmente gera esse esqueleto. Para outro exemplo de uso do "[AutoTrace](http://autotrace.sourceforge.net/)", veja Manipulação de Saída SVG, e Rasterizado para Contorno Vetorial.