⚠️ Ceci est un site de traduction non officiel, sans lien avec ImageMagick Studio LLC. Pour des informations officielles, consultez la page originale (https://usage.imagemagick.org/morphology/index.html).

Exemples ImageMagick -- Morphologie des formes

Préface et index des exemples ImageMagick
Introduction à la morphologie

La morphologie modifie une image de diverses manières en se fondant sur le « voisinage » proche des autres pixels qui l'entourent. Cela peut à son tour fournir une immense gamme d'effets, de l'expansion et de la contraction des formes (dilatation/érosion), à la distance au bord, jusqu'à l'amincissement en un squelette, ou axe médian. Même la méthode plus ancienne des techniques de « convolution » qui fournissent des techniques de flou et d'accentuation (section suivante) est, d'une certaine manière, un type de méthode morphologique. Essentiellement, la morphologie sert à la modification, à la détermination et à la découverte des formes des objets présents dans une image.


Introduction à la morphologie

La morphologie a été développée à l'origine comme une méthode permettant de nettoyer et d'étudier la structure des formes au sein d'une image. Elle fonctionne en comparant chaque pixel de l'image à ses voisins de diverses manières, de façon à ajouter ou retirer, éclaircir ou assombrir ce pixel. Appliqué sur toute une image, éventuellement de manière répétée, des formes spécifiques peuvent être trouvées et/ou supprimées et modifiées. Par exemple, si un pixel est blanc et complètement entouré d'autres pixels blancs, alors ce pixel n'est manifestement pas sur le bord de l'image. Vous pourriez alors vouloir rendre ce pixel noir, de façon à ne laisser allumés que les pixels de bord. C'est une méthode connue sous le nom d''[EdgeIn](#edgein)' (voir ci-dessous). L'ensemble du processus dépend en réalité de la définition d'un « élément structurant » ou « noyau », qui définit quels pixels doivent être classés comme « voisins » pour chaque méthode morphologique spécifique. La taille et la forme exactes de ce « voisinage » dépendent souvent précisément de ce que vous essayez d'obtenir, ou de ce que vous recherchez spécifiquement dans l'image. Voici quelques exemples de divers noyaux qui ont été convertis en images (à l'aide d'un script spécial « [kernel2image"](../static/img/scripts/kernel2image) ») montrant certains des « voisinages » autour d'un pixel central, l'« origine ».

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

Les images ont été mises à l'échelle pour mettre en évidence les éléments individuels du « noyau », et comme vous pouvez le voir, les noyaux typiques sont souvent très petits. En fait, le noyau 'Disk' montré ci-dessus est en réalité « [Raw Disk Kernel Image] », et c'est l'un des plus grands noyaux montrés ci-dessus. Cependant, les « noyaux » ne sont pas vraiment des images. Simplement un tableau de valeurs en virgule flottante dont un élément est désigné comme l'« origine » du noyau. Cet élément spécial est l'emplacement du pixel qui sera « affecté » par le voisinage défini, et il s'agit typiquement, quoique pas toujours, du pixel central d'un noyau symétrique. Notez que ce ne sont là que quelques exemples de voisinages possibles. Certains noyaux peuvent être agrandis, typiquement en augmentant un argument de « rayon » propre à ce noyau, tandis que d'autres, utilisés à des fins particulières, sont de taille fixe. Pour des noyaux simples, comme les deux premiers, la méthode morphologique pourrait être répétée (itérée) pour accroître la « taille » effective du noyau, de façon à affecter davantage de pixels plus éloignés de l'« origine » (telle que marquée). Cela ne fonctionne cependant pas toujours, et peut produire des résultats inattendus ; c'est néanmoins parfois plus rapide que d'utiliser directement un noyau plus grand, mais là encore ce n'est pas toujours le cas. La taille et la forme finales d'un « élément structurant », ou « SE », comme on appelle un noyau dans les articles de recherche sur la morphologie, sont importantes en tant que moyen de localiser et de rehausser ou de supprimer des éléments d'image plus grands ou plus petits que cette forme. C'est ce qui rend la morphologie extrêmement puissante comme moyen de trier les divers éléments au sein des images. Cependant, plus le noyau est grand, plus les méthodes morphologiques prendront de temps, il est donc préférable de garder les noyaux petits. Tous les noyaux montrés, à l'exception du dernier, sont en réalité pourvus d'une forme. Les parties transparentes ne font pas partie du « voisinage » défini du noyau. C'est-à-dire qu'elles n'ont aucune valeur valide et ne participeront à aucun des calculs de morphologie. Remarquez comment l'avant-dernier noyau 'Corner #0' possède non seulement des valeurs « on », mais aussi des valeurs « off », dans le cadre de sa « forme ». Les deux valeurs, tout comme celles qui sont transparentes (ne faisant pas partie de la forme), sont importantes pour les méthodes Hit-n-Miss et apparentées (voir ci-dessous). Ce noyau spécifique n'est que le premier d'une série de noyaux destinés à localiser les pixels « de coin » des formes binaires au sein d'une image. Le dernier « noyau » montré ci-dessus est entièrement défini sur une grande zone rectangulaire (carrée). De plus, contrairement aux autres noyaux qui n'utilisent que des valeurs de 1 (blanc), 0 (noir) ou une valeur spéciale « indéfinie », les valeurs de ce noyau vont en réalité de presque zéro (presque noir) sur les bords à une valeur maximale (blanc pur) au centre. Cependant, de tels noyaux peuvent aussi utiliser des valeurs négatives, voire des valeurs très grandes, bien au-delà de la plage normale des autres noyaux. Rappelez-vous qu'un noyau n'est réellement qu'un tableau de valeurs, et que celles-ci pourraient avoir n'importe quelle valeur, pas seulement une plage de 0 à 1. Ce type de noyau est particulièrement important dans les « opérations de convolution », une méthode spéciale qui existe depuis bien plus longtemps que la morphologie elle-même. Par conséquent, IM dispose d'un très grand nombre de noyaux intégrés, ou « nommés », de ce type. Cela sera examiné plus en détail dans la section suivante des exemples IM, « Convolution des images ». Maintenant, comme je l'ai déjà mentionné, les noyaux ne sont pas vraiment des images. Ce sont simplement un tableau de valeurs en virgule flottante. Nous examinerons ces valeurs réelles (qui ont été converties en une image pour l'affichage, ci-dessus) plus tard.

Opérateur de morphologie

L'opérateur « [-morphology](https://imagemagick.org/command-line-options/#morphology) » est très complexe, car il offre à l'utilisateur un grand nombre de contrôles sur ses actions.

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

Notez que vous devez fournir au moins deux éléments : la 'method ' de morphologie, qui indique à l'opérateur le type d'opération que vous voulez appliquer à l'image, et un 'kernel ' qui spécifie quels pixels « voisins » doivent affecter le résultat final. Les deux sont tout aussi importants et tous deux peuvent avoir des conséquences de grande portée. Vous pouvez obtenir la liste des méthodes disponibles à l'aide de « -list morphology ». La liste des noyaux intégrés que nous avons inclus dans IM peut être consultée avec « -list kernel ». Nous passerons en revue les diverses méthodes, et les noyaux que ces méthodes peuvent utiliser, plus tard. | _L'opérateur « [-morphology](https://imagemagick.org/command-line-options/#morphology) » (méthodes de base) et l'ensemble initial de noyaux ont été ajoutés à ImageMagick version 6.5.9-0 par moi-même, alors que j'étais en vacances en Chine. De décembre 2009 à janvier 2010.

Il est toutefois possible d'effectuer une morphologie simplifiée avec un noyau « carré » à l'aide de la méthode « [-convolve](https://imagemagick.org/command-line-options/#convolve) », plus ancienne et étroitement apparentée. Voir Techniques alternatives de morphologie de base ci-dessous.

_
---|---

Noyaux de forme intégrés de base

Comme le noyau est commun à toutes les méthodes de morphologie, et que les résultats des diverses méthodes dépendent fortement du noyau effectivement sélectionné, nous examinerons d'abord comment définir ou sélectionner un noyau à utiliser. Une bonne sélection de noyaux a déjà été prédéfinie pour vous et il n'est souvent pas nécessaire de chercher plus loin. Vous pouvez obtenir une liste des noyaux intégrés prédéfinis en utilisant « -list kernel ». Tous les noyaux ont une taille spécifique, typiquement un carré comptant un nombre impair de pixels par côté, dont le centre est l'« origine » du noyau. Cependant, comme vous le verrez, l'opérateur « [-morphology](https://imagemagick.org/command-line-options/#morphology) » n'est pas restreint à cette limitation. Le k_argument le plus courant utilisé pour les noyaux intégrés, et généralement le premier argument donné, est un 'radius '. Cela définit la taille du voisinage carré de taille impaire typique du noyau. La taille finale du noyau sera généralement le double du rayon plus un (pour le pixel central). C'est-à-dire qu'un 'radius ' de '2' créera un noyau de 5×5 pixels de côté. Bien qu'un 'radius ' définisse typiquement la taille du noyau final, et donc la vitesse globale de l'opération morphologique sur les images, ce n'est peut-être pas le facteur le plus important, en particulier pour les noyaux de convolution où les valeurs ont un plus grand effet sur les résultats que la taille du noyau. Si un 'radius ' est fixé à 0, ou laissé indéfini, le 'radius ' prendra automatiquement par défaut une valeur raisonnable ou la plus couramment utilisée, selon le noyau concerné. [IM Output]

Unity

Il s'agit d'un noyau spécial utilisé spécifiquement lorsque vous avez besoin d'un noyau « No-Op ». La plupart des méthodes morphologiques utilisant ce noyau reproduiront soit l'image originale, soit un résultat vierge. Ce noyau n'a aucun argument. Ce même noyau à élément unique peut aussi être généré à l'aide de '[Disk:0.5](#disk)', ce qui vous permet également de spécifier un argument de mise à l'échelle dans le cadre de la génération du noyau. [IM Output]

Diamond

Le noyau le plus minimal, quoique peut-être pas le plus simple, est le noyau intégré 'Diamond '. Une manière simple d'examiner le noyau de base est d'utiliser une méthode de morphologie Dilate sur une image contenant un seul pixel blanc sur fond noir. Cela étend fondamentalement le pixel unique à la « forme » du voisinage du noyau. Voici le résultat de l'utilisation de 'Dilate' avec le noyau intégré minimal 'Diamond', et la mise à l'échelle du résultat pour le rendre plus visible.

  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]

| Rappelez-vous que tous les résultats en image de noyaux dans cette zone des exemples IM ont été agrandis pour vous permettre de voir les pixels individuels. En réalité, tous les noyaux et les résultats que nous montrons sont très petits, comme il se doit. Dans ce cas, l'image dilatée ne fait que 11×11 pixels et a été mise à l'échelle 8 fois pour l'affichage.
---|---
Il s'agit en fait d'un noyau assez bon pour les opérations morphologiques, et il définit fondamentalement le voisinage pratique le plus minimal : le pixel d'origine, plus les quatre pixels en contact direct. Un autre nom pour ce type de noyau est un élément structurant 'Z4'. Il ressemble plutôt à un minuscule signe « plus ». La forme en losange n'apparaît que lorsque le rayon augmente. Le k_arg optionnel pour ce noyau peut prendre deux valeurs, comme ceci...

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

Pour tous les noyaux de forme, l'argument le plus important est radius et, comme mentionné précédemment, c'est un entier qui représente la distance du « centre » d'origine au bord le plus proche. Ainsi, le noyau 'Diamond' final est un carré (2 fois radius plus 1) contenant la forme en losange. Voici les résultats de l'utilisation d'un radius plus grand pour générer un grand noyau.

  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
(par défaut) | [IM Output]
Diamond:2 | [IM Output]
Diamond:3 | [IM Output]
Diamond:4
---|---|---|---

L'autre k_argument est scale qui vaut par défaut 1.0. Typiquement, il sert à modifier les valeurs effectivement utilisées par le noyau pour former la forme. Cela n'est généralement important que pour des méthodes spéciales comme Convolve et la morphologie en niveaux de gris. [IM Output]

Square

Le 'Square ' est le noyau le plus couramment utilisé en morphologie, car c'est le plus facile à appliquer à l'aide d'autres techniques alternatives. Ce n'est cependant pas le noyau le plus minimal (voir '[Diamond](#diamond)' ci-dessus). Par défaut, le noyau 'Square' utilise un voisinage de 3x3 pixels autour du « centre ». |

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

[IM Output]
Fondamentalement, cela signifie que les 8 voisins du pixel d'origine seront classés comme faisant partie du voisinage de ce pixel. Il en résulte un bon noyau pour moyenner les pixels, ou pour agrandir/rétrécir une forme d'un pixel. Comme tous les noyaux de forme, il prend les mêmes k_arguments que ceux montrés pour le noyau Diamond ci-dessus, le premier argument radius étant le plus important.

  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
(par défaut) | [IM Output]
Square:2 | [IM Output]
Square:3 | [IM Output]
Square:4
---|---|---|---

La valeur par défaut (radius=1) de ce noyau, comme mentionné, est un carré 3×3, et est communément connue sous le nom d'élément structurant 'Z8' (d'après le nombre de voisins immédiats concernés). [IM Output]

Octagon

Le noyau 'Octagon ' est un noyau de forme à 8 côtés. Et il a été spécifiquement conçu pour correspondre à la '[métrique de distance octogonale](../static/img/morphology/octagonal)'. Ne confondez pas les deux car ce sont des noyaux très différents. Voici les noyaux résultants pour de petits rayons...

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

Notez qu'au rayon 1, vous obtenez le même noyau qu'un noyau "Diamond". C'est pourquoi la taille par défaut de l'octogone est de rayon '2'. | _À partir de maintenant, j'utiliserai un script spécial kernel2image pour générer des images des noyaux car elles sont bien plus claires qu'avec une méthode brute « dilate-scale » (comme ci-dessus). Rappelez-vous toutefois que les noyaux sont en général très petits, même si les noyaux Octagon et Disk (voir plus loin) peuvent devenir très grands pour des usages spécifiques.


---|---
| _Le noyau "Octagon" a été ajouté dans IM v6.6.9-4, avec le noyau de distance "[Octagonal](#octagonal)".

---|---
[IM Output]

Disk

Le noyau 'Disk' est, comme vous vous y attendriez, une forme circulaire. Et il est couramment utilisé lorsqu'un très grand noyau morphologique est nécessaire. Notez toutefois qu'il s'agit d'un cercle booléen crénelé. Cependant, l'argument radius d'un disque peut être un nombre en virgule flottante, ce qui vous permet de produire une belle gamme de formes, en utilisant de petits rayons.

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

Le noyau 'Disk:4.3' est celui par défaut, et ce que je considère comme la première véritable forme de disque. Les disques de cette taille ou plus grands sont particulièrement bons pour arrondir et lisser généralement les formes de l'image. La taille finale du noyau contenant le disque est la valeur 'radius ' arrondie à l'inférieur, fois 2 plus 1. Ainsi, le noyau par défaut 'Disk:4.3' a un rayon de taille de noyau de 4, ce qui donne une taille finale de noyau de 4 fois 2 plus 1, et génère un noyau 9×9 pour contenir la forme du disque. Notez qu'une valeur inférieure à un (mais non nulle) produira toujours un noyau à pixel unique, bien que cela ne soit pas très utile. Au-delà, le noyau tend surtout à produire des noyaux qui peuvent aussi être générés avec les types de noyaux précédents. Ce n'est que lorsque le rayon devient grand que de véritables noyaux en forme de disque commencent à émerger. La chose la plus importante à noter est qu'un disque avec un rayon fractionnaire fonctionne bien mieux qu'avec un rayon entier. Ajouter une fraction d'environ 0.3 à 0.5 est généralement recommandé, pour éviter de générer un pixel isolé d'aspect étrange sur les côtés du disque. [IM Output]

Plus

Le noyau 'Plus' est en réalité un peu différent des autres noyaux de forme morphologiques, en ce qu'il est conçu pour représenter une « forme » spécifique plutôt qu'un simple « voisinage » autour d'un pixel. Utiliser un 'radius ' plus grand avec ce noyau n'augmente pas simplement la taille du noyau, mais allonge les bras du signe plus résultant. L'épaisseur des bras, en revanche, n'augmente pas.

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

La taille par défaut d'un noyau 'Plus' est un rayon de 2, produisant des « bras » de 2 pixels autour de l'« origine » centrale. Un noyau 'Plus:1' se trouve être identique au noyau 'Diamond' par défaut. Notez qu'un noyau 'Plus' n'est généralement pas utilisé pour les méthodes morphologiques normales, et devrait être évité à ces fins. Il est toutefois très utile si vous voulez trouver et mettre en évidence des points isolés dans une image, comme je le fais plus loin pour afficher les informations sur le squelette. Fondamentalement, il fournit une méthode de dessin de symboles, sans avoir besoin de savoir exactement où les « points » individuels se situent dans l'image. [IM Output]

Cross

Le noyau 'Cross' est exactement comme '[Plus](#plus)' mais pivoté de 45 degrés. C'est aussi juste une forme de noyau spéciale adaptée pour étendre des pixels afin de marquer l'emplacement de divers points

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

[IM Output]

Ring

Le noyau 'Ring', comme le noyau '[Plus](#plus)', est également conçu comme un noyau de « forme » spécial pour marquer des pixels et générer des motifs sur les images. Cependant, il ne prend pas seulement un rayon, il peut prendre deux rayons et est défini de la même manière que les noyaux Disk...

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

Ce qu'il fait, c'est allumer tout pixel qui tombe entre les deux rayons, quel que soit l'ordre des deux rayons donnés. Si aucun rayon n'est donné, il prend par défaut des rayons de '2.5' et '3.5', produisant un 'Ring:2.5,3.5', qui ressemble à un anneau creux de forme octogonale, idéal pour encercler un pixel. En faisant varier les deux rayons, vous pouvez créer un « anneau » de n'importe quelle taille et épaisseur. De petites modifications des rayons ajouteront et retireront un très petit nombre de pixels autour des bords, vous permettant un contrôle fin de l'aspect de l'anneau. Si les deux rayons sont à moins d'un pixel l'un de l'autre, vous pouvez aussi générer un anneau constitué de points épars et séparés, ce qui peut être utile comme voisinage à usage spécial. De petits rayons génèreront également des noyaux en forme de boîte, ce qui peut aussi être utile. Si le second rayon n'est pas donné, il prendra par défaut la valeur '0.5', ce qui définit effectivement un disque plein, mais sans le pixel central d'« origine ». En d'autres termes, un noyau de disque mais excluant le pixel d'« origine ». Voici des exemples de bon nombre des noyaux 'Ring' pouvant être générés...

[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]

Comme vous pouvez le voir, vous disposez de nombreuses possibilités en ajustant soigneusement les deux rayons, ce qui offre un bon moyen de montrer les emplacements d'intérêt dans une image. [IM Output]

Rectangle

Le noyau 'Rectangle' est étroitement lié au noyau '[Square](#k_square)' ci-dessus, et produit par défaut le même noyau carré 3x3. Mais plutôt qu'un simple argument de rayon, vous pouvez donner un argument 'geometry ' pour spécifier la taille exacte du noyau rectangulaire voulu. Voici quelques spécifications et une image des noyaux qu'elles produisent.

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

Par défaut, le noyau tentera de fixer l'« origine » du voisinage exactement au « centre » du noyau. Mais pour un rectangle de taille paire, il choisira le point immédiatement au-dessus et/ou à gauche du centre, selon le cas. Cependant, vous pouvez aussi spécifier des origines décentrées. Ce noyau particulier est également bon pour définir de longues lignes horizontales et verticales, vous permettant de rechercher de tels objets au sein des images. Nous y reviendrons plus tard. Pour l'instant, vous ne pouvez pas fournir de facteur scale pour un rectangle. Toutes ses valeurs de noyau seront fixées uniquement à 1.0.

Noyaux personnalisés définis par l'utilisateur

Vous n'êtes pas restreint aux seuls noyaux intégrés, mais pouvez aussi spécifier votre propre noyau, en donnant les valeurs exactes que vous voulez que le noyau utilise...

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

La spécification 'geometry ' est fondamentalement exactement comme l'argument du noyau '[Rectangle](#k_rectangle)' précédent. Elle donne la taille du noyau, et optionnellement l'« offset » de l'« origine » du voisinage. Si un seul nombre est fourni, il sera supposé être les dimensions d'un noyau carré. Rappelez-vous que la valeur de géométrie n'est PAS un argument de « rayon » mais la taille globale du noyau.
Si aucun 'geometry ' ou ':' n'est spécifié, alors vous utilisez la « vieille » forme de spécification. Un noyau carré de taille impaire, assez grand pour contenir toutes les valeurs données, sera généré. Ce n'est pas recommandé et n'est fourni que pour la compatibilité ascendante avec les anciennes versions d'ImageMagick. Après le ':' (qui est requis après une spécification 'geometry '), vous fournissez alors width × height valeurs en virgule flottante séparées par des virgules et/ou des espaces. Une valeur spéciale 'NaN' (signifiant « Not a Number », pas un nombre) ou un '-' seul, peut être utilisée pour spécifier que ce point du noyau ne fait pas partie du voisinage morphologique. Par exemple, voici une spécification d'un noyau carré de largeur 3, qui peut être utilisé pour un flou par convolution de l'image à pixel unique.
  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]
Avec un pixel unique, Convolve fonctionne presque de la même façon que Dilate, cependant Convolve utilise les valeurs du noyau, en développant et en additionnant les valeurs voisines. Dilate en revanche fonctionne généralement à l'aide d'une forme on/off (booléenne) et du maximum de tous les voisins. Cependant, lorsqu'il est appliqué à un pixel isolé unique avec une forme booléenne, vous obtenez le même résultat. Remarquez comment vous pouvez ajouter des espaces supplémentaires (ou même des sauts de ligne) à la chaîne d'entrée afin de séparer les lignes individuelles de la définition du noyau rectangulaire. Et ici j'ai défini une zone rectangulaire de 5×3, mais utilisé les valeurs spéciales 'nan' (pas un nombre) pour couper les coins et faire un noyau de forme ovale... |

  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]
Et enfin voici un exemple de spécification d'un voisinage rectangulaire, qui forme une forme en 'L' autour de l'« origine ». J'ai utilisé '-' au lieu de 'nan' pour spécifier les parties qui ne font pas partie du noyau. Notez que l'origine de ce noyau ne fait même pas partie de son propre voisinage, elle peut être située n'importe où à l'intérieur des limites rectangulaires du noyau. |

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

[IM Output]
Comme vous pouvez le voir, la spécification d'un noyau utilisateur est très flexible, vous permettant de spécifier à peu près n'importe quel type de noyau que vous souhaitez, qu'il s'agisse d'un noyau de convolution avec beaucoup de fractions, ou d'un noyau de forme avec des éléments « ne faisant pas partie du voisinage », pour les méthodes morphologiques.

Convertir une image en noyau utilisateur

Pour faciliter la génération de noyaux personnalisés, vous pouvez utiliser le script "[image2kernel](../static/img/scripts/image2kernel)" pour créer des noyaux. Par exemple, ici je transforme un petit drapeau ( ) en un fichier de données de noyau utilisateur ("[flag_kernel.dat](../static/img/morphology/flag_kernel.dat)"), puis je l'utilise pour dilater une image contenant quelques pixels.

  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]

Voir aussi Générer une image du noyau ci-dessous, qui peut générer des images (ou générer des versions agrandies et soignées) d'un noyau. Cette technique est également abordée dans Alternatives au dessin de symboles.

Itération (répétition) des opérations de morphologie

Comme vous l'avez vu, vous pouvez générer un noyau plus grand, de façon à appliquer une morphologie sur un voisinage plus grand. Cependant, dans la plupart des cas, une alternative plus rapide à l'utilisation d'un noyau plus grand est de simplement répéter (itérer ou boucler) l'opérateur de morphologie plusieurs fois. Cela signifie que l'effet de cet opérateur portera plus loin, ayant le même effet de base que l'utilisation d'un noyau plus grand, mais sans le coût de calcul additionnel de l'utilisation d'un noyau plus grand. Par exemple, voici une dilatation d'un pixel unique à l'aide d'un noyau 'Diamond:3'... |

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

[IM Output]
Mais vous pouvez aussi obtenir le même résultat en utilisant trois fois un noyau 'Diamond' plus petit (rayon 1)... |

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

[IM Output]
Vous n'utilisez toujours qu'un très petit noyau 3x3, mais en répétant trois fois l'opération morphologique de base pour produire le même effet que si vous utilisiez un noyau plus grand. En fait, répéter de petits noyaux de cette façon est en réalité bien plus rapide que d'utiliser le noyau beaucoup plus grand. | _Un grand noyau 'Diamond:3' a 81 éléments à traiter par pixel de l'image. Mais répéter 3 fois un noyau 'Diamond' plus petit revient à traiter 3×9, soit 27 éléments de noyau par pixel de l'image. Dans ce cas, c'est 3 fois plus rapide.

Ce gain de vitesse n'est pas énorme dans ce cas, mais les économies sont bien plus grandes à mesure que la taille des noyaux augmente._
---|---
Comme répéter une opération morphologique est très courant, plutôt que de répéter l'opération plusieurs fois, vous pouvez simplement demander à IM de boucler ou d'itérer l'opération, ce nombre de fois. |

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

[IM Output]
Notez la différence entre ceci et le premier exemple. Tout ce qui s'est passé, c'est que nous avons déplacé le ':3' du rayon du noyau 'Diamond' vers le nombre de fois que la méthode 'Dilate' doit être utilisée. Utiliser une 'iteration ' pour agrandir le voisinage effectif fonctionne pour la plupart des noyaux « circulaires » ou « convexes », tels qu'un 'Square' et un 'Diamond'. Mais cela ne fonctionne pas pour tous les types de noyaux. Par exemple, pour un noyau non convexe tel qu'un 'Plus' (qui n'est pas une forme « concave »), cela produira des résultats très inhabituels. Par exemple, ceci n'est pas la même chose que de passer d'un 'Plus' (rayon 2) à un noyau 'Plus:4' de taille double... |

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

[IM Output]
Notez que si vous utilisez un compte d''iteration ' de '0', la morphologie ne fera rien. C'est une manière utile de « désactiver » l'opérateur lorsque vous ne voulez pas qu'il fasse quoi que ce soit, mais que vous ne voulez pas le retirer de la ligne de commande. Voir l'affichage de la sortie détaillée, ci-dessous, pour un autre usage d'un compte d'itération nul. En utilisant une valeur spéciale de '-1', l'opération sera répétée jusqu'à ce qu'aucun changement supplémentaire ne soit observé dans l'image. C'est-à-dire que l'image atteint un point de « convergence ». Ceci est cependant dangereux, car dans certaines situations cela pourrait conduire à des opérations très longues à s'exécuter. Pour une opération telle que 'Dilate' par exemple, elle répéterait simplement la dilatation jusqu'à ce que l'image entière soit complètement remplie de blanc. Produisant fondamentalement une sorte de « remplissage par diffusion » emballé (voir l'exemple suivant ci-dessous). Itérer un noyau 'Disk' pour produire un effet de voisinage plus grand n'est généralement pas recommandé non plus. C'est parce que le noyau 'Disk' devient une forme de disque plus précise à mesure que le rayon grandit, alors qu'un disque itéré agrandira non seulement la forme mais aussi les erreurs (forme non-disque) du noyau. Ainsi, il peut être préférable d'utiliser un rayon plus grand (ce qui est plus lent) plutôt que d'itérer l'opération (ce qui produit un disque plus déformé). Cependant, lorsqu'un rayon 'Disk' devient vraiment grand, une combinaison de rayon et de multiples itérations pourrait produire un résultat plus rapide, mais tout de même acceptable. De la prudence et quelques expérimentations avec votre situation spécifique peuvent être nécessaires.

Sortie détaillée des changements

Si vous voulez voir les résultats de l'itération (répétition) d'une opération morphologique, vous pouvez définir l'option "[-define debug=True](https://imagemagick.org/command-line-options/#define)", qui active le contrôle opérationnel détaillé. À mesure que l'opérateur de morphologie itère, il rapportera un compte croissant de l'itération, et combien de pixels de l'image ont été changés par chaque étape itérée. La sortie va vers l'erreur standard, de sorte que vous pouvez toujours passer les résultats d'image par un tube. Par exemple, 'Dilateons' l'image à pixel unique à l'aide du plus grand noyau 'Octagon' jusqu'à ce que l'image entière ait été remplie de blanc et qu'aucun changement supplémentaire ne puisse être apporté à l'image. Rappelez-vous qu'une limite d'itération de '-1' signifie itérer indéfiniment, ou jusqu'à ce qu'aucun changement supplémentaire ne soit observé. | |

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

[IM Output]
| [IM Text]


Notez le nombre de changements apportés à chaque itération. Initialement, 20 pixels ont été convertis du noir au blanc. Puis 48 de plus à l'itération suivante, et ainsi de suite. Ce nombre croît généralement à mesure que le bord de la forme résultante s'agrandit, mais a ensuite commencé à décroître de nouveau lorsque la forme atteint la limite de l'image. À la quatrième dilatation, les 4 derniers pixels (dans les coins de l'image) ont été remplis. À la dernière dilatation (itération 5), l'image était déjà complètement remplie, de sorte qu'aucun changement supplémentaire n'a été effectué sur aucun pixel. Comme aucun changement n'a été apporté, la morphologie s'interrompt automatiquement, donnant un nombre final de changements pour cette étape de l'opération. Utiliser une itération infinie de '-1' comporte bien une limite interne. Celle-ci est actuellement fixée à la largeur ou la hauteur maximale de l'image. Ceci est fait pour empêcher ImageMagick d'entrer dans une boucle sans fin. Typiquement cependant, les opérations se terminent bien avant que cette limite interne ne soit atteinte. Certaines méthodes de morphologie sont en réalité définies en termes de méthodes plus simples et plus primitives. Par exemple, une méthode '[Smooth](#smooth)' est l'une de ces méthodes composées. La sortie "[-define](https://imagemagick.org/command-line-options/#debug)" générée en utilisant cette méthode montre les multiples étapes internes qui constituent son traitement.

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

[IM Text]

Si vous regardez, vous pouvez voir que '[Smooth](#smooth)' itère en réalité 4 méthodes plus primitives, et traite donc l'image en interne 8 fois pour effectuer l'opération demandée. Chaque ligne se compose de...

Smooth:_i_._s_ ceci montre la méthode de morphologie de haut niveau appliquée à l'image, ainsi que le compte d'itération 'i ' et l'« étape » primitive 's ' que IM est en train de traiter. Pour la méthode 'Smooth', ce premier nombre est toujours '1', car le « compte d'itération » donné par l'utilisateur est appliqué dans la méthode primitive de plus bas niveau. Dans d'autres méthodes, l'itération donnée par l'utilisateur peut être appliquée à ce niveau plus élevé plutôt qu'au niveau plus bas. Le second nombre d'« étape » est le compte de l'« étape » primitive qui est en cours d'application. 'Smooth' lui-même est composé de quatre de ces étapes, car il implémente les méthodes composées '[Open](#open)' et '[Close](#close)'. Dilate*:_i_._k_ Ceci est la méthode primitive en cours d'application. Le premier nombre i est de nouveau le compte d'itération donné par l'utilisateur (s'il est appliqué ici). Le second nombre 'k ' est le noyau appliqué par la méthode de morphologie primitive. Comme il n'y a qu'un seul noyau, il est donc toujours zéro dans ce cas. (Voir Gestion de noyaux multiples ci-dessous) Le '*' indique que le noyau a été réfléchi (ou pivoté de 180 degrés autour de l'origine) avant d'être appliqué par la primitive morphologique. Ceci est requis pour certaines méthodes morphologiques composées ; dans ce cas, la méthode '[Close](#close)' utilise toujours un noyau réfléchi dans son usage des méthodes primitives '[Dilate](#dilate)' et '[Erode](#erode)'. #6 => Changed 311 Total 637 Ceci est un rapport des résultats de l'application de la primitive de morphologie à l'image. Le nombre « hash » est un compte incrémental du nombre de passes primitives à travers l'image. Cela vous donne une bonne idée de l'intensité de calcul d'un opérateur de morphologie composé. Vous obtenez ensuite le nombre réel de pixels qui ont été modifiés d'une manière ou d'une autre pendant cette passe. S'il s'agit de la dernière d'un certain nombre d'itérations pour cette primitive et ce noyau spécifiques, un compte total des modifications de pixels est également fourni. Ceci ne reflète cependant pas le nombre total de pixels modifiés du début à la fin, seulement les changements causés par l'itération de bas niveau de l'opération de primitive et de noyau spécifique. Certains pixels peuvent changer plusieurs fois sous l'effet de certaines primitives morphologiques.

De ce qui précède, vous pouvez voir qu'en interne IM peut appliquer quatre boucles de traitement pour traiter entièrement une méthode de morphologie donnée. Cependant, typiquement, la plupart de ces boucles ne sont appliquées qu'une seule fois. | _Attention : le nombre de pixels qui changent peut ne pas être correct sur les machines exécutant un environnement multi-thread sur les machines multicœurs modernes ! Il n'est garanti exact que lorsqu'il est exécuté dans un environnement mono-thread. Je classe ceci comme un bug, mais pas comme un bug vital.

Si cela pose problème, alors assurez-vous de fixer la variable d'environnement "MAGICK_THREAD_LIMIT" à une valeur de '1' pour cette exécution spécifique d'ImageMagick, comme je l'ai fait dans les deux derniers exemples ci-dessus.

À partir d'IM v6.8.4, vous n'avez plus besoin du réglage d'environnement "MAGICK_THREAD_LIMIT", car les comptes sont correctement gérés dans un environnement multi-thread.

_
---|---

Affichage du noyau généré (à des fins de débogage)

Si vous souhaitez voir réellement les valeurs qui ont été utilisées pour définir un noyau particulier qui a été généré, vous pouvez définir un réglage spécial...

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

N'importe lequel des defines ci-dessus amène IM à afficher (vers l'« erreur standard ») toutes les informations sur un noyau généré, après que le noyau a été entièrement traité en préparation de son utilisation. (Voir Mise à l'échelle des noyaux de convolution). Par exemple, voici les valeurs réelles du noyau intégré '[Disk](#disk)'...

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

[IM Text]

Notez que comme je voulais seulement montrer le noyau, je ne me soucie pas du tout du traitement de l'image. Ainsi, j'ai fixé l''iteration ' de morphologie à '0' (ne rien faire), et je rejette aussi tout résultat d'image en utilisant un format de fichier de sortie null:. La valeur spéciale en virgule flottante 'nan' ci-dessus a la même signification que lors de la saisie d'un noyau défini par l'utilisateur. Elle signifie « Not A Number » (pas un nombre) et marque les parties d'un noyau qui ne font pas partie du voisinage. Ces valeurs sont ignorées par toutes les opérations morphologiques. Voici un autre exemple. Cette fois d'un noyau de convolution '[Comet](convolve.html#comet)'.

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

[IM Text]

Il s'agit en réalité de la moitié d'une courbe gaussienne à 1 dimension (sigma de 1.0), et cela peut fournir un moyen agréable d'extraire une telle courbe depuis ImageMagick. Notez également que l'« origine » de ce noyau spécifique (le pixel qu'il affecte) est décentrée (située en +0+0), ce qui n'est pas très courant. La taille et l'espacement des valeurs dans la sortie peuvent être contrôlés par le contrôle opérationnel de précision spécial. Celui-ci a été ajouté à IM à peu près en même temps que l'opérateur de morphologie. Par exemple, voici une répétition de l'exemple précédent mais en utilisant "[-precision](https://imagemagick.org/command-line-options/#precision)" pour limiter le nombre de chiffres significatifs de la valeur par défaut de 6 à 3.

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

[IM Text]

| L'option "[-precision](https://imagemagick.org/command-line-options/#precision)" a été ajoutée à ImageMagick version 6.5.9-1 pendant le cycle de développement de la morphologie. Ainsi, si la morphologie est disponible, precision peut aussi être considérée comme disponible.
---|---

Générer une image du noyau

Pour rendre les noyaux plus faciles à voir, plutôt que d'utiliser Dilate ou une convolution sur une image à pixel unique afin de voir ce qu'elle produit, j'ai créé un script spécial appelé "[kernel2image](../static/img/scripts/kernel2image)". Ce script extrait la sortie exacte de Show Kernel, et la convertit en une image du noyau. Le script "[kernel2image](../static/img/scripts/kernel2image)" a beaucoup d'options, depuis la sortie de l'image brute du noyau (par défaut) jusqu'à la spécification du niveau de mise à l'échelle, des écarts entre pixels, du montage, de l'étiquetage, et même de la coloration de l'« image de noyau » résultante. Le script rend bien plus facile de voir et de comprendre les divers noyaux, et est utilisé abondamment pour générer les images de noyaux affichées dans ces pages d'exemples. Par exemple, voici comment j'ai généré l'image du noyau "[Octagon](#octagon)". |

  kernel2image -10.1  -m "Octagon"  kernel_octagon.gif

[IM Output]
L'option spéciale '-10.1' signifie mettre à l'échelle tous les pixels à une taille de 10 pixels, mais inclure aussi un écart de 1 pixel entre ces pixels. Si le noyau est suffisamment mis à l'échelle, l'« origine » du noyau sera marquée par quelques cercles dessinés. Le '-m' spécifie ensuite que je veux qu'il crée un montage de l'image avec une étiquette d'identification du noyau "[Octagon](#octagon)" extrait, et des effets d'ombre. Et ici je génère une « image de noyau » du noyau défini par l'utilisateur en forme de 'L', que j'ai utilisé ci-dessus. |

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

[IM Output]
Si vous voulez créer un noyau à partir d'une image existante, un script "[image2kernel](../static/img/scripts/image2kernel)" peut être utilisé pour créer un fichier de données de noyau à partir d'une image. Ce script prend normalement une image en niveaux de gris, mais si une image multicolore est donnée, chaque canal de l'image est converti en un fichier de données de noyau distinct. Ici je crée les données de noyau utilisateur à partir d'une petite image de drapeau ( ), puis j'utilise "[kernel2image](../static/img/scripts/kernel2image)" pour reconvertir ces données en une « image de noyau » agrandie pour l'affichage. |

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

[IM Output]
REMARQUE : j'aurais pu générer la version « agrandie » de la petite image plus directement avec un script similaire "[enlarge_image](../static/img/scripts/enlarge_image)", mais cela aurait affiché l'image, et non les données de noyau, "[flag_kernel.dat](../static/img/morphology/flag_kernel.dat)".

Gestion d'une liste de noyaux multiples

Générer plusieurs noyaux

À partir d'IM v6.6.2-0, vous pouvez spécifier plusieurs noyaux qui seront appliqués à l'image un à la fois. Pour spécifier plusieurs noyaux, il suffit d'accoler chaque définition de noyau, séparées par un point-virgule ';'. Un point-virgule final à la fin est optionnel. Par exemple, ici je définis une liste de noyaux spéciale contenant une liste qui peut être utilisée pour la « correspondance de motifs » des pixels de coin.

     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,-  ;

Les points-virgules (';') supplémentaires n'ont pas d'importance, tant qu'au moins un est fourni entre les spécifications de noyau. Les espaces supplémentaires (y compris les sauts de ligne) n'en ont pas non plus, dans quelque spécification de noyau que ce soit. Voici une sortie Show Kernel de cette définition.

  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]

Et voici une image de noyau de ces quatre noyaux à l'aide du script spécial "[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]

En réalité, cette définition ne consiste qu'en un seul noyau qui a été développé pour former un ensemble de 4 noyaux, chacun pivoté de 90 degrés. À NOTER : cette définition est presque équivalente au noyau spécial de correspondance de motif '[Corners](#corners)' (voir ci-dessous), sauf qu'elle se limite aux coins de la forme réelle, et non à n'importe quel coin, d'arrière-plan ou d'avant-plan.

Développement en une liste de noyaux pivotés

Depuis IM v6.2.2-0, vous pouvez demander à IM de développer un noyau unique en une liste de noyaux pivotés à l'aide de l'un des trois indicateurs spéciaux, dans les noyaux nommés comme dans ceux définis par l'utilisateur. Les trois indicateurs spéciaux sont...

'@ ' Fait pivoter cycliquement les noyaux 3x3 par incréments de 45 degrés, produisant une liste allant jusqu'à 8 noyaux pivotés. (moyen mnémotechnique : '@' est circulaire)
'> ' Fait pivoter (noyaux carrés ou linéaires uniquement) par incréments de 90 degrés. (moyen mnémotechnique : le '>' forme un angle droit).
'< ' Produit également des rotations de 90 degrés, mais dans une séquence « miroir » (angles de rotation de 0, 180, -90, +90). Cette forme spéciale de développement par rotation fonctionne mieux pour les méthodes de morphologie telles que '[Thinning](#thinning)'. (moyen mnémotechnique : '<' est le miroir d'un angle droit).

Par exemple, ce même noyau ci-dessus peut être spécifié plus simplement ainsi...

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

Cela définit un noyau, que l'indicateur '>' indique ensuite à IM de développer en une liste pivotée de 90 degrés. Et voici une image de la liste multi-noyaux obtenue

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

[IM Text]

Et ici, je fais pivoter un noyau 3x3 selon une rotation « cyclique » de 45 degrés, le développant en une liste de 8 noyaux.

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

[IM Text]

Vous pouvez également faire de même pour n'importe quel noyau nommé intégré « unique » d'IM, en utilisant les mêmes indicateurs dans la section d'arguments de ces noyaux. Par exemple, ici je prends un noyau '[Blur](convolve.html#blur)' symétrique et je le développe en une liste pivotée de 90 degrés à l'aide d'un indicateur '>'.

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

[IM Text]

Notez que seuls 2 noyaux ont été générés, car un troisième noyau reproduirait exactement le premier. Cela est détecté et la génération de noyaux pivotés s'arrête. Cependant, si l'« origine » est décentrée, la séquence complète des 4 noyaux pivotés aurait été générée, car même si la « forme » du noyau correspond, l'emplacement de l'origine ne serait pas le même. De nombreuses définitions de noyaux intégrés génèrent automatiquement une liste multi-noyaux, de sorte que vous n'avez pas besoin de spécifier d'indicateur à cette fin. Autrement dit, le développement par rotation est également « intégré » à la définition de noyau spécifique. De tels noyaux fournissent typiquement aussi des « sous-types » de la définition de noyau unique d'origine, afin que vous puissiez choisir des noyaux spécifiques pour des usages spécifiques.

Fusion des résultats de plusieurs noyaux : réitérer ou composer

Lorsque vous avez défini plusieurs noyaux, la méthode de morphologie doit aussi savoir comment fusionner les résultats générés par plusieurs noyaux. Cela peut être contrôlé par l'utilisation d'un Define global...

    -define morphology:compose={_compose_method_}

La valeur par défaut de la plupart des méthodes de morphologie est le réglage 'None'. Cela signifie qu'après l'application de chaque noyau à l'aide de la méthode de morphologie donnée, l'image obtenue doit être utilisée comme source pour le noyau suivant. C'est simplement 'réitérer ', c'est-à-dire réutiliser l'image obtenue par l'application d'un noyau pour le noyau suivant. Par exemple, si j'effectue un Convolve à l'aide de 2 noyaux '[Blur](convolve.html#blur)' pivotés de 90 degrés, nous obtenons ce qui suit.

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

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

Comme vous pouvez le voir, les deux noyaux ont été appliqués à l'image l'un après l'autre, de sorte que chaque noyau travaille avec le résultat du noyau précédent. Autrement dit, il 'réitère ' le résultat d'un noyau avec le noyau suivant, en séquence. Cela équivaut à effectuer les deux étapes de la manière suivante.

  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]

En fait, c'est ainsi que l'opérateur Blur fonctionne réellement, pour générer les flous d'image plus rapidement. Voir Noyaux gaussiens vs Blur qui illustre cet usage plus en détail.
En réglant le '{_compose_method_}' sur une méthode autre que 'None', l'opération ne sera PAS réitérée. Au lieu de cela, chaque noyau sera appliqué à l'image d'origine, et les images obtenues seront ensuite composées ensemble à l'aide de la méthode '{_compose_method_}' spécifiée. Par exemple, si j'utilise une méthode de morphologie '[Lighten](compose.html#lighten)' pour générer une union des résultats séparés, nous obtiendrions..

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

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

Cela équivalait à effectuer...

  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]

Si vous n'êtes pas sûr de ce qu'IM fait réellement pendant une morphologie, activez la sortie détaillée des modifications. Par exemple, voici la sortie détaillée de la réitération avec chaque noyau...

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

[IM Text]

Et voici la sortie détaillée d'une union (composition Lighten) de chaque résultat de noyau....

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

[IM Text]

Les deux montrent clairement ce qu'ImageMagick fait pour générer l'image finale. Le nombre après la virgule décimale représente le numéro du noyau appliqué à chaque étape. Suivi à la fin par la façon dont il compose les images ensemble selon le réglage 'morphology:compose'. De nombreuses méthodes de composition mathématiques et leurs opérations équivalentes de type théorie des ensembles peuvent aussi être utilisées pour fusionner les résultats de l'application de chaque noyau à l'image d'origine. En résumé, ce réglage définit comment les noyaux individuels d'une liste multi-noyaux seront appliqués à l'image donnée. La valeur par défaut est la valeur de composition 'None', qui signifie simplement « réitérer » les résultats ; sinon, elle fusionnera tous les résultats selon la méthode de composition donnée.


Méthodes de morphologie de base

Les méthodes morphologiques constituent une technique de traitement d'image pour la recherche et l'analyse des formes des objets au sein d'une image. Agrandir, rétrécir, localiser des formes spécifiques, et ainsi de suite. Elles ont été initialement développées en pensant aux images binaires (noir et blanc pur), et de ce fait elles s'appliquent le plus souvent aux images seuillées contenant de simples formes en noir et blanc. Par convention, le blanc dans une image binaire représente l'avant-plan, tandis que le noir représente l'arrière-plan. Les noms des méthodes sont donc décrits selon cette convention. Cela ne veut pas dire que les opérateurs ne fonctionnent pas avec des images en niveaux de gris, ou dans certains cas des images couleur, mais leur objectif d'origine était de traiter des formes binaires. Les noyaux de forme de base déjà examinés ci-dessus sont les « formes » de voisinage les plus couramment utilisées pour les méthodes morphologiques. De tels noyaux sont souvent appelés « éléments structurants », car ils servent typiquement à déterminer la structure des formes au sein de l'image.

Erode (érosion) ( )

Comme son nom l'indique, la méthode '**Erode**' « ronge » la forme blanche à partir de tout pixel d'arrière-plan, la rendant plus petite. On peut aussi la voir comme un agrandissement des zones noires de l'image. Par exemple, voici une simple forme binaire « de type humain » qui a été érodée à l'aide d'un noyau '[Octagon](#octagon)'.

  magick man.gif   -morphology Erode Octagon  erode_man.gif

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

Son effet fondamental est de rendre plus fines les protubérances ou pointes que l'image peut avoir, ou de les supprimer complètement, mais il agrandit aussi tout trou présent (comme celui causé par le « bras » de cette image) dans l'image. En général, la taille du noyau détermine combien de pixels sont supprimés.

Dilate (dilatation) ( )

La méthode '**Dilate**' est le dual de 'Erode'. Elle étend les formes blanches, agrandissant une forme selon le noyau (et le nombre d'itérations) spécifié. Bien sûr, cela signifie aussi qu'elle « érode » les zones noires de l'image.

  magick man.gif   -morphology Dilate Octagon  dilate_man.gif

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

Remarquez comment la forme devient non seulement plus grande, mais son contour devient plus lisse. La grande échancrure entre les « jambes » a été comblée, tout comme le petit « trou » d'un seul pixel que contenait l'image. La taille et la forme du noyau déterminent combien de pixels sont ajoutés autour des bords de l'image. 'Dilate' et 'Erode' sont duaux. Autrement dit, (au moins avec un noyau symétrique) en inversant (négatif) l'image avant et après l'application de la méthode morphologique, vous effectuerez en réalité l'autre forme de l'opérateur. Par exemple, ici j'effectue une érosion en utilisant 'Dilate' sur les images inversées. |

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

[IM Output]

Open (ouverture) ( )

Voici l'effet de la méthode '**Open**', mais cette fois en utilisant un noyau '[Disk](#disk)' bien plus grand.

  magick man.gif   -morphology Open Disk  open_man.gif

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

En conséquence, vous verrez que 'Open' a lissé le contour, en arrondissant les pointes acérées, et a supprimé les parties plus petites que la forme utilisée. Elle déconnecte ou « ouvre » aussi les fins ponts. Cependant, elle ne supprime pas les « trous » ou lacunes qui peuvent être présents dans l'image, comme entre les « jambes » des formes. De plus, elle ne rend pas la taille « centrale » de base de la forme plus grande ni plus petite. Concrètement, ce qu'elle fait, c'est '[Erode](#erode)' une image puis la '[Dilate](#dilate)' à nouveau en utilisant le même noyau fourni

  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]

Notez qu'effectuer un 'Open' sur une forme déjà ouverte, avec le même noyau, ne produira aucun changement supplémentaire sur la forme. Par exemple...

  magick open_man.gif  -morphology Open Disk  open_man_twice.gif

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

Autrement dit, répéter une opération 'Open' avec le même noyau n'a aucun effet sur le résultat. De ce fait, tout nombre d'itérations fourni sera appliqué aux sous-méthodes individuelles de dilatation et d'érosion, et non à la méthode dans son ensemble, de sorte que l'itération puisse servir à « étendre » le noyau effectif plutôt qu'à répéter inutilement l'opération composée. Ainsi, une itération 'Open:2 ' sera en réalité appliquée à l'image sous la forme d'un 'Erode:2', suivi d'un 'Dilate:2'. Cela a pour effet général d'agrandir le « voisinage » effectif défini par le noyau. |

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

[IM Output]
Ici, vous pouvez voir que le voisinage plus grand obtenu a entraîné la suppression des extrémités que sont la « tête » et les « pieds » de l'homme. Le corps principal de la forme est resté pour l'essentiel intact, quoique d'apparence plus lisse, tandis que l'écart entre les jambes demeure inchangé. C'est le même effet que doubler la taille du noyau, bien que sa forme exacte puisse ne pas être exactement identique à celle d'un noyau de rayon double.

Close (fermeture) ( )

L'usage fondamental de la méthode '**Close**' est de réduire ou de supprimer les « trous » ou « lacunes » d'une taille proche de celle de l'« élément structurant » du noyau. Autrement dit, « fermer » les parties de l'arrière-plan d'à peu près cette taille.

  magick man.gif    -morphology Close Disk   close_man.gif

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

L'effet fondamental de cet opérateur est de lisser le contour de la forme, en comblant (fermant) les trous et les échancrures. Il forme aussi des « ponts » de connexion vers d'autres formes suffisamment proches pour que le noyau touche les deux simultanément. Mais il ne rend pas la taille « centrale » de base de la forme plus grande ni plus petite. Concrètement, ce qu'il fait, c'est '[Dilate](#dilate)' l'image puis la '[Erode](#erode)' à nouveau en utilisant le même noyau fourni, ce qui fait d'abord grandir l'image, puis rétrécir. C'est l'ordre inverse de ce que fait '[Open](#open)'.

  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]

Le résultat est que les pointes externes de l'image seront laissées telles quelles, mais les « baies » seront lissées et épaissies, et les « trous » et « lacunes » fermés. Des objets déconnectés très proches les uns des autres peuvent se retrouver liés. Comme avec '[Open](#open)', répéter la méthode '[Close](#close)' avec le même noyau n'apporte aucun changement supplémentaire à l'image. Utiliser une 'itération ' avec l'opérateur répétera toutefois les sous-méthodes internes, de manière à produire un effet d'arrondi plus fort, semblable à l'utilisation d'un noyau plus grand. Et tout comme les méthodes '[Dilate](#dilate)' et '[Erode](#erode)', les méthodes '[Open](#open)' et '[Close](#close)' sont duales. Vous pouvez reproduire l'effet de l'autre « dual » en inversant (négatif) l'image avant et après l'opération. |

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

[IM Output]

Smooth (lissage)

La méthode '**Smooth**' applique un '[Open](#open)' suivi d'un '[Close](#close)' de la forme, ce qui supprime d'abord les « petits objets » puis comble les « trous » ou « lacunes » d'à peu près la taille de l'« élément structurant » du noyau. Ici, nous lissons l'image à l'aide d'un noyau '[Octagon:3](#octagon)' de taille moyenne. |

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

[IM Output]
Comme vous pouvez le voir, toutes les « échancrures », « lacunes », « trous » et « pointes » ont été lissés et arrondis selon la taille et la forme du noyau. L'opérateur '[Smooth](#smooth)' est aussi souvent répété avec des éléments structurants de taille lentement croissante, afin de retirer progressivement le bruit des images. Si les parties retirées sont conservées, vous obtenez une « décomposition » morphologique de l'image utilisable pour une étude plus poussée. Voir Granularité ci-dessous. La méthode est particulièrement efficace pour nettoyer les documents numérisés. Notez que cela applique en réalité 4 opérations « primitives » distinctes à l'image d'origine. Elle est donc 4 fois plus lente qu'un simple '[Erode](#erode)' ou '[Dilate](#dilate)'.

Morphologie en niveaux de gris plate

Bien que, pour l'essentiel, les quatre méthodes morphologiques de base, ainsi que les méthodes ultérieures définies à partir de ces quatre méthodes, soient spécifiquement conçues pour fonctionner avec des images binaires, elles peuvent être appliquées aux images en niveaux de gris comme aux images couleur (même si les images couleur peuvent engendrer d'étranges effets de couleur). Exemple pratique d'opération en niveaux de gris souhaité ici Cependant, le noyau lui-même sera toujours considéré comme un simple voisinage « activé » ou « désactivé ». Toute valeur de noyau qui est soit un 'nan' soit inférieure à '0.5' sera considérée comme hors du « voisinage » qu'il définit. En résumé, les opérateurs ci-dessus appliquent un noyau « plat » sans aucune caractéristique de « hauteur » ni « tridimensionnelle », mais peuvent tout de même s'appliquer aux images en niveaux de gris.

Morphologie en vrais niveaux de gris ou tridimensionnelle

La morphologie en vrais niveaux de gris, ou tridimensionnelle (comme le formule une bibliothèque), ajoute ou soustrait en réalité les valeurs trouvées dans le noyau aux pixels voisins de l'image, avant de chercher les valeurs maximales/minimales comme résultat. Cela signifie qu'elle traite une image en niveaux de gris comme un « champ de hauteur » d'un objet morphologique tridimensionnel, et la forme en niveaux de gris du noyau comme la forme de lissage servant à ajuster ce champ de hauteur. Si les détails d'implémentation de la vraie morphologie en niveaux de gris sont bien documentés, son usage dans des situations pratiques ne l'est pas. Autrement dit, je n'ai trouvé aucun exemple utile d'utilisation de la vraie morphologie en niveaux de gris au-delà des « noyaux de forme plate », hormis une remarque sur son usage dans le traitement « photométrique ». De ce fait, je n'ai pas implémenté de vraie morphologie en niveaux de gris tridimensionnelle. Cependant, si des personnes ont réellement besoin de tels opérateurs morphologiques en niveaux de gris non plats, faites-le-moi savoir, et j'implémenterai les opérateurs appropriés. Notez que la méthode spéciale '[Distance](#distance)' (voir ci-dessous) est en fait semblable au fonctionnement de la vraie morphologie en niveaux de gris, en ce qu'elle ajoute la valeur du noyau à chaque valeur de pixel avant de prendre la plus petite valeur « minimale ». Cependant, cette méthode ne correspond ni à la définition morphologique de l'érosion 3D (soustraire et prendre le minimum) ni à celle de la dilatation (ajouter et prendre le maximum). Elle y est toutefois très étroitement liée, et pourrait probablement être implémentée à l'aide de ces méthodes.

Variante d'intensité pour les images couleur

Comme les quatre méthodes ci-dessus sont des méthodes de canal en niveaux de gris, les utiliser sur des images couleur peut engendrer des effets de couleur indésirables où un canal est modifié mais un autre ne l'est pas. Elles ne sont vraiment pas conçues pour un usage avec des images couleur multicanaux, seulement avec des images en niveaux de gris et binaires. Le résultat, pour les images couleur, est que les couleurs se déforment, devenant une teinte plus claire ou plus sombre selon l'opération. Dans cette optique, j'ai créé des versions « Intensity » de ces méthodes. 'ErodeIntensity', 'DilateIntensity', 'OpenIntensity', 'CloseIntensity'. Elles comparent les pixels au sein du « voisinage » défini, et remplacent la couleur du pixel courant selon l'intensité des pixels. Autrement dit, tout le pixel couleur est copié, et pas seulement les valeurs de canal individuelles. En conséquence...

Les variantes d'intensité ne génèrent aucune « nouvelle » couleur dans les images.

En raison de leur nature, les méthodes d'intensité ignorent complètement le réglage "[-channel](https://imagemagick.org/command-line-options/#channel)" actuel. Par exemple, ici j'utilise les variantes binaire et d'intensité de la morphologie '[Dilate](#dilate)' (étendre les zones claires) sur l'image intégrée "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]

Comme vous pouvez le voir, la méthode '[Dilate](#dilate)' normale peut générer différentes teintes dans chacune des grandes taches dilatées, car chaque canal est traité séparément. La deuxième dilatation d'intensité préserve toutefois la couleur complète des taches les plus claires, les étendant selon la forme booléenne du noyau. Les méthodes d'intensité ont aussi un schéma de dénomination abrégé, remplaçant le mot 'Intensity' par un simple 'I'. Ainsi, ici j'utilise une méthode 'CloseIntensity' mais avec le nom abrégé 'CloseI'. Par exemple, voici les résultats de l'utilisation de chacune des quatre variantes « Intensity » sur l'image rose intégrée. |

  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]
Les deux derniers peuvent convenir particulièrement comme opérateur de remplacement de l'opérateur Paint. Ces méthodes sont classées comme expérimentales, et les commentaires ou problèmes liés à leur usage sont les bienvenus. Si je ne reçois aucun commentaire, rien de plus ne sera ajouté !

Techniques alternatives de morphologie de base

Pour les personnes disposant de versions d'IM antérieures à v6.5.9-0, vous pouvez encore implémenter
certaines méthodes de morphologie de base.

Vous pouvez générer un noyau entièrement composé de uns. Par exemple, un tableau 7x7 de 1
(radius=3), en utilisant un sigma extrêmement grand et en spécifiant le rayon approprié,
à l'aide d'un flou gaussien.

Ainsi
    -convolve 1,1,1,1,1,.....
pour un total de 49 uns équivaut à
    -gaussian-blur 3x65535

Cela vous permet de générer un simple noyau carré pour les méthodes
morphologiques binaires.

Le 'Dilate' pour un noyau carré 3x3 (radius=1) est donc
    -gaussian-blur 1x65535 -threshold 0
'Erode' est donc
    -gaussian-blur 1x65535 -threshold 99.999%

Comme montré précédemment ci-dessus
'Open' est un 'Dilate' suivi d'un 'Erode'
'Close' est un 'Erode' suivi d'un 'Dilate'
et Smooth est un 'Open' suivi d'un 'Close'

Des noyaux carrés plus grands peuvent être spécifiés en utilisant des rayons plus grands.

Malheureusement, les autres formes de noyaux intégrées ne sont pas disponibles,
sans utiliser l'opérateur convolve pour définir manuellement leur forme.

Cela ne fonctionne aussi vraiment que pour la morphologie binaire. Pour implémenter une
morphologie en niveaux de gris plate, vous devrez utiliser une technique différente consistant à
générer une image séparée pour chaque pixel du noyau, et à la faire
tourner (roll) selon la position du pixel.

Les deux méthodes de composition, convolve seuillé et roll-shift, ont été
implémentées dans le script "morphology" de Fred Weinhaus, créé bien
avant l'ajout de l'opérateur "-morphology" à ImageMagick.

Consultez et téléchargez le script "Morphology" de Fred Weinhaus depuis
  http://www.fmwconcepts.com/imagemagick/morphology/index.php

Méthodes de morphologie par différence

Le niveau suivant des méthodes morphologiques est ce que j'appelle la morphologie par différence. Autrement dit, le résultat de ces méthodes de morphologie est la différence entre l'une des méthodes de morphologie de base précédentes et l'image d'origine, ou une autre méthode morphologique. Pour l'essentiel, elles renvoient les changements apportés à l'image d'origine par l'une des méthodes plus simples, vous donnant les contours, les ajouts ou les soustractions entre les images. Ce sont essentiellement des compositions d'image '[Difference](compose.html#difference)' ou '[Minus](compose.html#minus)' des résultats d'image.

EdgeIn

La méthode '**EdgeIn**', aussi appelée « gradient interne », trouve les pixels que l'érosion supprime de l'original. En conséquence, les pixels les plus proches du bord, mais qui faisaient partie de la forme d'origine, sont renvoyés.

  magick man.gif   -morphology EdgeIn Octagon  edgein_man.gif

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

Le bord obtenu fait environ la moitié de la taille du noyau donné, ce qui, pour un noyau '[Octagon](#octagon)', est plutôt épais. Plus typiquement, vous utiliseriez un noyau '[Diamond](#diamond)' ou '[Square](#square)' bien plus petit, pour produire un contour de la forme d'un seul pixel de large. Un exemple d'utilisation de '[EdgeIn](#edgein)' avec le canal alpha, pour extraire les pixels de bord, est montré dans Sparse Color comme opérateur de remplissage.

EdgeOut

La méthode '**EdgeOut**', aussi appelée « gradient externe », trouve les pixels qui ont été ajoutés à l'image d'origine par une dilatation de cette image. En conséquence, les pixels d'arrière-plan immédiatement voisins de la forme sont renvoyés.

  magick man.gif   -morphology EdgeOut Octagon  edgeout_man.gif

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

Un exemple d'utilisation de '[EdgeOut](#edgeout)' avec le canal alpha est montré dans Transparence de contour ou de halo.

Edge ou gradient morphologique

La méthode '**Edge**' renvoie un « gradient morphologique », qui peut être décrit soit comme l'addition des deux méthodes « edge » précédentes, soit plus spécifiquement comme la différence entre la forme érodée et sa forme dilatée.

  magick man.gif   -morphology Edge Octagon  edge_man.gif

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

Comme précédemment, la taille et la forme du noyau définissent l'épaisseur de l'image érodée. Son épaisseur équivaut essentiellement à cette taille de noyau, moins le pixel central. Ainsi, un noyau de rayon 3 produira généralement un 'Edge' de 6 pixels d'épaisseur (la taille du noyau est de 7 pixels d'épaisseur). Voici par exemple le contour 'Edge' de la forme en utilisant le noyau '[Diamond](#diamond)' minimal. |

  magick man.gif  -morphology Edge Diamond  man_outline.gif

Le bord fait deux pixels d'épaisseur, car il contient les pixels situés de part et d'autre du véritable « bord de pixel » de la forme d'origine. Le seul moyen d'affiner ce bord est en réalité de décaler toute l'image en diagonale d'un demi-pixel. [IM Text]
Pour plus de détails sur l'obtention de contours de formes de diverses manières, voir la section sur la détection de bords. À venir : génération du bord à l'aide d'une « ligne diagonale ».

Top-Hat

La méthode '**TopHat**', ou plus spécifiquement « White Top Hat », renvoie les pixels qui ont été supprimés par une ouverture de la forme, c'est-à-dire les pixels supprimés pour arrondir les pointes et les ponts de connexion entre les formes.

  magick man.gif   -morphology TopHat Disk  tophat_man.gif

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

Comme vous pouvez le voir, les pixels forment souvent de petits îlots fortement disjoints, sans aucun ensemble de pixels plus épais que le noyau utilisé. Le nom de la méthode, « Top Hat », se réfère en réalité à l'usage de l'opérateur lorsqu'il est appliqué à l'aide de la méthode pour la morphologie tridimensionnelle en niveaux de gris, et non avec des images binaires comme nous l'avons fait ici. Cet opérateur est plus couramment utilisé avec des images en niveaux de gris. À VENIR : exemple de top-hat en niveaux de gris

Bottom-Hat

La méthode '**BottomHat**', aussi connue sous le nom de « Black TopHat », correspond aux pixels qu'une fermeture de la forme ajoute à l'image. Autrement dit, les pixels qui ont servi à combler les « trous », « lacunes » et « ponts ».

  magick man.gif   -morphology BottomHat Disk  bottomhat_man.gif

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

Là encore, vous pouvez voir que cela produit aussi des « îlots » de pixels fortement disjoints, dont aucun n'est plus épais que le noyau utilisé. Cependant, ce sont toujours un ensemble d'îlots complètement différent de celui de la méthode précédente. À VENIR : exemple de bottom-hat en niveaux de gris


Utilisation des méthodes de morphologie de bas niveau

Morphologie de base et canaux

Toutes les méthodes de morphologie de base ci-dessus sont des méthodes de canal ; à ce titre, elles sont appliquées aux canaux individuels d'une image selon le réglage "[-channel](https://imagemagick.org/command-line-options/#channel)" actuel. Cela signifie que vous pouvez appliquer ces méthodes à des images couleur, à condition de ne pas être trop regardant sur les « fuites de couleur » provenant de zones transparentes non définies. Par exemple, '[Erode](#erode)' le canal alpha de l'image « figure humaine » d'origine, sans modifier les canaux de couleur.

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

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

Comme vous pouvez le voir, cela fonctionne bien. Pour d'autres exemples, voir Sparse Color comme opérateur de remplissage, qui utilise la méthode '[EdgeIn](#edgein)' pour trouver les pixels de bord d'une image. Voir aussi Transparence de contour ou de halo, qui utilise '[EdgeOut](#edgeout)' pour étendre les bords d'une image avec une couleur spécifique.

Recherche de formes spécifiques

La connaissance que l'on a d'un objet dépend de la manière dont on le sonde
(l'observe).                    -- Georges Matheron, le père de la morphologie

Utiliser Erode pour localiser des formes spécifiques dans une grande collection de formes. Poussé
à l'extrême, cela crée des [squelettes](#skeletons), voir aussi [amincissement de squelettes](#thinning_skeleton).

Restaurer des objets à l'aide d'Open (résultat lissé) ou de la [dilatation conditionnelle](#dilate_conditional).

Nécessite une forme d'analyse en composantes connexes (segmentation) pour compter
correctement les objets trouvés au sein d'une image.

Granularité d'un ensemble de formes

En utilisant une série d'opérations '[Open](#open)' sur une image avec des éléments structurants de taille lentement croissante, et en mesurant l'aire obtenue, vous pouvez rapidement obtenir un résumé du nombre de telles formes présentes dans l'image. En prenant la dérivée (pente) de ce résultat, vous obtenez un « spectre » du nombre et de la taille des formes qui composent l'image. Ce graphique est la 'granularité ' de l'image pour une forme particulière donnée. Voir Granulométrie (morphologie), Wikipedia. Les différences d'une taille à la suivante vous permettront aussi de séparer et de compter des éléments spécifiques en fonction de leur taille, et à leur tour de séparer des zones contenant des éléments de tailles et de formes différentes. Le résultat est une méthode de segmentation de texture. Démonstration de la détermination du nombre et de la taille d'un ensemble de formes. Cela nécessite toutefois une méthode de « comptage » (à ajouter) pour être pleinement implémenté. Note historique... Cet usage a en fait été le moteur initial de la création originelle des méthodes de morphologie, dans une compagnie minière parisienne, dans les années 1960. Il a permis à leurs créateurs de mettre au point un système automatisé pour analyser la structure granulaire de photos microscopiques d'échantillons de minéraux afin de déterminer leur aptitude à l'exploitation minière. Autrement dit, localiser et compter la taille et la quantité de minéral dans les échantillons. Par exemple : deux minerais peuvent contenir la même quantité de minéral recherché (généralement sous forme de grains ou de cristaux dans la roche), mais seul le minerai à grains plus gros pouvait être exploité efficacement, car il permettait de séparer plus facilement le gros minéral pur de la roche minéralisée environnante. C'était une tâche très laborieuse, que la morphologie a grandement facilitée.

Effets des noyaux asymétriques (tests des méthodes de base)

Voyons comment ces méthodes de base fonctionnent lorsqu'elles sont utilisées avec un noyau qui n'est pas symétrique. Par exemple, ici j'applique une forme en « L » définie par l'utilisateur contre une image de test morphologique spéciale (agrandie pour visualiser les pixels individuels). |

  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]
Ce qui donne les résultats suivants...

[IM Text] '[Erode](#erode)' transforme toute correspondance exacte de la forme du noyau en un unique pixel blanc au point de correspondance, l'« origine ». Il étendra aussi tout « trou » d'un seul pixel en cette même forme, mais « réfléchie » autour de l'« origine », c'est-à-dire comme si le noyau avait été pivoté de 180 degrés.

[IM Text] '[Dilate](#dilate)' Comme attendu, produit ces mêmes résultats, mais pour une forme « négative » et « réfléchie » de l'image ou du noyau. Un unique pixel blanc s'étend à la forme du noyau, tandis que tout trou de forme « réfléchie » correspondante rétrécit jusqu'à un « trou » d'un seul pixel.
Notez aussi que la frontière entre les moitiés positive et négative de l'image de test se déplace en conséquence de l'application des méthodes morphologiques de base ci-dessus. C'est à prévoir. Cela met en lumière un point spécifique concernant ces deux méthodes. Pour convertir une méthode '[Erode](#erode)' en '[Dilate](#dilate)' ou vice-versa, vous devez non seulement inverser (négatif) les images avant et après, mais aussi pivoter ou réfléchir le noyau autour de l'origine. Normalement, ce second aspect peut être ignoré, car la plupart des noyaux sont « symétriques ». Il ne devient important qu'avec des noyaux asymétriques définis par l'utilisateur. [IM Text] '[Open](#open)' comme mentionné précédemment, ne supprime généralement aucun « trou » dans l'image, cependant une forme correspondant exactement restera inchangée. Des formes plus grandes (comme la moitié négative de l'image de test) peuvent aussi subsister, mais peut-être légèrement modifiées.
[IM Text] '[Close](#close)' est un résultat exactement négatif du précédent, mais est défini de sorte qu'il n'a pas besoin que le noyau soit réfléchi (car il l'est par sa définition interne), seulement que l'image soit inversée.


Correspondance de motifs Tout-ou-rien (HMT)

Tout-ou-rien ( )

La méthode de morphologie 'Hit-And-Miss', également connue couramment sous le nom de "HMT " dans la littérature informatique, est une méthode de morphologie de haut niveau spécialement conçue pour trouver et localiser des motifs particuliers dans les images. Elle procède en recherchant une configuration particulière de pixels de « premier plan » et d'« arrière-plan » autour de l'« origine ». Depuis IM v6.6.9-4, vous pouvez utiliser n'importe lequel des noms de méthode 'HitAndMiss', 'Hit_N_Miss' ou simplement 'HMT', ainsi que leurs variantes, pour spécifier cette méthode de morphologie. Avant cette version, seul le nom de méthode 'HitAndMiss' pouvait être utilisé.
Par exemple, on peut chercher un pixel de « premier plan » qui a un pixel d'« arrière-plan » immédiatement à sa droite.
  magick man.gif   -morphology Hit-and-Miss '2x1:1,0'  hmt_right.gif

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

Comme vous pouvez le voir, le petit noyau à 2 éléments n'a mis en correspondance que les pixels situés sur le côté droit de l'image. Autrement dit, la méthode n'a renvoyé qu'un pixel particulier correspondant au motif donné. Le « noyau » ou « élément structurant » utilisé ne peut contenir qu'un motif composé de 3 types d'éléments : une valeur de '1' signifiant « premier plan », une valeur de '0' signifiant « arrière-plan », et aussi un troisième élément qui peut être spécifié soit par 'Nan', soit par '-', soit par une valeur de '0.5', qui signifie « peu importe » ou « n'importe quel pixel ». La valeur que vous employez pour l'« origine » est très importante, car elle définit si vous voulez seulement « toucher » la forme de premier plan ou le motif d'arrière-plan. Mais si vous fixez explicitement la valeur de l'« origine » à « peu importe », vous pouvez alors mettre en correspondance aussi bien des pixels de premier plan que d'arrière-plan qui présentent le bon voisinage environnant. Par exemple, si j'utilise un élément structurant tel que…

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

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

Vous obtenez tous les pixels de bord droit qui se trouvent soit à l'intérieur, soit à l'extérieur. Ainsi, vous marquez maintenant les deux côtés de la frontière de la forme, et vous extrayez un bord de 2 pixels de large. Cependant, tous les pixels ne correspondent pas au motif, donc tous les pixels ne sont pas doublés, mais en général c'est ce que vous obtenez. L'emploi d'une valeur « peu importe » pour l'« origine » est en fait très courant, surtout quand nous examinerons plus loin les méthodes Thicken et Thinning, qui se limitent soit à ajouter, soit à retirer des pixels. En « ne se souciant pas », la même définition de noyau peut servir pour l'une ou l'autre opération, car l'opération elle-même définit le type de « touches » qui vous intéresse.
Voici un autre exemple, mais cette fois je limite de nouveau mes « touches » aux pixels qui tombent à l'intérieur de la forme mais qui forment un coin orienté vers le nord-ouest.

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

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

En développant ce coin unique en un ensemble de coins pivotés de 90 degrés par l'ajout d'un drapeau '>', nous pouvons trouver tous les coins qui apparaissent à l'intérieur de la forme. |

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

[IM Output] [IM Output]
Comme vous pouvez le voir, la méthode '[Hit-And-Miss](#hmt)' localise et renvoie TOUTES les positions de pixels qui correspondent à l'un des motifs de noyau fournis. | _Si vous examiniez la sortie détaillée de l'opération "[-morphology](https://imagemagick.org/command-line-options/#morphology)" ci-dessus, vous constateriez que le '[Hit-And-Miss](#hmt)' utilise une méthode de composition '[Lighten](compose.html#set_theory)' pour créer une « union » de tous les pixels correspondant à chacun des noyaux de motif fournis.

Malheureusement, le compte de pixels « modifiés » correspond à tous les pixels qui sont désactivés par chaque application de noyau. Autrement dit, le nombre de pixels dans la forme, moins le nombre de pixels mis en correspondance par chaque noyau.

_
---|---
| _De la même manière, répéter la méthode Tout-ou-rien sur ses propres résultats est généralement inutile, car l'image aurait tellement changé que vous n'obtiendriez probablement plus aucune correspondance ensuite.

Vous pouvez, comme vous le voyez, utiliser les résultats pour modifier l'image d'origine afin de générer une image légèrement différente._
---|---
Vous pouvez utiliser un ensemble de noyaux plus sélectifs de ce qui vous intéresse spécifiquement. Par exemple, supposons que vous vous intéressiez aux points où trois lignes se rencontrent. Vous pouvez alors utiliser l'ensemble de noyaux '[LineJunctions](#linejunctions)', conçu spécialement à cet effet.

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif

[IM Output] [IM Output]

Comme vous pouvez le voir, seule une poignée de positions correspond à l'un des noyaux de cet ensemble. Cependant, les résultats peuvent rendre très difficile de voir réellement où se trouvaient les positions correspondantes dans l'image d'origine. C'est particulièrement gênant si vous traitez une image en niveaux de gris. Une solution consiste à étendre les correspondances à l'aide de '[Dilate](#dilate)' avec un noyau de forme, tel qu'un '[Ring](#ring)'. Par exemple… |

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

[IM Output]
Vous pouvez maintenant voir clairement les positions où cet ensemble particulier de noyaux a trouvé des jonctions de 3 lignes ou plus. Chaque noyau de '[LineJunctions](#linejunctions)' ne peut correspondre qu'à quelques positions particulières, si bien que la correspondance de motifs de cette façon peut être lente. Elle reste néanmoins très précise et fonctionne très bien. Un autre ensemble de noyaux '[Hit-And-Miss](#hitmiss)' similaire est le noyau '[LineEnds](#lineend)', qui peut servir à trouver les extrémités libres de toutes les lignes de l'image. |

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

[IM Output]
HitandMiss - avec des pixels de premier plan uniquement - > erode HitandMiss - avec de l'arrière-plan uniquement - > dilate inversé

Tout-ou-rien avec les images en niveaux de gris

Lorsque la méthode '[Hit-And-Miss](#hitmiss)' est appliquée à une image en niveaux de gris, la valeur effectivement renvoyée est la différence entre la valeur minimale de « premier plan » et la valeur maximale d'« arrière-plan ». Si un résultat négatif survient (aucun calcul), le résultat est « écrêté à zéro », car les valeurs négatives n'ont pas de sens réel. Autrement dit, elle renvoie la « séparation minimale » des valeurs entre les deux ensembles de pixels. Pour les formes booléennes, ce sera soit '0.0' (noir), soit '1.0' (blanc). Mais pour les images en niveaux de gris, cela équivaut au « dégradé » des pixels correspondants. On peut par exemple s'en servir pour identifier le degré de contraste présent entre un premier plan et un arrière-plan particuliers dans le motif correspondant. Si vous ne voulez vraiment qu'un résultat booléen (activé/désactivé) des pixels qui correspondent réellement au motif dans une image en niveaux de gris, vous devriez ajouter une option "[-threshold](https://imagemagick.org/command-line-options/#threshold) 0" après la commande.

Thicken (Ajouter des pixels à une forme)

La méthode 'Thicken' ajoute des pixels à la forme d'origine à chaque position correspondante. Par exemple, ici je cherche un pixel d'arrière-plan situé à deux pixels du bord droit de la forme.

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

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

Comme vous pouvez le voir, vous vous retrouvez avec une ligne de pixels juste à l'extérieur de la frontière d'origine de la forme. Vous pouvez itérer cette méthode 'Thicken' plusieurs fois pour poursuivre la séquence. |

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

[IM Output]
Cependant, comme des pixels sont ajoutés, l'origine du noyau de correspondance de motifs ne doit PAS correspondre à un pixel de premier plan, sinon vous ajouterez essentiellement un pixel là où un pixel est déjà présent. Ci-dessus, l'origine est fixée à un motif d'arrière-plan, de sorte que seuls les motifs d'arrière-plan correspondront réellement. Une autre possibilité est de toujours fixer l'origine à une valeur d'élément « peu importe ». En procédant ainsi, vous pourrez utiliser le même motif de noyau pour thicken '[Thicken](#thicken)', et comme vous le verrez plus loin, pour '[Thinning](#thinning)' également. La meilleure règle est donc de fixer l'origine à « peu importe ». | _Une autre façon de générer une opération '[Thicken](#thicken)' consiste à générer une union des résultats du '[Hit-And-Miss](#hitmiss)' de ce noyau avec le noyau spécial '[Unity](#unity)', afin d'inclure l'image d'origine dans les résultats.

Par exemple…_ |

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

[IM Output] [IM Output]

_En fait, le réglage de composition multi-noyaux n'est pas nécessaire dans l'exemple ci-dessus, car la méthode '[Hit-And-Miss](#hitmiss)' définit explicitement ce réglage de composition par défaut lorsqu'il n'est pas défini par l'utilisateur.

_

En général, '[Thicken](#thicken)' est utilisé pour agrandir des formes telles que des lignes, mais sans allonger ces lignes. Un ensemble spécial de noyaux, connu sous le nom de noyau '[ConvexHull](#convexhull)', permet de le faire. Par exemple…

  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 - Enveloppe convexe octogonale

Le véritable noyau '[ConvexHull](#convexhull)' est en réalité conçu pour travailler avec les formes d'image, et étendra une forme en une « enveloppe convexe octogonale ». Autrement dit, il essaiera de combler tous les vides entre les extrêmes jusqu'à produire un objet de « forme octogonale ».

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

[IM Output] [IM Output]
Voir la définition du noyau '[ConvexHull](#convexhull)' pour plus de détails, et pour comprendre pourquoi les deux méthodes '[Close](#close)' sont nécessaires.

Vous pouvez observer l'exécution des itérations en activant le réglage de sortie détaillée. Cela montrera toutefois que ce qui précède est très très lent. Chaque itération '[Thicken](#thicken)' n'ajoute réellement que quelques pixels à la forme à chaque itération. De ce fait, il peut falloir de nombreuses itérations avant que l'« enveloppe » complète soit achevée. Dans ce cas précis, l'image a nécessité 80 itérations '[Thicken](#thicken)', avec un '[ConvexHull](#convexhull)' à 8 noyaux. Cela signifie que ce qui précède a en réalité nécessité 640 itérations primitives, plus 4 autres itérations primitives nécessaires pour réaliser les deux méthodes '[Close](#close)'. Cela peut prendre un temps assez considérable. Fondamentalement, itérer à l'aide de la correspondance de motifs Tout-ou-rien peut être très très « lent », et si une technique alternative peut être trouvée, il faudrait l'utiliser à la place. Vous pouvez aussi vous en servir pour trouver quels points de l'image d'origine ont provoqué la création de cette forme octogonale, en obtenant une intersection (composition Darken) entre le bord de l'enveloppe convexe et la forme d'origine.

  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]

Toute forme connexe qui s'inscrit à l'intérieur de l'enveloppe convexe, mais qui comporte aussi au moins un pixel sur chaque bord de l'enveloppe convexe ci-dessus, générera la même enveloppe convexe octogonale.

Thicken avec les images en niveaux de gris

Lors du traitement d'une image en niveaux de gris, '[Thicken](#thicken)' ajoute le résultat de séparation premier plan/arrière-plan du '[Hit-And-Miss](#hitmiss)' au pixel d'origine. Cela peut donc servir à éclaircir les pixels correspondants, même lorsque le pixel d'« origine » ne fait pas partie de l'ensemble « arrière-plan ». Par exemple, reprenons l'exemple de détection de coins ci-dessus, mais avec une version grise à 50 % de la forme.

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

[IM Output] [IM Output]

Lorsque vous utilisez une version HDRI d'Imagemagick avec '[Thicken](#thicken)', il est probablement judicieux d'appliquer "[-clamp](https://imagemagick.org/command-line-options/#clamp)" ou "[-auto-level](https://imagemagick.org/command-line-options/#auto-level)" aux résultats pour éviter qu'ils ne débordent des limites de la plage de valeurs de pixels de l'image.

Thinning ( ) (Soustraire des pixels d'une forme)

La méthode 'Thinning' est le dual de '[Thicken](#thicken)'. Plutôt que d'ajouter des pixels, cette méthode les soustrait de l'image d'origine. Par exemple, retirons tout pixel situé à 4 pixels à l'intérieur du bord droit.

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

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

Pour que 'Thinning' fonctionne correctement, le noyau de correspondance de motifs doit avoir une origine contenant un pixel de premier plan, sinon la méthode n'a aucun pixel correspondant à retirer de la forme. | _Une autre façon de générer une opération '[Thinning](#thinning)' consiste à effectuer le complément relatif (à l'aide d'une composition MinusSrc) des résultats du '[Hit-And-Miss](#hitmiss)' à partir de l'image d'origine. Vous pouvez inclure cette image au début de la liste de noyaux (celle dont on « soustrait ») en utilisant un noyau '[Unity](#unity)'.

Par exemple…_ |

  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]

_C'est un style de thinning par « intersection », qui retire tous les pixels spécifiés de tous les noyaux en une seule étape, plutôt qu'un style « itératif » qui retire les pixels de chaque noyau en séquence. Voir le style de Thinning pour plus d'informations.

_

Connexité des lignes

FUTUR : lignes 4-connexes contre 8-connexes Voir la discussion dans les forums IM, De lignes 8-connexes à 4-connexes.

Thinning de la sortie d'un détecteur de contours

L'une des utilisations les plus courantes du thinning est de réduire la sortie seuillée d'un détecteur de contours tel que la convolution de Sobel à des lignes d'un seul pixel d'épaisseur, tout en préservant la longueur complète de ces lignes. Exemple utilisant une image de dégradé de distance.

Thinning jusqu'à un squelette

Le '[Thinning](#thinning)' d'images est en fait plus couramment utilisé que '[Thicken](#thicken)', car il sert à réduire les formes en des formes plus faciles à manipuler, telles que des squelettes. Ceux-ci, comme on le verra plus loin, sont censés être la ligne centrale de pixels entre deux (ou plus) bords de la forme. Un squelette est important car il fournit une très bonne description d'une forme très complexe. Par exemple, traiter l'image pour trouver le nombre de boucles, de segments de ligne et la façon dont ils sont agencés vous en dira long sur la forme que vous avez. Produisons donc un « squelette aminci » en appliquant '[Thinning](#thinning)' aux bords de la forme du personnage de façon répétée, jusqu'à ce qu'il ne reste que les lignes centrales.

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

[IM Output] [IM Output]

Un rapport détaillé sur ce qui précède aurait montré 18 itérations, avec 8 noyaux, totalisant 144 itérations primitives au total. C'est en fait bien plus rapide que de trouver son enveloppe convexe (ci-dessus), car les noyaux de thinning retirent des rangées et des colonnes entières de pixels à chaque itération, et pas seulement quelques-uns à la fois. Remarquez comment l'ensemble de noyaux '[Skeleton](#skeleton)' n'a pas réussi à agrandir le trou, de sorte qu'il n'a pas trouvé la ligne centrale entre le trou et le bord extérieur. C'est un défaut sérieux de ce noyau de thinning de squelette particulier, causé par le fait que les noyaux exigent tous au moins des pixels d'arrière-plan avant de produire la moindre correspondance de thinning. Vous pouvez utiliser des ensembles de noyaux de thinning de squelette pour résoudre ce problème. Une solution plus simple consiste à éroder légèrement l'image pour donner aux noyaux de la matière à traiter. Je vais aussi n'éroder et n'amincir que les canaux « rouge » et « vert », afin de laisser la forme d'origine en bleu.

  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]

Vous pouvez aussi voir que tout trou dans l'image s'est maintenant agrandi pour produire une plus grande boucle continue de pixels autour de lui. Voici un gros plan de la boucle autour du trou érodé. |

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

[IM Output]
Notez qu'il n'a pas produit de ligne centrale exacte entre le trou et le bord. De plus, comme la forme a été érodée, les lignes ne vont pas jusqu'au bord de la forme d'origine mais s'arrêtent un pixel avant. Autrement dit, l'extrémité des lignes a été légèrement « élaguée ». C'est là l'inconvénient de la solution par « érosion ». Le squelette est aussi limité à des lignes octogonales, ce qui signifie qu'il manque beaucoup de détails, bien que dans ce cas cette simplification puisse être une bonne chose. Voir la section sur les squelettes ci-dessous. Il s'agit d'un noyau '[Skeleton](#skeleton)' traditionnel qui, comme vous pouvez le voir, produit des lignes diagonales « épaisses », de sorte que toutes les parties du squelette sont « 4-connexes » ou « connectées en losange ». Il existe d'autres variantes de noyaux '[Skeleton](#skeleton)', qui produiront d'autres variations dans le « squelette aminci » résultant. Squelette plus fin, 8-connexe Ce squelette « traditionnel », comme mentionné, a des diagonales épaisses. Mais souvent ce n'est pas assez « fin ». Dans certaines situations, ce que vous voulez, c'est un squelette légèrement plus fin. Autrement dit, vous voulez un squelette « 8-connexe » plutôt qu'un squelette « 4-connexe ». Une solution consiste à utiliser une autre variante de génération de squelette, telle que celle produite à l'aide d'un noyau '[Skeleton:2](#skeleton2)' (que l'on trouve sur le site du tutoriel graphique HIPR2). Par exemple… |

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

[IM Output]
Et voici un zoom sur la zone de la boucle, montrant comment le squelette résultant est 8-connexe, avec des diagonales plus fines. |

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

[IM Output]
Cependant, j'ai constaté que de tels squelettes ne sont pas aussi précis que le squelette « traditionnel ». Fondamentalement, dans des cas de test, j'ai constaté que les diagonales étaient « amincies » du mauvais côté. Essentiellement parce que le côté des diagonales qui est retiré est contrôlé uniquement par l'ordre du noyau de thinning de « coin » dans l'ensemble de noyaux, et non par une quelconque décision liée à la nature de la forme.
L'alternative consiste à prendre un squelette « traditionnel » et à l'amincir de sorte que les diagonales soient toujours amincies du côté « extérieur » de la diagonale, tel que défini par les points d'extrémité de la diagonale. Le noyau de thinning spécial '[Diagonals](#diagonals)' est conçu pour cela, un noyau '[Corners](#corners)' étant utilisé ensuite pour « finir ». Amincissons donc davantage le squelette « traditionnel » précédent…

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

[IM Output] [IM Output]

Cette technique d'amincissement d'un squelette 4-connexe traditionnel est légèrement plus lente que le simple usage direct de la variante '[Skeleton:2](#skeleton2)'. Le thinning supplémentaire a nécessité 8 itérations de thinning des 8 noyaux, soit 64 itérations primitives. Vous pouvez aussi n'utiliser que le noyau '[Corners](#corners)', mais cela ne fait que générer la variante « HIPR », avec un choix simplement « aléatoire » du côté des diagonales qui a été aminci. Cependant, cela ne prend qu'une seule passe des 4 noyaux, et est donc bien plus rapide que d'utiliser '[Diagonals](#diagonals)'. Dans tous les cas, en partant d'un squelette 4-connexe « traditionnel », vous pouvez ensuite générer une version 8-connexe (d'un certain type) très facilement.

Informations sur le squelette

Lorsque vous avez un squelette (peut-être même à la fois une version 4-connexe et une version 8-connexe), l'étape suivante consiste généralement à obtenir davantage d'informations sur le squelette. Par exemple, combien d'« extrémités libres de lignes », de « jonctions de lignes » et de « boucles de lignes » sont présentes. Nombre d'extrémités de lignes Ici, j'utilise une recherche Tout-ou-rien de '[LineEnds](#lineends)' sur le squelette généré précédemment (en l'extrayant du canal « rouge »). J'effectue ensuite un Dilate de ces extrémités de lignes en anneaux et je les colore avant de les fusionner avec le squelette d'origine, pour rendre leurs positions bien visibles.

  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]

Notez que les lignes qui se connectent toutes les unes aux autres, ou à la boucle de pixels, n'ont pas été trouvées. Seules les extrémités libres de lignes ont été indiquées. Si vous faisiez un comptage de pixels (à l'aide d'une sortie d'histogramme), vous verriez que ce squelette a généré 12 extrémités de lignes. Nombre de jonctions de lignes Vous pouvez obtenir un comptage approximatif du nombre de jonctions de lignes dans une image en utilisant le noyau '[LineJunctions](#linejunctions)' avec un squelette 8-connexe , de préférence un squelette aminci à partir du squelette d'origine utilisé pour compter les extrémités de lignes. Ne mélangez pas deux variantes différentes de génération de squelette.

  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]

Si vous essayiez ce noyau directement avec un squelette 4-connexe traditionnel, vous obtiendriez plusieurs correspondances pour certaines des jonctions 'T', rendant le comptage très inexact. Le résultat, comme vous pouvez le voir, est de 12 jonctions de lignes, ce qui pour cette forme précise est correct. Cependant, pour certaines jonctions, le noyau '[LineJunctions](#linejunctions)' est inexact. Par exemple, une jonction diagonale 'X' à 4 lignes ne produira qu'une seule correspondance, tandis qu'une jonction orthogonale '+' produira 4 correspondances. Ces deux jonctions particulières devraient toutes deux produire 2 correspondances, pour maintenir correct le comptage des jonctions de lignes. Ainsi, pour obtenir un comptage exact, vous devrez ajouter 1 valeur de plus pour chaque jonction 'X', et soustraire 2 du comptage pour chaque jonction '+'.
Pour un squelette sans boucle, le nombre de jonctions devrait être inférieur de 2 au nombre d'extrémités de lignes. Cependant, si le nombre d'extrémités de lignes est égal au nombre de jonctions de lignes, cela signifie que vous avez une ou plusieurs boucles dans le squelette. Or, ce squelette a 12 extrémités de lignes et 12 jonctions. Il contient donc au moins une boucle continue de pixels quelque part dans l'image. Nombre de boucles FUTUR : étiquetage d'objets connexes

Élagage des lignes

Vous savez donc que cette image comporte au moins une boucle. Supposons que vous vouliez simplifier la forme pour ne garder que cette ou ces boucles. La solution consiste à « élaguer » toutes les extrémités de lignes de façon répétée jusqu'à les avoir toutes retirées. Pour un squelette 4-connexe comme celui-ci, vous pouvez même utiliser un plus petit ensemble de noyaux '[LineEnds](#lineends_subtypes)' pour rendre le processus environ deux fois plus rapide.

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

[IM Output] [IM Output]

Un rapport détaillé sur cela aurait montré que cela a pris 75 itérations avec 4 noyaux, aboutissant à 300 itérations primitives pour « élaguer » de l'image toutes les lignes ayant des extrémités libres. C'est environ deux fois plus d'opérations que ce qui a servi à trouver le squelette, ce qui montre à quel point cette opération peut être plus intensive. Utiliser un ensemble complet de noyaux '[LineEnds](#lineends)' (8 noyaux) aurait également pris 75 itérations, mais avec deux fois plus de noyaux, ce qui en fait 600 itérations primitives.

Élagage rapide des lignes

Technique d'élagage complet rapide..

  1/  Trouver les extrémités de lignes et les jonctions de lignes.
  2/  Supprimer les jonctions de lignes pour déconnecter complètement tous les segments de ligne.
  3/  Remplissage par diffusion, ou utiliser un dilate conditionnel pour retirer les segments « extrémité de ligne ».
  4/  Restaurer les jonctions de lignes.
  5/  utiliser cela comme carte sur l'image d'origine pour restaurer les « boucles ».

Nous avons déjà couvert la première étape… ce qui donne… |

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

[IM Output]
Pour déconnecter (ou séparer) tous les segments de ligne, vous pouvez utiliser un noyau '[LineJunctions](#linejunctions)'. Cependant, l'ensemble de noyaux par défaut ne déconnecte pas complètement les jonctions 'T' (il ne fait que les localiser). Pour déconnecter correctement tous les segments de ligne, vous devrez aussi ajouter des noyaux 'T' orthogonaux à l'ensemble de noyaux, et il est également préférable d'inclure une jonction '+'. Par exemple. |

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

[IM Output]
Le thinning avec ces correspondances déconnectera effectivement les segments, mais vous devez faire tout cela en une seule étape (voir le style de Thinning), sinon cela ne fonctionnera pas correctement. |

  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]
Voici un zoom de la « boucle » montrant les segments déconnectés. |

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

[IM Output]
À ce stade, nous pouvons maintenant retirer tout segment de ligne qui contient une correspondance avec l'« extrémité de ligne » découverte précédemment. Cela peut se faire soit par « remplissage par diffusion » à partir de ces points de « graine », pour les supprimer. Cela ne fonctionne toutefois que pour un squelette 4-connexe, ce que présuppose le remplissage par diffusion. Exemple ici On peut sinon utiliser la dilatation conditionnelle pour trouver tous les points simultanément et les retirer. Exemple ici - lorsque le Dilate ou Erode conditionnel est disponible. Si vous restaurez maintenant les jonctions de lignes, effectuez un élagage, et retirez les éventuels pixels isolés restants, vous aurez alors retiré rapidement tous les segments de ligne. Oui, cela semble faire beaucoup d'étapes, mais croyez-moi, c'est encore bien plus rapide que de devoir « élaguer l'extrémité des lignes » 300 fois pour obtenir le même résultat.

Style de Thinning - Séquentiel ou simultané

Si vous effectuiez un seul « élagage » de l'extrémité des segments de ligne, et le compariez à l'image d'origine, vous constateriez que le plus souvent un segment de ligne a été élagué de 2 à 4 fois, selon la forme et l'orientation exactes des lignes. Par exemple (image résultante agrandie), voici un thinning d'extrémités de lignes par défaut

  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]

C'est parce que, par défaut, chacun des noyaux '[Thinning](#thinning)' est appliqué aux résultats du noyau précédent, en séquence. Autrement dit, il retire tous les pixels sélectionnés par un noyau avant d'appliquer le noyau suivant à ce résultat, lequel peut (et va) sélectionner davantage de pixels à la même extrémité de ligne. En d'autres termes, il amincira par défaut l'extrémité des lignes plusieurs fois pour une seule « itération » complète à travers tous les noyaux fournis. Cela signifie que vous ne pouvez pas vous fier à la sortie détaillée pour avoir une idée exacte de la longueur de toutes les lignes en comptant le nombre de pixels retirés par une seule itération de cet opérateur. Cependant, vous pouvez modifier le fonctionnement de '[Thinning](#thinning)' pour qu'il ne retire que l'ensemble de pixels qu'une seule itération '[Hit-And-Miss](#hitmiss)' à travers tous les noyaux trouverait. Autrement dit, appliquer tous les noyaux à la même image au début de l'itération, les fusionner, puis ne retirer que ces pixels, une seule fois pour tous les noyaux. C'est-à-dire retirer tous les pixels sélectionnés par le HMT simultanément. En gros, vous réglez le réglage de composition multi-noyaux pour utiliser une méthode de composition '[Darken](compose.html#darken)', ce qui fera exactement cela. Plus précisément, en fusionnant tous les pixels sélectionnés en vue d'un unique retrait des pixels sélectionnés. Par exemple… |

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

[IM Output]
Ce qui s'est produit ici, c'est que chaque noyau des noyaux de correspondance de motifs ne sera appliqué qu'à l'image d'origine. Tous les pixels qui ont correspondu à l'original sont ensuite rassemblés. Autrement dit, nous ne retirerons qu'une « intersection » des résultats de tous les noyaux par rapport à l'original, en utilisant une composition « darken ». Mais le retrait se fait entièrement en une seule étape pour chaque itération à travers tous les noyaux. Le résultat est qu'une extrémité de ligne ne sera jamais mise en correspondance qu'une seule fois, même si plusieurs noyaux pouvaient correspondre à cette extrémité de ligne. Ainsi, seul le pixel unique de l'extrémité sera retiré, plutôt que 2 pixels ou plus, par différents noyaux. En résumé, ajouter un réglage de composition multi-noyaux '[Darken](compose.html#darken)' garantira que la méthode '[Thinning](#thinning)' effectue un « thinning simultané » (tous les noyaux simultanément), plutôt qu'un « thinning séquentiel » (un noyau à la fois - le défaut).
Cependant, si cela rend l'élagage des extrémités de lignes plus régulier, cela le rend plus lent et peut changer le résultat global d'un thinning. Prenons le cas d'un '[Thinning](#thinning)' de quelques boîtes en amincissant simultanément les bords gauche et droit.

  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]

Le « thinning simultané » a en réalité supprimé complètement le rectangle central ! Ce qui se passe, c'est que la forme a été amincie jusqu'à une épaisseur de deux pixels, puis les deux côtés du rectangle central « épais » ont correspondu au motif et les deux côtés ont été « amincis ». La même chose se produira si vous faites cela lors du Thinning jusqu'à des squelettes. Le « thinning séquentiel » par défaut, en revanche, a produit… |

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

[IM Output]
Comme vous pouvez le voir, il a préservé l'un des pixels (à droite) pour qu'il serve de ligne centrale de squelette. C'est parce qu'un ensemble de noyaux a d'abord aminci un côté d'une ligne centrale « épaisse », mais les noyaux ultérieurs n'ont pas correspondu à cette ligne « plus fine », de sorte qu'elle n'a pas été retirée. Essentiellement, il y a des situations où le « thinning séquentiel » (le défaut) est meilleur que le « thinning simultané » spécial, et vice-versa.

Noyaux de correspondance de motifs

Comme mentionné, un noyau de « correspondance de motifs » ou '[Hit-And-Miss](#hitmiss)' peut contenir 3 types d'éléments différents : premier plan, arrière-plan et « peu importe ». Une valeur de '1.0' ou (blanc) correspond aux pixels de premier plan. Une valeur de '0.0' ou (noir) correspond aux pixels d'arrière-plan. Vous pouvez utiliser soit une valeur de '0.5', soit la valeur spéciale 'Nan' ou '-' pour représenter des éléments de pixel qui ne font pas partie du voisinage et dont, par conséquent, vous « ne vous souciez pas ». Le '[Hit-And-Miss](#hitmiss)' ne correspondra qu'aux endroits où le plus petit pixel (minimum) de premier plan est supérieur au plus grand pixel (maximum) d'arrière-plan. Il renverra alors la différence entre ces deux valeurs, ou zéro. [IM Output]

Peaks

Le noyau 'Peaks' est une extension du noyau '[Ring](#ring)' montré précédemment. Deux arguments de rayon génèrent un « anneau » de pixels d'arrière-plan, entourant un unique pixel de premier plan à l'« origine » centrale. Voici quelques exemples parmi les noyaux 'Peak' les plus utiles…

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

Les noyaux ci-dessus peuvent servir soit à localiser de façon définitive une valeur de « pic » d'un seul pixel dans une mer de pixels plus sombres, soit à trouver toute petite forme qui s'inscrit entièrement à l'intérieur de l'anneau plus grand. Ils sont particulièrement utiles pour améliorer le contraste d'une recherche de correspondance de motifs par corrélation.

Edges

L'ensemble de noyaux 'Edges' correspond à tout pixel sur un bord plat d'une forme. Il ne correspond pas aux pixels d'un coin aigu à quatre-vingt-dix degrés, mais il correspondra à un pixel de coin sur une forme octogonale.

[IM Output]

Comme vous pouvez le voir, toutes les rotations de 90 degrés sont générées, mais elles sont ordonnées dans un ordre miroir « à bascule » qui produit généralement de meilleurs résultats. En général, ce noyau est utilisé comme une sorte de noyau '[Thinning](#thinning)' d'image, mais en l'état il ne parviendra pas à amincir les bords diagonaux, ni à générer un squelette correct d'une image. Par exemple…

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

[IM Output] [IM Output]

Voir les noyaux '[Skeleton](#skeleton)' ci-dessous.

Corners

Les noyaux 'Corner' localisent tout pixel de coin diagonal autour des bords d'une image. Voir '[Hit-And-Miss](#hitmiss)' ci-dessus pour un exemple de son utilisation.

[IM Output]

Ici, par exemple, je l'ai utilisé pour essayer d'amincir tous les bords diagonaux… |

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

Il peut être combiné avec le noyau '[Edges](#edges)' pour produire un thinning de squelette en une seule méthode. Voir les noyaux '[Skeleton](#skeleton)' ci-dessous pour un exemple de cela. [IM Output]

Diagonals

Le noyau 'Diagonals' est une alternative au simple usage d'un noyau '[Corners](#corners)' pour amincir des lignes diagonales 4-connexes en lignes diagonales 8-connexes. Il peut servir à amincir des lignes 4-connexes, en retirant l'ensemble de pixels extérieurs d'un coin vers le centre jusqu'à l'achèvement.

[IM Output]

Notez que les résultats devraient être complétés en utilisant un noyau '[Corners](#corners)', pour localiser et amincir les coins à 90 degrés. Voir Squelette plus fin pour un exemple d'utilisation. Sous-types de Diagonals En fournissant un argument 'type[,angle]' au noyau, vous pouvez sélectionner les sous-types spécifiques qui ont servi à constituer l'ensemble de noyaux ci-dessus.

[IM Output] [IM Output]

Cela vous permettra de spécifier votre propre ensemble de noyaux, pour amincir les diagonales exactement de la façon dont vous voulez qu'elles le soient. Par exemple, vous pourriez amincir séparément chacun des quatre types de diagonales (en utilisant les deux noyaux ci-dessus avec la même valeur d'angle). Ce faisant, vous pouvez réduire itérativement chaque type de diagonale un à la fois, en interrompant dès que toutes ces diagonales spécifiques ont été amincies, et ainsi réduire le nombre total d'« étapes de morphologie primitive » effectuées. exemple nécessaire En l'état, l'ensemble de noyaux par défaut essaiera simplement d'amincir toutes les diagonales simultanément et de façon répétée jusqu'à ce qu'elles aient toutes été amincies. Cela signifie que tous les noyaux seront appliqués jusqu'à ce que toutes les diagonales aient été amincies, et non pas seulement les diagonales qui ont besoin d'être amincies. Cela signifie qu'il effectue de nombreuses « étapes de morphologie primitive » qui ne sont plus nécessaires, la plupart des noyaux n'apportant aucun changement à l'image à chaque boucle. exemple complet nécessaire Rappelez-vous que chacune des quatre diagonales devrait toujours être traitée à l'aide des deux paires de noyaux (pour chaque angle spécifique), de sorte que les deux extrémités de chaque diagonale spécifique soient amincies ensemble, comme lorsque la diagonale fait partie d'un « arc ». Il existe une discussion connexe sur ce type d'opération de thinning/thickening dans le forum IM, De lignes 8-connexes à 4-connexes.

LineEnds

L'ensemble de noyaux 'LineEnds', comme montré dans Élagage des extrémités de lignes ci-dessus, est conçu pour localiser l'extrémité des lignes. Plus précisément, il trouve les extrémités de pointes aiguës.

[IM Output]

Comme vous pouvez le voir, il ne correspondra qu'aux lignes qui comportent au moins deux pixels, le pixel correspondant étant « coiffé » ou « entouré » par des pixels d'arrière-plan. Par exemple, ici nous utilisons '[Hit-And-Miss](#hitmiss)' pour trouver toutes les extrémités de lignes.

  magick lines.gif -morphology HMT LineEnds  hmt_lineends.gif

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

Oui, il y a beaucoup d'extrémités de lignes dans cette image. Mais vous devriez noter que les lignes qui se terminent par une « boucle » d'un certain type ne produiront pas de correspondance. Notez que si vous appliquez '[Thinning](#thinning)' à une image avec ce noyau en style « thinning itératif » (le défaut), des noyaux successifs pourraient correspondre à la même extrémité d'une ligne deux fois ou plus, réduisant ainsi la ligne de nombreuses fois au cours d'une seule itération de l'ensemble de la méthode '[Thinning](#thinning)'. Voir Thinning - Séquentiel vs simultané pour plus de détails. Sous-types d'extrémité de ligne Vous pouvez aussi donner à ce noyau un argument 'type[,angle]', qui renverra l'une des définitions de noyau unique qui a servi à générer l'ensemble de noyaux '[LineEnds](#lineends)' ci-dessus.

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

Ceux-ci peuvent ensuite être développés en une liste de noyaux pivotés selon vos besoins, ou pivotés vers un 'angle ' spécifique, selon les besoins. L'ensemble '[LineEnds](#lineends)' par défaut utilise en réalité la définition de noyau.

'LineEnds:1> ; LineEnds:2>'

Le 'LineEnds:3' est l'équivalent orthogonal du 'LineEnds:2' diagonal, qui ne trouvera que les extrémités de lignes bien éloignées de tout coin ou jonction diagonal. Le 'LineEnds:4' est un noyau d'extrémité de ligne traditionnel, qui est pivoté de façon cyclique pour produire 8 noyaux (par exemple 'LineEnds:4@). Cependant, il ne parviendra pas à localiser le dernier pixel d'une ligne se connectant à une jonction orthogonale « T ». L'ensemble '[LineEnds](#lineends)' par défaut, tel que défini ci-dessus, trouve toutefois ce pixel final aux jonctions « T », en utilisant le même nombre de noyaux.

LineJunctions

Là où '[LineEnds](#lineends)' trouve les extrémités d'un groupe de lignes, 'LineJunctions' trouvera les points qui forment une jonction de 3 lignes ou plus.

[IM Output]

Par exemple, nous utilisons ici '[Hit-And-Miss](#hitmiss)' pour trouver toutes les jonctions de lignes.

  magick lines.gif -morphology HMT LineJunctions hmt_junctions.gif

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

Le noyau '[LineJunctions](#linejunctions)' est généralement utilisé à deux fins.

  • Compter le nombre de jonctions de lignes dans une image, et ainsi progresser vers un décompte du nombre de segments de ligne dans le squelette.
  • Déconnecter tous les segments de ligne les uns des autres.

Notez toutefois qu'aux jonctions 'T' et '+' de l'image ci-dessus, le noyau de jonction 'Y' correspond à des points situés à un pixel de l'intersection réelle. De ce fait, les décomptes de jonctions peuvent ne pas être exactement ceux attendus, en particulier au '+' où quatre correspondances ont été trouvées au lieu des deux seulement requises pour un décompte de jonction. La prudence est recommandée. Voir Informations sur le squelette et Élagage rapide des lignes pour plus de détails sur ces deux aspects. Le noyau ne définit en réalité que les pixels de premier plan ; on peut donc l'appliquer simplement comme une méthode '[Erode](#erode)', au lieu d'une méthode '[Hit-and-Miss](#hitmiss)'. Sous-types de jonctions de lignes Ce noyau donne également accès aux divers sous-types, en spécifiant des arguments 'type[,angle]'. Cela peut servir à rechercher des types spécifiques de jonctions de lignes.

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

Le noyau 'LineJunctions:2' peut aussi être spécifié avec 'LineJunctions:3,45', et de même 'LineJunctions:5' et 'LineJunctions:4,45' sont équivalents. Le jeu de noyaux '[LineJunctions](#linejunctions)' par défaut n'utilise que les deux premières définitions de jonction (les jonctions 'Y' et 'T' diagonale), de la manière suivante…

'LineJunctions:1@ ; LineJunctions:2>'

Cela convient à des jonctions de lignes en connexité 8. Comme il en est discuté sur les forums IM « Kernels used by LineJunctions », si vous voulez tester uniquement les jonctions de lignes en connexité 4, il vous faudra rechercher des jonctions 'T' orthogonales et des jonctions '+'.

'LineJunctions:3> ; LineJunctions:5'

Cependant, comme les noyaux 'T' correspondront aussi à un '+', vous pouvez réduire ce qui précède à juste…

'LineJunctions:3>'

Un test d'image distinct pour les seules jonctions '+' à 4 branches peut servir à les séparer des jonctions 'T' à 3 branches, si cela est nécessaire pour déterminer les décomptes de segments de ligne.

Ridges

Les noyaux 'Ridges' servent à localiser les crêtes et les fines lignes de pixels, comme dans une image de Dégradé de distance. Ces noyaux sont expérimentaux et peuvent changer. Le noyau par défaut est conçu pour localiser des lignes de crête d'un seul pixel d'épaisseur.

[IM Output]

Ridges:2 Un sous-type spécial élargi conçu pour trouver des lignes de crête de deux pixels d'épaisseur. La complexité vient de la nécessité de localiser et de marquer une ligne inclinée de ce genre, y compris les miroirs de ces lignes.

[IM Output]

Ce jeu de noyaux est important car un « squelette morphologique » est en réalité constitué à la fois de lignes de 1 et de 2 pixels d'épaisseur.

ConvexHull

Le jeu de noyaux 'ConvexHull' est conçu pour épaissir les formes de manière à produire une « enveloppe convexe octogonale » de la forme. C'est-à-dire la plus petite forme octogonale pouvant contenir la totalité de la forme.

[IM Output]

Il existe deux jeux de noyaux tournés de 90 degrés, l'un étant l'image miroir de l'autre. Comme l'origine est en réalité un élément de « fond », il est vraiment censé être utilisé uniquement comme un noyau de motif '[Thicken](#thicken)'. Toutefois, le noyau échouera pour les images contenant des « fentes » horizontales ou verticales, comme celles que nous avons dans la forme « man ».

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

[IM Output] [IM Output]

La solution est de '[Close](#close)' ces fentes (et le trou central) avant d'utiliser '[ConvexHull](#convexhull)'. |

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

[IM Output]
Notez que ci-dessus, j'ai aussi répété le '[Close](#close)' après avoir utilisé '[ConvexHull](#convexhull)'. La raison en est que tout « trou » important dans une image sera lui aussi réduit par le '[Thicken](#thicken)' jusqu'à des pixels isolés ou des « fentes » orthogonales. Répéter le '[Close](#close)' supprime ces trous sans affecter la forme finale. Voici un autre exemple, où la forme originale (blanc) a été étendue à l'aide d'un épaississement en enveloppe convexe (rouge). |

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

[IM Output]
Comme vous pouvez le voir, le résultat est une forme octogonale, tandis que le trou central a été réduit à une fente de deux pixels, prête à être fermée.

Skeleton

Générer des « squelettes » par amincissement d'une forme donnée n'est pas une chose facile. Même avec le même jeu de noyaux, réordonner les noyaux peut engendrer une variation différente du « squelette » final. Pour cette raison, je n'ai pas implémenté un seul jeu de noyaux 'Skeleton', mais un certain nombre d'entre eux, qui peuvent être sélectionnés en donnant un numéro d'argument 'type '.

Skeleton:1

Le premier jeu, celui par défaut, '**Skeleton:1**', est un noyau d'amincissement traditionnel, tel qu'il a été utilisé en premier. C'est fondamentalement exactement comme le noyau '[Edges](#edges)' ci-dessus, mais tourné cycliquement par incréments de 45 degrés. [IM Output] |

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

[IM Output]
Le résultat est un « squelette aminci » raisonnable d'une forme, bien que les diagonales aient tendance à rester un peu épaisses d'un côté. Fondamentalement, le squelette produit est en connexité 4, ce qui vous permettra d'utiliser une technique d'Élagage rapide. Notez aussi que ce jeu de noyaux ne dilate pas correctement un trou d'un seul pixel dans l'image. Autrement dit, le squelette autour de ce trou n'est même pas proche de la ligne médiane entre le trou et le reste de l'image. Pour plus de détails, voir Amincissement jusqu'à un squelette.

Skeleton:2

La variante '**Skeleton:2**' est presque exactement la même que la version traditionnelle 'Skeleton:1'. Elle a été trouvée dans la documentation des HIPR2 Image Processing Resources. [IM Output] |

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

[IM Output]
Si vous comparez ceci avec le jeu précédent, vous remarquerez que le pixel interne des coins a été supprimé. Cela permettra ensuite à l'opération d'amincissement de retirer l'épaississement supplémentaire des diagonales. Toutefois, cet amincissement diagonal n'est pas symétrique, et dépend fortement de la forme de l'image et de l'ordre dans lequel les noyaux sont appliqués. La variante 'Skeleton:2' est très étroitement liée au simple fait d'utiliser une liste de noyaux combinée '**Edges;Corners**'. [IM Output] |

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

[IM Output]
La seule différence entre ceci et ce qu'utilise 'Skeleton:2' est l'ordre des noyaux dans la liste. Remarquez comme le squelette résultant diffère lui aussi, alors même que le même jeu de noyaux a été utilisé. Cela montre que la génération de squelettes par amincissement est en réalité assez fragile, car un simple changement d'ordre peut produire des résultats différents dans le squelette connecté.

Skeleton:3

Le '**Skeleton:3**' a été développé dans une étude formelle sur l'utilisation de noyaux d'amincissement (voir les noyaux ThinSE ci-dessous), dans un article de recherche « Connectivity-Preserving Morphological Image Transformations » de Dan S. Bloomberg, 1991. Il a développé un bon nombre de tels squelettes, et a mis en tableau les résultats de l'étude. Ce qui suit est le meilleur qu'il ait pu concevoir, qui génère un squelette en connexité 4. Toutefois, contrairement aux squelettes précédents, celui-ci nécessite l'utilisation de 3 noyaux tournés (12 au total). [IM Output] |

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

[IM Output]
Il convient de noter que le premier groupe de noyaux tournés ne contient qu'un seul pixel de fond. Cela signifie que ce squelette a pu ouvrir le trou d'un seul pixel présent dans la forme « man », et produire un squelette orienté sur la ligne médiane. Il ne génère pas trop de branches, produit des lignes propres et lisses, et s'amincit aussi complètement. Tout compte fait, c'est l'un des meilleurs noyaux d'amincissement de squelette.

ThinSE

Le même article de recherche « Connectivity-Preserving Morphological Image Thansformations » de Dan S. Bloomberg a en réalité développé, à partir de principes premiers, une gamme complète d'« éléments structurants d'amincissement » 3x3 minimaux, tous conçus pour préserver soit les lignes en connexité 4, soit les lignes en connexité 8. Le jeu de noyaux '**ThinSE:**{_type_}' est une liste de tous ces éléments structurants, et ils sont énumérés ci-dessous, triés en groupes selon la connexité et la force de préservation. Le '{_type_}' est un nombre basé sur les numéros d'élément en exposant (connexité) et en indice utilisés dans l'article de recherche. Ainsi, le noyau '**ThinSE:41**' est le premier des éléments préservant les lignes en connexité 4. Vous pouvez aussi ajouter un angle de rotation, ou générer un jeu d'indicateurs tournés ou tournés en miroir pour la définition de noyau donnée.

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

Le tout dernier « noyau d'amincissement général », '**ThinSE:482**', vous pourriez le reconnaître comme étant le même noyau que celui utilisé pour définir le jeu de noyaux de détection de contours. Ce noyau général est en réalité le noyau de base à partir duquel tous les autres noyaux d'amincissement montrés ci-dessus ont été développés. C'est le noyau par défaut du jeu. Notez que les deux noyaux généraux 'ThinSE:481' et 'ThinSE:482' sont les seuls noyaux liés par rotation. C'est-à-dire que 'ThinSE:481x45' est équivalent à 'ThinSE:482'. Beaucoup des autres jeux de noyaux HMT intégrés sont en réalité définis en interne en termes de ces noyaux. Par exemple, le jeu de noyaux '**ThinSE:41 ; ThinSE:42 ; ThinSE:43**', et son expansion tournée, produira les 12 noyaux utilisés pour créer le jeu '[Skeleton:3](#skeleton3)'. Ce squelette était répertorié dans l'article comme le meilleur jeu de noyaux trouvé pour produire un bon squelette aminci. Les autres noyaux d'amincissement générateurs de squelette sont aussi définis à l'aide des noyaux ci-dessus.
Soyez toutefois averti que certains noyaux, tels que 'ThinSE:44', qui bien que conçus pour préserver la « connexité », ne préservent en réalité pas les extrémités de ligne et, de ce fait, feront qu'un squelette sera élagué jusqu'à un point unique, ou un ensemble d'anneaux connectés. Tous les noyaux ne définissent pas la valeur de l'origine centrale, ce qui signifie que vous pouvez utiliser ces « noyaux d'amincissement » non seulement pour Amincir des formes, mais aussi pour Épaissir des formes, afin de générer des SKIZ (zones d'influence). Si vous regardez attentivement, vous remarquerez probablement que chacun des noyaux en connexité 4 est en réalité aussi présent sous une forme négative et tournée de 180 degrés dans le jeu en connexité 8, et vice versa. Par exemple, 'ThinSE:41' et 'ThinSE:84' sont des rotations inversées l'une de l'autre. La raison en est que les connexités 4 et 8 sont étroitement liées l'une à l'autre par la dualité des méthodes morphologiques d'amincissement et d'épaississement (utilisant des images inversées). Essentiellement, un « noyau d'amincissement » préservant une connexité 4, ensuite utilisé pour épaissir une image, produira un squelette de fond en connexité 8 (SKIZ non élagué) autour de la forme, et vice versa. Ainsi, en utilisant les formes inversées (de sorte que les méthodes épaississement et amincissement sont échangées), vous pouvez générer l'autre forme de connexité pour la même opération.


Morphologie de dégradé de distance

La méthode de morphologie 'Distance' est la première des nombreuses méthodes spécialisées possibles. Ce qu'elle fait, c'est utiliser un noyau spécialisé pour mesurer la distance de chaque pixel de premier plan par rapport au « bord » de la forme. Plus précisément, elle mesure la distance du pixel par rapport à une valeur de couleur « zéro » ou « noire ». Elle ne fonctionne cependant qu'avec des formes purement binaires (blanc sur noir), bien que, comme vous le verrez plus loin, vous puissiez modifier une forme anticrénelée pour l'exploiter avec la méthode de distance. Et uniquement avec des noyaux de distance spécialement conçus. Le noyau de distance est appliqué à l'image de sorte que chaque pixel se voie attribuer la plus petite valeur de pixel plus la valeur du noyau pour cette distance. Ceci est appliqué partout dans l'image simultanément, à l'aide d'un algorithme qui ne nécessite pas d'itérations multiples, comme nous l'avons vu dans les méthodes de morphologie précédentes. De ce fait, c'est à peu près aussi rapide qu'une seule opération morphologique primitive, ce qui est fulgurant comparé, disons, à une méthode morphologique de squelette par amincissement. Comme elle est appliquée sur l'ensemble de l'image, aucun argument 'iteration ' n'est nécessaire, car répéter (itérer) la même opération de noyau n'entraînera aucun changement supplémentaire dans le résultat. Avant IM v6.6.9-4, un compte d'itérations de '-1' était nécessaire, car le noyau était appliqué à l'aide d'une technique similaire à un Erode normal. Ce n'est plus nécessaire, et tout argument « iteration » donné, autre que zéro (aucune action), est désormais simplement ignoré.
Voici un exemple d'utilisation de la méthode 'Distance', sur notre forme « man ».
  magick man.gif -threshold 50% \
          -morphology Distance Euclidean:4 \
          +depth  distance.png

[IM Output] [IM Output]

Eh bien, c'était vraiment passionnant, PAS DU TOUT ! Le problème, c'est que la couleur de l'image finale est très, très sombre. Mais si vous avez un bon écran, et que vous pouvez regarder de près, vous verrez peut-être une forme « fantôme » très sombre là où se trouvait le « man ». Ce qui s'est passé, c'est que, du moins pour cette petite image, tous les pixels sont « proches » du bord, et ne reçoivent donc pas une très grande valeur de « distance ». | _Une image PNG est recommandée pour tout usage de la méthode 'Distance'. Cela, parce qu'elle peut fournir une plus grande « profondeur » de valeur de sortie que, par exemple, le GIF, sans aucune perte de couleur comme le JPEG.

C'est aussi la raison pour laquelle le réglage de profondeur "+depth" a été utilisé pour garantir que la sortie soit réinitialisée à une profondeur de 16 bits (pour ma version Q16 d'IM), même si j'ai lu une image source GIF 8 bits.

Pour les utilisateurs disposant d'une version Q8 d'IM, je vous suggère de lire à propos de l'option de noyau de distance 'scale' dans les noyaux de distance (ci-dessous), afin d'ajuster les « valeurs d'échelle » utilisées (voir la section suivante ci-dessous). Utiliser des versions Q8 d'IM avec des noyaux de distance non entiers (comme ce noyau de distance euclidienne) n'est pas recommandé, bien que cela produise un résultat moins précis.

Voir la section des exemples IM sur la qualité et la profondeur, pour une meilleure compréhension de ces deux aspects.


---|---
Par défaut, les noyaux de distance intégrés appliqueront une valeur de couleur de « 100 × {_distance_pixel
} » à chaque pixel. Si un pixel est plus clair que cela, il est fixé à cette valeur de sorte que la plus petite distance d'un pixel à un bord quelconque soit attribuée. Le résultat est que les pixels tout au long du bord même d'une forme se verront attribuer une valeur supérieure de 100 unités à la couleur de fond. Le pixel suivant plus à l'intérieur recevra 100 unités de plus. Le nombre exact d'unités attribuées est donné par le noyau de distance utilisé. Regardons donc la plus grande valeur de couleur qui a été fixée dans l'image ci-dessus.

  magick identify -verbose distance.png | grep max:

[IM Text]

C'est-à-dire que la plus grande valeur de couleur dans l'image résultante était '1616', faisant du pixel le « plus clair » de l'image un gris très sombre à 2,5 %, et de sa distance au bord le plus proche 16,16 pixels. Autrement dit, nous voyons une image très sombre, mais pas vraiment complètement noire. Utilisons le mathématique "[-auto-level](https://imagemagick.org/command-line-options/#auto-level)" pour ajuster les valeurs de couleur résultantes de sorte que le pixel le plus clair, ou le plus distant d'un bord, soit fixé à blanc. Ainsi, nous pouvons réellement voir tout l'effet du « dégradé de distance » généré. |

  magick distance.png -auto-level  distance_man.gif

| Comme nous ne nous soucions plus des valeurs exactes de « distance » générées pour cette image, seulement de l'effet visible de la distance, l'image peut maintenant être enregistrée et affichée en utilisant le format de fichier image GIF.
---|---
[IM Output]
Voici ce que fait la méthode 'Distance'. Générer un dégradé sur la forme donnée, définissant à quelle distance chaque pixel se trouve du bord le plus proche, selon le noyau de distance spécifique utilisé. Une autre façon de rendre l'image de « distance » résultante plus claire est d'utiliser en fait une valeur de 'scale ' de noyau de distance plus grande, par exemple une valeur de 3000 unités (les utilisateurs Q8 peuvent probablement utiliser une valeur de 20). |

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

[IM Output]
Notez que le dégradé de distance n'a pas couvert du noir au blanc, atteignant un pic à une certaine valeur de niveau de gris. Comme nous connaissons déjà la « distance » du pic, nous pouvons calculer que ce pic maximal vaut 16.16 * 3000 => 48480, soit environ 74 % de gris. Vous pouvez aussi utiliser un facteur d'échelle en pourcentage, par exemple utiliser une valeur de plage de couleur de 8 % pour chaque distance de pixel par rapport au bord. |

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

[IM Output]
Comme vous pouvez le voir, cette fois-ci nous avons atteint notre limite de valeur maximale avant d'atteindre la distance maximale. Vous pouvez calculer que la distance maximale que le dégradé de distance peut couvrir est (100 % à la plage maximale) / (8 % par pixel) => 12,5 distance_pixel. Bien sûr, si vous utilisiez une version HDRI d'ImageMagick, les valeurs de distance complètes seraient conservées en mémoire, du moins jusqu'à ce que vous Clamp sa valeur, ou l'enregistriez dans un format de fichier image non à virgule flottante. Vous pouvez aussi spécifier directement la distance de pixel maximale qui vous intéresse en utilisant l'indicateur d'échelle de distance spécial, '!'. Comme nous connaissons déjà que notre forme a une distance maximale au bord de 16,16, demandons au moins une limite de 18 pixels. |

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

[IM Output]
L'indicateur '!' mettra la distance à l'échelle de manière à donner 'n' valeurs de niveau de gris avant que la limite de plage de couleur ne soit atteinte. Ainsi, une valeur de 1 ne « fondra » (ou ne rendra gris) que les pixels qui sont un voisin direct du bord de l'image. Comme vous pouvez le voir, toutes les méthodes d'échelle dépendent cependant fortement de la taille réelle de la forme sur laquelle vous exécutez la méthode 'Distance'. Trop petite, elle est très sombre et peut ne pas être précise pour vos besoins. Trop grande, la distance peut se voir « écrêtée » par la valeur de couleur maximale possible de la qualité à la compilation de votre ImageMagick. Pour plus de détails sur le facteur 'scale ' dans le noyau, voir la section noyau de distance ci-dessous. Je voudrais faire une dernière remarque à propos de la « forme » de type humain utilisée dans ces exemples. La forme contient un « trou » d'un seul pixel qui a créé une sorte de « puits de dégradé » autour de lui. Cela produit un effet très marqué sur la moitié supérieure de l'image de « dégradé de distance » résultante. Une solution à cela est de supprimer ce trou, en utilisant '[Close](#close)', afin de rendre la forme « propre et lisse ». Par exemple…

  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]

Bien sûr, cela a aussi pour effet de « fermer » également l'espace entre les « jambes » de la forme, ce qui affecte la moitié inférieure du résultat final. Une solution alternative est d'utiliser une méthode de remplissage par diffusion pour extraire l'extérieur de l'image, et le transformer en un nouveau masque. Le résultat est que tous les trous ont été fermés, mais la frontière extérieure de l'image a été préservée. Par exemple…

  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]

Noyaux de distance

Le noyau donné est très spécial, car il sert à définir les mesures de distance réelles qui doivent être attribuées à chaque pixel. Par exemple, voici la sortie Show Kernel de l'un des « noyaux de distance » intégrés.

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

[IM Text]

Le point important à noter est que l'« origine » (dans ce cas le centre exact du noyau) a une valeur de zéro. C'est très important. Cette « origine » est ensuite entourée de valeurs plus grandes, qui augmentent linéairement à mesure que la distance à cette « origine » croît. Si le noyau n'est pas défini de cette manière spécifique, des effets inattendus et étranges peuvent en résulter. La valeur donnée dans le noyau est la « valeur » réelle qui sera ajoutée à une distance déjà « connue », attribuée à un pixel si cette valeur est plus petite que ce qui est déjà attribué. Le résultat est que les pixels « blancs » sont rendus plus sombres à mesure qu'ils sont proches d'un bord, et linéairement plus clairs (s'ajoutant aux valeurs précédemment attribuées) à mesure qu'ils s'éloignent du bord. Tous les noyaux de distance intégrés fournis peuvent prendre deux k_arguments optionnels…

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

Le premier argument, comme pour tous les noyaux de forme, est le radius du noyau, qui définit la taille du noyau généré. Par défaut, le radius est fixé à '1' pour les noyaux de distance intégrés, ce qui donne un très petit noyau de 3 sur 3, qui dans la plupart des cas fonctionne assez bien. Le second argument 'scale ' fixe l'échelle de distance utilisée pour représenter la distance d'une longueur d'un pixel. Comme montré dans l'exemple ci-dessus, il vaut par défaut '100'. C'est-à-dire qu'un pixel qui reçoit une valeur finale de pixel ou de niveau de gris de disons '300' devrait être exactement à '3 pixels' du bord. Échelle de distance Comme mentionné précédemment, une grande valeur de 'scale ' est utilisée afin que vous puissiez employer des distances « fractionnaires » pour des mesures de distance plus « exactes ». Toutefois, seul le noyau de distance '[Euclidean](#euclidean)' fourni utilise de telles valeurs « fractionnaires ». Dans les exemples précédents, la « plus grande distance » attribuée était '1700', ce qui déborderait une version Q8 d'ImageMagick (voir Qualité, profondeur de bits en mémoire). Un IM Q8 ne permet aux valeurs de couleur d'atteindre qu'une valeur maximale de 255 (2Q => 28 => 256 valeurs de couleur, allant de 0 à 255). De ce fait, utiliser un scale plus petit tel que '10' ou '20' fonctionnera mieux pour les utilisateurs employant la variante à la compilation IM Q8. Bien que ce soit bien moins précis lorsqu'il est utilisé avec un noyau '[Euclidean](#euclidean)'. Pour cette raison, il est recommandé que les utilisateurs de versions Q8 d'IM se limitent à utiliser les autres noyaux de distance « entiers », avec un facteur d'échelle de '1'. Vous pouvez aussi spécifier l'échelle de distance comme un pourcentage de la plage de couleur complète en incluant un '%' dans le facteur d'échelle. Cela signifie que si vous utilisez une échelle de '12.5%' de la plage de valeurs de couleur, alors vous pourrez obtenir une métrique de distance d'environ 8 pixels avant que la distance ne déborde les limites de la plage de couleur de la version d'IM que vous utilisez. Alternativement, vous pouvez à la place utiliser un '!' qui signifie que l'échelle est un diviseur de la plage de couleur. C'est-à-dire que si vous spécifiez une échelle de '20!', l'échelle de distance sera réglée de sorte que la limite de plage de couleur sera atteinte à 20 pixels du bord de l'image. Toutefois, même avec ces « indicateurs d'échelle spéciaux », vous aurez encore de sévères limitations de précision de plage dans les versions Q8 d'IM. Elle n'a simplement pas la plage pour les valeurs de données nécessaires à de nombreuses opérations de distance. Bien sûr, tout scale (y compris en virgule flottante complète) peut être utilisé avec précision pour les versions HDRI d'IM, car les valeurs de couleur résultantes sont aussi stockées comme valeurs à virgule flottante. Veillez juste à remettre la plage de couleur à l'échelle de manière appropriée avant de tenter d'enregistrer une telle image dans des formats de fichier image non à virgule flottante.
Un certain nombre de noyaux de mesure de distance différents sont fournis, dont un qui peut être utilisé de deux manières différentes. Chaque noyau fournit différentes « métriques de distance » résultantes pour spécifier la distance du pixel par rapport au bord, et définit fondamentalement ce qui doit être considéré comme le « bord le plus proche ».

Noyau de distance de Chebyshev (échiquier)

Le noyau de distance '**Chebyshev**' est le plus simple, et spécifie que tous les pixels autour de l'« origine » sont simplement à 1 unité de distance de leurs voisins. C'est-à-dire que les 8 voisins sont « à côté » les uns des autres. Ainsi, non seulement les quatre voisins immédiats sont à une distance de 1 unité, mais les voisins diagonaux sont eux aussi exactement à 1 unité. Ceci est souvent comparé à la distance en cases que parcourt une pièce d'échecs « Roi » ou « Reine » sur un échiquier, et est donc aussi souvent connu sous le nom de métrique de distance « échiquier (Chessboard) ». Notez toutefois que les noyaux de distance utilisent un facteur {scale} par défaut de 100 unités de distance, par pixel de distance. De ce fait, la distance est de 100 unités pour chaque pas s'éloignant de l'origine. C'était aussi le noyau qui a été utilisé dans les exemples précédents ci-dessus. Voici le noyau réel qu'il génère…

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

[IM Text]

Le nom de ce noyau est celui du mathématicien russe Pafnouti Chebyshev qui a le premier décrit mathématiquement cette forme de mesure de distance. Vous pouvez en savoir plus sur cette mesure sur Wikipedia, Chebyshev Distance. En utilisant une mesure de distance 'Chebyshev', la distance finale d'un pixel est la plus grande valeur X ou Y jusqu'au bord le plus proche. Toutefois, comme la distance diagonale n'est que de 1 unité, la distance maximale au sein d'une image est habituellement plus petite que ce à quoi vous vous attendriez. Générons un « dégradé de distance » en utilisant cette « métrique » de noyau. Cependant, pour que nous puissions voir ce qui se passe, utilisons une méthode de morphologie 'Iterative Distance' plus lente avec un compte d'itérations infini. | |

  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]


| _La méthode de morphologie 'Iterative Distance' calcule la distance en appliquant le noyau de distance de façon répétée jusqu'à ce qu'aucun changement de valeur ne soit plus observé.

C'est bien plus lent que la méthode 'Distance' plus habituelle, qui utilise une méthode à deux passes pour fixer la distance sur l'image dans son ensemble. Toutefois, la sortie détaillée de la méthode 'Distance' est bien moins intéressante.


---|---
J'ai activé l'indicateur Verbose afin que la commande affiche combien de pixels ont été changés (tous les pixels blancs) par l'opération, durant chaque itération (passe) à travers l'image. Ensuite, j'ai extrait la distance « maximale » générée ('1400'), avant d'ajuster le résultat (le normaliser) en une image où vous pouvez voir le dégradé résultant. La distance maximale '1400' est la valeur des pixels les plus clairs de l'image (en réalité c'est une grappe de 4 tels pixels). Cette information est le résultat le plus important de ce noyau (métrique) de distance, car elle représente la taille du plus grand carré qui tiendra à l'intérieur de cette forme. Spécifiquement, un rayon de 14 pixels, ou un carré d'environ (R-1)*2+1 => 27 pixels de côté, centré sur ces 4 pixels maximaux. Comme toutes les unités de distance de ce noyau sont toujours des multiples de '100', cette valeur de distance finale devrait toujours être un multiple de '100', et n'aura jamais de composante fractionnaire. Fondamentalement, ce noyau produira une distance entière, et vous pouvez utiliser un simple _scale
de '1 unité' avec ce noyau sans perte d'aucune information de distance. Ceci est recommandé si vous utilisez une version Q8 d'ImageMagick, ou si vous l'appliquez à de très, très grandes images. Voici un agrandissement du dégradé entre les « jambes » de la forme, qui met en évidence les caractéristiques du dégradé de distance généré. |

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

[IM Output]
Comme vous pouvez le voir, le noyau de distance '[Chebyshev](#chebyshev)' produit un dégradé très carré. C'est une caractéristique spécifique de cette forme simple de métrique de distance, et reflète directement la nature carrée du noyau de distance lui-même. Ce qui précède montre aussi les 4 pixels de distance maximale dans le « ventre » de la figure, près du haut de l'image. En centrant un carré sur l'un quelconque de ces 4 points, vous pouvez générer le plus grand carré de taille impaire entièrement contenu dans la figure. Soyez toutefois averti qu'il peut y avoir un certain nombre de tels « pics ».

Noyau de distance de Manhattan (taxi)

Le noyau de distance '**Manhattan**' mesure la distance en additionnant les valeurs X et Y jusqu'au bord le plus proche. C'est fondamentalement la distance que vous devez parcourir lorsque vous êtes restreint à des déplacements uniquement de type grille, comme un taxi dans les rues de grandes villes comme Manhattan, à New York. De ce fait, d'autres noms plus courants pour cette mesure sont la métrique de distance « taxi (Taxi Cab) » ou « pâté de maisons (City Block) ». Vous pouvez en savoir plus sur Wikipedia, Manhattan Distance. Voici le noyau réel qu'il génère…

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

[IM Text]

Notez que les diagonales ont maintenant une valeur de '200', soit 2 unités depuis le centre. C'est-à-dire que pour atteindre un pixel diagonal, il vous faudrait traverser deux pixels dans les déplacements de type grille mentionnés. En conséquence, les diagonales tendent à être plus grandes qu'attendu, de sorte que les mesures de distance finales tendent elles aussi à être plus grandes. Extrayons à nouveau la distance maximale et l'image de « dégradé de distance » en utilisant cette « métrique ». | |

  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]


Je n'ai pas utilisé 'Iterative Distance' cette fois, et même si je l'avais fait, le décompte total des pixels changés ne serait pas exact. Seul le noyau '[Chebyshev](#chebyshev)' précédent fixe une distance de pixel une seule et unique fois. Notez comme la distance maximale finale pour l'image est bien plus grande, à '1700' unités de distance, faisant que le ou les pixels maximaux au sein de la forme sont à 17 pixels du bord. Ce noyau de distance est aussi un noyau « entier », de sorte que vous pouvez régler le scale à juste '1 unité' sans perte d'information. Voici un agrandissement du dégradé. |

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

[IM Output]
Comme vous pouvez le voir, le noyau de distance '[Manhattan](#manhattan)' a généré un dégradé de type losange, ce qui est fondamentalement ce que représente cette métrique de distance simple, comme le reflètent les valeurs réelles du noyau.

Noyau de distance octogonal

Le noyau de distance '**Octagonal**' est un peu différent des deux autres. Il est créé en générant d'abord une distance de Manhattan pour les pixels tout au bord même, puis en utilisant Chebyshev pour les pixels situés à 2 unités de distance du bord. Il répète ensuite en utilisant la distance de Manhattan pour les pixels à 3 unités de distance, et ainsi de suite. Le résultat est un « entrelacement » ou une « moyenne » des distances résultant de l'utilisation des deux noyaux plus simples. Comme ce noyau est basé sur un entrelacement de deux noyaux de distance entiers, c'est lui aussi un noyau de distance entier. De ce fait, un scale de '1 unité' peut être utilisé pour produire des valeurs plus petites, pour des versions d'ImageMagick de moindre qualité, ou de très grandes mesures de distance. La forme de distance est aussi un mélange des deux noyaux et produit ainsi l'équivalent du noyau de forme '[Octagon](#octagon)'. Voici le noyau réel qu'il génère…

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

[IM Text]

Notez que le noyau a une taille minimale et par défaut de rayon 2, formant un noyau de 5x5 pixels. Ce noyau légèrement plus grand est nécessaire pour générer l'« entrelacement » des noyaux. La distance globale sera en général très légèrement plus petite qu'une distance vraie. Ici, nous calculons à nouveau la distance maximale… | |

  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]


Le résultat de '1500' est une distance « entière », et se situe en réalité entre la distance de Chebyshev trop petite et la distance de Manhattan trop grande. Toutefois, en général, il devrait être raisonnablement proche de la distance réelle vraie jusqu'au centre de la forme, tout en restant une valeur « entière ». Voici un agrandissement du dégradé. |

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

[IM Output]
Vous pouvez voir clairement les distances « octogonales » qui se sont développées autour du haut de l'espace entre les jambes. Vous pouvez aussi voir que la diagonale a été générée en utilisant un entrelacement de lignes diagonales épaisses et fines.

Noyau de distance octogone fractionnaire (Fractional Octogon)

Aucun noyau de distance nommé n'a été fourni. Mais il s'insère joliment dans la séquence de noyaux de distance que nous étudions à ce stade. Vous pouvez générer un autre type de noyau de distance entier en utilisant une forme octogonale. Toutefois, la distance entière dans ce cas utilise une valeur unitaire de 2 par pixel, si bien qu'en réalité les valeurs de distance générées doivent être divisées par deux, produisant une valeur fractionnaire à partir des petits entiers qui sont générés. D'où le nom « octogone fractionnaire (Fractional Octogon) ». Pour ce faire, nous utilisons une distance entière de 2 entre les pixels voisins, et de 3 pour la diagonale.

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

Comme des « demi-entiers » peuvent être générés, la plus petite échelle minimale utilisable est '2 unités'. Et bien que ce ne soit pas aussi précis qu'un « mouvement de cavalier », cela fonctionne bien. L'octogone de ce noyau a des « pointes » dans la direction orthogonale, plutôt que des « faces plates » comme le génère le noyau précédent. Il est lié, sans être tout à fait le même, au prochain noyau du « mouvement de cavalier », et pourrait être considéré comme une sorte de forme « quasi entière » du noyau 'knights'. Si vous voulez le mettre à l'échelle de la même manière que les noyaux de distance IM précédents, vous pouvez utiliser ce noyau.

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

Voici un exemple | |

  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]


Le résultat de '34' est une distance « entière », mais doit être divisé par 2 pour produire un résultat de distance maximale réelle de 17. Toutefois, bien que ce soit aussi un entier, il pourrait tout aussi facilement ressortir comme une distance fractionnaire de 16,5. Cet aspect fractionnaire des résultats de distance est la raison pour laquelle la plupart des noyaux sont définis en utilisant des unités de 100, et deviendra plus prédominant dans les noyaux ultérieurs à mesure que nous nous éloignons des noyaux de distance purement entiers. Voici un agrandissement du dégradé. |

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

[IM Output]
Le dégradé (si vous étudiez attentivement les résultats) est une forme octogonale. Mais il est difficile de voir les pixels qui ont des valeurs de distance communes. Pour voir la forme plus clairement, j'ai pris l'image ci-dessus et coloré un ensemble de pixels de la même valeur de couleur, en rouge. |

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

[IM Output]
Comme vous pouvez le voir, les pixels de même valeur sont généralement séparés selon un motif de « mouvement de cavalier », mais forment des lignes qui engendrent une forme octogonale. L'octogone est toutefois tourné de 45 degrés par rapport au noyau de distance octogonal. C'est aussi cette différence de forme qui fait que la distance maximale finale est plus grande. Essentiellement, un octogone plus grand tourné de cette manière s'insère mieux dans la forme, d'où le résultat de distance maximale plus grand. Un autre noyau de distance fractionnaire « entier » utilisable est celui-ci, bien que la distance soit exprimée en termes de 3 unités au lieu de 2. C'est-à-dire que les résultats doivent être divisés par 3 pour obtenir la distance en termes de taille de pixel, ce qui n'est pas vraiment un excellent diviseur à utiliser. C'est toutefois une autre métrique de distance de type octogonal.

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

Le noyau de distance euclidienne (mouvement de cavalier) ci-dessous génère lui aussi un style de forme octogonal (tous les noyaux de distance 3x3 le font), mais tente d'être aussi précis que possible le long des diagonales. Cela peut être ou non la meilleure idée, mais c'est le noyau de distance octogonal le plus logique mathématiquement de ce type.

Noyaux de distance de chanfrein (Chamfer)

Aucun noyau de distance nommé n'a été fourni. Mais il s'insère joliment dans la séquence de noyaux de distance que nous étudions à ce stade. Un noyau de distance « chanfrein (Chamfer) » (pas encore implémenté) est défini en utilisant juste les nombres (typiquement des entiers) qui doivent servir à remplir la matrice de distance. Vous pouvez par exemple lui donner 2 nombres pour définir n'importe quel noyau de distance de type « octogonal » 3x3, comme décrit ci-dessus. Voici les définitions des noyaux entiers précédents, Chebyshev Chamfer:1,1
Manhattan Chamfer:1,2
Octogone fractionnaire Chamfer:2,3
Octogone fractionnaire alternatif Chamfer:3,4
--- ---
Tous ces noyaux sont de simples noyaux de rayon 1. Les valeurs données peuvent être considérées comme les valeurs réelles d'« échelle de distance » qu'il devrait utiliser. Notez toutefois que le noyau entier Octogonal précédent nécessite un noyau de chanfrein de rayon 2 à 3 nombres pour le définir. Le noyau de chanfrein le plus connu est un noyau de rayon 2, 'Chamfer:5,7,11', qui génère une distance très précise, et génère aussi des valeurs de distance entières, ce qui le rend bien adapté aux utilisateurs Q8. Traditionnellement, le noyau (chanfrein 5,7,11) est de la forme…
'5:  -   11   -   11   -
    11    7   5   7    11
     -    5   0   5    -
    11    7   5   7    11
     -   11   -   11   -'

OU multipliez ce qui précède par 20, pour produire la même échelle de distance de pixel (100) utilisée normalement par ImageMagick pour les noyaux de distance…

'5:  -   220   -   220   -
    220  140  100  140  220
     -   100   0   100   -
    220  140  100  140  220
     -   220   -   220   -'
Notez comme le noyau ne remplit pas réellement TOUTES les distances du noyau. C'est parce que ces valeurs obtiendront leurs distances à partir des autres valeurs déjà fournies. C'est-à-dire que vous n'avez pas réellement besoin de remplir tout le tableau à deux dimensions pour définir complètement un noyau de distance, bien que ce soit typiquement fait pour un traitement plus facile. Voici une liste d'autres noyaux de chanfrein connus (n'utilisant que des valeurs entières) que j'ai trouvés dans mes recherches. 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]
Comment 5 valeurs sont placées pour définir un noyau de chanfrein de rayon 3

Le noyau mis en évidence dans le tableau ci-dessus est le noyau de distance de chanfrein le plus connu et le plus couramment utilisé. Il génère une image en utilisant seulement de petites valeurs entières, de sorte que les grandes images de dégradé de distance peuvent être stockées sans perte de précision. Il est aussi très précis, du moins suffisamment pour à peu près tous les usages imaginables. En prime, les résultats de distance ne créent pas de décimales récurrentes, juste une fraction à un chiffre une fois normalisés. C'est une autre raison pour laquelle il est souvent choisi par de nombreux logiciels de traitement d'image. Le "Chamfer:5,7,11" devrait être considéré comme le noyau de distance de « chanfrein » par défaut.

Noyau de distance euclidienne (mouvement de cavalier)

Le noyau '**Euclidean**' est généré en utilisant des nombres de distance exacts en virgule flottante. Mais pour que cela fonctionne avec les versions non-HDRI d'ImageMagick, il faut utiliser des distances diagonales fractionnaires. Comme la diagonale qui a une valeur égale à la racine carrée de 2, une valeur d'environ 1,4142 unités de distance. Pour permettre que cela fonctionne, les distances sont mises à l'échelle par une valeur de 100 (comme dans tous les noyaux ci-dessus), afin de produire une distance fractionnaire en pourcentage. Voici le noyau par défaut qu'il génère…

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

[IM Text]

Or, en utilisant le radius par défaut de 1, bien que ce soit une grande amélioration par rapport aux noyaux précédents en termes de précision, il présente encore quelques limitations. Fondamentalement, il fournit une distance en termes de seulement diagonales à 45 degrés et de mouvements orthogonaux (X et Y). C'est-à-dire que les distances ressemblent quelque peu à un « mouvement de cavalier » dans le jeu d'échecs. Voici la distance maximale et l'image de « dégradé de distance » qui ont été créées en utilisant le noyau 'Euclidean' par défaut, ou « mouvement de cavalier ». | |

  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]


Comme vous pouvez le voir pour cette forme précise, vous obtenez également une valeur de distance de '1700' unités de distance. Normalement, le résultat serait une distance fractionnaire, entre la plus petite distance '[Chebyshev](#chebyshev)' et la plus grande distance '[Manhattan](#manhattan)'. C'est purement par chance qu'elle est ressortie comme un simple multiple de '100' et qu'elle s'est en plus trouvée être identique à la distance '[Manhattan](#manhattan)'. La distance réelle jusqu'à un pixel est en fait la somme de la distance diagonale et de la distance orthogonale (selon les axes). Ce n'est donc pas tout à fait une distance euclidienne parfaite, mais c'est ce qui s'en approche le plus tout en utilisant le plus petit noyau de distance possible (de rayon 1). Voici un agrandissement du dégradé entre les « jambes » de la forme. |

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

[IM Output]
Comme vous pouvez le voir, le dégradé a un aspect bien plus arrondi, sans l'effet de « niveaux » ou de « terrasses » en pelure d'oignon que l'on obtient avec un noyau de distance « entier ». C'est parce que chaque pixel a plus de chances de se voir attribuer une distance fractionnaire individuelle depuis le bord. La forme finale du dégradé est cependant en réalité à peu près « octogonale », mais avec des pointes comme une boussole, plutôt qu'avec des faces plates en haut et en bas comme avec le noyau de distance '[Octagonal](#octagonal)' précédent. Pour un travail de distance général (comme l'« adoucissement »), ce noyau 'Euclidean' par défaut, ou « mouvement du cavalier », fournit un bon résultat. Cependant, comme vous n'obtenez pas de distances « entières », vous ne pouvez pas l'utiliser avec un facteur d'échelle de distance de '1', ce qui le rend moins utile pour les versions Q8 d'ImageMagick.

Noyau de distance euclidienne plus grand

En augmentant le 'radius ' du noyau 'Euclidean' généré, vous produisez une métrique de distance « pythagoricienne », ou vraie distance « euclidienne », encore plus précise. Plus le radius est grand, plus le résultat est précis, mais le fonctionnement de la méthode morphologique '[Distance](#distance)' prendra plus de temps, bien que moins d'itérations de ce type soient nécessaires. Au-delà d'un rayon de 4, cependant, vous n'obtiendrez pas beaucoup plus de précision, mais vous subirez une perte de vitesse bien plus importante. Voir Distance avec une forme anti-crénelée ci-dessous pour quelques exemples d'utilisation de très grands noyaux 'Euclidean' afin d'améliorer la précision. Voici un vrai noyau 'Euclidean' utilisant le rayon recommandé de 4, qui génère un noyau 9×9 plus grand…

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

[IM Text]

L'avantage supplémentaire d'utiliser un rayon de 4 est que le noyau contient aussi le triangle de Pythagore, dont les côtés sont 3,4,5, ou, avec l'échelle de noyau par défaut, 300,400,500 unités. Bien que cela puisse réduire le nombre de composantes fractionnaires dans l'image résultante, l'effet est vraiment mineur. C'est néanmoins un choix logique pour plus de précision. Voici son application… | |

  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]


Grâce à l'utilisation de ce noyau 'Euclidean' de rayon plus grand, la distance maximale finale est la mesure de distance maximale la plus précise à ce jour. Cela rend aussi improbable l'obtention de plus d'un pixel « le plus brillant » dans l'image, à moins que la forme ne soit très régulière. Voici un agrandissement du dégradé entre les « jambes » de la forme. |

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

[IM Output]
Comme vous pouvez le voir, le dégradé produit un dégradé circulaire presque parfait autour de l'extrémité de l'« écart entre les jambes ». Le coût de l'utilisation de ce noyau est, comme je l'ai dit plus haut, un temps d'exécution légèrement plus lent.

Comparaison des noyaux de distance

Voici de nouveau une comparaison côte à côte des agrandissements. Cela montre clairement les dégradés très différents générés par chacune des quatre métriques de distance utilisées.

[IM Output]
Chebyshev
(Échiquier) | [IM Output]
Manhattan
(Taxi) | [IM Output]
Octagonal
(Mixte) | [IM Output]
Euclidean
(Mouvement du cavalier) | [IM Output]
Euclidean
(radius=4)
---|---|---|---|---

Voici une autre comparaison, obtenant cette fois la distance depuis un unique pixel noir proche du coin inférieur gauche, sans aucun agrandissement des 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
(Échiquier) | [IM Output]
Manhattan
(Taxi) | [IM Output]
Octagonal
(Mixte) | [IM Output]
Euclidean
(Mouvement du cavalier) | [IM Output]
Euclidean
(radius=2) | [IM Output]
Euclidean
(radius=4)
---|---|---|---|---|---

Ces images montrent clairement les lignes le long desquelles les pixels sont considérés comme plus proches du pixel de départ que vous ne l'attendez probablement, et comment les différents noyaux deviennent plus lisses à mesure qu'ils gagnent en complexité. Seul le dernier ne présente aucune ligne visible de « pixels plus proches », mais même au rayon 4 elles sont présentes. Pour ce noyau, les lignes n'apparaissent qu'à une grande distance de la source. Un rayon de 7 produit des résultats encore meilleurs, mais au prix d'une grande perte de vitesse ; une telle précision est cependant parfois nécessaire pour éviter des artefacts dans l'image résultante. Rappelez-vous que seuls les trois premiers noyaux produisent des distances entières, utilisables sur une version Q8 d'ImageMagick (avec un ajustement d'échelle approprié, voir la description de chaque noyau). Et ce sont ceux-là qu'utilisent typiquement de nombreux logiciels de traitement d'images. Le calcul de la distance depuis un unique point sera revu plus loin dans les exemples de Distance contrainte ci-dessous.

Noyaux de distance spéciaux définis par l'utilisateur

Vous n'êtes pas limité aux noyaux de distance qui vous ont été fournis. Tant que vous respectez les règles, à savoir utiliser une valeur nulle à l'« origine » et une valeur de distance croissante autour d'elle, vous pouvez générer d'autres effets de distance très intéressants. Par exemple, j'applique ici un très petit noyau défini par l'utilisateur qui dit simplement d'augmenter la valeur de tout pixel situé à droite. |

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

[IM Output]
Remarquez l'effet de l'écart entre les jambes, qui « réinitialise » le dégradé lentement croissant qu'il génère. Et ici, je crée un dégradé de distance à partir des deux côtés seulement, mais avec une échelle différente pour chaque côté ! |

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

[IM Output]
Ce ne sont là que quelques exemples de variantes de noyaux de distance possibles. Si vous en imaginez d'autres, faites-le-moi savoir. Notez que si votre image sort mal, c'est probablement que le réglage de l'origine de votre noyau est erroné, ou que l'origine n'avait pas une valeur « nulle ». Cela n'est pas vérifié par la fonction de distance morphologique.

Distance avec une forme anti-crénelée

La méthode Distance fonctionne très bien. Mais le meilleur test de son bon fonctionnement consiste à appliquer la fonction de distance à un cercle, puis à lui appliquer Shade afin de mettre en évidence la moindre erreur que la fonction pourrait générer.

  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]

Vous pouvez voir d'après ce qui précède que, bien que vous obteniez un résultat d'aspect « conique », il est loin du « cône » lisse. Il est recouvert d'un réseau de crêtes radiales partant des bords. En regardant de près le bord du cône ombré, vous verrez que le cône n'a pas la base circulaire lisse de la forme d'origine. Il est fortement « crénelé » ou « en escalier », et ce sont ces « marches » que la fonction de distance reflète pour former les crêtes radiales que l'on voit. Le problème est que la méthode de distance n'a aucune idée des petits pixels « gris » d'anti-crénelage que le cercle utilise autour du bord pour lui donner cet aspect lisse. En fait, tout pixel « gris » est généralement considéré comme un pixel entier plutôt que comme le pixel de bord partiel anti-crénelé qu'il représente. Ce qu'il nous faut faire, c'est inclure d'une manière ou d'une autre ces valeurs de bord grises dans le résultat, et cela se fait à l'aide d'une étape de prétraitement avant l'application de la méthode de distance. |

  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]
Ce qui a été fait a d'abord consisté à transformer tous ces pixels gris, d'une représentation de la part du pixel qui se trouvait à l'intérieur de la frontière du cercle, vers une représentation de la distance du pixel au bord du cercle. Comme vous pouvez le voir d'après le résultat, presque toutes les erreurs de bord en escalier ont été corrigées. Les erreurs finales encore visibles ne se produisent que loin du bord et deviennent plus visibles vers le centre du « cône ». Elles sont causées par l'itération de la fonction de distance, tous les 4 pixels (la taille du noyau de distance euclidienne), encore et encore. Ainsi, les inexactitudes mineures se trouvent amplifiées à mesure que l'on s'éloigne du bord. Ce n'est généralement pas un problème dans la plupart des situations, mais vous pouvez réduire, voire peut-être même éliminer, ces petites erreurs en utilisant un noyau euclidien plus grand, afin de produire un résultat bien plus précis et plus lisse. Cependant, cela prend plus de temps à générer. |

  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]
Le résultat est une fonction de distance presque parfaite pour une forme anti-crénelée ou lisse. Voici un autre exemple, utilisant cette fois les deux noyaux de distance définis par l'utilisateur de la section précédente.

   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]

Sans le traitement spécial des pixels anti-crénelés, ce qui précède ne produirait pas un dégradé aussi lisse sur l'ensemble de l'image. En l'état, il nous reste encore à restaurer la « forme » de la forme d'origine.

Adoucir les formes à l'aide de la distance

La technique ci-dessus peut être appliquée au canal alpha d'une forme afin d'« adoucir » correctement l'objet. Par exemple, voici un adoucissement « lissé » de 10 pixels autour d'un objet en forme.

   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]

Cela préservera EXACTEMENT tous les bords, contrairement à la technique plus simple d'adoucissement par flou. J'aurais pu appliquer ce qui précède directement sur le canal alpha, si ce n'est que certains opérateurs traitent le canal de transparence non pas comme des « valeurs alpha » mais comme des « valeurs d'opacité » (en particulier l'opérateur "[-white-threshold](https://imagemagick.org/command-line-options/#white-threshold)"). J'ai donc extrait le canal alpha afin de le manipuler comme une image en niveaux de gris, avant de le fusionner de nouveau dans l'image finale. Le noyau de distance spécial effectue trois itérations d'un noyau euclidien de 4 pixels, pour générer un dégradé de distance suffisant près du bord de la forme. L'opérateur "[-level](https://imagemagick.org/command-line-options/#level)" transforme ensuite cela en un dégradé linéaire allant du bord ('0') jusqu'à 10 pixels ('1000' unités) à l'intérieur de la forme.. Le réglage "[-virtual-pixel](https://imagemagick.org/command-line-options/#virtual-pixel)" est aussi fourni pour garantir que toute forme touchant le bord du conteneur d'image rectangulaire soit également considérée comme entourée de transparence. Le résultat de la fonction de distance est dans ce cas une « rampe linéaire » ou un « biseau », qui peut produire des effets d'aspect net. Ainsi, une petite modification "[-sigmoidal-contrast](https://imagemagick.org/command-line-options/#sigmoidal-contrast)" lissera cette transition de la transparence vers l'opaque. Plus la force est élevée ('3' ci-dessus), plus l'adoucissement sera net au bord. Si vous préférez que l'adoucissement « se fonde » plus doucement dans la transparence, remplacez le '0%' dans le code ci-dessus par '50%' pour placer l'« épaule » de la courbe sigmoïde au milieu de l'adoucissement de 10 pixels. Adoucissement de forme bitmap Si la forme est un bitmap, comme issu d'une image GIF ou d'un masque d'image, alors vous pouvez simplifier l'opération d'adoucissement ci-dessus. Par exemple…

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

[IM Output] [IM Output]

Le changement clé est que vous avez bien moins de prétraitement et de post-traitement autour de la fonction de distance : vous pouvez simplement spécifier une unité de distance spéciale à l'aide de '3!'. Ce qui générera un dégradé linéaire de 3 pixels autour du bord de la forme. Un autre exemple de ce type d'adoucissement (un « adoucissement linéaire » plus grand) est visible dans Vignettes, bords adoucis. Vous pouvez utiliser l'opérateur "[-sigmoidal-contrast](https://imagemagick.org/command-line-options/#sigmoidal-contrast)" dans ce qui précède pour lisser de plus grands adoucissements, mais soyez averti qu'à l'heure actuelle il traite la transparence comme des valeurs « matte » plutôt que comme des valeurs alpha. Ainsi, une valeur de '100%' devrait être utilisée à la place de '05' dans la solution précédente. Pour les formes bitmap, il peut être préférable d'appliquer un "-blur 1x0.7" au canal alpha, pour le lisser légèrement, avant d'appliquer l'adoucissement de distance précédent, plus complexe, à ces résultats.


Morphologie conditionnelle ou contrainte

Nous examinons ici des techniques où les opérations de morphologie répétées sont contraintes ou limitées à une zone ou région particulière d'une image. Fondamentalement, des techniques que l'on peut utiliser pour s'assurer que l'on ne « déborde » pas ou que l'on ne croît pas au-delà d'une certaine limite ou zone d'intérêt. Cela nécessite généralement une image « masque » d'un certain type, et se fait typiquement à l'aide d'un masque de protection en écriture, pour limiter les pixels qui sont mis à jour.

Dilatation conditionnelle

La méthode morphologique Dilate, comme vous le savez, étend une forme donnée selon un voisinage de noyau donné. La « dilatation conditionnelle (Conditional Dilation) » est essentiellement la même chose, mais elle fixe une limite à la distance sur laquelle la dilatation peut se propager lorsqu'elle est appliquée de façon répétée à une image. Un remplissage par diffusion Draw est, en un sens, la « dilatation conditionnelle » ultime. Il remplira simplement tout voisinage orthogonal (voisinage noyau Diamond) qui se trouve être de la même couleur que le point de départ. Par exemple, nous pouvons sélectionner un unique point dans l'un de plusieurs disques, et le dilater conditionnellement (remplissage par diffusion) jusqu'à ce que ce disque ait été entièrement recoloré, le séparant des autres formes.

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

[IM Output] [IM Output]

De même, vous pouvez utiliser l'opérateur Floodfill pour faire la même chose, mais seulement si le point de départ correspond aussi à une « couleur conditionnelle » fournie par l'utilisateur. |

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

[IM Output]
Dans ce cas, le floodfill « vert » a « touché un disque » (et l'a rempli), tandis que l'opération de floodfill « bleu » n'a pas correspondu, si bien qu'aucun disque n'a été rempli. Le problème de ces méthodes de « remplissage par diffusion » est que vous ne pouvez dilater qu'à partir d'un unique point fourni par l'utilisateur. C'est cependant très rapide, et cela fonctionne sur l'image dans son ensemble. Un Dilate répété ou itéré est identique au floodfill mais peut avoir plusieurs points de départ, tout en n'ayant aucune compréhension des limites ou des bornes de l'opération de remplissage qu'il fournit. Pour limiter ses effets, nous devons fournir non seulement les « points de départ » mais aussi les « bornes conditionnelles » du remplissage. Pour ce faire, nous créons un masque de protection en écriture (les parties de l'image qui sont protégées en écriture).

  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]

Ci-dessus, nous avons d'abord utilisé une méthode Erode pour localiser tout disque plus grand qu'un rayon de 7 (diamètre 7x2+1 => 15 pixels). Nous « dilatons conditionnellement » ensuite les points découverts de la même quantité afin de restaurer « parfaitement » l'objet trouvé. Notez que la « dilatation conditionnelle » est très différente de l'utilisation d'une méthode Open pour la restauration d'objet. Cette méthode aurait généré la forme « diamant » interne du noyau, plutôt que la forme exacte de l'objet d'origine. Elle ne gère pas non plus les points de départ « de forme étrange » ou « décentrés ». Le nombre d'itérations '15' n'est pas critique, mais devrait être assez grand pour restaurer complètement l'objet. | _Rappelez-vous qu'il vaut mieux utiliser un petit noyau, tel qu'un Diamond ou un Square avec un nombre d'itérations lors de l'exécution d'opérations de morphologie de base, plutôt qu'un noyau bien plus grand, tel qu'un Disk de grand rayon.

Cela devient particulièrement important lorsque l'on effectue une dilatation conditionnelle, car de grands noyaux pourraient en fait « sauter » par-dessus les écarts qui séparent plusieurs objets.

_
---|---
| _N'utilisez pas un nombre d'itérations '-1' ou (quasi) infini avec un masque d'écriture. La morphologie d'IMv7 ne réalise actuellement pas que des pixels sont non inscriptibles, et de ce fait n'abandonnera pas lorsqu'elle ne voit plus de changements dans l'image, car elle voit toujours des changements (qui ne sont jamais écrits) autour des bords de la forme.

Cela sera corrigé avec IMv7, qui a fourni une réorganisation interne majeure permettant à l'opérateur d'être un peu plus intelligent vis-à-vis des pixels protégés en écriture.

_
---|---
Voici un autre exemple de la polyvalence de l'utilisation d'un masque de protection en écriture. Trouver les disques qui seront touchés par une ligne diagonale traversant l'image.

  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]

Notez que l'étape de masquage supplémentaire (utilisant une composition Multiply) garantit que seuls les objets que la ligne traverse réellement à travers seront « trouvés ». Sans cette étape, les objets également proches de la ligne, c'est-à-dire dans le rayon du noyau des « points de départ » (juste en contact ci-dessus), seraient eux aussi « dilatés ». Bien sûr, si vous souhaitez inclure les « objets proches », alors n'hésitez pas à dilater la ligne (pour l'élargir) avec un noyau disque du rayon approprié, avant de faire l'étape de masquage initiale. Cela vous donnera plus de contrôle sur la « proximité » que de vous fier au rayon du noyau carré. En résumé, une dilatation conditionnelle peut être considérée comme un remplissage par diffusion Draw multipoints qui, bien que plus lent, peut être plus polyvalent pour sélectionner exactement ce qui doit être rempli, ou « découvert ».

Distance contrainte

La méthode morphologique Distance peut facilement servir à trouver la distance d'un point à l'intérieur d'un objet par rapport à un bord. Mais elle peut aussi servir à trouver la distance de chaque point à l'intérieur de l'objet par rapport à un autre point. Par exemple, je découvre ici la distance de chaque point par rapport à un unique point « de départ » (à vol d'oiseau)…

  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]

La distance depuis un point est masquée par la forme de l'objet, car ce sont les seuls points qui nous intéressent. Le problème est que le dégradé de distance ci-dessus représente une distance « à vol d'oiseau », c'est-à-dire directe, jusqu'au « point de départ ». Le simple fait de masquer ce dégradé par l'objet n'y change rien. Malheureusement, ce n'est généralement pas ce qu'un utilisateur souhaite en tant que « distance depuis le point de départ ». Si la forme représentait une île, vous seriez bien mouillé si vous vouliez prendre la « route directe » d'un bout à l'autre de cette île. Ce que vous voulez réellement, c'est la distance limitée aux chemins « à l'intérieur de l'objet ». Autrement dit, vous voulez que la distance soit « contrainte » par l'objet lui-même, et suive le plus petit chemin possible, à l'intérieur de l'objet. Pour ce faire, nous pouvons mettre en place un masque de protection en écriture de sorte que, lors du calcul du dégradé de distance, il ne traverse pas (n'écrive pas dans) les zones « interdites » ou l'arrière-plan de l'image.

  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]

Le résultat, comme vous pouvez le voir, est un dégradé correct de « distance à travers l'image », qui montre clairement que la plus grande distance (blanc) depuis le point de départ est l'autre bout de l'île, qui n'est qu'à « un jet de pierre » de l'autre côté de l'écart dans l'objet.
Notez que je n'ai pas simplement utilisé une méthode Distance normale, mais une méthode morphologique de plus bas niveau 'Iterative_Distance'. La méthode Distance normale est une méthode de distance RAPIDE spéciale à 2 passes qui s'applique à l'image dans son ensemble. De ce fait, le masque d'écriture ne restreint pas ses actions le long d'une « rangée » de pixels, et il n'a donc que peu d'effet. Le résultat est que 'Distance' a tendance à « sauter » par-dessus les écarts horizontaux, indépendamment du masque d'écriture. Autrement dit, la méthode Distance normale n'est pas correctement « contrainte ». La méthode 'Iterative_Distance', en revanche, fonctionne davantage comme une méthode de morphologie de base plus simple et n'est appliquée que de façon incrémentale au voisinage local. C'est en réalité plus proche d'une forme en dégradé de « dilate », et c'est de fait étroitement lié à une méthode de vraie morphologie en niveaux de gris. Comme elle traite l'image par « étapes incrémentales » plus petites, la méthode 'Iterative_Distance' sera « contrainte » par le masque d'écriture. Malheureusement, elle est aussi bien plus lente. Au lieu de 2 passes à travers l'image, ce qui précède effectue 150 passes, comme indiqué par le nombre d'itérations donné à la méthode de morphologie. Il est préférable d'essayer de garder ce nombre d'itérations aussi petit que possible, mais assez grand pour couvrir la plus grande distance qui sera trouvée dans l'image. | _N'utilisez pas un nombre d'itérations '-1' ou (quasi) infini avec un masque d'écriture. La morphologie d'IMv7 ne comprend pas que certains pixels sont non inscriptibles, et de ce fait n'abandonnera pas lorsqu'elle ne voit plus de changements dans l'image, car elle voit toujours des changements aux « pixels non inscriptibles » autour des bords de la forme.

Cela sera, on l'espère, corrigé avec IMv7, qui fournit une réorganisation interne majeure permettant à l'opérateur d'être un peu plus intelligent, en comprenant que certains pixels ne sont pas inscriptibles, et en évitant ainsi de les calculer ou de les compter comme ayant été « modifiés ».

_
---|---
Enfin, vous remarquerez que j'ai utilisé un noyau de distance qui n'a qu'un rayon de 1, même si de tels noyaux ne sont pas aussi précis. C'est important, car un noyau plus grand pourrait faire sauter le dégradé de distance par-dessus tout écart plus petit que son rayon. Voir Dilate conditionnel ci-dessus. Si plus de précision est nécessaire, alors vous devrez vous assurer qu'il n'y a aucun écart plus petit que le noyau de distance que vous voulez utiliser. Cela inclut les écarts dus à un virage marqué du bord de l'image.


Génération de squelettes de formes.

En cours de rédaction

D'après HIPR2 Morphology
http://homepages.inf.ed.ac.uk/rbf/HIPR2/morops.htm


Le squelette/MAT peut être produit de deux manières principales. La première
consiste à utiliser une forme d'amincissement morphologique qui érode
successivement les pixels du bord (tout en préservant les extrémités des segments
de ligne) jusqu'à ce qu'aucun amincissement ne soit possible, moment auquel ce qui reste approxime le squelette.

L'autre méthode consiste à d'abord calculer la transformée en distance de
l'image. Le squelette se situe alors le long des singularités (c.-à-d. les plis ou
les discontinuités de courbure) de la transformée en distance. Cette dernière approche est
mieux adaptée au calcul du MAT, car le MAT est identique à la transformée en distance
mais avec tous les points ne faisant pas partie du squelette ramenés à zéro.

Note : le MAT est souvent décrit comme le « lieu des maxima locaux » sur la
transformée en distance. Ce n'est pas vraiment vrai au sens habituel de l'expression
« maximum local ». Si la transformée en distance est affichée comme un tracé de surface en 3D
avec la troisième dimension représentant la valeur de gris, le MAT peut être imaginé
comme les crêtes sur la surface 3D.



Définition ??

Squelette morphologique (par érosion ?), (par amincissement)

Les squelettes se calculent soit par amincissement répété, soit par transformée
en distance, en trouvant les « plis », ou crêtes, sur la surface 3D (transformée par
ligne de partage des eaux ?).

   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


Une définition de la transformée de l'axe médian (MAT) utilise l'intensité de chaque point
pour représenter la distance jusqu'au bord. À savoir que le squelette était utilisé comme
masque pour la transformée en distance. La méthode de la transformée en distance y est mieux
adaptée, et son calcul est probablement plus rapide que par amincissement.

Le SKIZ (squelette par zones d'influence) est un squelette de l'arrière-plan, le
négatif de l'opération. C'est-à-dire qu'il divise les régions les plus proches de chaque
objet de premier plan. (généré par épaississement)

En général, un SKIZ est réduit à de simples zones, ou bassins, en érodant aussi les
extrémités des segments de ligne, à moins qu'ils ne soient rattachés à un bord de l'image.

Identifier les formes par leurs squelettes.
   distance entre les points « d'extrémité » les plus éloignés,
   nombre de « boucles » ou de régions dans l'image,
   nombre de points triples.

De la distance au squelette

Une manière rapide et grossière de générer un « squelette morphologique » brut à partir d'une image consiste à appliquer la méthode '[TopHat](#tophat)' au dégradé de distance. Par exemple, voici un squelette de la forme après qu'elle a été un peu ouverte pour lisser légèrement son contour. |

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

[IM Output]
C'est fondamentalement un squelette morphologique. Il ne montre que les pixels où un « carré » maximal (plus communément appelé « boule maximale ») a pu être trouvé, ce qui explique son aspect incomplet. Il reste cependant un résultat très brut, avec de nombreux pixels isolés. Étonnamment, cela fonctionne. Sans le '[Open](#open)', le résultat est très mauvais, à cause du contour si grossier de la forme. L'utilisation d'une mesure de distance euclidienne produit un meilleur squelette de la forme. |

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

[IM Output]
Mais comme vous pouvez le voir, vous obtenez aussi plus de bruit, et le squelette, bien que plus complet, est aussi très sale avec de nombreuses valeurs en niveaux de gris. Voici un agrandissement de la « tête » du squelette, montrant à quel point il reste disjoint. |

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

[IM Output]
Bien sûr, ce qui précède pourrait être soumis à un seuil et utilisé comme masque avec le dégradé de distance réel qui a servi à le générer. Cela vous permettra de retrouver la taille réelle (rayon de distance) des disques maximaux qui composent le squelette, vous laissant recréer la forme d'origine.

Squelette à l'aide d'Autotrace

Une autre alternative à la génération de squelette est d'utiliser le programme "[AutoTrace](http://autotrace.sourceforge.net/)" et son option centerline spéciale. Notez qu'il suppose du noir sur blanc pour son traitement, en raison de son lien avec l'impression et la conversion de polices. Par exemple…

  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]

Notez que la centerline générée se présente sous la forme d'une courbe lisse en raison de la nature vectorielle du procédé. Elle est aussi déconnectée, avec des trous dans les boucles du squelette et des branches déconnectées. Cependant, je n'ai pas examiné comment "autotrace" génère réellement ce squelette. Pour d'autres exemples d'utilisation de "[AutoTrace](http://autotrace.sourceforge.net/)", voir Gestion de la sortie SVG et Contours du matriciel au vectoriel.